pax_global_header00006660000000000000000000000064147350776120014526gustar00rootroot0000000000000052 comment=1d98c65d282554ffb6997dba67b0f8e41e22e169 NASA-SW-VnV-ikos-1d98c65/000077500000000000000000000000001473507761200146165ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/.clang-format000066400000000000000000000006521473507761200171740ustar00rootroot00000000000000--- BasedOnStyle: Google --- Language: Cpp SpacesInAngles: true AccessModifierOffset: -2 DerivePointerAlignment: false AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline BinPackParameters: false BinPackArguments: false PenaltyBreakBeforeFirstCallParameter: 5000 PenaltyReturnTypeOnItsOwnLine: 500 SpacesBeforeTrailingComments: 1 IncludeBlocks: Preserve --- NASA-SW-VnV-ikos-1d98c65/.clang-tidy000066400000000000000000000070251473507761200166560ustar00rootroot00000000000000Checks: '*,-cert-dcl03-c,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-fuchsia-default-arguments,-fuchsia-multiple-inheritance,-fuchsia-overloaded-operator,-fuchsia-statically-constructed-objects,-google-runtime-references,-hicpp-no-array-decay,-hicpp-static-assert,-llvm-header-guard,-misc-non-private-member-variables-in-classes,-misc-static-assert,-modernize-use-default-member-init,-readability-const-return-type,-readability-else-after-return,-readability-magic-numbers,-readability-named-parameter' CheckOptions: - { key: readability-identifier-naming.NamespaceCase, value: lower_case } - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } - { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase } - { key: readability-identifier-naming.TypedefCase, value: CamelCase } - { key: readability-identifier-naming.ClassCase, value: CamelCase } - { key: readability-identifier-naming.StructCase, value: CamelCase } - { key: readability-identifier-naming.EnumCase, value: CamelCase } - { key: readability-identifier-naming.UnionCase, value: CamelCase } - { key: readability-identifier-naming.MemberCase, value: lower_case } - { key: readability-identifier-naming.PrivateMemberPrefix, value: _ } - { key: readability-identifier-naming.ProtectedMemberPrefix, value: _ } - { key: readability-identifier-naming.FunctionCase, value: lower_case } - { key: readability-identifier-naming.MethodCase, value: lower_case } - { key: readability-identifier-naming.VariableCase, value: lower_case } - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } - { key: readability-identifier-naming.StaticVariableCase, value: CamelCase } - { key: readability-identifier-naming.GlobalVariableCase, value: CamelCase } - { key: modernize-use-default-member-init.UseAssignment, value: 1 } # Reasons for disabling checks: # * cert-dcl03-c: It generates false positives with ikos_unreachable() # * cppcoreguidelines-avoid-magic-numbers: It generates too many warnings # * cppcoreguidelines-non-private-member-variables-in-classes: It generates warnings for protected members of classes # * cppcoreguidelines-pro-bounds-array-to-pointer-decay: It generates warnings for ikos_assert_msg() # * fuchsia-default-arguments: We allow default arguments # * fuchsia-multiple-inheritance: We allow multiple inheritance # * fuchsia-overloaded-operator: We allow overloads of operators # * fuchsia-statically-constructed-objects: We allow static objects # * google-runtime-references: We allow output parameters as reference # * hicpp-no-array-decay: It generates warnings for ikos_assert_msg() # * hicpp-static-assert: It generates false positives with ikos_unreachable() # * llvm-header-guard: We use #pragma once # * misc-non-private-member-variables-in-classes: It generates warnings for public members of structures # * misc-static-assert: It generates false positives with ikos_unreachable() # * modernize-use-default-member-init: We prefer to explicitly initialize member variables # * readability-const-return-type: It generates contradicting warnings with check cert-dcl21-cpp # * readability-else-after-return: We allow else after return # * readability-magic-numbers: It generates too many warnings # * readability-named-parameter: We allow unnamed parameters NASA-SW-VnV-ikos-1d98c65/.github/000077500000000000000000000000001473507761200161565ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/.github/workflows/000077500000000000000000000000001473507761200202135ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/.github/workflows/build-linux.yml000066400000000000000000000020421473507761200231700ustar00rootroot00000000000000name: Build tool on Linux on: push: pull_request: jobs: build-linux: runs-on: ubuntu-latest env: MAKEFLAGS: -j4 steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get install --yes \ gcc g++ cmake libgmp-dev libboost-dev libboost-filesystem-dev \ libboost-thread-dev libboost-test-dev \ libsqlite3-dev libtbb-dev libz-dev libedit-dev \ python3 python3-pip \ llvm-14 llvm-14-dev llvm-14-tools clang-14 - name: Compile IKOS run: | mkdir build cd build cmake \ -DCMAKE_INSTALL_PREFIX="/opt/ikos" \ -DCMAKE_BUILD_TYPE="Debug" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-14/bin/llvm-config" \ .. make sudo make install - name: Add IKOS to the path run: | echo "/opt/ikos/bin" >> $GITHUB_PATH - name: Confirm that it runs run: | ikos --version NASA-SW-VnV-ikos-1d98c65/.github/workflows/build-macos.yml000066400000000000000000000021601473507761200231340ustar00rootroot00000000000000name: Build tool on OSX on: push: pull_request: jobs: build: runs-on: macos-latest env: LDFLAGS: "-L/opt/homebrew/opt/llvm@14/lib" CPPFLAGS: "-I/opt/homebrew/opt/llvm@14/include" steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | brew tap nasa-sw-vnv/core brew install cmake gmp boost tbb llvm@14 apron sqlite - name: Adjust path run: echo "/opt/homebrew/opt/llvm@14/bin" >> $GITHUB_PATH - name: Test LLVM run: | which llvm-config - name: Compile IKOS run: | mkdir build cd build cmake \ -DCMAKE_INSTALL_PREFIX="$HOME/ikos" \ -DCMAKE_BUILD_TYPE="Debug" \ -DLLVM_CONFIG_EXECUTABLE="$(which llvm-config)" \ -DPYTHON_EXECUTABLE:FILEPATH="$(which python3)" \ .. make make install - name: Add IKOS to the path run: | echo "$HOME/ikos/bin" >> $GITHUB_PATH - name: Confirm that it runs run: | ikos --version NASA-SW-VnV-ikos-1d98c65/.gitignore000066400000000000000000000004461473507761200166120ustar00rootroot00000000000000build/ install/ !doc/install/ # Editors *.swp *~ .ycm_extra_conf.py # Python *.pyc __pycache__ # Object files *.o *.ko *.obj *.elf # Libraries *.lib *.a # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # IKOS *.ar *.db NASA-SW-VnV-ikos-1d98c65/CMakeLists.txt000066400000000000000000000076511473507761200173670ustar00rootroot00000000000000#******************************************************************************* # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR) project(ikos) set(PACKAGE_VERSION "3.5") # # Build settings # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "In-source builds are not allowed. Please clean your source tree and try again.") endif() if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE) endif() if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "Install directory" FORCE) endif() message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "CMake generator: ${CMAKE_GENERATOR}") # Add path for custom modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Generate compile_commands.json, used by clang-tidy set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) include(HandleOptions) # Enable tests enable_testing() # Add ikos core message(STATUS "Including core") add_subdirectory(core) set(CORE_FOUND TRUE) set(CORE_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/core/include") # Add abstract representation message(STATUS "Including ar") add_subdirectory(ar) set(AR_FOUND TRUE) set(AR_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/ar/include") set(AR_LIB ikos-ar) # Add llvm frontend message(STATUS "Including frontend/llvm") add_subdirectory(frontend/llvm) set(FRONTEND_LLVM_FOUND TRUE) set(FRONTEND_LLVM_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/frontend/llvm/include") set(FRONTEND_LLVM_TO_AR_LIB ikos-llvm-to-ar) set(FRONTEND_LLVM_IKOS_PP_EXECUTABLE "$") # Add analyzer message(STATUS "Including analyzer") add_subdirectory(analyzer) # Tests add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS build-core-tests build-frontend-llvm-tests build-analyzer-tests) # Doxygen add_custom_target(doc DEPENDS doxygen-ar doxygen-core doxygen-analyzer) NASA-SW-VnV-ikos-1d98c65/CONTRIBUTORS.md000066400000000000000000000005611473507761200170770ustar00rootroot00000000000000NASA Contributors ----------------- * Maxime Arthaud * Thomas Bailleux * Guillaume Brat * Clément Decoodt * Arnaud Hamon * Jorge Navas * Elodie-Jane Simms * Nija Shi * Sarah Thompson * Arnaud Venet * Alexandre Wimmers External Contributors --------------------- * [avemilia](https://github.com/avemilia) * [Sung Kook Kim](https://github.com/skkeem) * Aditya Thakur NASA-SW-VnV-ikos-1d98c65/LICENSE.pdf000066400000000000000000002650151473507761200164040ustar00rootroot00000000000000%PDF-1.3 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x\r}W2iB6ZˑwmRcI<ʩrU9=`IRӧg@?{!ÿ:+*ȋ/Ǜ}\ۑ,xU}Ei43E\qY]uĤtҼYO5:cyQYٵ1ESYq7Ξb{c+q*w.. Ƙw)WB?w0*J'tu]SN 1*΋w.˱w6[1!9s #읬(/eOZ(dp(hx)Wƞ;Di.Wޠ]DoEA#aW%u0}cD%j\xhDI/^4UMk&,9!q3]9bGXkB+hVMחެ z ¨%Mt",%1ȳ9hK hՖllF;jqF5dEьL$70맱kV=̫ZD}Ds1ވX@^5L\*|D%*7<'L324POah&Kc 3pUŊ$pPVex+ԘSN':4 AɃc63.v2f?.b wKW ?WS3$k= Q^$VBܠ(=mnϰH*46*RH7>x0ьC]F):;f3bJfXF8hin2RÏT=.DGmI$"arh%>i (yZ.ϠK5v/O"Jq)ъEri cru2]AP_8Y Ǫ [[Ihdx+3( %@Y縐W-ypzhm fj PDFh+aSTjRJh*G)rbZI]T  JƮݜ5gI0LrpBr|wl1уM؜YXtNG.@ \˰קnjs!v( :LBy4820דsZQ6RYrtB=m~/+s9YɓO3uVUU9'S"GMG45@)eyQV*$ #n4{s?%1= ՎRO9ޖRAfϫu5U>iAWE5%YlmݝO-7wߺg@v b7E"Bd;.e_gu-j#@g@`8c?uYd]>mUu+, 6?'ϋJ3GEnQwsUdp8H7xKqQO?oD@ a8{ew`}'R]k!f3WHSkQFwc<$ G%pŏ< *5$# @+e8ذ N)`7g'u=)neјnNvPyJ]x`շ 7o5$!IdB"MItkU(p:1-z#'I\RcGo,.5m '|h]_؎:A|16N(yc=8faY7υ}哖Iϴ^ n_=yarObQ |0@"[Kr"80« U͆U&ݘboo&-r*P-䌂,? *2K MXϐk1ck(r<{Ȃ` X+IyS7ljk2m QxPݥ[c*BN%^*A ;f{&Y8Od%4oȏJ~QaQ{%%K]| 0B  8;,{Ox 33gN 8j }X% C8aW6oiÍLIs1ɗ}'Gd>ymƯӌe4a%bK.Pan2 l#Dl I[$[,xV.ltxRZ²W89'"=3^0de4t1xƚ1kpln TjDӨBO2(/( ȀɍyͬS öNfh\oȂ(Me5OpL鿭Ķ-;8LuKw^'дYne+,Ws ѦZv 11kJdfwE@̪T>$]mdƬ~ŝ=CTfxabVջ=~@r O,}f$!JѱK+2(tЀV\؁h҉T2h#;S[3z9'
; . pm+WjKǫ,v*}M<ܟ(t\NmuYk*}1IH*3dG2_IdoĥٖY/g,%,FΛ'Z@=ibb&[=}zZ? Er)]ܙ~>(RAWbr%C^K-Y o4ATݼDH/~3Eޟܼ+3fq6 .wO+qc4)w endstream endobj 5 0 obj 4154 endobj 2 0 obj << /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792] >> endobj 6 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT4 11 0 R /TT6 13 0 R /TT2 9 0 R >> >> endobj 14 0 obj << /Length 15 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xwTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf endstream endobj 15 0 obj 2612 endobj 7 0 obj [ /ICCBased 14 0 R ] endobj 17 0 obj << /Length 18 0 R /Filter /FlateDecode >> stream x\r}W%<8( آđsQTJrUf)=tY_⏟|#gEeֿ">x8Ƶy~EoX*>U|w?|BqY]?V,W~xl肭lF{`6o>Nw8ݕL}%ɗxoWٟ[7Ab^Es=D=c-Yx?oL@.uQ& 4?@uy*zNXǃ0O;Rnu]{jl &@J ,_1^[dwD)րfX|Q Nyn}"v (WWȐdZ`Mb 1Q敆ۭU4ee7 TCIʑoʭ&oƆl'/O.gWc6?\t"=$$El|gcōj ߡ-3%lByO1=R#Q8ڎY/hYXxjDG V`~MsrĬ/=R9܉X|sS -bO7~c[͠}@Jr!/z+S+A׸w"}C!|ʩ@]a0FX`ppw%VgS[@ϰwAmE^ho^WYD\)B+*m'"&Q zo&FZ*L~TABl3icReM߹Qz˓b->[+ P =\,BAMvo ?' #yC}y3w+UMFd7 5@tb 6w:wFJp4J ȼzPll%W"5RWC/6D؆n|ijT9k>O;=_EV\T6+ Vv,Mغۘ y]#Ns4)۲Fp_9}{Hsp*2^]ӣ@wN߳5Fdibt2:(27=t[ =۞I&c3q'Ҟqb|pw@>;˜Xo4HoKB@OyDړ8@ĉN;q+.Mgqy$ހ3v6J.o]w4BVu[Sk|I_?1n6FY,j-`X b9Fw#2>3`Ҙ2x>u}eN狏CtUs ) O${vLN3h [اbmh~hШ0a ct"LT\oMC]ӍYDZMFѺu' 3(ΰv& ==; d&DX)ђ"-)aw2LQP6gQMV;8-00qסZ6l"NfdϜ^)񦥳9|]:*6F< -Ye5㻉yttv<%$H`I8 [4O.JZyT-L4kNw0e h]e5>6k:F&{u1naw~eͧM+1r9>龦{+Fb{I|A 7K-#.wߣmmKPF,m)3sZv.1[?n r _! WO~ݶY$zȁ׸^QXPL1;v2nXWh.~3QG⻄ `^D+lӻ3 `VymɌ; Z>Jg3Jnnoph9SDH&ާ?rk FYp>&,K1ȯ`I?,D endstream endobj 18 0 obj 3456 endobj 16 0 obj << /Type /Page /Parent 3 0 R /Resources 19 0 R /Contents 17 0 R /MediaBox [0 0 612 792] >> endobj 19 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs2 20 0 R /Gs1 21 0 R >> /Font << /TT6 13 0 R /TT2 9 0 R >> >> endobj 20 0 obj << /Type /ExtGState /AAPL:AA true >> endobj 21 0 obj << /Type /ExtGState /AAPL:AA false >> endobj 23 0 obj << /Length 24 0 R /Filter /FlateDecode >> stream x\n}W4(K9;zrw9%k#k6SE9PdMW_E%/V{Щ*&nRW0#'K KӦ _MߧJתD!KRVP:^0iT8YӬ)$QySu>DjG&Q_Ө{p ë﯃qtxh1]wBP}zwakQw+Gۇ+w/` tA<62f'ެwQY72%'b{7K~nrf*)U.L_!6|tJ$?O>'$ `q9Hn}tß`M!e;ƺ;#0-Eq/A2t OG_&o9CX_o"›o-oG 0TZgpqwPpZ3R``pD غL"gMI!5ݢ2]e՛WP;&eV=g #%;Ͻ螭Mm9 =`F#3D4&'A$n ߸C8&&nYlߐhtqIeK4u. SP7_o6zUq!^y5$X lVɢ n=W<5 g%|DwWW| e袈<%C?ߍ rJ.]:V8 !BJ|GrqK"l!eSr + x$ El8"%X@꒨s/8BO*ZGz# B̸_- |=89>ꑚw~pU@dـx >j߂`1>|bbZ)I"uơ~yƥLk9Cp\k sV5]Z$*z/.9b@C)e 5AF.uD٘c Δ? KwLVԱN@ B Ƽ%"#YX E/2gRo2&ggmC!l SV`NaOݰ%O0ՖtD!g  "ǜ`&+ݖH/ ({,rc]0.cWmf""RBwr"G:7:ΫF!h/n>O]-kI&w ,:jkT`ΕB ^cR.^H,zQl#P jK%6PVzmuirXy9Z1p\NTg|6INVY;R#Y\bng a#Xj'0jEx:|`Oҽ?A Das 4$wQqbۄ§}Dg!ÝG&GRb>\N)1"sDOL3 6$aׅǕ~mfd]Io 6;`SQ˂{ [0aF-n$8lʢZ<(ֲqYvQ>"ok9}!Cy XӮoطՙx[bn\RZmv^[`SrFkR"ܣڧ(r+"iuJ!8+;ETm˝hˮi/^Q6pCqc؋Np:#UTRREWPRww#{o^Ame7m1.S pg6Fb侟ּ\OTFaY;+2&dz']ou"8r8U4nqG5ҁuN9ΨPC.ӊθQKJ>z M\|^phiv!Dp !7Tbdå6\9H O|eJ[CxtqUSfrmcPoMi ;@K5L P;h *j/%| pCJEl^Miռ.BL;JDb" g t::P@GBt\-kaZ 4,]GxWpTMYt(t-ԙWК h7KTנ6V:{ay;!vBLj3%d4X$12BPq)x\࿜ßEuZW.8%EH!Hb BJ vhb`fv2wdJZĐ5;vinE13wٓFI:~Ro  :" / nh['¤m&OS}ESig)fe7}4-BVOn].6FcLϻ=lq!928  g5w?bimoAyiI? iqSLZ2-F/Ab'?MgxǓ|rJL:A$ |< VIف071})f)}Np[J=Uյ}MjH7ixC lW7s&<u4tNi9ȠA o.Rx-?m)OjkUq=F%-Z^p֕Գz6bFRc{ endstream endobj 24 0 obj 3388 endobj 22 0 obj << /Type /Page /Parent 3 0 R /Resources 25 0 R /Contents 23 0 R /MediaBox [0 0 612 792] >> endobj 25 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT6 13 0 R /TT2 9 0 R >> >> endobj 27 0 obj << /Length 28 0 R /Filter /FlateDecode >> stream x[kF_aK}Vggۏ>~Kq͏$t~n?YiZ^R?apwN8ܯ$}Ţ|$U{mUQ4+zްD.οas Ï2ෟy{/A7bxD}cozaET$%8sj/<}"վ!߽歇kଞF|za 3WiAsXeZxYvkڀz954svXA[#}\v_ד.J͕2upUkq,0 2yhv3߉2ՈY$I\lnZO JI O a3kC/ZQx{x9ѴRO]"0D%9P&_+'-$EZEU^LAF[KrWDLj1?0T]])q (%@mcCUo׃h-"{$ @'yFAHAl3| -9o@4sO*) EA#͇xeǦ} FS~1}#㏼u"4)N}v%9#-aDiF B&MkݻAR} oAHDQKAprjQF2 !ߓ&hT!!O@߂~-lIdyŒ炆WLrDpJ0֧[|9HfOɽìS"q<(X/gK jHʀ;/Ͳ!·pFw d%@ 'jx7m"?w^B,K:vZGCKVc姇W8COs5$zEV* 1W\b^O/dw!& E37LrGr4vj \\05Z86_ O["P.AC0 H4[Rk/ӫR.SӺ` B)xFG ƦS‰pb4$IUQVVYVl84>bfDH7M=s7>6-e !rvx?6oO9'(8 O!w9h*#=/I蜢!͒}5٣U)P{#'eeW5=DD1F͜C#RWCVF$Х#Uǃ#[`Ԣ"XrD>IY.6l.P,,PNkz9,#Qr)Lav $lr9R]ȖlkĄUqRRR/ZN" +O|@Ilq<;41 dfе<ȷ ݎBՁT_M PѬfg5./E)Xd/zlh\m{a&n`^'@6۹Pz&e6Ÿլ) {0`iWvJCmn‬[N $X0%Ii AS"OܪhNL"erCm)R \.{ʺ_QUl%qY~ئ~!Gg/d\6/(# &bRr7'@c c.oF@·sq<6ٝ7@]7[5gQ%ob~C&ӳ+>).q.N7-yC^yVMrGd~.#'%Q|J򦃑^:%YT~KjW5S@(-S6gJD#ir6]Y%'e~-4) ! TaI GZ, 2 "n'nT}x,kZxI7^xj__̖9> endobj 29 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT6 13 0 R /TT4 11 0 R /TT2 9 0 R >> >> endobj 31 0 obj << /Length 32 0 R /Filter /FlateDecode >> stream xkWHȩD*mNɭq(j4- @tH<ѡ $Sٹ'{VyUC>T۟җi;jcU ]SJt=Kޥw".n>-Jߤ`d=iYBӬrַO͚`jYr$j StE6iݧƈ8=ҟ?wc%Y2 yC2}}"i:aOB3LUIk'G;wT?/Ōsk >|9C \')ėDbd́S{)՟N:M&NФz_\_m٩Ē74^_d 2FqE+GJy3':g hyaA&˻ˢ店,Kܢ@V%ureɋ]}7˴)t{G>Ոsӊ|q [O),ml:_8VѺP(%'Bv>RlXx8 !C/Sv w<9?BvSQb%p Fg7: ?RKd59TM>!TKAސE^+q pƙ(/A?wh! gznsU1븓&Tk8H)tm״0`Ҙ 0HG8 lU5/ȏ7x'^xЈ_sђ']]ϴ jd>z<˵.:-LQ(p.vNnZ6> v_ EU>SDߊ{s.Ỡ"K@f1ۚr=e[b B{j'2eCxg,F*tnGPgVU^~> c-.olFMm4}k}C ut9tEVޖX*w" ?o\9ZVZ,d>LLGxcI-^qmٴ}^UR"io9]]LNesg+֭+<.qXO7.P~hL چIqwMxͫQ_&#K8OHtGꤋ%Zs؅ ! MA l<谾O7@>/ˇGYYmVߴy_mV(Pp@:.pt{!Gx` ,xRxp,v}*gaen+/Hpg"oS kr'zO݃;:s]37*WEٲ؜NJkY} 礱%ۍ7[ǺVa(&Q[9$,>6 i-_+6 r%]H7\jj̦ <:'a7$uCxr_#~~D <\DٌErZ{픴K`P10h[DCiS;7Gn"G@Waij}W[Ij@jUc]p'C/{eLU 什g]E?͗r"= قܦh(u{nEn~*S4V1kDh :oCZQ&I@b={]r, WY)38xKm_m0= U"8B,fFomQЇEIn;u,EeqKxs %VMG(cX Jb8Պ'4$emӚޥ1B(EMiYOw |(҆;W_`Qy8a?.@}0qP]9Z9fJa5~b;K8 I1ZTfR{u Q86Cs*"A0lGV+"Ih_1_@b5(,k4x͜ʼn5H$!4S '$L kϠSbC3#,5w, ,d~&J2fA?ƑހF%bɗu佛 7Q_㣡r`∗oD0=B?g!T[,-H2]J^K'^} Ȫ*&ojKu6WPÉX5Q:λ x3ʚ)p%pze,dELGel|I ?zPn7)``M("jd hB̻Ȣ5AVwV7:ӕ?ĽqZ{SA>?+#:DD]@YDExLrI#X>dx5ryaP/g>TI̊HsGsP.k:4(4-1T3tTs /p`JT4H4n ~5A@VG\ O垼GGJv*R^VŸ+vK0&a*}a&A%U endstream endobj 32 0 obj 3438 endobj 30 0 obj << /Type /Page /Parent 3 0 R /Resources 33 0 R /Contents 31 0 R /MediaBox [0 0 612 792] >> endobj 33 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs2 20 0 R /Gs1 21 0 R >> /Font << /TT6 13 0 R /TT2 9 0 R >> >> endobj 35 0 obj << /Length 36 0 R /Filter /FlateDecode >> stream x[ko_A!BnZQo3J6@cZHmHG%%j<1AD]ǹ^r>zwEO_T2}GIFIէ_U۫Œ%K uMw}*Uި?j׃0C*+Tto{rRqV5_f ^!Nj>k*+ȓDMVɳ*.jo U.Pѻu f~=y1W7 F:빴+8Nlu5 38>G*?9R R*MI;_e xy t};uvn[h;6y<+vs)`/$!dDF~ ~BAlj"ߑbtϞ8*q' ~w`uqV&; c9@*ZJ'Z_FADٿ4+ݷH |QNTY5qYF!0$ 0dD#(|f!(06V<J%fiǖ b{>ȇ:0k90giMڐt'UtLSb9ɇ&?2D24αkefQlxHNĚ3.YP z DϜGP* "1юszYpIP ڋa>i !ݽh[EZV %t'E4a5:{AJ,P|v3b_IP '3 .b#WP?O ,"jqx;B49bYJ?iӃvh: U@YEH@n % = &s A[ PiTߧB}d5Zx'1iS![>FX>tF.ZZf_Tm,0J"XxܵG#{k`Xan]U2 ~p&)Sy⎚y!jn F)25)ӎww4흁d1"MfnS?nIe!:o\I=uReq5 .VIyƾHבKY![V_ES5Z .K|%dOqG~1єg&X뙐gaWaͮ" |ɸ`-r8bu$IJRdH$g]eb>պ6nM"{°(q\KǓY n%5=;;>c|lː{J}ѐI֕Xȶy (TѤ@ɍ 2a+WHpIuongo@Fk+%1}hɡZE&.FbHzn+1dJ9Hɬ$]1k-M$S4MuuSq]+A[{%hqӘrٵݒRe 3=uBa|%Bq f2Ԭ]E@aU ˁ o+fs\3`ԩK9׌.wJ67-P5a@!ZdXτ݇Ӹ6' Ř,cVD5¯eUyx]hXUJT,XP)XnDE9.x)-d'U{wiEӡ I\@}(ҕL> S08OlzѠ -^Tr%:hx&y~27AD~wbOTY 0ɱw E/^& ha'h- o, 2, ,m*m^< 8bKf2` ӔfiK!*y%l'o㮿q vU\[H`[ 8!6 ʇGq*]$ kכfc7`g+jA3ۓ9^Q,4:zO=:AK iN5Ӣ38??5*;m(IhL2:)Rd-f 1y*+ÔZo}өgE߻v ߱WOW8N $|* 9g* 5&d_PtPךSB,#Fs_]Y੮.96Tǝe&@ +$Β I! !fKŖ.hUm+?]1ҡF/lk &g ?H 8B7pZ|4I  ߑ֞N a!qQp rnu{iתj]TW tZLEVA5=T!:}nݮCDesA8rㄫ*e)fXq#Qt#s`@8@P؈aX(8R~kϰU)9(7I3YnדЁ9]!by-eDOޠ7j 3dN as7ћkM#s0ؖm)R#f ׋.bf83r2ˆ5tDjd``<.) q\pb?8a0if4 ͱ| endstream endobj 36 0 obj 3137 endobj 34 0 obj << /Type /Page /Parent 3 0 R /Resources 37 0 R /Contents 35 0 R /MediaBox [0 0 612 792] >> endobj 37 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs2 20 0 R /Gs1 21 0 R >> /Font << /TT6 13 0 R /TT4 11 0 R /TT2 9 0 R >> >> endobj 3 0 obj << /Type /Pages /MediaBox [0 0 612 792] /Count 6 /Kids [ 2 0 R 16 0 R 22 0 R 26 0 R 30 0 R 34 0 R ] >> endobj 38 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 13 0 obj << /Type /Font /Subtype /TrueType /BaseFont /EXDTAD+ArialMT /FontDescriptor 39 0 R /ToUnicode 40 0 R /FirstChar 33 /LastChar 33 /Widths [ 278 ] >> endobj 40 0 obj << /Length 41 0 R /Filter /FlateDecode >> stream x]n D|C!U"6j@k|J=쁙y0,?ww 1%\Jayִ`Ijf֑ ےp@J3$fÀǢ}Er~W_c}cCO=#:}S-"FhLDmI!\CoY;0{m,#D+j|UɬDMC-Z 8U˃u~n4p endstream endobj 41 0 obj 223 endobj 39 0 obj << /Type /FontDescriptor /FontName /EXDTAD+ArialMT /Flags 4 /FontBBox [-665 -325 2000 1039] /ItalicAngle 0 /Ascent 905 /Descent -212 /CapHeight 716 /StemV 0 /Leading 33 /XHeight 519 /AvgWidth 441 /MaxWidth 2000 /FontFile2 42 0 R >> endobj 42 0 obj << /Length 43 0 R /Length1 464 /Filter /FlateDecode >> stream x+)*Me`h``f`HM,` %Si6 @MJFnI9ra5@>[nb|;@B^bn*TĎq Gr qp $>#PVS L  1`Al3gư|K-zb *kt@ ï2`@ (d 2Beyx"@> .+c@PQPH020Q`>ǁ7* `dgcc`pp qtv,L rG endstream endobj 43 0 obj 306 endobj 9 0 obj << /Type /Font /Subtype /TrueType /BaseFont /CPGQXD+TimesNewRomanPSMT /FontDescriptor 44 0 R /ToUnicode 45 0 R /FirstChar 33 /LastChar 106 /Widths [ 250 500 611 722 333 556 722 556 611 722 722 667 667 722 722 889 333 444 444 333 722 556 250 667 944 611 722 722 408 250 333 722 389 500 500 444 333 500 778 278 500 444 500 278 278 444 278 333 722 389 500 500 500 500 500 500 500 278 500 500 500 722 444 500 500 500 500 500 333 278 760 180 278 722 ] >> endobj 45 0 obj << /Length 46 0 R /Filter /FlateDecode >> stream x]n@<,EۑR*Q>Ba;4;?fr|mcsuMtx$\7˛oͥ /]Y&m~0w܎I߾m~6M%IU6v,֗66R#y#fkKT7qsLJJ~(~qކfiU 3_%e!J$x_9[$P ;ު\HH@Fk L #UJFHMi#AI72p#[I \̅ՠ lm`.m0j6\X ʘ fY sN@Q9FOM֒o; ʙ0j_\T/qH4+NWAU~@r oWE&hU54GxVxTe+k_.Ծ\=R~\KaO~(# Gj u b,ߤ A$I)1[PQ\b(, &Ap1NKmA #ZY9RTIˠ8%ڪR}Եq;F7DogD{C|3q9T endstream endobj 46 0 obj 643 endobj 44 0 obj << /Type /FontDescriptor /FontName /CPGQXD+TimesNewRomanPSMT /Flags 4 /FontBBox [-568 -307 2046 1039] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 447 /AvgWidth 401 /MaxWidth 2000 /FontFile2 47 0 R >> endobj 47 0 obj << /Length 48 0 R /Length1 55596 /Filter /FlateDecode >> stream xy|U?>Nӹ7Ý!7I%$r SPL 5%aV$aPPK:k֢VMxA+裶NN֡O-Z'ZjQ{>7y~޿ϧy}Y{Z{úˉ $%_Y${nXϕn\ѻru@=Ẅ́<Ԫre¯]\V# Z\9 !4ٳfX{uUc'GEo򤬷X;m'\#Ɏ1X@~I4&BTʼ]CȥţË hZ,ϼ~]_U"u_Wȴ&uJzDנ5s ~k`G;O!>p A 7"ށ+jppd[9R'W6>)eaňS.#i,5˕Gt^|ɥuyIXJF`qA…d&fY,nVfj="T6PXrҠ%}-KpCXBE؁ i/|a1m% 'P2̨5֌Z!t!"Vsy B1ZMD19Y(Q2dDc,f(!#!J ~ϵ%ڻ o?x rY*K*746UADVuflq57ƧGGJ% Fxz`onafB8 B#Cc?AOP2a1 Wכvw!q7<9M-F؅ `콸~;ۧԧP w#Y=;>#"kB݅||>^}BBlW#EEVVjj*JM8,f?e|zYbdX4;8 뛌s%MFf#bdJ1P/T2 `<`Gc_8)s,@ Oe}M)LՇ}u3G TR1Tj ]/iihh.LTi5~GhZIkyZVLK 9Υ581%(HDŽQ-V:w MY[I)ִ&{qjB5mVwb7)מY^ŕNm?D(MlkA[SG%ԧs$y-JBShC:R7ʮW=SRwmy1ϔTfoMM뿤ckZ^tX_żnj8ߍY/n#$Ȼ QVF[xgL xi j 1/ +cwb3}0fe0(yH+C>4>CJ_5CHv(}rCr} c}}S_@GliPKWe9BW 쩁%~вJv-YS-oN- 5y)o5-ڇ˛PwsÛ~^k^`SV{ZZVz>%S:by:y .WcJ;Yw\EKHBSRFN>MM DʛL65ٿ31:LkPm M!qbok׮CXn8uy+2 ԴR -)eCvvqhqdqlqMhMdMlqNhNdNl1i5D$K}!_+SeHk lM 5֯#ׂlqpMpsp{pWp_P.i?(7 -(&ukĬ/[d-ft:YצS6 '$FaXPAW!vwSczUJ}T}L}B}ZjYݦR;Իպ֥I'Mi(ӭE0Z%KuOXOmquǧ7R|9G!T!EPDk?#A$7 C#F([6st`C.T$k*'vȥsҖ siCSÍUyMfF[ |*Jep<2dmJx6Ƒw֭сQE~mеڵ؅2׎'ۡ&>742!?"Dx/3+{Vu9 e.˞d,!w]$LNqYrÐȝd:y#& x := v6بG$~9MZ1N 酦Y}q+9{T0sI ٣FbWo} g %P/#/e%LG5}]Z^N&䷴ F{ Q== yBrt=3&GY0UIL"n^Mޤt gS1 '3br:9 GOkUJ֓Md3%8: 2K#_2z&>ڤ:.`%S09=c߂U&i^SZO1^H/+vz7M7L?RZ*[,YHVah(yH i^kaxVuSD̗AثwchPB/k1l`$!$Mΰt{;l0kPAߑzv-=ʞOIj'=~I O{p/إ.V$?V]xOf7R7Nbx7ƫtffuqpQ%hw>I!?*GVe{y"{4*U"`I̷j/Q~'];]o!o@t$-;tHL|lS c<4:/!L3r4H!go.~cu@R'$aA [ R.rEw @׹VnHF@~ !Hk{!@HCiB(z4~ %2dW/[mf !]|p˺}kXseZb\(7N0nښqDEyY$VC]NVToHfѠi5j(%4˟vhhƌr^uk])?}OϯF7z_zʹT72Kȟz9OE#[sß:/P;@[쫚)oIM۰j󦆦.+/#Cyzdȥl!jL 15SPsK¥Ft/K] :RtВ&̸҅LUnROMi/Mi-%+nXZ}I{J-)KmN6U0nzK;nv_k]>BGHȴiXVnKO-)777:mn ;6[q+,6|ι!yzy<:@W 0Ndd2 g!'@u M]rUz 8֍kᖹd /jL0%&15 oz/i$Uf R%jY<`eWc_ C241ǩ[(%4`jeU̷HE nRR=qެt@zTN ==5~iPo_= AĿwJ]Ɛ@~:=8Rm^TH+SrHmUHZҁRpC+C2۞"`bi)ut&O7^߽\v&j :ЅE89@ Kxt0: e:fw(] `Wۅ::0P.;z_4:>ԩ|Uԯ:kQ1Sm.DR`F@wSEf2Pů^ŚL~kf2(|(Bonk`]o[.nTh&[`=F!T s 2 4B\?vB]3" ,CIJRh+xgwx;!~ pZ2(ۈ !_IKpf1'!1V]I:bAހЂ>GڌFc PfmDB0`uiA:0NAv" @.O5v`w,"K΀UUMŁ iq:&&S8&TdRݥ?5c&@J4z\M-y ܯpC$'=Yk./L1vuJFj^f'UUn#vaݫ{q tmj(m>S Tq8FhqHd|Z l^ƮgiW0umfMd;oh-^QQ_7VeVYKR X0|803(lW iIIيZk+XŽ˷?yw]p^ZVں⻙+y)C|H/9]yK~ZSq=W$l]cAGFZ+9h z\+( Ӵffv4AavNZjv>j59&,U*-& 5P<X٧hk)+g/ no7 tU㦭]rr.`0O8x:z|z\Ȟk`ѓ@J XXGwnSiPC\fǠNscOKIBnhjzV+2*!{McԤ#}+kiX621<x BRz A-ߣR Ӛ{FX8֑ON t*./-iGgL/?Re)(*j&N@~%5(OqF?['xY$<6Yex^zB;k:=.#r-**4hfj~Qo߲-_]gYg}P}}U/~nss[a!QyMo{l1ap԰rbiJC『BlT˱* 4M6/_9_OS/ g~ǓsЭrbflf8gRyZ8ِ @'S}ؾ\/}bѽc#~3SeͬuuLu6;L [%յϙ@޴iN$zh^&H*@f(4RS!PCHM5U ՎIj *kk />{1+F=習|2]ҳp2_Fz{x}ߡ~cȜ > ~_I7?D' u:`kҵMӷtdB\UZ4666U<>>\bߏfjK֑XL"ivrX&BA%Ѣ4u#܏Hƒؓtl3< blbXtَk6i'WG8: 9H>wTq9vsS}Xξ5Ouj+hYT@8 jU恍%%kF./^Bt3z8_ƜKַqH'J@z!nIa8NlFd0DpN"@!MmVU-ӓ׳jp?`hk˼^bOkz!`r@j'K:*hӆZ5qt,@TxafU=eݸiMEYh`[V?EE9}s+q)P=֗kxߎIƕ+]ېwzݛ#j@6mLBC-k|?JQ3F Up2_Q٪wRɥ]KO*Kd#w&Q`vB1La[؊S"ŏm7z8 Feeq{Lm]Jr-!rmų8¾\C(ԁli{*3?Ʒ0 s{,pmUc[|.WV^-Oy+Ӫf.vхUln}9HgdGď} 0'JfgOCx6dK̞wM# 9CKUBn ]Ɨ ;aGeT"NJ^U#QT0"(mnQ%>%1X%hXgNsRVӵύnjFՍjq, Cp#"d7܃sri~ic斾*jv]]z`o !ȷ8Tc\YñbL4 Y.ZTpw!+|F¬7r}Ft៫\Ojböhp~MCZ)qm,4B*6U4+S0ۡͦ!3DyCv"XV־`~. FW~3| …+ۡəu>o.B.G+s:Wk{i}B:ə}qw:a£T5V4ܯ?h9\WWsVT_|`RUMhC8A!MQPhŸ A'Ii+"|FɌRiIE^M$8˕NG4sTZ٥5F)ϫԅ|iq\nG௫Djx2lVx\ӛ)ÅJ"#Wz ^ge& tJ ڽWJqiмUj>CCO/_~y C{{>|-ә[]@"׭3tEnH4.mUx,%H^aJe B<{9lJfHixU֙q c-i4H6eSI0=|Pewm\@|hVSniǷBۉtJG{UM)ۡkyD;;\Ox=%z|>C[z#=E:-ڸ~ b@X}P*S ?%K2;& 7:玾Q]w?/>ؗD"f{{%_{EHD-F=@D| [ eWL."mU9_׹}I&MjO7o/#敵j.UWɁ2Dou!ry͑m7ᷪމh0+%PrxEdEeKxVBXT|7HDO{wkIge$39 ^wNoVir}[RTRu4] ε^M7nn)VaGsA* 8J)#5q_XL(*]QIf+b1e; p:Q)<ilőӔT.@nM{M(#Xe1 :! "3ZH"K9Rg 06 6Af7yѼ)K Ug2Aww Y$:zw ~N(jnNV XաK5Nh8"Uј=ZEqU4V t\P*IUExU[)TAԀKѡ ~wlĝ` ֤5 uEអBStei( $i͇H%p8)˓@MU%ܯU*q JW,9[Vaiy/b~׌^Y\]em<]lw%[ = E'\FxW>ZCW Y-━к>;+fYTp{ɧ}:ahgm<0S,^T_R`EKWN U9ͳa8 ]~nIr3V nv[(0*jt/-~9xfR Vvmj1+0WM~[ߺvé{o|ioE}Ɵ~o{Uԫ.Tvp[7әw=Zp/}{rFQ+ @5+-T]xMʥ6)҅BX  k[Qb,q(RCN㱽d\["P =c|+I&GLAGRQpij⿱r⯝Z`#R j$REZ[Y̑!G4d8e6G`SТE#PB+TA=m6|Nlc$B[?3˒F'E<DƐee@[dj̊d 8HdГg^_?c؍C 'N`bgIvrmWU^{=З'6{mV'Z ܤ?Z+bZ9yDٟ "S_fۃX`u4U̫Xڬ;lce|lZEyIx( fy mQj iY2cTљ5ˠ@s~dWV 5_sN>TI j?s2}E+'"oHtrL\#*+[|S.q ٜ Yc˪256=eBФzok>pܶoP(Ğ.9 p>yΌn6.fFDž'e|+zy5]y/ZOl]Qfh DՑՙgȏ҅Ph.sГH:tljG9WӠAp\:t :$<e 8@M$WLbHhk?*?Q~-N=;rm x>;*kr |@(rB&kR (aI$ c2Y=G4]yWn 0 ޖBRd$E]mזD]>Dҧ .NmԸ\r>W,lhj1K$ UMweM(M/d5&UK4UFO]2k:bbFh{ 'bœ!-lj MdBP^U یlHS8M岄Y9dV+s 1Fޝ-O<8g:BKB 7ex+Ww&+,3I$vdqHev&.QUޔR>UʼZ{1_Pe8(ɒ1z JG%^::3)~M"i"X-NΚ̅Q;+ ]8c\~菳bOp^Ė3Wѫk2e U>eJEg/XOK&J+}f`3;LjZk[LʠДe{]8e '@~Gf]R?S9E o4]2-.2:B X4e@]Z!/n >zbD99Q?:t<S-ogsLV'9USe~ %U2cmwZsfXp{nFnc67F9@QZkŻ|jAP1VY 7,};蕚̎:rnRyٽs}ާpL2Q{850%R1N5t}ubze[v:9-)kBQM j*i qRDRo8js*W+뒃d}K>rOT+G+Ǯcl?p|a,5mhmA2U'_|NҔ}.g Xp-H@(gK(:Pd i%v>1w89lL6-6DE\8Pvʕ?^op+8EtF>솉 P`'`WƾɥIH'};+!A"n%kl:[.| .ajO:Gp9K|6Rr'ՁO G(Lj/l(=@Z3qEڒXS+rG$H,,Җ=\*D\võH/lXG|[Tg7 ~y w@Mg VZu;LSQbV?!{Ye`Њ ڮ>/PLjj5nC\U:\NU'(+iεXRR%Ao"xF1J;KNI'O @2HE)ZC:SQAGC<#b D{Vv .E L u rh2ILguXKTgCfYE52&ԓeQvMa9DXF@ QvXRJuy lYuXਃư%{+:ȱo⤉g5~}Ml>s%a_KY>f_ŀ7s~`ܸ{j~cInl7kĩZc1p'pkYP 3=+5~aK#˹t` >Wϕ`)Kh+R!'˩!j ˉMD4&}&/ _V5,),ũF!jSIu3+,TP"UvU8V!TQEfNQ&loY^WS9<'GQq3;DrC-s'" #MwGb1nDŎ*q3F?89o,yBŠ?gj>q"  Wz<maiZB Bpoakˑy7.};T'j+$;zA蓐4 \8?o|\SŞU̸q^U:~IcosÛ>f{ZK[f β.'$Jz+i횻6Syt wkf~DLPaVx"x/5KtVk_~"}ʟ;G1mgdY6JT'(?CEYGQ!v|6#bj_aztNQԂb['sSQ9 Y)X7 o&+ xlH798Қ}.=U"s]BϓtpӊS f^eŎyA 9no:ۯ8ڭ~jN=l𫖏,oꦮgp̫gn?L*m? xx`#V[WcNvnU(5H[χ/f)gvbE"*Ijַֿ!xUdn[lF>U 7[7C+?RFor#pI5O_+\@Db. n3 ɬ,-)kJK(h6>ii4 w^%4C6W<7u;. \ZԐaHTXP[U8VV `QA B>D,PR'2ƕ&r=8C89(8Fp:yRkH;v_yP"UP8鯬39l8ߊtQo.՜8]=HuIɌ ^_ɍe2=>˲2jDwrvqmjp1 ~;KWLjv3pet8yKVK5U~WrGg(lIQ_xuCS{ݺguq61J3ɜt4sMv'}ͻQT?M`)a ߹7bscjK\l_X\R*)=Z/ӯ33m0z{}6Mƭ[㏊VIVcXT{jF}%%pWĤ#MQ % 1WU;>1QyI%՗\RhIK_?$YoWso䣉gJ_?]_pv k} ~llZsy=萫i5L)n(5QCtzdlq*{pI4$K  ;ZY[m}·AT"~rk(_-Vr'3!l D!@~ ۠wwBI>Yzg/Ҝ׿ߒ?}oVOGpT@~Yz;nFR2=.v%w^^+VS`F?rG7|bŧNVɣ0nYϝ&c׉ůKXfjy~J"'T|3TZ fU\!qR".)hAgり9һL-brky-H$ !$6$v%'ł8f#,yqG߫nˆا 0{[H9 GPsB)[DB$Cpߔs>eF"9W@ǚS(g5~ՕyWx&Mud|}CgSLK"3[hwz7] T8s@}[k0ګ=5\^5ڊ@`0/52f|W+??=?ͼT7pΙzp p@Yaya ^> ۷HbZ4{ÂTYRCF}>Dxb/zX׬+56VU];^3֒***jdz6{\/01f&藽sV7YRPHH6f66:kK.> i.Uݔ%]|6TtvED唒 6,-4b(nK qe ΄nR Ďwo_ س"/q] @ {Mn?毢΋zfu _ Ҝ]bQ>eN:|_%@3)$8}9>L;6ɪ{ XlGK!]*_kU=NTdp$ӣoGg:`>,Q1 ׄDtcxʴ6*8|dZ'/w02]j6cpӔ5/LPS5LILpT9  Aug$i FO0hZ`d0M:sHf"I"f"udSlERN_ h1Zͯ&?C6H|〚|p`IN{x64qpuز(V9X4OrX (/6䂗􄋻khr>z0 ) ĵ@D<_3#,biy,Ծ c< .֋1/#__A}:0d7-:RWai@ĭLx*t'aTV_ǒ %cZh6d2~l b=Ka+b\"ddfnHg۰%h`=NkKǵ0֫k[9sRo!RFzom{秥l~&@g ~1c"D=Wk9(7l.zeVctSbsC++-X KK K5UՋkaiزֆIl@=VLvJ L0.xf Dk֘lclfi'GN([c1 "] "1Y_[>6:CgFmzfWHfk>b ,sgj4 jbi#?}iumד/RЃ-$묯 `Nv9=,ΉN cS,^b؞U! fCf?WxVNT+M׭3R<,>; ,-4qfm-4gf1 9 Ph Șm&hְH<&߁L3(>kOhYݹ~f|}&z\?Cq35ugP@y;]_.Ux43o,V_fTؾp[LO32fcz{)~xՇ9$jmOI=[uZ{TR|Zο,+@&M4 לF)D>@_s1s"nDKy,SPnu` [S&XqB i%m0DȎd&mmc:l{ {Hy4hۣ:>~*TG>טWlbzLPVg+5OMJ 88ԡб!솎;wWsKkkRk:i-͛= TL}3͊%ڌ!UDYш9b[Z1Q}ȶ%:RjUASYY (&ns 01bsmtj_MQXp[WS>UVRn>XF?I`CrM5KC e(2v{qd ]sS/U7KhK`GdDz~3S&"Fzd>/rOBo0P1AY}ʊm9vd]X\|v>3]W)V$yMiԻ^hj>y h+HhP36Ç4a4TO3F^_QH@iUWs+It?57* u"Ho }9q^|62y0 VYoϘlHؕr9s+r ϜDOQosLS=*WGJbXV q8]nH|-!rZ%rǮYqPҍP-A;pƶ !GH&岚'ɬ=JG=7&'_.(/ͶǻEϥ̣&GdSn>}usPM5Դ<_߶t@kn[d m% K\8{j]֏V> Mq- V=OA vWk^5pYhv"wvW7ٍAPKZX2TCې{aL*ڠ6(Ǩ0LGa6*c4+t#뻧7]<HSj!#d&ىQ˞ʊYUhS\d&uVlJKH,e$6 tݞ[n-! iS %9=L-͓i+OTgX5dI?g&o_o)e6\5X{cJ:b-=Ԉ {lc6,̃108(-G;nQda> =M@%,}RPqhuSqfTQ /a ч\bm=9 j? ;d F6yY6lCMFF}gjѷp}zl>$u!" |bw37ܞ(U69VwY1t)vU V/|`n[Vf_Vtt(&/(5Gg$`} GPF<S6}9D*N OɇB3zxC1xlq NDŽP^ҝ>4G|df8~(Kr 4t g1&XAdՋw dy$$鼍0ӏ msY& 1I;J?G~[yєX߫n4dp!÷,B X|yǐ7 F4 9uL: 8j`0aGPnW.sL8Xv|kN:9$c4%zS|4tklZj|rª&TCBe9!=f1- ڪ:"5kD }o6 LP ';cyisɕf?7WPɼl7ӟ0Ң*L[Ws~:вt2*%yT1O.í*"m')c^煟 4@@H7tjJ<׷wizA*0^ iutuLti\O탁uL=.ڇ{+C# h=N'B!xz/DIuˉ,d{VyKާO%ʾ^*^I%%6_팦SRCd¿3XS)G+ $J9i"m'l}]W3^aB؍+OE#3PWTN;Q1%@Mms_~떩-OlᤇHɓ[mzӚ+ oYߏnT$Ҡau ?P岦`BV?d"FVP(&pĘL!`ٗ>ww;˳n[:=g싿_y9w,Us7ޙ[p#Μ@\u[<-W9'E3:Y$-x ׅpQ *B{LqR.pGW:K pMJ2 :/,A9L_$g!^f}bbcqGKp[s#8C$]GT`)$3jɣ<?d1ׯ?ڤ ͗pg.\S%_aqxdUҪUQӈeEa2'/WnU&J jI rr*yzSة>&m,޼}ȓX">/ٌe?k2+[R(\u Ixa3uoC냨42w[ ,G WTĒ3Hd9KQJF, RVe2gd)ɮtyT&vOHSxty_Z@ ErtM?;ѭv#%swRhmTSGLJK?* 7\qoLc3?Wk9Hn3}B(CqlܗElifgYHH24MlfdK&@Xb=xϫ͓d(hЃțT(?o;-p; EsG \kaf[4^l|8p(듚$+~($/͹O}@00Ͼ(|.A#vlKMNNWwwX8 Jbܗ|KH -NL<2iL6J0kEیB &!v0oaCL"ʧ].!";:יNTτ؀ I1.?2(Ld`ك=?իOPa$Qd9k\7O6 \6P y_&cBAja@O3f,/p"UzX&|0H|WH+AqUFe\:rpAxϞ\z'^L*ZMҩʙLaŵyz^o/^"ab:^1Lj{׀b&ěoBcvs|}ٷ|scvw>XhGs>:ǒ.y~c뎯;.QJכ\gzز{՝Y-px.}H@ &"pٚ;gW.ìĮ0L_+)쫅&Tez1*#6i-扺̢y7[6 K\6S0?հ )l\}C 5eCXfiI e6vv lިWtm ~O/- ",0 >'5$D(共dXXpҞH+cGC:sFu]mni}5fs{t ~ r_47}/`'E$x5 ~ưA6b@6ni88*֧' ׮]$v)&? h-'K[O(-zrI/;E9KQԫ$IVU/C4A*eꕔ!Eu2J[Df%!mɪz, 1@:;{: \%۞[]cYиL M͘0ܱ,&\RZy16_c+W=:KXڹXeK{5q 08cU/ /V蘂q';H=G1ɩ$\pǜ&Wh f3N,(Rnִ%-eaŬ.. C+7Ë̓|d..(ẍrt;R3ȧaN@LH=/FE5|+YGw}t%'\|sr2Ub;?k]6̿x㼞=v6}ywg{D3l2/?5|n31vɖ+>7^`"ٙL_.sm_Yuv^el[Ơo`?e{ŧϓ~dni9!Ym^#$(G{39}LW.]tt RưK o#/Jqj^Ga xDqwd~C̆GhTK :6PSұZ%]WzyL *݊e2-3<&)yZ0$;;F;:FE&;u;Fm ?dҗWz&&$#sbp `'܁bJpP"+[0gkH%GhRt8&^1 sJ>ꭚZQgٲh,u5mz_ y,7LNBd_u2Sm˴Ǧ LJQ.b>ygtJ2+ uA,$.&n>7 8x"K2 2G._08Χ /i/,xK a|/3WH%QpyjsjT͘h3ĵrᠹkn3{پAstnNc9s|igL/8,cCC@ G4r"2\1m.- u#5vكd(L=te->{h =P&}ތã868AƞȰXf"+s*cR3QEyWW_k{̢V Gz0ń(Ry;Ki]z 4H/3N+լaG&8qDzz&Bl8FCc 4\92|O:mCeaN*7LR\QML )X0[:j8 ɍ_ޖ2݌q^jY':gjopܹ@"X|OSS=28vebza.Sh[&)GL14N JD3+)K%~ 6NgyV@iG&An[Zn'h%ZJ^)e K.4P]O@S0#$;hZ/WQ;iH~\x JNN=\[A\$/~B6iNZJ ?8y84,07 #aJ̨vH6DYa ۄ_<+ˍp#AސܤlvoN~Q8ǭ|uuI<j&fck|R5 DmɯK1b\*UL%h˦5$|vy{ܕp&͗F9[pèH^*Π}z<{ w `9-튻ZSr S\2`w.*F?·OH*o[6#^%$J6Y&dҔ|u'TxTFMT&I5&c(§&̘]>^ٛҐ(f Cf]OR- LK$z PL*TdSi+78nٛz Rv{jz_5 LazhD8oͳ39T{@Lѓ5HEIZ1u mm~k6(6>Xeɂ,T# . D @wåO `STC.CH/M<2^%!5BCI[cP JL:Y͏/[R9K>8oes梅߇+˦+ ~˩Fn>yv_'2z{3X&S.ع0NA m3a!Uz>I-'6s|@J:`'azlłֲt=K]d(`(~gkl>hrQŸ0 qhTGNe2diXq੠5a&6Zha=A&7܅%{1!-ncń9L$, )뇡꙰a;'&y*nx4/Ɂ I{Iw|d6Zi^ʖmtPtTu#SfkؚT' [) 8M2I+FVJ΅n>*%nؗR7 -uKU]6M|@OV$ ӥK׬nM)DpTpa 0({ZL-yN\VDadywX]]gd $d,nx1]Zs^LHwu;I*iv' `i1"i Tdq8JNjEPTP+DqGwC$16c XM(o~SKrbXu` EhhKΐ"'>r.74^xO_0<3Iv CB ]+G{ )\1p\/{iUD'9kι]>UVBF^ - aSt P vP'}x66m[7nYWw#p94 F)H)A6p`znqZETpm;~i v~}v|o75rsӿӟoӋ OBCzZ:,tyw?jL4 yDg 8]{9\Hp/(gث`vQӉ %4=CyEcm'<_ Bemfו?@z˭[|Sz76kuM=FmBB 慒O |B'zJQt&"ypՙ'dqT ]QU&4;֡ƦϩSM@.kY ddpR-ūպd{r\-[TVu`mUYRE BWu*(k!>O~c?s3(^ۄ%Rhq/FDL0l D3' @sH΅}$gu#$yس E9o%׳# FKx 魘% u/}u^x?1ߏGc~ sX6P7-^gY4LUw1|'CAPb<:,slNyNCIrYo#;/0uh chJ7ž$NOEBEלpI!;gͣdɟq~̞}3fzw7[A*2L9#vsKݍ&1aئG%EzxZ8>WG[a #CfKriQنv$.yr=o=Pßy8)".OE5 澨|6c%GǺǻͮCL g##MuUW3mfy}Cwwø<2mQq Hϵ= uhϤ?yJByqyy[v>~5ë1{ҙ,ɪtb=(9Dh"0%Ї hm"6+WPw"75ph@nscfsQטkeҷWCߩp.Kygtpp1$/]L}BGtcQ><"ۍ*ETϮ` 3L5H}[y7G}̇p_E:zPzˉXTYJD2-1Ls餂)F5 *5#~J HtNSii{1ៈLD'b}!(%~t5s_/O ja-<&7DrkR ˍ 6 m;UZ@  ᖡ+$a[U' 4xQ9vs5 ,QtSH8^O/nP,lQD"JMWmj<(Cys`h@'VAs(:Hy0rv!ĉTT>o\):RW?{usB@BōO 4Vm?r|g, Dy/Gs+l1 e{ˇ^."3: NsS:k]ߢ, 3ͣSh}HL9u8\B|I^gƠ׸?Q1|)]v=sm27kLܱdՄ7P8S.Y1^oXx^5r"n^KHf 9|z|^eu?S]3XxI]'¿3eWGϢ ^!&N`ܭ kVهjzH$c`dhej@}̑ Q9 2Dd> ;Q&ƹ,-@K;#TE>J׉ Z꠽.X'ab@=q41iE.oOXuYKd** Va [`UBFH|u**ɽvkkz;hKpdoâh#^fBJ WicT @o T@ fWBUN3#!)fE^ Zle]cO IwٜMEGiuٲY;?LUu?s´g6UR S,k)Xs!M]fM+͔gZJ@r#>—we(g5 ~[g-܈R3cӏ^.wRd[(rz^r*xZYa6yruzٷ va{.IU*ō0:Qs\#7|8pŖ K2B̂²Ҹ2콅{٧Åg*e+:±JR0Sm ZRZ0\iev{s=ֻ vrۈكG(`JНPt* rBp΄+N$ସ{/NS5]-V)S,H"Y> (Y,gq Bp1RA3Usx`oM2)z䪢- "md^LSBV4WA"qΦ&+CHkp ÿ L zPueQ5dIeb ~&W7䘖};U˓`(2llp 1T㫅]|.qUt~],+JюIIm GNNɶ) q"@m Hfz Nܑ-CTKi̖uMY 4z8%"SINZgW>zwjO{yj{¯3!:3D;2 4nJs@B[$`R鬆B84`+:<,mCqO(d%_Rӿ(_ӿdy; T0/^՛Yǵ!^8u ^ #/{p$d='zrë:n1!deBܐ3_f;;;yb7t[]l;W@ŵXiJݟk= m˕ sK Kzmm6礝Nár ɥܮrRI\ Vde`ĺwx`͚y ,]MPdPkHTF2@)zNKa.#~LuCp]zvա;UwhGYa;R,滇qדּ$eÒg}zkv_wrjva[5 bWPF,gRvtD\F7XT^5̠3M kSa#m ~JE^]^ɃYS=: .ۛ:'ף+Q]_T'L`Hp;YR'{n2z鮟ރ<آob$YA' GQSs!? H.>P7z!&5G}퓰-ކ;s6 χ=3عqKgm$(k>sJ$ +4|[Vu>W=ޏ2Vc ["֒/f<Ժgzt5"WD)bU5|s-/D>_zJ844R.3nQ )w̐E G"vهʥ7@JJ{j-es,)jNmn]=IW+) pBNjxj CݩK/"ǥDgdž2ey 7D(;u>[Z0eS'J>AZh6[JʌjAf/YQ5c1aY=z8làf+rwy%?7Ɲ #:7V)^7w]+Iʁe|nuYi5\r͉9ʬR碭#~̙; O~]vCķ`1"Ÿ5 ߤX}3pL`28N=}ƾtCJg6paBBotH^$^qK~C$Flvq$^fz6u+۲i짏.&?_~hPUmw41 :Юelfu6cՑ b4\$P}+\<2B'OzQ2CB9/vnj{-B0!3EIW6eC.vŪe2PnPEMwMiogn j+geNF=x<0wxūV\+ʛ/}he+l endstream endobj 48 0 obj 39156 endobj 11 0 obj << /Type /Font /Subtype /TrueType /BaseFont /VTCDZV+TimesNewRomanPS-BoldMT /FontDescriptor 49 0 R /ToUnicode 50 0 R /FirstChar 33 /LastChar 77 /Widths [ 722 722 556 250 778 611 667 722 722 722 778 944 667 722 389 500 250 500 833 444 389 500 444 444 556 556 333 333 778 278 500 556 278 500 444 333 333 333 278 556 500 500 667 556 930 ] >> endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream x]n@<,EĘHJɋnBa;n*uq>9Lrx=Lqxk]O2׏v'{ם%I>.[<avU8`䲭7Iᆳ}\~,],_st>zv{d_},Mf:Ť$N>lWWy*@D0ša "f'1k "0SͶr "T {1 #B8g0^>(0N0y_Cp(ρ55XV&kJZ3Y-T%Dl5XRY%J*U ɚ[B2QUpRKCҰ {A!%sP*>ڔ+$LT͆g@ =q:;g+.qwp-` ӆ endstream endobj 51 0 obj 477 endobj 49 0 obj << /Type /FontDescriptor /FontName /VTCDZV+TimesNewRomanPS-BoldMT /Flags 4 /FontBBox [-558 -328 2000 1055] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 457 /AvgWidth 427 /MaxWidth 2000 /FontFile2 52 0 R >> endobj 52 0 obj << /Length 53 0 R /Length1 28700 /Filter /FlateDecode >> stream xy|?<\ɺei%$ےeo^_8$;9 $N Bh ZR m'\.G-mғZJBK~by\}_zx$|ڙٙ=#oxJb$Ä'/Y:Dt`͛Bc] /)? Dv[WQBfU^tE!O֭FA!O3՗lG/^|>ڇ,|r|C^~=#CWNS/ZR$,!t2`+B yx=D<rՕ;.|xv*Kc>y|@tV~|7AQrDyD&@%":TE*Ш4bT3+rW#!.d#VmKx%DVsȣ `])5h>L#nO5k;b0U3ӳ-Fn׫lX F`b^ldZtTGuqSE0c fo#i]*%mC؉M!Ujv '*Y%tXpJKT*C\,B'Hw7)?P`ZS=hIs.RCrBb$>nP"*JJ OVT+?;"80?>b-?#Y~?Cz C}T7bT h ! #d/beXF\6L!1"x{0"?_?_#feXa}4>! R (5+~}4Qnῡ4@2hz16W-Le~_Khuܢ9~I#7ћwQ(E)_eW9t㇉ uGkqڜS{2 {R=֮@m(7T8+Dన".R!Rb>|HKS96im2ĿEv!܏ /5d[5->_+!<(zDoa3F^4#7\uQgo*kg&7a,zs0(+}YJu#&[6d#މp#-;, Kx;bV[)YjxjM9#ʜM&T֜?XFВ#| к0B8 {Uy·8HqMtFqmmm6NWkXTRD!^=/Czntb,m횦7{ioߥ٥厴G'G o珴o?smHx/tIU"M6:mN^%i 4|Q6y2r{YQՌijNh>֨{5!ͰffF#j6Q}ɽE݋8aĻ1G<+v R2^%%!d) }vÈw!$pߣ]{8R E9G(E&EE`<'YJB\Rf c?xڋQ6ʈ{7rRAKߏp'im땜r{ܽ#%ܽ8x$@PzI xr"BMqX{rS x{#(=dG"_I))VVE> f^%Şci{rW  JݦrsQ\0R9ڋ8o*~%/Tbl̯HG$sIxc%~_ȖQg$Fa19bc|0b~W]\elQLu$O[Ṷ'1QU-`\"$>Od2e{Qz^NTќR=ĿBj~xMnER6HZ@ /$Q!*>#Xv2q*XN|txz݉;M: ށV5e@M=7&PR6[(q/r!YBqiNqVY2'ZьVbsĩ*Xf ƣϰ59sg9Hb:Q>ZL@Siڠ֡Egt:Fq:#ctℜd&CXvA,p,FpTY;Yډs YY]})f?[Nf- e̗FaޢZY,2kAM,Y{g!Bi zmĵfo5N_Ap+e)O2kl5KLge.tw2w.>]h֬4#Z4#= f(_ft?"bfhj#ک4oQ}0`2K}1I(&+:Y%&uMw)>6]K Xy[GMH!-f_o"O2YhK.Mv\"?td$DKe,1֊R}U۞?|Ï)ZQh'- QXXўhѷO͏N)䥗$UVyoP)y)2 MlXKGNL%䥛a(J{=uUB):'oQ=[  Dx/?sz-k&NE`BtP#wtnZA/{#%t55$Y.L*7:\f.vNx\C~M/"OG l:}8Gz'b Bnr/@`ͦ*M.%a;2A{K/98H_Eb2#Ws$,#RډGI鉗'AmjćD&j(Eurzh-I,PAc-Atr30-mr hu9c' v_3A$?"/tIm$Hדr/20DߦG)rҋ\wzIo(d!hx nZ8顿G7N\j!r|BTOMACͮc.I\ߧubm$ \ +r$Gȟ)Ói}ң}n=ý>wª7Ui/?0N$'j&vM7)eIN`Z2EM5xw\$c>`3PrBGN 1}g9™ ->^OU[>~Z6{$QZWːL ߍd3ق5+~0gɑgkuN }i2N~+3A{[^I7ӻCK%5=Nߥڹix^|n%r)|{)/6^KnB&~VW֪^Uo>]=CD\}{_TT}R=SfT֠B5YSf_6ɧJs7~}+-zfF(o3IZBT]J)bg_ȫ|~-~)QNަOp?<@g{cv+Sr;=ć6r|@N|9_Uzkx͚&!:oUlw -SytMɻ Uy/HkJF@?UEAAC|,RRo⯣gvl[s7Q ZQ(4Bך7ɽd'9;I&T!r\1UO8z\B.&=! .Hj%E{$Mp/V.> -E[H~\6RoVR?~J*r9vvO4F.Z )c!.H'!R"Zr+!Ȑ_@1Pt,r.vR0ut%+p}J-ۄ |v s 8DŽ2rL{ɿ-c: L ]p A<7ܰȢQ.Hy~DwuAZU ٧ 1Nt.OCoOMB289j\MH_}^mjH8w:6SS]UH'e%XTCb0Py=nQd Vd4uZ'HwKSC`VOOKR0 hdC칥ZK-WWKR%B-%UBٟwIQh^ҷuI)%ݣw)i30u{Vwt0ԝyT9o4tJ+ r`D҈T- V$8ww~xŬOz%Q,LVH+.KGw֖ĸ]Y'=_f9_;&X;{}Yߏ>,:c*;5zY,C)oUx]\i5ߎ,9gk8ɇ&N_whǂ>)mKK;Ȏsx5-ɄJ,zNI)Yj9_,esfde`f'XXހ EY}iVЎO0@:KNhb'U2<ղtl2M$h;cMoJҋ]ߔlo2d YC0 d5c8e5ß|L~y\3g\EݫRP?k4kޢPIkB=[P&S٢>ϡ8?)/ 2}*?+F:`RBCSBo'i)|kd-L;צgZZhꦂ1U M1c2)$H;A)1 6Tщ÷SoǫM[tM;iA_\`G(RB$209N VjUJ_RVh2Jr2Ai? $C/Uj{PLW(..lCjЃ'͹a\sAB+X XA4#h89"] (ۧ@_%<Xi$+2P֫zd.%kn&ҕZ$0veS1^!yfy,AYcڲP^`CSƥĄk  &%ڙ kmВQ\J|IKtj 6Y;aᩡFi2{=`-OU{ջ5^yk8b| z˥ ~`i;]%Zs~1G7wCg#E-V&_K:K(ZO ZKxuK,m'z(UOR822G83Bڐ" ¶"Z"gCYYM>1zWqw`'rvA+WQ!HxӋ"ɄmQ۲^p^0/i;v h vnܱ+^pVftzmEW?]9z'4,2΋+s;GԩoZUwqӫ0"$hCerl2+ι;LLWfWT[WMJ%.6;ΒEfii˅,+}D"34F~ƐR齦ypvƬP4R$^deKҌw6-O^R#>5Ǖftjpuֲ]]Jxc@O7w^W{Xh-чDhk9 VACJ8NX: "thɂk]og+z=*t܏s   썟:K?Iҁ$hs\55pmMu]]-KmI#E٫B53՟=qUwy,V:u{t8=(<.o$GdQku[W'&opSmc]bΡnaa#NAau!iet1iwr8 [>3qjambAԜz7 e\Ҳn_Aș zÛ K1G8 sj41j!6ߩdR?)7N2 V6H]]1Z#% qjX:}E.Mgm=+?矜ؑ Νf{T 7^2˷̏<䥳nm|h,mhl_I!fњf؍V~'uz=ǎ:=s1i]U,?ΰk,7~YwnYMBd3)(Eviů_?묬$s>5<ޒήX62(ѮAY["`۴I(=wՉI4t8 80jW-TЊ}?4i748|Z.\3s+=Nh~pʦS?aMN"R s=M>cڌ3xMsSKӔ&, p<ny5]?3L40%QG!.?f3|n52Qu5&6L HQЩ<-dAij[3)P+nDk!ួV:8'@p G*Wp~%3\vD0P:gh^W9}PLGڙN3u[o }~`Y r՞m5Ӗݹ8]0|YJ*BU  Fp:^GBB ]嫉VYK$exkFj$<s6pξB*z9*b1S^+c,#t[a RL%Gu"qwL/IPFXVie2)N +_ }<WTHjXU?"ӡՄõ_Hp5W5+hlZi(9~ ];b|~97Ovw{#)Y5&55FbXv]޴hѥ-t|Ou]=yJM^C51<7da1f@&_WuobZZVVͶG4rߠqxxuFU jqfyƢVmf`'( c6E&[8tIFm8cjE%Vh =^i#ԩ9`q}pu)"ruިXc6acuzf!F4ňK}9dk2e&1mKavhQb{H㻷m v=?/7֪/߱y3te[N}.kk؎WEȧ\* T y _r69Qq3C}nnÝGG )l`jd[~ء6Qg2LІBO$WUNy GM8(HTCLZ3q pwkݮ{VL2ΣhڹZ N>q4cmu; I.lKM.IOnKLޟ%\C].kh E3gn SV#F0Ôذ1 } p節I8Z%a||$ Mnl6G56 4Lf iҸ$Ն^#U$㦞UK2Msulg>Qm;RE xӦoeϋ9-*RQq,;&ЋeAPGr&nJI3&vWkWDϫF5.ij^vcB}O|w_L;Bې_ xGeJ;"|#dQcɠHx"$o衧8[+ jzz3 (8r8U/ŽS8x<M^Nld S92`F݌ZC ՈDKx6f1b 4 %DW.wRKi7cNKq5Q_|f!_m{aי6i)ԫouOO,mUֹ$Y͂_whr^+J;Oop:7 UT-Ff|kw&$5ic :üμf^)9Ө`svYb;j+ʹWIj;E%50)1Nf]EQa};es0Ejfl҂Y\Ǖ3j[;KR5+nl뢤k!g6{SXLt%67d "ܚȃ$6$v5pΕ7M` R} W]NCձ:l)l/'hoO hDbjZdu@i4_%@<)  Feo;I8}/-;T ygup_cb4'/nFk`ȡ/f !7,띮LCP,MW:8QU~o n.` B%7&C 82W$@@MÜ B6NQPbғ2!%]]-= ԜR#$Ň=+^%>K^?۽]Q16/$8^ny׳vp̍ [LBqU(榀NHk h# T={ aM@+tGj4tZ-.UO=hK|UD%VZLO=U 7 lĪCIAe2I2PT fmW]2AGEElZzy2EX"J&rXk= ÷]]]Sa* 'T%HQ§F'<,MsAa[:hͮ7>-64=!6M欎6_G͜ݦz^?Lт-РMdȾZ#Unc5#g׮š@U=An&ƣ4wݪ>p9EE"\ 1 3 'ꢻ o+~#W^ݜKGRfsRqX^,pfkem~{Uo7fNi6UUŗ6{7v[x3gઑV:GCKPG)K`ZCa֯5̪NOz23)3-4(qTq:cԩCʭAfĨCL %-* X&d1iщӲy&뽜}4GnGD^ ԢQhwZ.*Ó` ̤g+.λqݯwq;ҹW{υ}VQ/1Ͽ?V;g?_T-SPf\@!Pl!Cn"PS&"F$+줢XSd n0 =vbGlOI0qAg*G$Bά I2gVcnEnN#9i*EC 3َlz\~Ţ1^mm|٪IY*I][KN\P-4TMile9lՉA *Mq$=y |5sC*6Zf(cIK+v&/x#obeE+[7ݐI3Ɵj5Éϴ IGq2?*(Y~0ܑl5K*۩ԨXxU[9uyyv 5?hMof؃-dZJJW\z:J8r+U.~wMkz茡m"]"NxUe\[9TR]c7AW'u[E0[O9S CKnjc1KR$@%4FA+SڰȍEL[I9U }Sr8䞕6{\'HC[8fn;uԳcMlǸXݱXEEhGɥ1 Z)"|hj$঍܏G*xgcwZf0Pщ[:Vұ Vr$NFS"urʤB;uj6l6H}=춱GM!A5y#a(̸J=9+T<,V3 v4vBt Lh``% W7`g1`_̦|*O/hp8C SS+$&a[LՇ>;{K#k^v|d/XaAlwKpeFU!ZnR{vO-ʘYڇSOL8u,FX_RZmvfL>*ݷɞڇ:S ~#z}U*ۺ5غ}s}zՠsnj8#Əiu ndy,Y^RD35fJMOU5_j~QǚS5!ڿ.sn25fݬ_5uzίb}J7OwteɌ#zx{|9 >-BÁXr<]V**Ο_b_Z 5D5LU; ne10v"ΥKg9LxRqx#f{37yJhWY& -˖i,b^Λqwǽ˜pZtEm afC|zӆeg´1-`oBS62kLdID8.C$y ΄@a}1Yb8oH Ab%M %_cd tzH?KaAZ zgİMK;Q~jc[6\ZhIp#0wAjo󭃏^u77h z0fFU]ItϧU֭T=4ng4=y&&gL䗀I%hhTO_^ѿ?qZs BqBq~acpwѓEOaǁa8o)>_p K\ A6y> =q6<]eȒl#m ~-紗fo_# kXWk'1x49 3{Dodh7/BnhaF)pjK0V642(Yּ@cʱBu̯[]b+9c?ܣ׸be$`Fx~X5gE[shN ́:I},ǀccsgC3unNuҧ"`dԻ.ɸ.jVl8#FKAc%t-$QD j^A{+3,/GyÓk W$‰?_1>;p ?٠d V0b.xm u;MvHÅ}(:v̎f#lOu/mY=/?bN)nx~Bמk^ߨwh#a):pv]&rj(gDWlAIjW"4*j^PTISؐݖ6kZLOi(NÖxe0,MEO6~g6QAG LtA*Mæ]& Q& ޕi"a07@'`A'7)"IoLQR3l SNpLkfr]3/ '݁Q6Yn_5hNI;BqMO]e;PyƖ <1>˺ӻ7:biV۲ DzS@Id ~kyaL0Zc7,{ZuH+;Pq.F_i4u1OL_&6[u7$I=iG;2]6h-3M;W|@V*K2M!rz2U=Q^%;F@n)x9]Gb'ɪimw<`q sMӧ{F'NИ6U{6FQKӌ^6Dֶtv\ PQ^-;Jte5#f'x"JҲL9SwG˹-=P؅htla.-OgN)8etx9ҸLODY g fB1;Z0Khd(~zo(@LJi3%Ԝk  UX~#T{ݾ0y.L+U%t5u\0[L]Jz*+W{tv9oJp3\[FaJMq7F5!Z$^HbįBޒ]aj#vR,⎫PqGEܶ9*XBDg̥2u}/m=[b1/3 wU\S-#!)"t2uӝ0ϙ1R918U`[p'cAM`6 vOYVm&P(KK0{EEWt浭AGEb@7׫Q.^E:q㒋:U?Q+D"^Y;zTX;~ %I0HOlea`$(+Ġ,aFHQ}=k6N]mgUe2 HUdl1 )B1חce/^m{yl\):#8j!X;U,LкzoTzSTTzCvDڣbF"IKh$*rJr3H #*N$m$URUz*`PiTMKsi0]LRHL;=;}lj:%*Z9k2u//{w|?ITPRR/_$vZ/5hgk D2'ڹv>h;6}?fLy;A\'!.1%g q_cة\bgX oQh0՚xqJ]m R9)XPq?w7*7Xg,*ŐN Idtp5eLssussc \\ӧY6ld'ׇt+,l)Znj *NJP[<&d/O6;#.:V3D5Nz6e#OzpK/M~#Hl|1$;puAo\syzo+Iu)㪮p[[ް@K_ MNykF,Ƿ#_gJ}n:P 6Rl4̏ /aRC4u[kCQeL㗆e`nSJPao*JRU $zMcpMʯMM~SpsWVU+T~Se"ML)O(/x'%+.xQ—*1U:y3FrQmZFb6϶r&6PPɶ [=>x,x٨I )qv!^lNTtũ NsWN<қjfwc}`MOguyLc\^پ$Fmqٹ;> $= g ҒFKQ T[]ײd]QF?6?$4넶I]41U-kclv|~<ה͍ !,wYxoZyOuk%tø *eyH}4n`:Ll{3a:ompبtK1 ~ " ǥ_J6TmEQPҔr9 .1 ͝mvIB\[S<$ɾ*"3!HP(BD^*EKd>ؕIhAa`4%Ȇ?,Jz);j$u$v9 q+Zfhz0n)yfKP?R}ZRnNiNBZ$I8[iZ=IZaʎw+WJЛFhhC$U^AjѪͰcw'^ ') ^ڭ_Z暷7"& =% }]Djs W>h^ckrM Viyq+Ƭ|.r u~ti5scmT>8{S+}&vt M; Nй[j7ȏBI;9{/phxϏ;vz@.?X>ڀKrÝ^D&1[NGl(i(|QWҀ ?XX XȪvRsYK1wO=K`I8=ssF (J]lyŎۺ9Uq-iTx <#=#B;qBĔԁ˷9 <n餬̅?Ip'^ E#! W?D[94:B1 n@\_LP"d]V\mՐ Xx r2"F [uDt5%uN|ڢ-1=9;o.rMϼqG3!)S\GK糼O6|/_O]\i^5BBWaD&d2 $Z/̐9XM/E"A{HH_$|/TDzDҼ! ' X-oIV c2˒7|93gI*9q4l[|Ecd+&B w0A#oc~1lxBxo#Btf v5[}M[Ǧĵ{#4ަ3f73e~ 'A.\ppӀ+[--WW 1*eE.DH,hTӕDb5-~=(Myuf|l.1Ծ<2UzR鰩f/?[9Ω+=+PJ'45RFB)jt Jb0K<|n?] * "F.µ:-DݨA{!$HiDyCgO}:Mb/8SFЍ^뫝{Q0D(]yvv3:j{n\u͖yjŸxqYH=ԲsYfx^nz=37{cA(RcچT:"` J_ .R~ˇW7SdX+AeҭS¨%Wbe0$#N@얯|[R!9yK6reV^:?y刼[6o(~pڔP,"jO۩6k^_C +MʷsqrQL):=<'%%/&K\PCE W9$a"l9Gd _˄R!XZYpZ\ >7f)c!O+eY+Q~h$A' {o%˔<^+ Щk/:)Jm ۠> endobj xref 0 60 0000000000 65535 f 0000091183 00000 n 0000004270 00000 n 0000026360 00000 n 0000000022 00000 n 0000004250 00000 n 0000004374 00000 n 0000007231 00000 n 0000000000 00000 n 0000027673 00000 n 0000000000 00000 n 0000068392 00000 n 0000000000 00000 n 0000026528 00000 n 0000004495 00000 n 0000007210 00000 n 0000010820 00000 n 0000007267 00000 n 0000010799 00000 n 0000010927 00000 n 0000011078 00000 n 0000011131 00000 n 0000014670 00000 n 0000011185 00000 n 0000014649 00000 n 0000014777 00000 n 0000018834 00000 n 0000014887 00000 n 0000018813 00000 n 0000018941 00000 n 0000022598 00000 n 0000019063 00000 n 0000022577 00000 n 0000022705 00000 n 0000026090 00000 n 0000022856 00000 n 0000026069 00000 n 0000026197 00000 n 0000026478 00000 n 0000027010 00000 n 0000026691 00000 n 0000026990 00000 n 0000027258 00000 n 0000027653 00000 n 0000028877 00000 n 0000028138 00000 n 0000028857 00000 n 0000029123 00000 n 0000068370 00000 n 0000069319 00000 n 0000068746 00000 n 0000069299 00000 n 0000069570 00000 n 0000090933 00000 n 0000090955 00000 n 0000091026 00000 n 0000091079 00000 n 0000091102 00000 n 0000091144 00000 n 0000091163 00000 n trailer << /Size 60 /Root 38 0 R /Info 1 0 R /ID [ <6f7a951f79e1d0cadd3019496534a7f4> <6f7a951f79e1d0cadd3019496534a7f4> ] >> startxref 91327 %%EOF NASA-SW-VnV-ikos-1d98c65/LICENSE.txt000066400000000000000000000337771473507761200164620ustar00rootroot00000000000000NASA OPEN SOURCE AGREEMENT VERSION 1.3 THIS OPEN SOURCE AGREEMENT (“AGREEMENT”) DEFINES THE RIGHTS OF USE, REPRODUCTION, DISTRIBUTION, MODIFICATION AND REDISTRIBUTION OF CERTAIN COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE UNITED STATES GOVERNMENT AS REPRESENTED BY THE GOVERNMENT AGENCY LISTED BELOW ("GOVERNMENT AGENCY"). THE UNITED STATES GOVERNMENT, AS REPRESENTED BY GOVERNMENT AGENCY, IS AN INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT DISTRIBUTIONS OR REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, DISTRIBUTES, MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED HEREIN, OR ANY PART THEREOF, IS, BY THAT ACTION, ACCEPTING IN FULL THE RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT. Government Agency: NASA Ames Research Center Government Agency Original Software Designation: NASA Ames Research Center Government Agency Original Software Title: Inference Kernel for Open Static Analyzers (IKOS) User Registration Requested. Please Visit http://opensource.arc.nasa.gov/ Government Agency Point of Contact for Original Software: Guillaume P. Brat 1. DEFINITIONS A. “Contributor” means Government Agency, as the developer of the Original Software, and any entity that makes a Modification. B. “Covered Patents” mean patent claims licensable by a Contributor that are necessarily infringed by the use or sale of its Modification alone or when combined with the Subject Software. C. “Display” means the showing of a copy of the Subject Software, either directly or by means of an image, or any other device. D. “Distribution” means conveyance or transfer of the Subject Software, regardless of means, to another. E. “Larger Work” means computer software that combines Subject Software, or portions thereof, with software separate from the Subject Software that is not governed by the terms of this Agreement. F. “Modification” means any alteration of, including addition to or deletion from, the substance or structure of either the Original Software or Subject Software, and includes derivative works, as that term is defined in the Copyright Statute, 17 USC 101. However, the act of including Subject Software as part of a Larger Work does not in and of itself constitute a Modification. G. “Original Software” means the computer software first released under this Agreement by Government Agency with Government Agency designation NASA Ames Research Center and entitled Inference Kernel for Open Static Analyzers (IKOS), including source code, object code and accompanying documentation, if any. H. “Recipient” means anyone who acquires the Subject Software under this Agreement, including all Contributors. I. “Redistribution” means Distribution of the Subject Software after a Modification has been made. J. “Reproduction” means the making of a counterpart, image or copy of the Subject Software. K. “Sale” means the exchange of the Subject Software for money or equivalent value. L. “Subject Software” means the Original Software, Modifications, or any respective parts thereof. M. “Use” means the application or employment of the Subject Software for any purpose. 2. GRANT OF RIGHTS A. Under Non-Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with respect to its own contribution to the Subject Software, hereby grants to each Recipient a non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to the Subject Software: 1. Use 2. Distribution 3. Reproduction 4. Modification 5. Redistribution 6. Display B. Under Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with respect to its own contribution to the Subject Software, hereby grants to each Recipient under Covered Patents a non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to the Subject Software: 1. Use 2. Distribution 3. Reproduction 4. Sale 5. Offer for Sale C. The rights granted under Paragraph B. also apply to the combination of a Contributor’s Modification and the Subject Software if, at the time the Modification is added by the Contributor, the addition of such Modification causes the combination to be covered by the Covered Patents. It does not apply to any other combinations that include a Modification. D. The rights granted in Paragraphs A. and B. allow the Recipient to sublicense those same rights. Such sublicense must be under the same terms and conditions of this Agreement. 3. OBLIGATIONS OF RECIPIENT A. Distribution or Redistribution of the Subject Software must be made under this Agreement except for additions covered under paragraph 3H. 1. Whenever a Recipient distributes or redistributes the Subject Software, a copy of this Agreement must be included with each copy of the Subject Software; and 2. If Recipient distributes or redistributes the Subject Software in any form other than source code, Recipient must also make the source code freely available, and must provide with each copy of the Subject Software information on how to obtain the source code in a reasonable manner on or through a medium customarily used for software exchange. B. Each Recipient must ensure that the following copyright notice appears prominently in the Subject Software: Copyright © 2011 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. C. Each Contributor must characterize its alteration of the Subject Software as a Modification and must identify itself as the originator of its Modification in a manner that reasonably allows subsequent Recipients to identify the originator of the Modification. In fulfillment of these requirements, Contributor must include a file (e.g., a change log file) that describes the alterations made and the date of the alterations, identifies Contributor as originator of the alterations, and consents to characterization of the alterations as a Modification, for example, by including a statement that the Modification is derived, directly or indirectly, from Original Software provided by Government Agency. Once consent is granted, it may not thereafter be revoked. D. A Contributor may add its own copyright notice to the Subject Software. Once a copyright notice has been added to the Subject Software, a Recipient may not remove it without the express permission of the Contributor who added the notice. E. A Recipient may not make any representation in the Subject Software or in any promotional, advertising or other material that may be construed as an endorsement by Government Agency or by any prior Recipient of any product or service provided by Recipient, or that may seek to obtain commercial advantage by the fact of Government Agency's or a prior Recipient’s participation in this Agreement. F. In an effort to track usage and maintain accurate records of the Subject Software, each Recipient, upon receipt of the Subject Software, is requested to register with Government Agency by visiting the following website: http://opensource.arc.nasa.gov/. Recipient’s name and personal information shall be used for statistical purposes only. Once a Recipient makes a Modification available, it is requested that the Recipient inform Government Agency at the web site provided above how to access the Modification. G. Each Contributor represents that that its Modification is believed to be Contributor’s original creation and does not violate any existing agreements, regulations, statutes or rules, and further that Contributor has sufficient rights to grant the rights conveyed by this Agreement. H. A Recipient may choose to offer, and to charge a fee for, warranty, support, indemnity and/or liability obligations to one or more other Recipients of the Subject Software. A Recipient may do so, however, only on its own behalf and not on behalf of Government Agency or any other Recipient. Such a Recipient must make it absolutely clear that any such warranty, support, indemnity and/or liability obligation is offered by that Recipient alone. Further, such Recipient agrees to indemnify Government Agency and every other Recipient for any liability incurred by them as a result of warranty, support, indemnity and/or liability offered by such Recipient. I. A Recipient may create a Larger Work by combining Subject Software with separate software not governed by the terms of this agreement and distribute the Larger Work as a single product. In such case, the Recipient must make sure Subject Software, or portions thereof, included in the Larger Work is subject to this Agreement. J. Notwithstanding any provisions contained herein, Recipient is hereby put on notice that export of any goods or technical data from the United States may require some form of export license from the U.S. Government. Failure to obtain necessary export licenses may result in criminal liability under U.S. laws. Government Agency neither represents that a license shall not be required nor that, if required, it shall be issued. Nothing granted herein provides any such export license. 4. DISCLAIMER OF WARRANTIES AND LIABILITIES; WAIVER AND INDEMNIFICATION A. No Warranty: THE SUBJECT SOFTWARE IS PROVIDED “AS IS” WITHOUT ANY WARRANTY OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT “AS IS.” B. Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT. 5. GENERAL TERMS A. Termination: This Agreement and the rights granted hereunder will terminate automatically if a Recipient fails to comply with these terms and conditions, and fails to cure such noncompliance within thirty (30) days of becoming aware of such noncompliance. Upon termination, a Recipient agrees to immediately cease use and distribution of the Subject Software. All sublicenses to the Subject Software properly granted by the breaching Recipient shall survive any such termination of this Agreement. B. Severability: If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement. C. Applicable Law: This Agreement shall be subject to United States federal law only for all purposes, including, but not limited to, determining the validity of this Agreement, the meaning of its provisions and the rights, obligations and remedies of the parties. D. Entire Understanding: This Agreement constitutes the entire understanding and agreement of the parties relating to release of the Subject Software and may not be superseded, modified or amended except by further written agreement duly executed by the parties. E. Binding Authority: By accepting and using the Subject Software under this Agreement, a Recipient affirms its authority to bind the Recipient to all terms and conditions of this Agreement and that that Recipient hereby agrees to all terms and conditions herein. F. Point of Contact: Any Recipient contact with Government Agency is to be directed to the designated representative as follows: Guillaume P. Brat guillaume.p.brat@nasa.gov NASA-SW-VnV-ikos-1d98c65/README.md000066400000000000000000000226711473507761200161050ustar00rootroot00000000000000IKOS ==== [![License](https://img.shields.io/badge/license-NOSA%201.3-blue.svg)](LICENSE.pdf) [![Release](https://img.shields.io/badge/release-v3.5-orange.svg)](https://github.com/NASA-SW-VnV/ikos/releases/tag/v3.5) [![Linux Build](https://github.com/NASA-SW-VnV/ikos/actions/workflows/build-linux.yml/badge.svg)](https://github.com/NASA-SW-VnV/ikos/actions/workflows/build-linux.yml) [![MacOS Build](https://github.com/NASA-SW-VnV/ikos/actions/workflows/build-macos.yml/badge.svg)](https://github.com/NASA-SW-VnV/ikos/actions/workflows/build-macos.yml) IKOS (Inference Kernel for Open Static Analyzers) is a static analyzer for C/C++ based on the theory of Abstract Interpretation. Introduction ------------ IKOS started as a C++ library designed to facilitate the development of sound static analyzers based on [Abstract Interpretation](https://www.di.ens.fr/~cousot/AI/IntroAbsInt.html). Specialization of a static analyzer for an application or family of applications is critical for achieving both precision and scalability. Developing such an analyzer is arduous and requires significant expertise in Abstract Interpretation. IKOS provides a generic and efficient implementation of state-of-the-art Abstract Interpretation data structures and algorithms, such as control-flow graphs, fixpoint iterators, numerical abstract domains, etc. IKOS is independent of a particular programming language. IKOS also provides a C and C++ static analyzer based on [LLVM](https://llvm.org). It implements scalable analyses for detecting and proving the absence of runtime errors in C and C++ programs. License ------- IKOS has been released under the NASA Open Source Agreement version 1.3, see [LICENSE.pdf](LICENSE.pdf) Contact ------- ikos@lists.nasa.gov Release notes ------------- See [Releases](https://github.com/NASA-SW-VnV/ikos/releases). Troubleshooting --------------- See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) Installation ------------ To install IKOS on **Linux** or **macOS**, we recommend to use **[Homebrew](https://brew.sh/)**. First, install **Homebrew** by following [these instructions](https://docs.brew.sh/Installation). Then, simply run: ``` $ brew install nasa-sw-vnv/core/ikos ``` For Windows, consider using [Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/install). How to run IKOS --------------- Suppose we want to analyze the following C program in a file, called *loop.c*: ```c 1: #include 2: int a[10]; 3: int main(int argc, char *argv[]) { 4: size_t i = 0; 5: for (;i < 10; i++) { 6: a[i] = i; 7: } 8: a[i] = i; 9: printf("%i", a[i]); 10: } ``` To analyze this program with IKOS, simply run: ``` $ ikos loop.c ``` You shall see the following output. IKOS reports two occurrences of buffer overflow at line 8 and 9. ``` [*] Compiling loop.c [*] Running ikos preprocessor [*] Running ikos analyzer [*] Translating LLVM bitcode to AR [*] Running liveness analysis [*] Running widening hint analysis [*] Running interprocedural value analysis [*] Analyzing entry point 'main' [*] Checking properties for entry point 'main' # Time stats: clang : 0.037 sec ikos-analyzer: 0.023 sec ikos-pp : 0.007 sec # Summary: Total number of checks : 7 Total number of unreachable checks : 0 Total number of safe checks : 5 Total number of definite unsafe checks: 2 Total number of warnings : 0 The program is definitely UNSAFE # Results loop.c: In function 'main': loop.c:8:10: error: buffer overflow, trying to access index 10 of global variable 'a' of 10 elements a[i] = i; ^ loop.c: In function 'main': loop.c:9:18: error: buffer overflow, trying to access index 10 of global variable 'a' of 10 elements printf("%i", a[i]); ^ ``` The `ikos` command takes a source file (`.c`, `.cpp`) or a LLVM bitcode file (`.bc`) as input, analyzes it to find runtime errors (also called undefined behaviors), creates a result database `output.db` in the current working directory and prints a report. In the report, each line has one of the following status: * **safe**: the statement is proven safe; * **error**: the statement always results into an error (or is unreachable); * **unreachable**: the statement is never executed; * **warning** may mean three things: 1. the statement results into an error for some executions, or 2. the static analyzer did not have enough information to conclude (check dependent on an external input, for instance), or 3. the static analyzer was not powerful enough to prove the absence of errors; By default, ikos shows warnings and errors directly in your terminal, like a compiler would do. If the analysis report is too big, you shall use: * `ikos-report output.db` to examine the report in your terminal * `ikos-view output.db` to examine the report in a web interface Further information: * [Analyze a whole project with ikos-scan](analyzer/README.md#analyze-a-whole-project-with-ikos-scan) * [Examine a report with ikos-view](analyzer/README.md#examine-a-report-with-ikos-view) * [Analysis Options](analyzer/README.md#analysis-options) - [Checks](analyzer/README.md#checks) - [Numerical abstract domains](analyzer/README.md#numerical-abstract-domains) - [Entry points](analyzer/README.md#entry-points) - [Multi-threading](analyzer/README.md#multi-threading) - [Optimization level](analyzer/README.md#optimization-level) - [Inter-procedural vs Intra-procedural](analyzer/README.md#inter-procedural-vs-intra-procedural) - [Fixpoint engine parameters](analyzer/README.md#fixpoint-engine-parameters) - [Partitioning](analyzer/README.md#partitioning) - [Hardware addresses](analyzer/README.md#hardware-addresses) - [Other analysis options](analyzer/README.md#other-analysis-options) * [Report Options](analyzer/README.md#report-options) - [Format](analyzer/README.md#format) - [File](analyzer/README.md#file) - [Status Filter](analyzer/README.md#status-filter) - [Analysis Filter](analyzer/README.md#analysis-filter) - [Verbosity](analyzer/README.md#verbosity) - [Other report options](analyzer/README.md#other-report-options) * [APRON Support](analyzer/README.md#apron-support) * [Analysis Assumptions](analyzer/README.md#analysis-assumptions) * [Analyze an embedded software requiring a cross-compiler](analyzer/README.md#analyze-an-embedded-software-requiring-a-cross-compiler) * [Model library functions to reduce warnings](analyzer/README.md#model-library-functions-to-reduce-warnings) Build from source ----------------- Below are instructions to build IKOS from source. This is only for advanced users that want to either package IKOS for an operating system or to experiment with the codebase. Otherwise, please follow the instructions [above](#installation). ### Dependencies To build and run the analyzer, you will need the following dependencies: * A C++ compiler that supports C++14 (gcc >= 4.9.2 or clang >= 3.4) * CMake >= 3.4.3 * GMP >= 4.3.1 * Boost >= 1.55 * Python >= 3.3 * SQLite >= 3.6.20 * TBB >= 2 * LLVM and Clang 14.0.x * (Optional) APRON >= 0.9.10 Most of them can be installed using your package manager. Note: If you build LLVM from source, you need to enable run-time type information (RTTI). ### Build and Install Now that you have all the dependencies on your system, you can build and install IKOS. As you open the IKOS distribution, you shall see the following directory structure: ``` . ├── CMakeLists.txt ├── LICENSE.pdf ├── README.md ├── RELEASE_NOTES.md ├── TROUBLESHOOTING.md ├── analyzer ├── ar ├── cmake ├── core ├── doc ├── frontend ├── script └── test ``` IKOS uses the CMake build system. You will need to specify an installation directory that will contain all the binaries, libraries and headers after installation. If you do not specify this directory, CMake will install everything under `install` in the root directory of the distribution. In the following steps, we will install IKOS under `/path/to/ikos-install-directory`. Here are the steps to build and install IKOS: ``` $ mkdir build $ cd build $ cmake -DCMAKE_INSTALL_PREFIX=/path/to/ikos-install-directory .. $ make $ make install ``` Then, add IKOS in your PATH (consider adding this in your .bashrc): ``` $ PATH="/path/to/ikos-install-directory/bin:$PATH" ``` ### Tests To build and run the tests, simply type: ``` $ make check ``` Contributors ------------ See [CONTRIBUTORS.md](CONTRIBUTORS.md) Publications ------------ * Sung Kook Kim, Arnaud J. Venet, Aditya V. Thakur. **Deterministic Parallel Fixpoint Computation.** In _Principles of Programming Languages (POPL 2020)_, New Orleans, Louisiana ([PDF](https://arxiv.org/pdf/1909.05951.pdf)). * Guillaume Brat, Jorge Navas, Nija Shi and Arnaud Venet. **IKOS: a Framework for Static Analysis based on Abstract Interpretation.** In _Proceedings of the International Conference on Software Engineering and Formal Methods (SEFM 2014)_, Grenoble, France ([PDF](http://ti.arc.nasa.gov/publications/16610/download/)). * Arnaud Venet. **The Gauge Domain: Scalable Analysis of Linear Inequality Invariants.** In _Proceedings of Computer Aided Verification (CAV 2012)_, Berkeley, California, USA 2012. Lecture Notes in Computer Science, pages 139-154, volume 7358, Springer 2012 ([PDF](http://ti.arc.nasa.gov/publications/4767/download/)). Coding Standards ---------------- See [doc/CODING_STANDARDS.md](doc/CODING_STANDARDS.md) Overview of the source code --------------------------- See [doc/OVERVIEW.md](doc/OVERVIEW.md) NASA-SW-VnV-ikos-1d98c65/TROUBLESHOOTING.md000066400000000000000000000104601473507761200174300ustar00rootroot00000000000000Troubleshooting =============== This document covers some common issues with IKOS, and how to solve them. Contact ------- ikos@lists.nasa.gov Installation issues ------------------- ### "Could NOT find LLVM" while running cmake CMake could not find LLVM. First, install LLVM. This can usually be done with your package manager. If this message still shows up, it means cmake cannot find the `llvm-config` command. You can either add the LLVM binary directory in your PATH, or give cmake the full path to llvm-config, using `-DLLVM_CONFIG_EXECUTABLE=/path/to/llvm-config` For instance, if you installed LLVM using Homebrew on Mac OS X, you can add LLVM in your path using: ``` $ PATH="$(brew --prefix)/opt/llvm/bin:$PATH" ``` ### "Could NOT find Clang" while running cmake CMake could not find Clang. First, install Clang. This can usually be done with your package manager. If this message still shows up, it means cmake cannot find the `clang` command. You can either add the clang binary directory in your PATH, or give cmake the full path to clang, using `-DCLANG_EXECUTABLE=/path/to/clang` ### "Could not find ikos python module" while running ikos The ikos command could not import the ikos python module. The module should be under `/path/to/ikos-install/lib/python*/site-packages` If the ikos python module is in another directory, make sure it is in your PYTHONPATH: ``` export PYTHONPATH=/path/to/ikos-python-module ``` ### "Two passes with the same argument (-domtree) attempted to be registered!" while running ikos You are probably trying to build IKOS with shared libraries (using `-DBUILD_SHARED_LIBS=ON`) and LLVM was linked statically (using `libLLVMxxx.a`). Unfortunately, this doesn't work because LLVM uses global constructors to register command line options, and the global constructors end up being called twice. Compiling IKOS with both `-DBUILD_SHARED_LIBS=ON` and `-DIKOS_LINK_LLVM_DYLIB=ON` should fix the issue by linking against the libLLVM shared library. ### "/usr/bin/ld: cannot find -lLLVMCore" while running Make Your LLVM library was built as one single shared library `libLLVM.so` (`LLVM_BUILD_LLVM_DYLIB=1`), but CMake was configured to query specific library components and match link flags against them. Compiling IKOS with both `-DBUILD_SHARED_LIBS=ON` and `-DIKOS_LINK_LLVM_DYLIB=ON` should fix the issue by linking against the single libLLVM shared library. ### `memory access violation at address: 0x00000088: no mapping at fault address` while running tests This is a bug in the APRON library. Some OS distributions provide outdated versions of APRON. Building APRON from source (https://github.com/antoinemine/apron), instead of relying on a version made available via the OS' package repository, should fix the issue. Analysis issues --------------- ### Exited with signal SIGKILL IKOS probably ran out of memory. See [Running ouf of memory](#running-out-of-memory) ### Running out of memory IKOS might run out of memory on huge code bases. Consider using the option `--no-fixpoint-cache`. It disables the cache of fixpoint for called functions, which decreases the memory usage at the cost of run time. Known issues ------------ ### Source Code Fortification Source code fortification aims at making your source code more robust. It replaces regular `memset()`, `memcpy()` and `memmove()` calls to `__memset_chk()`, `__memcpy_chk()` and `__memmove_chk()`. According to Linux Standard Base Core Specification 4.1, the interfaces `__memset_chk()`, `__memcpy_chk()` and `__memmove_chk()` shall function in the same way as the interface `memset()`, `memcpy()` and `memmove()`, respectively, except that `__memset_chk()`, `__memcpy_chk()` and `__memmove_chk()` shall check for buffer overflow before computing a result. If an overflow is anticipated, the function shall abort and the program calling it shall exit. The Buffer Overflow Analysis (BOA) in IKOS handles `__memset_chk()`, `__memcpy_chk()` and `__memmove_chk()` as unknown library functions, and won't report any warning. Consider using `-D_FORTIFY_SOURCE=0` when you compile your source code to LLVM bitcode manually. ### Analyzing multi-threaded code IKOS does not handle analyzing multi-threaded code. Handling multi-threaded code in a sound static analyzer based on Abstract Interpretation (such as IKOS) is challenging and an ongoing research topic. NASA-SW-VnV-ikos-1d98c65/analyzer/000077500000000000000000000000001473507761200164435ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/CMakeLists.txt000066400000000000000000000365021473507761200212110ustar00rootroot00000000000000#******************************************************************************* # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR) if (POLICY CMP0074) cmake_policy(SET CMP0074 NEW) endif() if (POLICY CMP0077) cmake_policy(SET CMP0077 NEW) endif() project(ikos-analyzer) # # Build settings # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "In-source builds are not allowed. Please clean your source tree and try again.") endif() if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE) endif() if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "Install directory" FORCE) endif() if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "CMake generator: ${CMAKE_GENERATOR}") endif() # # Dependency checks # # Add path for custom modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") find_package(Threads REQUIRED) set(CUSTOM_BOOST_ROOT "" CACHE PATH "Path to custom boost installation") if (CUSTOM_BOOST_ROOT) set(BOOST_ROOT "${CUSTOM_BOOST_ROOT}") set(Boost_NO_SYSTEM_PATHS TRUE) endif() find_package(Boost 1.55.0 REQUIRED COMPONENTS filesystem system thread) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) find_package(GMP REQUIRED) include_directories(SYSTEM ${GMP_INCLUDE_DIR}) include_directories(SYSTEM ${GMPXX_INCLUDE_DIR}) find_package(TBB 2 REQUIRED) include_directories(SYSTEM ${TBB_INCLUDE_DIRS}) find_package(SQLite3 REQUIRED) include_directories(SYSTEM ${SQLITE3_INCLUDE_DIR}) find_package(APRON) if (APRON_FOUND) include_directories(SYSTEM ${APRON_INCLUDE_DIRS}) add_definitions("-DHAS_APRON") endif() find_package(PythonInterp REQUIRED) find_package(Core REQUIRED) include_directories(${CORE_INCLUDE_DIR}) find_package(AR REQUIRED) include_directories(${AR_INCLUDE_DIR}) find_package(FrontendLLVM REQUIRED) include_directories(${FRONTEND_LLVM_INCLUDE_DIR}) find_package(LLVM REQUIRED) include_directories(SYSTEM ${LLVM_INCLUDE_DIR}) if ((LLVM_VERSION VERSION_LESS "14") OR (NOT (LLVM_VERSION VERSION_LESS "15"))) message(FATAL_ERROR "LLVM 14 is required.") endif() # Add path to llvm cmake modules list(APPEND CMAKE_MODULE_PATH ${LLVM_CMAKE_DIR}) include(LLVMConfig) if ((NOT LLVM_ENABLE_RTTI) AND (NOT WIN32)) message(WARNING "LLVM was built without run-time type information (RTTI)") endif() set(LLVM_ENABLE_WARNINGS TRUE) set(LLVM_REQUIRES_EH TRUE) set(LLVM_REQUIRES_RTTI TRUE) include(HandleLLVMOptions) include(AddLLVM) option(IKOS_LINK_LLVM_DYLIB "Link IKOS against the libLLVM dynamic library" OFF) find_package(Clang REQUIRED) if (NOT (LLVM_VERSION VERSION_EQUAL CLANG_VERSION)) message(FATAL_ERROR "LLVM and Clang versions do not match.") endif() # # Compiler flags # include(AddFlagUtils) add_compiler_flag(REQUIRED "CXX14" "-std=c++1y") add_compiler_flag(REQUIRED "FVISIBILITY_INLINES_HIDDEN" "-fvisibility-inlines-hidden") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compiler_flag(REQUIRED "WEVERYTHING" "-Weverything") add_compiler_flag(OPTIONAL "WNO_SWITCH_ENUM" "-Wno-switch-enum") add_compiler_flag(OPTIONAL "WNO_PADDED" "-Wno-padded") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT" "-Wno-c++98-compat") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT_PEDANTIC" "-Wno-c++98-compat-pedantic") add_compiler_flag(OPTIONAL "WNO_C99_EXTENSIONS" "-Wno-c99-extensions") add_compiler_flag(OPTIONAL "WNO_COVERED_SWITCH_DEFAULT" "-Wno-covered-switch-default") add_compiler_flag(OPTIONAL "WNO_EXIT_TIME_DESTRUCTORS" "-Wno-exit-time-destructors") add_compiler_flag(OPTIONAL "WNO_GLOBAL_CONSTRUCTORS" "-Wno-global-constructors") add_compiler_flag(OPTIONAL "WNO_WEAK_VTABLES" "-Wno-weak-vtables") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") add_compiler_flag(REQUIRED "WALL" "-Wall") add_compiler_flag(REQUIRED "WEXTRA" "-Wextra") add_compiler_flag(OPTIONAL "WNO_MAYBE_UNINITIALIZED" "-Wno-maybe-uninitialized") add_compiler_flag(OPTIONAL "WNO_REDUNDANT_MOVE" "-Wno-redundant-move") add_compiler_flag(OPTIONAL "WNO_UNUSED_LOCAL_TYPEDEFS" "-Wno-unused-local-typedefs") endif() # # Targets # include_directories(include) # install intrinsic.h install(FILES include/ikos/analyzer/intrinsic.h DESTINATION include/ikos/analyzer) # ikos-analyzer binary add_executable(ikos-analyzer src/ikos_analyzer.cpp src/analysis/call_context.cpp src/analysis/fixpoint_parameters.cpp src/analysis/hardware_addresses.cpp src/analysis/literal.cpp src/analysis/liveness.cpp src/analysis/memory_location.cpp src/analysis/option.cpp src/analysis/pointer/constraint.cpp src/analysis/pointer/function.cpp src/analysis/pointer/pointer.cpp src/analysis/pointer/value.cpp src/analysis/value/abstract_domain.cpp src/analysis/value/global_variable.cpp src/analysis/value/interprocedural/concurrent/analysis.cpp src/analysis/value/interprocedural/concurrent/function_fixpoint.cpp src/analysis/value/interprocedural/init_invariant.cpp src/analysis/value/interprocedural/sequential/analysis.cpp src/analysis/value/interprocedural/sequential/function_fixpoint.cpp src/analysis/value/interprocedural/sequential/global_init_fixpoint.cpp src/analysis/value/interprocedural/sequential/progress.cpp src/analysis/value/intraprocedural/concurrent/analysis.cpp src/analysis/value/intraprocedural/concurrent/function_fixpoint.cpp src/analysis/value/intraprocedural/sequential/analysis.cpp src/analysis/value/intraprocedural/sequential/function_fixpoint.cpp src/analysis/value/machine_int_domain.cpp src/analysis/value/machine_int_domain/apron_interval.cpp src/analysis/value/machine_int_domain/apron_octagon.cpp src/analysis/value/machine_int_domain/apron_pkgrid_polyhedra_lin_cong.cpp src/analysis/value/machine_int_domain/apron_polka_linear_equalities.cpp src/analysis/value/machine_int_domain/apron_polka_polyhedra.cpp src/analysis/value/machine_int_domain/apron_ppl_linear_congruences.cpp src/analysis/value/machine_int_domain/apron_ppl_polyhedra.cpp src/analysis/value/machine_int_domain/congruence.cpp src/analysis/value/machine_int_domain/dbm.cpp src/analysis/value/machine_int_domain/gauge.cpp src/analysis/value/machine_int_domain/gauge_interval_congruence.cpp src/analysis/value/machine_int_domain/interval.cpp src/analysis/value/machine_int_domain/interval_congruence.cpp src/analysis/value/machine_int_domain/var_pack_apron_octagon.cpp src/analysis/value/machine_int_domain/var_pack_apron_pkgrid_polyhedra_lin_cong.cpp src/analysis/value/machine_int_domain/var_pack_apron_polka_linear_equalities.cpp src/analysis/value/machine_int_domain/var_pack_apron_polka_polyhedra.cpp src/analysis/value/machine_int_domain/var_pack_apron_ppl_linear_congruences.cpp src/analysis/value/machine_int_domain/var_pack_apron_ppl_polyhedra.cpp src/analysis/value/machine_int_domain/var_pack_dbm.cpp src/analysis/value/machine_int_domain/var_pack_dbm_congruence.cpp src/analysis/variable.cpp src/analysis/widening_hint.cpp src/checker/assert_prover.cpp src/checker/buffer_overflow.cpp src/checker/checker.cpp src/checker/dead_code.cpp src/checker/debug.cpp src/checker/division_by_zero.cpp src/checker/double_free.cpp src/checker/function_call.cpp src/checker/int_overflow_base.cpp src/checker/memory_watch.cpp src/checker/null_dereference.cpp src/checker/pointer_alignment.cpp src/checker/pointer_compare.cpp src/checker/pointer_overflow.cpp src/checker/shift_count.cpp src/checker/signed_int_overflow.cpp src/checker/soundness.cpp src/checker/uninitialized_variable.cpp src/checker/unsigned_int_overflow.cpp src/database/output.cpp src/database/sqlite.cpp src/database/table.cpp src/database/table/call_contexts.cpp src/database/table/checks.cpp src/database/table/files.cpp src/database/table/functions.cpp src/database/table/memory_locations.cpp src/database/table/operands.cpp src/database/table/settings.cpp src/database/table/statements.cpp src/database/table/times.cpp src/exception.cpp src/json/json.cpp src/util/color.cpp src/util/log.cpp src/util/progress.cpp src/util/source_location.cpp src/util/timer.cpp ) if (IKOS_LINK_LLVM_DYLIB) set(IKOS_ANALYZER_LLVM_LIBS "LLVM") else() llvm_map_components_to_libnames(IKOS_ANALYZER_LLVM_LIBS core ipo irreader support transformutils ) endif() target_link_libraries(ikos-analyzer Threads::Threads ${FRONTEND_LLVM_TO_AR_LIB} ${IKOS_ANALYZER_LLVM_LIBS} ${SQLITE3_LIB} ${Boost_LIBRARIES} ${GMP_LIB} ${GMPXX_LIB} ${TBB_LIBRARIES} ${AR_LIB} ) if (APRON_FOUND) target_link_libraries(ikos-analyzer ${APRON_LIBRARIES}) endif() install(TARGETS ikos-analyzer RUNTIME DESTINATION bin) # python wrapper option(APPEND_GIT_VERSION "Append the current git commit to the version number" OFF) option(FORCE_UPDATE_VERSION "Force the update of the version on every build" OFF) # settings/__init__.py configure_file(python/settings.cmake.in python/settings.cmake @ONLY) if (NOT FORCE_UPDATE_VERSION) add_custom_command( OUTPUT "python/ikos/settings/__init__.py" COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/python/settings.cmake" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/python/settings.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/python/ikos/settings.py.in" VERBATIM) else() add_custom_command( OUTPUT "python/ikos/settings/__init__.py" "[update-version]" # missing file to force rebuild COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/python/settings.cmake" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/python/settings.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/python/ikos/settings.py.in" VERBATIM) endif() add_custom_target(ikos-python-settings ALL DEPENDS "python/ikos/settings/__init__.py" ) # setup.py configure_file(python/setup.py.in python/setup.py @ONLY) option(INSTALL_PYTHON_VIRTUALENV "Install a python virtual environment for ikos" ON) option(PYTHON_VENV_EXECUTABLE "Path to the python executable of an existing virtual environment") if (INSTALL_PYTHON_VIRTUALENV) install(CODE " message(STATUS \"Running python -m venv ${CMAKE_INSTALL_PREFIX}/libexec\") execute_process(COMMAND \"${PYTHON_EXECUTABLE}\" -m venv \"${CMAKE_INSTALL_PREFIX}/libexec\") message(STATUS \"Running ${CMAKE_INSTALL_PREFIX}/libexec/bin/python -m pip install -U pip\") execute_process(COMMAND \"${CMAKE_INSTALL_PREFIX}/libexec/bin/python\" -m pip install -U pip) message(STATUS \"Running ${CMAKE_INSTALL_PREFIX}/libexec/bin/python -m pip install -U pygments setuptools\") execute_process(COMMAND \"${CMAKE_INSTALL_PREFIX}/libexec/bin/python\" -m pip install pygments setuptools) message(STATUS \"Running ${CMAKE_INSTALL_PREFIX}/libexec/bin/python -m pip install .\") execute_process(COMMAND \"${CMAKE_INSTALL_PREFIX}/libexec/bin/python\" -m pip install . WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/python\") ") set(PYTHON_VENV_EXECUTABLE "${CMAKE_INSTALL_PREFIX}/libexec/bin/python") else() # This can be used by the Homebrew formula or by package maintainers. if (NOT PYTHON_VENV_EXECUTABLE) message(FATAL_ERROR "Please specify -DPYTHON_VENV_EXECUTABLE= when using -DINSTALL_PYTHON_VIRTUALENV=OFF") endif() endif() # python web resources install(DIRECTORY python/ikos/view DESTINATION share/ikos) # python scripts configure_file(script/ikos.py.in script/ikos @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos" DESTINATION bin) configure_file(script/ikos-config.py.in script/ikos-config @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos-config" DESTINATION bin) configure_file(script/ikos-report.py.in script/ikos-report @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos-report" DESTINATION bin) configure_file(script/ikos-view.py.in script/ikos-view @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos-view" DESTINATION bin) configure_file(script/ikos-scan.py.in script/ikos-scan @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos-scan" DESTINATION bin) configure_file(script/ikos-scan-cc.py.in script/ikos-scan-cc @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos-scan-cc" DESTINATION bin) configure_file(script/ikos-scan-c++.py.in script/ikos-scan-c++ @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos-scan-c++" DESTINATION bin) configure_file(script/ikos-scan-extract.py.in script/ikos-scan-extract @ONLY) install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/script/ikos-scan-extract" DESTINATION bin) # # Regression tests # enable_testing() add_custom_target(build-analyzer-tests) add_subdirectory(test/regression EXCLUDE_FROM_ALL) # # Doxygen # find_package(Doxygen) if (DOXYGEN_FOUND) configure_file(doc/doxygen/Doxyfile.in doc/Doxyfile @ONLY) add_custom_target(doxygen-analyzer ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMENT "Generating IKOS Analyzer API documentation with Doxygen" VERBATIM ) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doc/html" DESTINATION doc/analyzer OPTIONAL) endif() # # If it's the top level CMakeLists.txt, Add some aliases # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS build-analyzer-tests) add_custom_target(doc DEPENDS doxygen-analyzer) endif() NASA-SW-VnV-ikos-1d98c65/analyzer/README.md000066400000000000000000001001061473507761200177200ustar00rootroot00000000000000IKOS Analyzer ============= This folder contains the implementation of the analyzer. Table of contents ----------------- * [Introduction](#introduction) * [Installation](#installation) - [Dependencies](#dependencies) - [Build and Install](#build-and-install) - [Tests](#tests) - [Documentation](#documentation) * [How to run IKOS](#how-to-run-ikos) * [Analyze a whole project with ikos-scan](#analyze-a-whole-project-with-ikos-scan) * [Examine a report with ikos-view](#examine-a-report-with-ikos-view) * [Analysis Options](#analysis-options) - [Checks](#checks) - [Numerical abstract domains](#numerical-abstract-domains) - [Entry points](#entry-points) - [Multi-threading](#multi-threading) - [Optimization level](#optimization-level) - [Inter-procedural vs Intra-procedural](#inter-procedural-vs-intra-procedural) - [Fixpoint engine parameters](#fixpoint-engine-parameters) - [Partitioning](#partitioning) - [Hardware addresses](#hardware-addresses) - [Other analysis options](#other-analysis-options) * [Report Options](#report-options) - [Format](#format) - [File](#file) - [Status Filter](#status-filter) - [Analysis Filter](#analysis-filter) - [Verbosity](#verbosity) - [Other report options](#other-report-options) * [APRON Support](#apron-support) * [Analysis Assumptions](#analysis-assumptions) * [Analyze an embedded software requiring a cross-compiler](#analyze-an-embedded-software-requiring-a-cross-compiler) * [Model library functions to reduce warnings](#model-library-functions-to-reduce-warnings) * [Overview of the source code](#overview-of-the-source-code) Introduction ------------ The IKOS Analyzer is an abstract interpretation-based static analyzer that aims at proving the absence of runtime errors in C and C++ programs. See [Checks](#checks) for the full list of available checks. Installation ------------ IKOS Analyzer can be installed independently from the other components, but we recommend to build the analyzer from the root directory. To do so, follow the instructions in the root [README.md](../README.md). ### Dependencies To build and run the analyzer, you will need the following dependencies: * A C++ compiler that supports C++14 (gcc >= 4.9.2 or clang >= 3.4) * CMake >= 3.4.3 * GMP >= 4.3.1 * Boost >= 1.55 * Python >= 3.3 * SQLite >= 3.6.20 * TBB >= 2 * LLVM and Clang 14.0.x * (Optional) APRON >= 0.9.10 * IKOS Core * IKOS AR * IKOS LLVM Frontend ### Build and Install To build and install the analyzer, run the following commands in the `analyzer` directory: ``` $ mkdir build $ cd build $ cmake \ -DCMAKE_INSTALL_PREFIX=/path/to/analyzer-install-directory \ -DLLVM_CONFIG_EXECUTABLE=/path/to/llvm/bin/llvm-config \ -DCORE_ROOT=/path/to/core-install-directory \ -DAR_ROOT=/path/to/ar-install-directory \ -DFRONTEND_LLVM_ROOT=/path/to/frontend-llvm-install-directory \ .. $ make $ make install ``` ### Tests To build and run the tests, simply type: ``` $ make check ``` ### Documentation To build the documentation, you will need [Doxygen](http://www.doxygen.org). Then, simply type: ``` $ make doc $ open doc/html/index.html ``` How to run IKOS --------------- Suppose we want to analyze the following C program in a file, called *loop.c*: ```c 1: #include 2: int a[10]; 3: int main(int argc, char *argv[]) { 4: size_t i = 0; 5: for (;i < 10; i++) { 6: a[i] = i; 7: } 8: a[i] = i; 9: printf("%i", a[i]); 10: } ``` To analyze this program with IKOS, simply run: ``` $ ikos loop.c ``` You shall see the following output. IKOS reports two occurrences of buffer overflow at line 8 and 9. ``` [*] Compiling loop.c [*] Running ikos preprocessor [*] Running ikos analyzer [*] Translating LLVM bitcode to AR [*] Running liveness analysis [*] Running widening hint analysis [*] Running interprocedural value analysis [*] Analyzing entry point 'main' [*] Checking properties for entry point 'main' # Time stats: clang : 0.037 sec ikos-analyzer: 0.023 sec ikos-pp : 0.007 sec # Summary: Total number of checks : 7 Total number of unreachable checks : 0 Total number of safe checks : 5 Total number of definite unsafe checks: 2 Total number of warnings : 0 The program is definitely UNSAFE # Results loop.c: In function 'main': loop.c:8:10: error: buffer overflow, trying to access index 10 of global variable 'a' of 10 elements a[i] = i; ^ loop.c: In function 'main': loop.c:9:18: error: buffer overflow, trying to access index 10 of global variable 'a' of 10 elements printf("%i", a[i]); ^ ``` The `ikos` command takes a source file (`.c`, `.cpp`) or a LLVM bitcode file (`.bc`) as input, analyzes it to find runtime errors (also called undefined behaviors), creates a result database `output.db` in the current working directory and prints a report. In the report, each line has one of the following status: * **safe**: the statement is proven safe; * **error**: the statement always results into an error (or is unreachable); * **unreachable**: the statement is never executed; * **warning** may mean three things: 1. the statement results into an error for some executions, or 2. the static analyzer did not have enough information to conclude (check dependent on an external input, for instance), or 3. the static analyzer was not powerful enough to prove the absence of errors; By default, ikos shows warnings and errors directly in your terminal, like a compiler would do. If the analysis report is too big, you shall use: * `ikos-report output.db` to examine the report in your terminal * `ikos-view output.db` to examine the report in a web interface Analyze a whole project with ikos-scan -------------------------------------- To run IKOS on a large project, you shall use ikos-scan. ikos-scan is a command line utility that runs the static analyzer over a codebase after performing a regular build. The ikos-scan command works by overriding the environment variables `CC` and `CXX` to intercept the compiler commands. Behind the scene, it builds the original program as well as the LLVM bitcode file that is necessary to run the analyzer. To use ikos-scan, just prefix your build commands with `ikos-scan`. For instance, to analyze pkg-config: ``` $ tar xf pkg-config-0.29.2.tar.gz $ cd pkg-config-0.29.2 $ ikos-scan ./configure [...] $ ikos-scan make [...] Analyze pkg-config? [Y/n] ``` ikos-scan will produce a `.bc` file for each executable in your project. You can analyze them with specific options using `ikos [options] program.bc`. Examine a report with ikos-view ------------------------------- ikos-view provides a web interface to examine IKOS results. It is available directly in the analyzer. The web interface shows the source code with syntax highlighting, and allows you to filter the warnings by checks. To use ikos-view, first run the analyzer on your project to generate a result database `output.db`, then simply run: ``` $ ikos-view output.db ``` It will start a web server. You can then launch your favorite web browser and visit [http://localhost:8080](http://localhost:8080) Note that if you want syntax highlighting, you will need to install [Pygments](http://pygments.org): ``` $ pip install --user pygments ``` Analysis Options ---------------- This section describes the most relevant options of the analyzer. ### Checks The list of available checks are: * **buffer overflow analysis**, `-a=boa`: checks for buffer overflows and out-of-bound array accesses. * **division by zero analysis**, `-a=dbz`: checks for integer divisions by zero. * **null pointer analysis**, `-a=nullity`: checks for null pointer dereferences. * **assertion prover**, `-a=prover`: prove user-defined properties, using `__ikos_assert(condition)`. * **unaligned pointer analysis**, `-a=upa`: checks for unaligned pointer dereferences. * **uninitialized variable analysis**, `-a=uva`: checks for read of uninitialized variables. * **signed integer overflow analysis**, `-a=sio`: checks for signed integer overflows. * **unsigned integer overflow analysis**, `-a=uio`: checks for unsigned integer overflows. * **shift count analysis**, `-a=shc`: checks for invalid shifts, where the amount shifted is greater or equal to the bit-width of the left operand, or less than zero. * **pointer overflow analysis**, `-a=poa`: checks for pointer arithmetic overflows. * **pointer comparison analysis**, `-a=pcmp`: checks for pointer comparisons between pointers referring to different objects. * **soundness analysis**, `-a=sound`: checks for instructions that could make the analysis unsound, i.e miss bugs. * **function call analysis**, `-a=fca`: checks for function calls through function pointers of the wrong type. * **dead code analysis**, `-a=dca`: checks for unreachable statements. * **double free analysis**, `-a=dfa`: checks for double free, invalid free, use after free and use after return. * **debugger**, `-a=dbg`: prints debug information, using `__ikos_print_values("desc", x)` and `__ikos_print_invariant()`. * **memory watcher**, `-a=watch`: prints memory writes at a given memory location, using `__ikos_watch_mem(ptr, size)`. By default, all the checks are enabled except: * **unaligned pointer analysis**, because it needs a congruence domain to generate meaningful results. See [Numerical abstract domains](#numerical-abstract-domains). * **unsigned integer overflow analysis**, because it is not an undefined behavior according to the C standard. * **pointer overflow analysis**, because it is redundant with the buffer overflow analysis. * **memory watcher**, because it is slow. If you want to run specific checks, use the `-a` parameter: ``` $ ikos -a=boa,nullity test.c ``` Note that you can use the wildcard character `*`, `+` and `-`: ``` $ ikos -a='*,-sio' test.c ``` In this example, all the checks are enabled except signed integer overflow checks. ### Numerical abstract domains IKOS is based on the theory of [Abstract Interpretation](https://www.di.ens.fr/~cousot/AI/IntroAbsInt.html). The analysis uses a numerical abstract domain internally to model integer variables. The list of available numerical abstract domains are: * `-d=interval`: The interval domain, see [CC77](https://www.di.ens.fr/~cousot/COUSOTpapers/publications.www/CousotCousot-POPL-77-ACM-p238--252-1977.pdf). * `-d=congruence`: The congruence domain, see [Gra89](http://www.tandfonline.com/doi/abs/10.1080/00207168908803778). * `-d=interval-congruence`: The reduced product of interval and congruence. * `-d=dbm`: The Difference-Bound Matrices domain, see [PADO01](https://www-apr.lip6.fr/~mine/publi/article-mine-padoII.pdf). * `-d=var-pack-dbm`: The Difference-Bound Matrices domain with variable packing, see [VMCAI16](https://seahorn.github.io/papers/vmcai16.pdf). * `-d=var-pack-dbm-congruence`: The reduced product of DBM with variable packing and congruence. * `-d=gauge`: The gauge domain, see [CAV12](https://ti.arc.nasa.gov/publications/4767/download/). * `-d=gauge-interval-congruence`: The reduced product of gauge, interval and congruence. * `-d=apron-interval`: The APRON interval domain, see [Box](http://apron.cri.ensmp.fr/library/0.9.10/apron/apron_21.html#SEC54). * `-d=apron-octagon`: The APRON octagon domain, see [Oct](http://apron.cri.ensmp.fr/library/0.9.10/apron/oct_doc.html). * `-d=apron-polka-polyhedra`: The APRON polka polyhedra domain, see [NewPolka](http://apron.cri.ensmp.fr/library/0.9.10/apron/apron_25.html#SEC58). * `-d=apron-polka-linear-equalities`: The APRON polka linear equalities domain, see [NewPolka](http://apron.cri.ensmp.fr/library/0.9.10/apron/apron_25.html#SEC58). * `-d=apron-ppl-polyhedra`: The APRON PPL polyhedra domain, see [PPL](http://apron.cri.ensmp.fr/library/0.9.10/apron/apron_29.html#SEC65). * `-d=apron-ppl-linear-congruences`: The APRON PPL linear congruences domain, see [PPL](http://apron.cri.ensmp.fr/library/0.9.10/apron/apron_29.html#SEC65). * `-d=apron-pkgrid-polyhedra-lin-cong`: The APRON Pkgrid polyhedra and linear congruences domain, see [Pkgrid](http://apron.cri.ensmp.fr/library/0.9.10/apron/apron_33.html#SEC69). * `-d=var-pack-apron-octagon`: The APRON octagon domain with variable packing. * `-d=var-pack-apron-polka-polyhedra`: The APRON Polka polyhedra domain with variable packing. * `-d=var-pack-apron-polka-linear-equalities`: The APRON Polka linear equalities domain with variable packing. * `-d=var-pack-apron-ppl-polyhedra`: The APRON PPL polyhedra domain with variable packing. * `-d=var-pack-apron-ppl-linear-congruences`: The APRON PPL linear congruences domain with variable packing. * `-d=var-pack-apron-pkgrid-polyhedra-lin-cong`: The APRON Pkgrid polyhedra and linear congruences domain with variable packing. By default, IKOS uses the fastest and least precise numerical domain, the **interval** domain. If you want to run the analysis with a specific domain, use the `-d` parameter: ``` $ ikos -d=var-pack-dbm test.c ``` For most users, we recommend to analyze your project with the fastest and least precise domain (i.e, interval) first, and then try slower but more precise domains until the analysis is too long for you. This is the best way to reach a low rate of false positives (i.e, warnings). Here is a list of numerical domains, sorted from the fastest and least precise to the slowest and most precise: * `-d=interval` * `-d=gauge-interval-congruence` * `-d=var-pack-dbm` * `-d=var-pack-apron-octagon` * `-d=var-pack-apron-ppl-polyhedra` * `-d=dbm` * `-d=apron-octagon` * `-d=apron-ppl-polyhedra` You should consider running different analyses in this specific order. Please also note that: * Floating point variables are safely ignored. * In order to use the **APRON** abstract domain, you need to build IKOS with APRON first. See [APRON Support](#apron-support). ### Entry points By default, the analyzer assumes the entry point of the program is `main`. You can specify a list of entry points using the `--entry-points` parameter: ``` $ ikos --entry-points=foo,bar test.c ``` IKOS analyses each entry point independently, as if they were running in different processes. ### Multi-threading The analyzer can use multi-threading to speed up the analysis. You can specify the number of threads to use with the `--jobs` or `-j` parameter: ``` $ ikos --jobs=4 test.c ``` Use `-j` to use all available threads. By default, the analyzer only uses one thread. **Warning:** APRON numerical abstract domains are currently NOT thread-safe and might cause crashes. ### Optimization level The parameter `--opt` allows you to set the optimization level. Optimizations are performed by running a set of LLVM passes on the analyzed code. Available levels are: * **none**: Disable all optimizations. * **basic**: Basic set of optimizations (similar to `-O1`). This is the default value. * **aggressive**: Aggressive optimizations (similar to `-O3`). This is not recommended since it might hide errors. The translation from LLVM to AR might fail because of unsupported instructions. ### Inter-procedural vs Intra-procedural An **inter-procedural** analysis analyzes a function considering its call stack while an **intra-procedural** analysis ignores it. The former produces more precise results than the latter but it is often much more expensive. By default, IKOS performs an inter-procedural analysis. Use `--proc=intra` to perform an intra-procedural analysis. ### Fixpoint engine parameters The analyzer uses the theory of Abstract Interpretation to compute a fixpoint of the semantic of the program. The fixpoint engine can be tuned using several parameters. When visiting a loop, the engine will first compute a fixed number of iterations, then use a widening strategy periodically to approximate the behavior of the loop, until convergence. The fixed number of iterations performed before the widening strategy can be set using `--widening-delay`. By default, it is 1. The period of the widening strategy can be set using `--widening-period`. By default, it is 1, thus the widening strategy is always applied. The widening strategy can be set using `--widening-strategy=`: * **widen**: Use the widening operator to approximate the behavior of the loop (default) * **join**: Use the join operator, effectively computing all iterations (very slow) After reaching a fixpoint, the engine will perform extra iterations to regain precision using a narrowing strategy, until convergence. The narrowing strategy can be set using `--narrowing-strategy=`: * **narrow**: Use the narrowing operator, ensuring a fast convergence * **meet**: Use the meet operator, convergence can be slow * **auto**: Use the narrowing operator if available for the numerical abstract domain. Otherwise, perform 2 iterations using the meet operator (default) You can specify a fixed number of narrowing iterations to perform using `--narrowing-iterations`. You can specify the widening delay for a given function using `--widening-delay-functions`. For instance, `--widening-delay-functions="main:10, f:32"`. ### Partitioning The analyzer can use abstract domain partitioning based on integer variables using the `--partitioning` option. Using `--partitioning=return`, the analyzer will split the states at the end of a function according to the function return codes. This can be used to improve the precision of the analysis on the following code pattern: ```c int init() { int status = xxx(); if (status < 0) { return -1; // Error in xxx } status = yyy(); if (status < 0) { return -2; // Error in yyy } zzz(); return 0; // Success } ``` Instead of performing the abstract union and lose precision, the analyzer will keep 3 invariants for each outcome of the `init` function. Using `--partitioning=manual`, the analyzer will split the states according to the values of a given integer variable, set with `__ikos_partitioning_var_int(x)`. By default, partitioning is disabled. ### Hardware addresses In C code for embedded systems, it is usual to read or write at specific addresses to communicate with the hardware. By default, IKOS treats memory accesses at specific addresses as errors. You can provide the `--hardware-addresses` parameter to specify a range of valid memory addresses: ``` $ ikos --hardware-addresses=0x20-0x40 project.bc ``` During the analysis, IKOS will assume that memory accesses in the range `[0x20, 0x40]` (in bytes, inclusive) are safe. ### Other analysis options * `--globals-init`: use the given strategy for initialization of global variables. * `--no-init-globals`: disable global variable initialization for the given entry points. * `--no-liveness`: disable the liveness analysis. * `--no-pointer`: disable the pointer analysis. * `--no-widening-hints`: disable the detection of widening hints. * `--no-fixpoint-cache`: disable the cache of fixpoint for called functions. * `--no-checks`: disable all the checks * `--argc`: specify the value of `argc` for the analysis. * `--no-libc`: do not use libc intrinsics. Useful for bare metal programming. See `ikos --help` for more information. Report Options -------------- This section describes the most relevant report options supported by `ikos` and `ikos-report`. ### Format You can specify the format of the report using the `--format` (or `-f`) parameter. Available formats are: * **text**: Text format, convenient for the terminal; * **csv**: CSV format, convenient for spreadsheet import; * **json**: JSON format, convenient for developers. * **web**: Web interface, using ikos-view. * **no**: Disable the report. By default, if the report has less than 15 entries, it will be printed out using the text format. We recommend to use [ikos-view](#examine-a-report-with-ikos-view) to examine reports of large projects. ### File By default, the report is generated on the standard output. You can write it into a file using `--report-file=/path/to/report` ### Status Filter Use `--status-filter` to filter unwanted checks. Possible values are: **error**, **warning**, **safe**, **unreachable**. Note that you can use the wildcard character `*`, `+` and `-`. ### Analysis Filter Use `--analyses-filter` to filter unwanted checks. Possible values are described in [Checks](#checks). Note that you can use the wildcard character `*`, `+` and `-`. For instance: ``` $ ikos-report --analyses-filter='*,-boa' output.db ``` This will generate a report with all the checks, except buffer overflows. ### Verbosity Use `--report-verbosity [1-4]` to specify the verbosity. A verbosity of one will give you very short messages, where a verbosity of 4 will provide you with all the information the analyzer has. #### Other report options See `ikos-report --help` for more information. APRON Support ------------- [APRON](http://apron.cri.ensmp.fr/library/) is a C library for static analysis using Abstract Interpretation. It implements several complex abstract domains, such as the Polyhedra domain. IKOS provides a wrapper for APRON, allowing you to use any APRON abstract domain in the analyzer. To use APRON, first download, build and install it. Consider using the svn trunk. You will also need to build APRON with [Parma Polyhedra Library](http://bugseng.com/products/ppl/) enabled. Set `HAS_PPL = 1` and define `PPL_PREFIX` in your `Makefile.config` Now, to build IKOS with APRON support, just provide the option `-DAPRON_ROOT=/path/to/apron-install` when running cmake. For instance: ``` cmake \ -DCMAKE_INSTALL_PREFIX=/path/to/ikos-install \ -DAPRON_ROOT=/path/to/apron-install \ .. ``` See [Numerical abstract domains](#numerical-abstract-domains) for the list of numerical abstract domains. Analysis Assumptions -------------------- This section describes the assumptions made by the analyzer about the code. First, the analyzed code is compiled with the **Clang** compiler using the host target. Thus, Clang is responsible for specifying the data model (size of types), the data layout (alignments), the endianness, the signedness of `char`, the semantic of floating points, etc. depending on the host target. The analyzer uses the generated LLVM bitcode from Clang. This means that you can get different results depending on your host target. During the analysis, the analyzer will make the following assumptions: * The program is single-threaded. * The program does not receive signals. * The program does not receive interrupts. * Extern functions (without implementation) do not update global variables. * Extern functions can write on their pointer parameters, but only with one level of indirection: ```c extern void f(int** p); // Assume to write on *p but not **p ``` * Extern functions do not call user-defined functions (no callbacks). * Extern functions can throw exceptions. * Extern functions return well-initialized values. * Recursive function calls can update any value in memory. * Recursive function calls can throw exceptions. * Recursive function calls return well-initialized values. * Assembly codes are treated as extern function calls. * C standard library functions do not throw exceptions. Analyze an embedded software requiring a cross-compiler ------------------------------------------------------- Running the analyzer on an embedded software that requires a cross-compiler can be challenging. You should try to use [ikos-scan](#analyze-a-whole-project-with-ikos-scan) first, but this will probably fail with compiler errors. To solve this issue, you will need to create an alternative build file that compiles everything to LLVM bitcode. For instance, if you use `make`, you could create `Makefile.llvm` based on `Makefile`. In the alternative build file: * Locate the build rules that generate intermediate object files (`.o`). * In these rules, add the flag `-save-temps=obj` to the cross-compiler commands. This will generate a preprocessed file `.i` in addition to the `.o`. * At the end of these rules, add a command to compile the preprocessed file `.i` to LLVM bitcode `.bc` using: `clang -c -emit-llvm -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone -o `. * Locate the build rules that link the intermediate object files into binaries or shared libraries. * At the end of these rules, link the LLVM bitcodes `.bc` together using `llvm-link`. For instance, in `Makefile.llvm`: ``` %.o: %.c $(CC) -c $(CPPFLAGS) $(CFLAGS) -save-temps=obj $< -o $@ clang -c -emit-llvm -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone $(subst .o,.i,$@) -o $(subst .o,.bc,$@) program: a.o b.o $(CC) $(CPPFLAGS) $(CFLAGS) a.o b.o -o $@ llvm-link a.bc b.bc -o $@.bc clean: rm -f *.o *.i *.s *.bc ``` Then, run your build tool using the alternative build file to generate the LLVM bitcode (e.g, `make -f Makefile.llvm`). You can finally analyze your program by running ikos on the generated LLVM bitcode file (e.g, `ikos program.bc`). Model library functions to reduce warnings ------------------------------------------ The analyzer doesn't require the libraries used by your program. It will consider library functions as unknown extern functions and make some [assumptions](#analysis-assumptions) about them. The analyzer will produce a warning for each call to an unknown function. You can use `ikos-report --analyses-filter=sound output.db` to list these warnings, or filter the "ignored call side effect" in ikos-view. You can model library functions to improve the precision of the analysis and reduce the number of warnings. To model a library function, simply write a small implementation for it and link it in your program. This is usually called a "stub". For instance, a stub for `fgets` could be: ```c #include char* fgets(char* restrict str, int size, FILE* restrict stream) { __ikos_assert(size >= 0); __ikos_forget_mem(stream, sizeof(FILE)); __ikos_abstract_mem(str, size); return __ikos_nondet_int() ? str : NULL; } ``` The analyzer provides helper functions to implement these stubs, see [include/ikos/analyzer/intrinsic.h](include/ikos/analyzer/intrinsic.h) Note that most functions of the C standard library are already modeled, but not all of them. Overview of the source code --------------------------- The following illustrates the directory structure of this folder: ``` . ├── doc │ └── doxygen │ └── latex ├── include │ └── ikos │ └── analyzer │ ├── analysis │ │ ├── execution_engine │ │ ├── pointer │ │ └── value │ ├── checker │ ├── database │ │ └── table │ ├── json │ ├── support │ └── util ├── python │ └── ikos │ └── view │ ├── static │ │ ├── css │ │ └── js │ └── template ├── script ├── src │ ├── analysis │ │ ├── pointer │ │ └── value │ │ └── machine_int_domain │ ├── checker │ ├── database │ │ └── table │ ├── json │ └── util └── test └── regression ``` #### doc/ Contains Doxygen files. #### include/ * [include/ikos/analyzer/intrinsic.h](include/ikos/analyzer/intrinsic.h) contains definition of IKOS intrinsics that can be used in analyzed source code. ##### include/ikos/analyzer/analysis * [include/ikos/analyzer/analysis/call_context.hpp](include/ikos/analyzer/analysis/call_context.hpp) contains definition of a call context and the call context factory. * [include/ikos/analyzer/analysis/context.hpp](include/ikos/analyzer/analysis/context.hpp) contains definition of the global context of the analyzer. * [include/ikos/analyzer/analysis/literal.hpp](include/ikos/analyzer/analysis/literal.hpp) contains definition of the literal factory. It converts an AR operand to an AR-independent format. * [include/ikos/analyzer/analysis/liveness.hpp](include/ikos/analyzer/analysis/liveness.hpp) contains definition of the liveness analysis. It computes the set of live and dead variables for all functions. * [include/ikos/analyzer/analysis/memory_location.hpp](include/ikos/analyzer/analysis/memory_location.hpp) contains definition of symbolic memory locations (global, stack, heap-allocated, etc), and the memory location factory. * [include/ikos/analyzer/analysis/option.hpp](include/ikos/analyzer/analysis/option.hpp) contains definition of analysis options. * [include/ikos/analyzer/analysis/variable.hpp](include/ikos/analyzer/analysis/variable.hpp) contains definition of variables (local, global, etc), and the variable factory. ##### include/ikos/analyzer/analysis/execution_engine * [include/ikos/analyzer/analysis/execution_engine/context_insensitive.hpp](include/ikos/analyzer/analysis/execution_engine/context_insensitive.hpp) contains definition of `ContextInsensitiveCallExecutionEngine`, a call execution engine for context-insensitive analyses. * [include/ikos/analyzer/analysis/execution_engine/engine.hpp](include/ikos/analyzer/analysis/execution_engine/engine.hpp) contains definition of base classes for execution engines. It defines an API to execute AR statements. * [include/ikos/analyzer/analysis/execution_engine/inliner.hpp](include/ikos/analyzer/analysis/execution_engine/inliner.hpp) contains definition of `InlineCallExecutionEngine`, a call execution engine performing dynamic inlining. * [include/ikos/analyzer/analysis/execution_engine/numerical.hpp](include/ikos/analyzer/analysis/execution_engine/numerical.hpp) contains definition of `NumericalExecutionEngine`, the main execution engine of the analyzer. It executes AR statements on an abstract domain. ##### include/ikos/analyzer/analysis/pointer * [include/ikos/analyzer/analysis/pointer/constraint.hpp](include/ikos/analyzer/analysis/pointer/constraint.hpp) contains definition of `PointerConstraintsGenerator`, a generator of pointer constraints given an AR function or global variable. * [include/ikos/analyzer/analysis/pointer/function.hpp](include/ikos/analyzer/analysis/pointer/function.hpp) contains definition of a function pointer analysis. * [include/ikos/analyzer/analysis/pointer/pointer.hpp](include/ikos/analyzer/analysis/pointer/pointer.hpp) contains definition of a pointer analysis. ##### include/ikos/analyzer/analysis/value * [include/ikos/analyzer/analysis/value/abstract_domain.hpp](include/ikos/analyzer/analysis/value/abstract_domain.hpp) contains definition the abstract domain used during the value analysis. * [include/ikos/analyzer/analysis/value/interprocedural.hpp](include/ikos/analyzer/analysis/value/interprocedural.hpp) contains definition the interprocedural value analysis. * [include/ikos/analyzer/analysis/value/intraprocedural.hpp](include/ikos/analyzer/analysis/value/intraprocedural.hpp) contains definition the intraprocedural value analysis. * [include/ikos/analyzer/analysis/value/machine_int_domain.hpp](include/ikos/analyzer/analysis/value/machine_int_domain.hpp) contains definition the machine integer abstract domain used during the value analysis. ##### include/ikos/analyzer/checker Contains definition of the different checks on the code (buffer overflow, division by zero, etc.), given the result of an analysis. ##### include/ikos/analyzer/database/table Contains definition of the different output database tables. ##### include/ikos/analyzer/json Contains definition of a JSON library. ##### include/ikos/analyzer/support Contains various helpers, e.g, assertions. ##### include/ikos/analyzer/util Contains definition of utilities for the analyzer, e.g, logging, colors, timers, etc. #### python/ * [python/ikos/analyzer.py](python/ikos/analyzer.py) contains implementation of the `ikos` command line tool. * [python/ikos/report.py](python/ikos/report.py) contains implementation of the `ikos-report` command line tool. * [python/ikos/settings.py.in](python/ikos/settings.py.in) contains implementation of the `ikos-config` command line tool. * [python/ikos/view.py](python/ikos/view.py) contains implementation of the `ikos-view` command line tool. ##### python/ikos/analyzer/view Contains the web resources for ikos-view. It includes HTML, CSS and JS code. #### script/ Contains python entry points for the command line tools. #### src/ Contains implementation files, following the structure of `include/ikos/analyzer`. * [src/ikos_analyzer.cpp](src/ikos_analyzer.cpp) contains the implementation of `ikos-analyzer`. This is the entry point for all analyses. NASA-SW-VnV-ikos-1d98c65/analyzer/doc/000077500000000000000000000000001473507761200172105ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/doc/doxygen/000077500000000000000000000000001473507761200206655ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/doc/doxygen/Doxyfile.in000066400000000000000000001552041473507761200230070ustar00rootroot00000000000000#******************************************************************************* # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "Analyzer" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@/doc" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. # Obsolete # SHOW_DIRECTORIES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = NO # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = NO # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/src" \ "@CMAKE_CURRENT_SOURCE_DIR@/include" \ "@CMAKE_CURRENT_SOURCE_DIR@/doc/doxygen/intro" # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */.git* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = ikos::analyzer:: #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. # Obsolete # HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = pdflatex \\nonstopmode\\input # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = YES # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the reference definitions. This must be a list of .bib # files. The .bib extension is automatically appended if omitted. This # requires the bibtex tool to be installed. For LaTeX the style of the # bibliography can be controlled using LATEX_BIB_STYLE. See also \cite # for info how to create references. CITE_BIB_FILES = "${CMAKE_SOURCE_DIR}/doxygen/latex/biblio.bib" NASA-SW-VnV-ikos-1d98c65/analyzer/doc/doxygen/intro000066400000000000000000000026641473507761200217530ustar00rootroot00000000000000/// @mainpage IkosCC /// /// @section Introduction /// /// IkosCC is static analyzer based on abstract interpretation /// customized for proving absence of certain runtime errors on avionics /// software written in C. /// /// Currently, IkosCC proves abscence of the following runtime errors: /// /// - buffer overflow /// - integer division by zero /// - null dereference /// - use of uninitialized integer variables /// - user-defined properties (similar to C assert) /// /// IkosCC takes as input ARBOS AR \cite ikos code obtained after /// preprocessing LLVM bitecode \cite llvm. At its core, /// IkosCC relies on a value analysis 'a la' Mine \cite Mine06 that /// allows reasoning about scalars, pointers and memory /// contents. The value analysis has been extended with nullity and uninitialized variable /// information and it is parametric on the numerical domain /// (e.g., intervals \cite intervals, DBMs \cite dbm, octagons \cite octagons, etc). /// IkosCC uses a state-of-the-art fixpoint iterator \cite amatoSAS13. /// /// All the analyses in IkosCC are implemented as ARBOS plugins. /// The design of IkosCC is such that it significantly facilitates the /// tedious and non-trivial task of implementing new analyses. /// /// @section Documentation /// /// The documentation is, for now only, composed of the Doxygen /// documentation of the code. /// /// @section People /// /// Jorge A. Navas (jorge.a.navaslaserna@nasa.gov) /// NASA-SW-VnV-ikos-1d98c65/analyzer/doc/doxygen/latex/000077500000000000000000000000001473507761200220025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/doc/doxygen/latex/biblio.bib000066400000000000000000000334551473507761200237320ustar00rootroot00000000000000@Misc{clang, title ={A {C} language family frontend for {LLVM}}, howpublished = {Available at: \url{http://clang.llvm.org}} } @Misc{dragonegg, title ={{D}ragon{E}gg -- {U}sing {LLVM} as a {GCC} backend}, howpublished = {Available at: \url{http://dragonegg.llvm.org/}} } @Misc{mnav, key={mnav}, title ={{Micro {NAV} Autopilot Software}}, howpublished = {Available at: \url{http://sourceforge.net/projects/micronav/}} } @Misc{paparazzi, key={paparazzi}, title ={{Paparazzi Autopilot Software}}, howpublished = {Available at: \url{http://wiki.paparazziuav.org/wiki/Main_Page}} } @InProceedings{frama-c, Title = {Frama-C: A Software Analysis Perspective}, Author = {Cuoq, Pascal and Kirchner, Florent and Kosmatov, Nikolai and Prevosto, Virgile and Signoles, Julien and Yakobowski, Boris}, Booktitle = {{SEFM}}, Year = {2012}, OPTAddress = {Berlin, Heidelberg}, Pages = {233--247}, OPTPublisher = {Springer-Verlag}, } @inproceedings{llvm, author = {Chris Lattner and Vikram S. Adve}, title = {{LLVM:} {A} Compilation Framework for Lifelong Program Analysis {\&} Transformation}, booktitle = {{CGO}}, year = {2004}, pages = {75--88}, OPTcrossref = {DBLP:conf/cgo/2004}, OPTurl = {http://doi.ieeecomputersociety.org/10.1109/CGO.2004.1281665}, OPTdoi = {10.1109/CGO.2004.1281665}, OPTtimestamp = {Tue, 28 Oct 2014 22:20:09 +0100}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/conf/cgo/LattnerA04}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{ikos, author = {Guillaume Brat and Jorge A. Navas and Nija Shi and Arnaud Venet}, title = {{IKOS:} {A} Framework for Static Analysis Based on Abstract Interpretation}, booktitle = {{SEFM}}, year = {2014}, pages = {271--277}, OPTcrossref = {DBLP:conf/sefm/2014}, OPTurl = {http://dx.doi.org/10.1007/978-3-319-10431-7_20}, OPTdoi = {10.1007/978-3-319-10431-7_20}, OPTtimestamp = {Tue, 28 Oct 2014 22:45:12 +0100}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/conf/sefm/BratNSV14}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{intervals, author = {Patrick Cousot and Radhia Cousot}, title = {{S}tatic {D}etermination of {D}ynamic {P}roperties of {P}rograms}, booktitle = {Proceedings of the second international symposium on Programming, Paris, France}, year = {1976}, pages = {106-130}, } @inproceedings{dbm, author = {Antoine Min{\'{e}}}, title = {A Few Graph-Based Relational Numerical Abstract Domains}, booktitle = {{SAS}}, year = {2002}, pages = {117--132}, OPTcrossref = {DBLP:conf/sas/2002}, OPTurl = {http://dx.doi.org/10.1007/3-540-45789-5_11}, OPTdoi = {10.1007/3-540-45789-5_11}, OPTtimestamp = {Tue, 28 Oct 2014 22:51:39 +0100}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/conf/sas/Mine02}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @article{octagons, author = {Antoine Min{\'{e}}}, title = {The octagon abstract domain}, journal = {Higher-Order and Symbolic Computation}, volume = {19}, number = {1}, pages = {31--100}, year = {2006}, OPTurl = {http://dx.doi.org/10.1007/s10990-006-8609-1}, OPTdoi = {10.1007/s10990-006-8609-1}, OPTtimestamp = {Thu, 08 Feb 2007 15:24:34 +0100}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/journals/lisp/Mine06}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @Article{congruences, author = {Philippe Granger}, title = {Static Analysis of Arithmetical Congruences}, journal = {International Journal of Computer Mathematics}, year = {1989}, OPTkey = {}, OPTvolume = {}, OPTnumber = {}, OPTpages = {}, OPTmonth = {}, OPTnote = {}, OPTannote = {} } @inproceedings{cil, author = {George C. Necula and Scott McPeak and Shree Prakash Rahul and Westley Weimer}, title = {{CIL:} Intermediate Language and Tools for Analysis and Transformation of {C} Programs}, booktitle = {{CC}}, pages = {213--228}, year = {2002}, OPTcrossref = {DBLP:conf/cc/2002}, OPTurl = {http://dx.doi.org/10.1007/3-540-45937-5_16}, OPTdoi = {10.1007/3-540-45937-5_16}, OPTtimestamp = {Wed, 29 Jun 2011 15:49:36 +0200}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/conf/cc/NeculaMRW02}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{Cousot_POPL77, author = {Patrick Cousot and Radhia Cousot}, title = {Abstract Interpretation: A Unified Lattice Model for Static Analysis of Programs by Construction or Approximation of Fixpoints}, booktitle = {Proceedings of the Fourth Annual Symposium on Principles of Programming Languages}, pages = {238--252}, year = {1977}, } @inproceedings{Cousot_PLILP92, author = {P. Cousot and R. Cousot}, title = {Comparing the {Galois} Connection and Widening/Narrowing Approaches to Abstract Interpretation}, editor = {M. Bruynooghe and M. Wirsing}, booktitle = {International Symposium on Programming Language Implementation and Logic Programming}, OPTvolume = {631}, OPTseries = lncs, pages = {269--295}, OPTpublisher = springer, year = {1992}, } @inproceedings{CousotC79, author = {Patrick Cousot and Radhia Cousot}, title = {Systematic Design of Program Analysis Frameworks}, booktitle = {{POPL}}, pages = {269--282}, publisher = acm, year = {1979}, OPTee = {http://doi.acm.org/10.1145/567752.567778}, OPTcrossref = {DBLP:conf/popl/79}, OPTbibsource = {DBLP, http://dblp.uni-trier.de}, } @inproceedings{VenetB04, author = {Arnaud Venet and Guillaume P. Brat}, title = {{P}recise and {E}fficient {S}tatic {A}rray {B}ound {C}hecking for {L}arge {E}mbedded {C} {P}rograms}, booktitle = {PLDI}, year = 2004, pages = {231-242}, } @unpublished{CodeHawk, author={{Kestrel Technology}}, title={{C}ode{H}awk}, note={\url{http://www.kestreltechnology.com}}, } @unpublished{polyspace, author={{MathWorks}}, title={{Polyspace}}, note={\url{http://www.mathworks.com/products/polyspace}}, } @inproceedings{amatoSAS13, author = {Gianluca Amato and Francesca Scozzari}, title = {{L}ocalizing {W}idening and {N}arrowing}, booktitle = {SAS}, year = {2013}, pages = {25-42}, } @inproceedings{AstreeESOP05, author = {Patrick Cousot and Radhia Cousot and J{\'e}r{\^o}me Feret and Laurent Mauborgne and Antoine Min{\'e} and David Monniaux and Xavier Rival}, title = {The {A}STRE{\'E} {A}nalyzer}, booktitle = {ESOP}, year = {2005}, pages = {21-30}, OPTee = {http://dx.doi.org/10.1007/978-3-540-31987-0_3}, OPTcrossref = {DBLP:conf/esop/2005}, OPTbibsource = {DBLP, http://dblp.uni-trier.de} } @inproceedings{Venet04, author = {Arnaud Venet}, title = {A Scalable Nonuniform Pointer Analysis for Embedded Programs}, booktitle = {{SAS}}, pages = {149--164}, year = {2004}, OPTcrossref = {DBLP:conf/sas/2004}, OPTurl = {http://dx.doi.org/10.1007/978-3-540-27864-1_13}, OPTdoi = {10.1007/978-3-540-27864-1_13}, OPTtimestamp = {Thu, 07 Jul 2011 15:49:50 +0200}, OPTbiburl = {http://dblp1.uni-trier.de/rec/bib/conf/sas/Venet04}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{Mine06, author = {Antoine Min{\'{e}}}, title = {Field-sensitive value analysis of embedded {C} programs with union types and pointer arithmetics}, booktitle = {{LCTES}}, pages = {54--63}, year = {2006}, OPTcrossref = {DBLP:conf/lctrts/2006}, OPTurl = {http://doi.acm.org/10.1145/1134650.1134659}, OPTdoi = {10.1145/1134650.1134659}, OPTtimestamp = {Tue, 22 May 2012 15:24:56 +0200}, OPTbiburl = {http://dblp1.uni-trier.de/rec/bib/conf/lctrts/Mine06}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{wrapped, author = {Jorge A. Navas and Peter Schachte and Harald S{\o}ndergaard and Peter J. Stuckey}, title = {Signedness-Agnostic Program Analysis: Precise Integer Bounds for Low-Level Code}, booktitle = {{APLAS}}, pages = {115--130}, year = {2012}, OPTcrossref = {DBLP:conf/aplas/2012}, OPTurl = {http://dx.doi.org/10.1007/978-3-642-35182-2_9}, OPTdoi = {10.1007/978-3-642-35182-2_9}, OPTtimestamp = {Mon, 04 Feb 2013 12:47:37 +0100}, OPTbiburl = {http://dblp1.uni-trier.de/rec/bib/conf/aplas/NavasSSS12}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{Mine12, author = {Antoine Min{\'{e}}}, title = {Abstract Domains for Bit-Level Machine Integer and Floating-point Operations}, booktitle = {{ATx'12/WInG'12}}, pages = {55--70}, year = {2012}, OPTcrossref = {DBLP:conf/cade/2012atx}, OPTurl = {http://www.easychair.org/publications/?page=1847256608}, OPTtimestamp = {Mon, 02 Dec 2013 17:53:48 +0100}, OPTbiburl = {http://dblp1.uni-trier.de/rec/bib/conf/cade/Mine12}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @article{pagai, author = {Julien Henry and David Monniaux and Matthieu Moy}, title = {{PAGAI:} {A} Path Sensitive Static Analyser}, journal = {Electr. Notes Theor. Comput. Sci.}, volume = {289}, pages = {15--25}, year = {2012}, OPTurl = {http://dx.doi.org/10.1016/j.entcs.2012.11.003}, OPTdoi = {10.1016/j.entcs.2012.11.003}, OPTtimestamp = {Fri, 26 Dec 4448949 03:57:04 +}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/journals/entcs/HenryMM12}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{Cousot_Halbwachs_POPL78, author = {P. Cousot and N. Halbwachs}, title = {Automatic Discovery of Linear Constraints among Variables of a Program}, booktitle = {{POPL}}, pages = {84--97}, OPTpublisher = acm, year = {1978}, } @article{SimonK10, author = {Axel Simon and Andy King}, title = {The two variable per inequality abstract domain}, journal = {Higher-Order and Symbolic Computation}, volume = {23}, number = {1}, pages = {87--143}, year = {2010}, OPTurl = {http://dx.doi.org/10.1007/s10990-010-9062-8}, OPTdoi = {10.1007/s10990-010-9062-8}, OPTtimestamp = {Fri, 18 Jul 4427186 20:22:56 +}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/journals/lisp/SimonK10}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @article{Bouaziz12, author = {Mehdi Bouaziz}, title = {TreeKs: {A} Functor to Make Numerical Abstract Domains Scalable}, journal = {Electr. Notes Theor. Comput. Sci.}, volume = {287}, pages = {41--52}, year = {2012}, OPTurl = {http://dx.doi.org/10.1016/j.entcs.2012.09.005}, OPTdoi = {10.1016/j.entcs.2012.09.005}, OPTtimestamp = {Tue, 17 Jan 4454733 10:10:24 +}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/journals/entcs/Bouaziz12}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{Minevmcai06, author = {Antoine Min{\'{e}}}, title = {Symbolic Methods to Enhance the Precision of Numerical Abstract Domains}, booktitle = {{VMCAI}}, pages = {348--363}, year = {2006}, OPTcrossref = {DBLP:conf/vmcai/2006}, OPTurl = {http://dx.doi.org/10.1007/11609773_23}, OPTdoi = {10.1007/11609773_23}, OPTtimestamp = {Wed, 21 Dec 2005 14:41:43 +0100}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/conf/vmcai/Mine06}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @book{NNH, author = {Flemming Nielson and Hanne {Riis Nielson} and Chris Hankin}, title = {Principles of Program Analysis}, publisher = springer, year = {1999}, } @Misc{regehr-undefined, title ={{A} {G}uide to {U}ndefined {B}ehavior in {C} and {C}++}, howpublished = {Web blog \url{http://blog.regehr.org/archives/213} accessed 10 April 2015} } @Misc{llvm-undefined, title ={{W}hat {E}very {C} {P}rogrammer {S}hould {K}now {A}bout {U}ndefined {B}ehavior}, howpublished = {Web blog \url{http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html} accessed 10 April 2015} } @article{Karr76, author = {Michael Karr}, title = {Affine Relationships Among Variables of a Program}, journal = {Acta Inf.}, volume = {6}, pages = {133--151}, year = {1976}, OPTurl = {http://dx.doi.org/10.1007/BF00268497}, OPTdoi = {10.1007/BF00268497}, OPTtimestamp = {Tue, 11 Jan 2011 17:20:08 +0100}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/journals/acta/Karr76}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} } @inproceedings{Gauge, author = {Arnaud Venet}, title = {The Gauge Domain: Scalable Analysis of Linear Inequality Invariants}, booktitle = {{CAV}}, pages = {139--154}, year = {2012}, OPTcrossref = {DBLP:conf/cav/2012}, OPTurl = {http://dx.doi.org/10.1007/978-3-642-31424-7_15}, OPTdoi = {10.1007/978-3-642-31424-7_15}, OPTtimestamp = {Tue, 03 Jul 2012 08:52:37 +0200}, OPTbiburl = {http://dblp.uni-trier.de/rec/bib/conf/cav/Venet12}, OPTbibsource = {dblp computer science bibliography, http://dblp.org} }NASA-SW-VnV-ikos-1d98c65/analyzer/doc/doxygen/latex/overview.tex000066400000000000000000002224331473507761200244000ustar00rootroot00000000000000\documentclass[a4]{article} %% BEGIN MACROS \usepackage{newlfont} \usepackage{multicol} \usepackage{wrapfig} \usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} \usepackage{amsmath,amsfonts,amssymb} \usepackage{stmaryrd} % for semantic brackets [[ ]] \usepackage{xspace} \usepackage{color} \usepackage{listings} \usepackage{newlfont} \usepackage{ulem} % to show deleted text \usepackage{url} \usepackage[noend]{algorithmic} \usepackage{algorithm} \usepackage{hyperref} \usepackage{float} \usepackage[table]{xcolor} \usepackage{graphicx} \usepackage{fancyhdr} \usepackage{alltt} \usepackage{epsfig,psfrag} \usepackage{graphicx} \usepackage{caption} \usepackage{srcltx} \usepackage{theorem} \usepackage{latexsym} \usepackage{textcomp} \usepackage{setspace} \usepackage{cite} \usepackage{array} \usepackage{mdwmath} \usepackage{mdwtab} \usepackage{enumerate} \usepackage{wrapfig} \usepackage{subfig} %% \makeatletter %% \@ifpackageloaded{tex4ht}{% %% \def\pgfsysdriver{pgfsys-tex4ht.def}% %% }{% %% % only needed inside a class %% \begingroup\expandafter\expandafter\expandafter\endgroup %% \expandafter\ifx\csname HCode\endcsname\relax %% \else %% \def\pgfsysdriver{pgfsys-tex4ht.def}% %% \fi %% } %% \makeatother \usepackage{tikz} \usetikzlibrary{arrows,shapes.geometric,fit} \usetikzlibrary{calc} \usepackage[colorinlistoftodos,textwidth=4cm, shadow]{todonotes} \newcommand{\jorge}[1]{\todo[size=\small, color=green!40, inline]{TODO: #1}} \newcommand{\ignore}[1]{} % components and tools \newcommand{\arbos}{\textsc{Arbos}\xspace} \newcommand{\ikoscc}{\textsc{IkosCC}\xspace} \newcommand{\ikospp}{\textsc{IkosPP}\xspace} \newcommand{\ikos}{\textsc{Ikos}\xspace} \newcommand{\llvmgcc}{\texttt{llvm-gcc}\xspace} \newcommand{\llvmopt}{\texttt{opt}\xspace} \newcommand{\cgs}{\textsc{cgs}\xspace} \newcommand{\astree}{\textsc{Astre\'e}\xspace} \newcommand{\codehawk}{\textsc{CodeHawk}\xspace} \newcommand{\polyspace}{\textsc{PolySpace}\xspace} \newcommand{\framac}{\textsc{Frama-C}\xspace} \newcounter{proglineno} \newcommand{\putno}{\refstepcounter{proglineno}$\langle$\arabic{proglineno}$\rangle$~} \newcommand{\negate}[1]{\mbox{$\neg\ #1$}} \renewcommand{\vec}{\overline} \newcommand{\st}{\cdot} \newcommand{\cpp}{C\texttt{++}\xspace} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Drawing control flow graphs % Usage: \cfg{Terminals}{Nodes}{Straight Edges}{Additional Markup} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcommand{\cfg}[5][scale=0.8]{ \begin{tikzpicture}[yscale=-1,#1] \tikzstyle{terminal}=[draw,circle,minimum size=5pt,inner sep=0pt] \tikzstyle{stmt}=[draw,rectangle,inner sep=0.2pt, scale=0.8] \tikzstyle{edge}=[draw,thick,-stealth] %% \foreach \pos/\id in {#2} %% \node[terminal] (\id) at \pos {}; \foreach \pos/\id/\lbl in {#3} \node[stmt] (\id) at \pos {\lbl}; \foreach \start/\dest in {#4} \path[edge] (\start) -- (\dest); #5 \end{tikzpicture} } %% Wrapping a tabular environment in a macro, %% so it doesn't conflict with Tikz stuff. \newcommand{\wtab}[1]{ \begin{tabular}{l} #1 \end{tabular} } \newlength\CellWd \setlength\CellWd{0.87cm} % \DivRec{}{}{}{anchor node} \newcommand\DivRec[4]{% \node<+-> (#3) [draw,text width=6\CellWd,minimum height=30pt] [anchor=south] at (#4) {}; \foreach \a/\texto in {#2} {\draw<+-> let \p1=(#3.south west), \p2=( $ (#3.north east) - (#3.north west) $ ), \n1={veclen(\x2,\y2)/#1} in (\x1+\a*\n1,0|-#3.north) -- (\x1+\a*\n1,0|-#3.south); \path let \p1=(#3.south west), \p2=( $ (#3.north east) - (#3.north west) $ ), \n1={veclen(\x2,\y2)/#1} in node[xshift=-\n1/2] at (\x1+\a*\n1,0|-#3.center) {\texto}; } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % tiny CFG \tikzstyle{stmt} = [ellipse, text centered, draw=black, minimum width=0.3cm] \tikzstyle{edge} = [thick,-stealth] \tikzstyle{cfg} = [rectangle,minimum width=1cm,minimum height=1cm, text centered, draw=black] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \tikzstyle{file} = [rectangle, rounded corners, minimum width=0.75cm, minimum height=1cm, text centered, draw=black, fill=gray!30] \tikzstyle{tool} = [rectangle, minimum width=1cm, minimum height=0.5cm, text centered, draw=black, fill=red!30] \tikzstyle{ikoscc} = [rectangle, minimum width=1cm, minimum height=1cm, text centered, draw=black, fill=blue!30, ultra thick] \tikzstyle{fixpo} = [rectangle, minimum width=1cm, minimum height=1cm, text centered, draw=black, ultra thick] \tikzstyle{va} = [rectangle, minimum width=5.5cm, minimum height=3cm, text centered, draw=black, ultra thick] \tikzstyle{results} = [rectangle, rounded corners, minimum width=0.5cm, minimum height=1cm, text centered, draw=black, fill=green!30] \tikzstyle{arrow} = [thick,->,>=stealth] \tikzstyle{subblock} =[ draw, rectangle, minimum height=1.25cm, minimum width=1.5cm,align=center] \tikzstyle{analysis} = [rectangle, minimum width=1.25cm, minimum height=1cm, text centered, draw=black] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% END MACROS \begin{document} \title{\ikoscc: An Abstract Interpretation-Based Static Analyzer for Avionics Software} \author{Jorge A. Navas \\ NASA Ames Research Center / SGT} \maketitle %\begin{abstract} %\end{abstract} \normalem \section{Introduction} \label{sec:intro} \ikoscc is a static analyzer based on abstract interpretation customized for certifying avionics software. % \ikoscc relies on the framework of \emph{Abstract Interpretation}~\cite{intervals,Cousot_POPL77} to ensure that any property inferred holds for all possible executions of the program. The fundamental idea behind abstract interpretation is to approximate all possible values that a program variable can take at any program point by a set that can guarantee the soundness of the analysis while can be represented efficiently. Unfortunately, the use of approximations may result into \emph{false alarms}. That is, the analyzer can report a potential error when the program is actually safe. Therefore, the main challenge is to minimize the number of false alarms without sacrificing scalability, otherwise it can defeat the usefulness of the analyzer. Although a general-purpose static analyzer with a negligible false alarm rate is highly desirable it is often impractical. Instead, \ikoscc has been carefully designed for being effective at proving absence of runtime errors caused by C undefined behavior in avionics software. % Such software rarely contains dynamic allocation (i.e., no \texttt{malloc}) \todo{This turns out not to be true. \textsf{mnav} performs \texttt{malloc}'s inside loops.} and loop bounds are often statically known (but not always). Although these features simplify static analysis, there are other challenges. For instance, the control flow is often complex; there are many pointers simulating call by reference; there are arrays; and, finally, the program state is kept in a large global structure. % Currently, \ikoscc can prove absence of the following runtime errors: \begin{itemize} \item buffer overflow (out-of-bound array indexing) %\item integer overflow \item integer division by zero \item null pointer dereference \item read of uninitialized variables \item violation of user-defined properties to prove additional runtime properties (similar to C \texttt{assert}) \end{itemize} The rest of this document is organized as follows. Section~\ref{sec:overview} presents a general overview of the tool. Section~\ref{sec:preprocessor} describes \ikospp, a pre-processor that can optimize the input program to facilitate the task of static analysis. Section~\ref{sec:analysis} presents the internal design of \ikoscc describing which abstract domains are used and how they are combined. \ignore{, as well as, some key implementation details. Section~\ref{sec:related} describes some related work.} Section~\ref{sec:usage} describes how to use the analyzer, Section~\ref{sec:results} describes our experimental evaluation with real C flight control systems and software used in several NASA missions, and finally, Section~\ref{sec:future} states current limitations of the tool as well as future improvements. \section{Overview} \label{sec:overview} \begin{figure}[t] \begin{center} \begin{minipage}{0.5\linewidth} \begin{tikzpicture}[node distance=1.75cm] %%%%%%%%%%%%%%%% % nodes %%%%%%%%%%%%%%%% \node (c) [file] {.c}; \node (llvmgcc) [tool, right of=c] {\llvmgcc}; \node (bc) [file, right of=llvmgcc] {.bc}; \node (ikospp) [ikoscc, right of=bc] {\ikospp}; \node (ppbc) [file, right of=ikospp] {.bc}; \node (opt) [tool, below of=ikospp] { \begin{tabular}{c} \llvmopt: \\ \begin{scriptsize} %\setlength\tabcolsep{0} \begin{tabular}{c} \texttt{-mem2reg} \\ \texttt{-lowerswitch} \\ \texttt{-loweratomic} \end{tabular} \end{scriptsize} \end{tabular} }; \node (arbc) [file, below of=opt] {.bc}; \node (arbos) [tool, left of=arbc] {\arbos}; \node (ar) [file, left of=arbos] {.ar}; \node (ikoscc) [ikoscc, left of=ar] {\ikoscc}; \node (results) [results, above of=ikoscc] { \begin{tabular}{c} Results: \\ \begin{scriptsize} \begin{tabular}{l} safe \\ error \\ warning \end{tabular} \end{scriptsize} \end{tabular} }; %%%%%%%%%%%%%%%%% % arrows %%%%%%%%%%%%%%%%% \draw [arrow] (c) -- (llvmgcc); \draw [arrow] (llvmgcc) -- (bc); \draw [arrow] (bc) -- (ikospp); \draw [arrow] (bc) -- (opt); \draw [arrow] (ikospp) -- (ppbc); \draw [arrow] (ppbc) -- (opt); \draw [arrow] (opt) -- (arbc); \draw [arrow] (arbc) -- (arbos); \draw [arrow] (arbos) -- (ar); \draw [arrow] (ar) -- (ikoscc); \draw [arrow] (ikoscc) -- (results); \end{tikzpicture} \end{minipage} \end{center} \caption{Architecture Overview} \label{fig:architecture} \end{figure} Figure~\ref{fig:architecture} illustrates the overall architecture of our static analyzer. % First, a C input program is translated to LLVM bitcode~\cite{llvm} via \llvmgcc. Once we have obtained the bitcode, a pre-processor called \ikospp performs optimizations and transformations. Such pre-preprocessing is optional and its only mission is to optimize the LLVM bitcode to make easier the task of static analysis. Even if the pre-processor is disabled, we must use LLVM \llvmopt tool for performing few transformations in order to ensure correct results: SSA transformation, lowering of \texttt{switch} instructions into \texttt{if-then-else}s, and lowering of \texttt{atomic} instructions. Next, \arbos~\cite{ikos} translates the bitcode into an Abstract Representation (AR) form. Before that, it performs some further LLVM transformations such as ensuring the presence of only one exit block per function, lowering constant expressions, and lowering \texttt{select} instructions. Compared to the LLVM bitcode, the AR takes a different angle on how to express the semantics of a C program. % For example, $\phi$ nodes originated from SSA form are replaced with assignments, the instruction set is more regular and the control flow is expressed in a declarative way using non-deterministic choices and \emph{assume}s rather than conditional branch instructions. Finally, complex LLVM instructions such that \texttt{getElementPtr} used to model pointer arithmetic are replaced by atomic operations on the pointer offsets expressed in bytes. % The rationale behind the use of AR is that any generic abstract interpretation algorithm can process it without any change in its implementation. Then, \ikoscc takes AR code as input, performs analysis on it, and finally, reports the results to the user. Currently, results are being stored in a database but it is straightforward to output the results to different formats. % To facilitate the development of new analyses, \arbos provides a \emph{plugin framework} that allows these analyses to use the AR code as intermediate representation in a very simple way. This is very similar to the functionality provided by the LLVM tool \texttt{opt} but we replace the use of LLVM bitcode with AR code. All the analyses implemented in \ikoscc are defined as \emph{arbos plugins}. The rest of this document focuses on the two new components of our architecture: \ikospp and \ikoscc. The rest of the components have been described elsewhere (e.g.,~\cite{ikos}). \section{\ikospp} \label{sec:preprocessor} \ikospp is a pre-processor that performs compiler optimizations and pre-processing to simplify the static analysis task. %The use of %\ikospp is completely optional and it does not affect the soundness of %the results. The most relevant transformations are: %% without bullets %% As a first transformation we \emph{internalize} all functions to %% enable global optimizations such as replacement of \emph{global %% aggregates} (e.g., arrays and structs) with \emph{scalars}. These %% can have a huge impact later on the analysis since data that resides, %% in principle, in the heap or stack can be lowered to registers and %% therefore might be represented using integer variables. From the %% perspective of a static analyzer, having a scalar variable facilitates %% significantly the analysis' tasks since no memory reasoning is %% needed. For instance, this code fragment: \texttt{struct foo $\{$ int %% x, int y $\}$; int main () $\{$ ... $\}$} might be transformed into: %% \texttt{int main () $\{$ int x; int y;... $\}$}. We also perform dead %% code elimination, and CFG simplifications to make the bitcode smaller %% and simpler. Some loop transformations are also performed to ensure %% that loops have one single entry and exit, loop-closed SSA to satisfy %% that no SSA variable is used outside of the loop, and simple %% loop-invariant code motion. \begin{itemize} \item \emph{internalization} of all functions to enable global optimizations such as replacement of \emph{global aggregates} (e.g., arrays and structs) with \emph{scalars}. These can have a huge impact later on the analysis since data that resides, in principle, in the heap or stack can be lowered to registers and therefore might be represented using integer variables. From the perspective of a static analyzer, having a scalar variable facilitates significantly the analysis' tasks since no memory reasoning is needed. For instance, this code fragment: \begin{small} \begin{verbatim} struct foo { int x; int y; } int main () { ... } \end{verbatim} \end{small} \noindent can be transformed into: \begin{small} \begin{verbatim} int main () { int x; int y; } \end{verbatim} \end{small} \item \emph{dead code elimination} and \emph{CFG simplifications} to make the bitcode smaller and simpler \item some \emph{loop normalizations} to ensure that loops have one single entry and exit, \emph{loop-closed SSA} to satisfy that no SSA variable is used outside of the loop, and simple \emph{loop-invariant code motion} %% \item \emph{removal of side-effect-free calls (e.g., printf-like %% calls)}. For instance, the removal of \texttt{printf} calls can %% trigger (via dead code elimination) the removal of strings in case %% they only feed these calls. Strings are represented in LLVM bitecode %% as constant global arrays of chars. \end{itemize} Note that most of these transformations have often a direct impact either in terms of accuracy (e.g., replacement of replacement of aggregates into scalars) or efficiency (e.g., dead code elimination). However, another major benefit from using \ikospp is the possibility of replacing more expensive abstract domains with cheaper ones without incurring in any loss of precision. \begin{figure}[t] \centering \begin{tabular}[h]{cc} \begin{minipage}[t]{0.5\linewidth} \begin{tabbing} xx \= xx \= xx \= \kill $\langle 1 \rangle$ \> \textbf{if} (*) \\ $\langle 2 \rangle$ \> \> x = -10; \\ $\langle 3 \rangle$ \> \textbf{else} \\ $\langle 4 \rangle$ \> \> x = 20; \\ $\langle 5 \rangle$ \> y=x; \\ $\langle 6 \rangle$ \> \textbf{if} (y $\leq$ 0) \\ $\langle 7 \rangle$ \> \> y = -x; \\ \end{tabbing} \end{minipage} & \begin{minipage}[t]{0.5\linewidth} \begin{tabbing} xx \= xx \= xx \= \kill $\langle 1 \rangle$ \> \textbf{if} (*) \\ $\langle 2 \rangle$ \> \> x = -10; \\ $\langle 3 \rangle$ \> \textbf{else} \\ $\langle 4 \rangle$ \> \> x = 20; \\ $\langle 5 \rangle$ \> \textbf{if} (x $\leq$ 0) \\ $\langle 6 \rangle$ \> \> y = -x; \\ $\langle 7 \rangle$ \> \textbf{else} \\ $\langle 8 \rangle$ \> \> y = x; \\ \end{tabbing} \end{minipage} \\ \mbox{(a)} & \mbox{(b)} \\ \end{tabular} \caption{Original program and after transformed by \ikospp} \label{fig:vmcai06-1} \end{figure} For example, if we would analyze the program in Figure~\ref{fig:vmcai06-1}(a) with intervals~\cite{intervals} we would infer before $\langle 5 \rangle$ is executed that $x \in [10,20]$ and after $\langle 5 \rangle$ that $x \in [10,20],~ y \in [10,20]$. If $\langle 7 \rangle$ is reached then we would have $y \in [-20,-10], x\in [10,20]$ and after \emph{joining} with the else branch that keeps unchanged $y$ we would obtain that $y \in [-20,20], x\in [10,20]$. However, note that after $\langle 6 \rangle$ is executed we know that $y$ cannot be a positive number but also the same for $x$ holds since we know that $x = y$. By adding this fact we could infer after $\langle 7 \rangle$ that $y \in [0,10]$ and therefore after joining with the omitted else branch we could have inferred a more precise bound $y \in [-10,20]$. % Using a relational domain such as linear equalities~\cite{Karr76}, DBM\cite{dbm} or Octagons~\cite{octagons} we could have also inferred the most precise bound for $y$. However, as we will describe in Section~\ref{sec:analysis} these relational domains are more expensive and we prefer to avoid them unless it is strictly necessary. % Min\'{e}~\cite{Minevmcai06} made first this observation and to mitigate this problem he proposed a simple abstract domain to keep track of syntactic relations~\cite{Minevmcai06} between variables that can be combined with intervals while keeping same time complexity than the original intervals. % Our main insight here is that \ikospp can help us avoid implementing this new abstract domain since its transformations can cover some of these cases. Figure~\ref{fig:vmcai06-1}(b) shows the transformed program after executing \ikospp. Note that at line $\langle 5 \rangle$ \ikospp replaces $y$ with $x$ in the branch condition so that intervals by itself can infer that $y \in [-10,20]$. Although most of these transformations are provided directly by LLVM, note that they focus on facilitating the task of code generation and ultimately, reducing execution time and/or memory requirements. The goal of \ikospp differs substantially from that since our goal is to help static analysis by increasing precision and/or reducing analysis time. A good example of this mismatch is the LLVM pass \texttt{instcombine} which performs peephole optimizations. Some of these optimizations replace \texttt{mul X, 2} which is a linear arithmetic operation into \texttt{shl X, 1} which is a bitwise operation. \todo{This is not probably the best example.} For code generation the latter is better because CPUs have generally specific instructions to perform left shift in one clock cycle. However, thought most abstract domains can model precisely linear arithmetic operations they cannot usually handle bitwise operations and thus, we could have significant precision losses. Another peephole optimization is to replace branch instructions into logical operators. This can also have a very negative impact on static analysis in terms of precision.\todo{Need to review this a bit. We ran some experiments and \texttt{instcombine} always improve our results.} Another example is \texttt{indvars} which transforms each loop to have a single canonical \emph{induction variable} starting at zero and stepping by one. This transformation is very relevant because it can trigger other LLVM optimizations that can further simplify or even delete loops. It can help static analysis for at least two reasons: speed up fixpoint convergence (most of the analyzer's time is spent on loops), and it can improve the efficiency of relational domains since within a loop only relations with respect to the induction variable would suffice, and thus, it would reduce the need of keeping track $O(n^{2})$ relations to $O(n)$. However, \texttt{indvars} rewrites exit loop conditions which are inequalities (e.g., $x \leq 10$) into disequations (e.g., $ x \neq 10 \equiv x < 10 \vee x > 10$). This can produce significant precision losses since standard abstract domains cannot reason about disjunctions. Therefore, we also modify some of the steps performed by the above LLVM passes to avoid incurring into unnecessary precision losses. \ignore{ These issues can be avoided by disabling or modifying some of the steps performed by the above LLVM passes. However, there are other problems. \begin{figure}[t] \centering \begin{tabular}[h]{cc} \begin{minipage}[t]{0.5\linewidth} \begin{tabbing} xx \= xx \= xx \= \kill \textbf{int} x[10]; \\ \textbf{int} i; \\ \textbf{for} ($i=0$; $i < 10$; $i=i+1$) $\{$ \\ \> x[i] = 0; \\ $\}$ \\ \end{tabbing} \end{minipage} & \begin{minipage}[t]{0.5\linewidth} \begin{tabbing} xx \= xx \= xx \= \kill \textbf{int} x[10]; \\ \textbf{int} i, *b; \\ \textbf{for} (b = $\&$x[0]; ; $b=b+4$) $\{$ \\ \> *b = 0; \\ \> $i=i+1$; \\ \> \textbf{if} ($i \geq 10$) \textbf{break}; \\ $\}$ \\ \end{tabbing} \end{minipage} \\ \mbox{(a)} & \mbox{(b)} \\ \end{tabular} \caption{Original program and after induction variable transformation} \label{fig:indvars} \end{figure} Figure~\ref{fig:indvars}(a) shows a program that traverses a C array and updates each of its cells to zero, and Figure~\ref{fig:indvars}(b) shows the same program after being transformed by \texttt{-indvars}. For clarity, we show the corresponding C transformed program rather than LLVM bitcode. Let us assume that we would like to prove that the program in Figure~\ref{fig:indvars}(a) cannot access the array \texttt{x} out of bounds. For that, using intervals~\cite{intervals} we can infer that $0 \leq i \leq 9$ inside the loop, and therefore all the array writes are safe since the size of \texttt{x} is $10$. Using Figure~\ref{fig:indvars}(b) we know that the induction variable is $i$ and we can still infer its bounds $0 \leq i \leq 9$ using intervals. However, the array is now accessed via the pointer \texttt{b}. In order to prove safety we need to infer the relationship $b = 4 \times i$ (the constant $4$ is assuming the size of \texttt{int} is $4$ bytes). This invariant cannot be expressed anymore with intervals, and thus, we would need to use a more expressive (but expensive) abstract domain. Note that even octagons are not expressive enough. We would need to use at least TVPI~\cite{SimonK10}. With a reduced product of intervals with congruences we would obtain $\langle 0 \leq i \leq 9, b \equiv 4\mathbb{Z} + 0\rangle$ but this does not help. } %% // Another example from Mine's paper. %% // Again, it turns out that LLVM optimizations is enough so no need of %% // "linearization" here. %% void lin_1(){ %% int x,y,z; %% if (__ikos_unknown()) x= 5; else x=10; %% y = 3 * x - x; // LLVM ==> y = 2*x; %% __ikos_assert(y >= 10 && y <= 20); %% } %% // Another example from Mine's paper. %% void lin_2(){ %% int t,x,y,z; %% if (__ikos_unknown()) x= 5; else x=10; %% if (__ikos_unknown()) y= 2; else y=4; %% if (__ikos_unknown()) z= 6; else z=9; %% t = (x*y) - (x*z) + z; // t = [-74,19] %% // LLVM ==> (y-z)*x +z ==> t = [-64,-1] %% __ikos_assert(t >= -74 && t <= 19); %% } \section{\ikoscc} \label{sec:analysis} This section assumes that the reader is familiar with the basic concepts of Abstract Interpretation. Giving an introduction about Abstract Interpretation is beyond the scope of this document. For details, we refer to~\cite{Cousot_POPL77,CousotC79,NNH}. Figure~\ref{fig:ikoscc} depicts the core of the analyzer. First, the AR code is translated into a standard Control Flow Graph (CFG). This translation is straightforward since AR code already removed $\phi$ nodes (replaced with \emph{assignments}) and branch instructions (replaced with \emph{assume}s), among other simplifications. Basic blocks in the AR code are mapped to nodes in the CFG and edge $i \rightarrow j$ is added in the CFG if a basic block $i$ is a predecessor of block $j$ in the AR code. At the core of all analyses we have a \emph{fixpoint iterator} and a \emph{value analysis}. The fixpoint iterator computes the least fixed point of a set of equations extracted from the semantics of the program~\cite{intervals,Cousot_POPL77}. Since some domains might have \emph{infinite ascending chains} termination must be ensured via a \emph{widening} operator which is provided by the underlying abstract domain. Moreover, a \emph{narrowing} operator must be also provided to recover from precision losses caused by widening~\cite{Cousot_PLILP92}. \ikoscc provides a state-of-the-art fixpoint iterator that interleaves widening and narrowing in a very precise manner~\cite{amatoSAS13}. However, other fixpoint iterators can be plugin without effort. The semantics of the program is approximated using a value analysis 'a la' Min\'{e}~\cite{Mine06}. This value analysis computes for each program variable the set of all possible values to which the variable can be bound considering all possible executions. Figure~\ref{fig:ikoscc} shows how the analyses interact with the fixpoint iterator and the value analysis. All the analyses consist of two phases: \emph{analysis} and \emph{check}. The goal of the analysis phase is to compute all the invariants that hold at the entry of each CFG node. To achieve this, a fixpoint over the CFG is computed. During the fixpoint computation, given the abstract state $Pre^{\#}$ that holds at the entry of a CFG node the value analysis computes its abstract image $Post^{\#}$ representing the abstract state holding at the exit of that node. Upon completion of the analysis phase, each analysis checks for its property of interest using the invariants computed during the analysis phase, and reports to the user the results. \begin{figure}[t] \begin{center} \begin{minipage}{1.0\linewidth} \begin{tikzpicture} %%%%%%%%%%%%%%%% % nodes %%%%%%%%%%%%%%%% \node (ar) [file,yshift=-2cm] {.ar}; %% \node (entry) [stmt, scale=0.5,right of=ar,xshift=3.5cm,yshift=1.5cm] {}; \node (loop) [stmt, scale=0.5,below of=entry] {}; \node (looptt) [stmt, scale=0.5,left of=loop, below of=loop] {}; \node (loopff) [stmt, scale=0.5,right of=loop, below of=loop] {}; \node (loopbody) [stmt, scale=0.5,below of=looptt] {}; \node (return) [stmt, scale=0.5, below of=loopff] {}; \draw [edge,scale=0.5] (entry) -- (loop); \draw [edge,scale=0.5] (loop) -- (looptt); \draw [edge,scale=0.5] (loop) -- (loopff); \draw [edge,scale=0.5] (looptt) -- (loopbody); \draw[edge,scale=0.5] (loopbody.east) -- (4.5,-5.5) -- (loop); \draw [edge,scale=0.5] (loopff) -- (return); %% \node (cfg) [draw=red, thick, fit={(entry) (loop) (looptt) (loopff) (loopbody) (return)}] {}; \node (fixpo) [fixpo, right of=entry, xshift=2cm,yshift=-0.75cm] {\textsf{Fixpoint}}; \node (va) [va, below of=fixpo, yshift=-2cm] {}; \node [below right, xshift=1cm] at (va.north west) { \begin{tabular}{c} \\ \textsf{Value Analysis} \\ \scriptsize (Scalar $\times$ Ptr $\times$ Mem) \\ \scriptsize Abstract domains: \end{tabular} }; \DivRec{6}{1/Int,2/Cong,3/DBM,4/Oct,5/Null,6/Init}{domains}{va.south} \node (boa) [analysis, right of=va,xshift=3cm,yshift=2cm] {\textsf{boa}}; \node (dbz) [analysis, below of=boa] {\textsf{dbz}}; \node (null) [analysis, below of =dbz] {\textsf{null}}; \node (uva) [analysis, below of=null] {\textsf{uva}}; \node (prover) [analysis, below of=uva] {\textsf{prove}}; \node (analyses) [draw=black, ultra thick, fit={ (boa) (dbz) (null) (uva) (prover)}] {}; \node (IkosCC) [draw=blue, ultra thick, dotted, fit={(cfg) (fixpo) (va) (analyses)}] {}; \node (results) [results, right of=analyses, xshift=1.5cm] { \begin{tabular}{c} Results: \\ \begin{scriptsize} \begin{tabular}{l} safe \\ error \\ warning \end{tabular} \end{scriptsize} \end{tabular} }; %%%%%%%%%%%%%%%%% % arrows %%%%%%%%%%%%%%%%% \draw [arrow] (ar) -- (cfg); \draw [arrow] (cfg) -- (fixpo); \draw [arrow] ([yshift=0.8cm] cfg.east) -- ++(6.5,0) -- ([xshift=0.2cm] analyses.north); \draw [arrow] ([xshift=-0.4cm] fixpo.south) -- ( [xshift=-0.4cm] va.north) node [midway, left] {$Pre^{\#}$}; \draw [arrow] ([xshift=0.4cm] va.north) -- ([xshift=0.4cm] fixpo.south) node [midway, right] {$Post^{\#}$}; \draw [arrow] (analyses) -- (results); % \draw [arrow] (fixpo.east) -- (analyses.north); \draw [arrow,<->] (fixpo.east) -- node [left, above] {analyze} node [left, below] {check} ++(3.25,0) -- (analyses.north); %\draw [arrow] ([yshift=0.1cm] va.east) -- ([yshift=0.1cm] analyses.west) ; %\draw [arrow] ([yshift=0.7cm] analyses.west) -- ([yshift=0.7cm] va.east); \end{tikzpicture} \end{minipage} \end{center} \caption{Internal Design of \ikoscc} \label{fig:ikoscc} \end{figure} \subsection{Value Analysis} \label{subsec:value} %\vspace{2mm} %\noindent \textbf{Value Analysis.} We adopt the modular design of~\cite{Mine06} in which all the operations performed by the value analysis are reduced to simpler operations using a base numerical abstract domain. Here and in the rest of this section, we refer to this base numerical abstract domain as $\mathcal{N}^{\#}$. Similar to~\cite{Mine06} our value analysis can also model program variables with different degrees of precision which are presented from the coarsest to the finest: \begin{enumerate} \item integer scalars: models integer scalar variables originated from LLVM numeric \emph{registers}. Each of these scalar variables are mapped directly to a \emph{dimension} in $\mathcal{N}^{\#}$. %This level of precision is suitable when only integer variables are %relevant for the property of interest. \item integer scalars and pointer addresses (but not contents): models integer and pointer registers. Each pointer $p$ represents a pair $\langle B, o \rangle$ where $B$ is the base address and $o$ represents the offset from the base address of the object that contains $p$. A major benefit of using a low-level language like LLVM as input of our analyzer is that pairs $\langle B, o \rangle$ are already represented as different pointer registers, and thus, in practice, each pointer register can be directly translated to a dimension in $\mathcal{N}^{\#}$. For aliasing purposes, given a pointer $p$ we keep track, in a \emph{flow-sensitive} manner, of the set of possible memory locations ($\mathtt{\&}$'s addresses and \texttt{malloc}-like allocation sites) to which $p$ may point to. The points-to sets can also include function pointers. This level of precision is suitable when in addition to reason about integer scalars the analysis needs also to know if two pointers can point to the same memory location but it can ignore their contents. \item memory contents: models integer scalars, pointer addresses, and pointer contents but only with integer type. The heap is modelled by a set of synthetic \emph{cells}. To deal precisely with pointer casts and type unions in C programs, a cell is represented by a triple $\langle B, i, s\rangle$ which models all the bits starting at offset $i$ starting from base address $B$ up to $i + s - 1$. As a result, each cell can then be mapped into another dimension in $\mathcal{N}^{\#}$. In this case, this new dimension approximates the content of the cell. For each memory read/write the value analysis needs to update accordingly these cells. In doing so, aliasing between cells must to be taken into account. This modelling is precise enough even in presence of pointer castings, pointer arithmetic, and function pointers. Note that a key feature of the Min\'{e}'s approach is that both integer scalars, pointer offsets, and cells are ultimately represented as dimensions in $\mathcal{N}^{\#}$. Nevertheless, this heap modelling is just an abstraction and therefore, we may lose precision in some cases. The main limitation is that cells can be only of integer type which means that we can only model pointers with one level of indirection. That is, we can model precisely the content of a pointer $p$ defined as $\texttt{int *p}$ but we cannot, for instance, to model the content of pointers of the form $\texttt{int **p}$. \end{enumerate} \subsection{Base Numerical Abstract Domains} %\vspace{2mm} %\noindent \textbf{Base Numerical Abstract Domains.} As we mentioned above, the value analysis reduces all its operations to simpler operations using a base numerical abstract domain $\mathcal{N}^{\#}$. New abstract domains can be easily added following a very simple interface. Currently, \ikoscc provides out-of-the-box the following classical domains: \begin{itemize} \item Int: intervals~\cite{intervals} expresses constraints of the form $\pm x \leq k$ where $ x$ is a variable and $k$ is a constant. \item Cong: congruences~\cite{congruences} expresses constraints of the form $a\mathbb{Z} + b$ where $a$ and $b$ are integers. For instance, all even numbers are represented as $2\mathbb{Z} + 0$ while all odd numbers are as $2\mathbb{Z} + 1$. \item DBM: difference-bounds matrix~\cite{dbm} can express constraints $x - y \leq k$, where $x,y$ are variables and $k$ is a constant. \item Oct: octagons~\cite{octagons} expresses constraints $\pm x \pm y \leq k$, where $x,y$ are variables and $k$ is a constant. \end{itemize} It is folklore in Abstract Interpretation that each of these domains represents a trade-off between precision and complexity. The least expensive domains are Int and Cong. Both have a time complexity of $O(n)$ (where $n$ is the number of program variables). They are called \emph{non-relational} domains because they model each variable alone without considering the rest. Int is suitable for representing the \emph{bounds} of a variable (e.g., the constraints $x \leq 100 \wedge -x \leq -10$ denote that $x$ is between $10$ and $100$) while Cong can model the \emph{density} of a variable by expressing for instance, that $x$ is an even number or multiple of $6$ ($2\mathbb{Z} + 0$ and $6\mathbb{Z} + 0$, respectively). DBM and Oct are called \emph{relational} domains because they can express relations among variables. For instance, the constraints $(x - y \leq 0)~ \wedge~ (y - x \leq 0)$ denote that $x$ is equal to $y$ even if their bounds might be unknown. DBM is strictly more precise than Int but its time complexity increases to $O(n^{3})$. Oct is strictly more precise than DBM and it preserves a worst-case time complexity of $O(n^{3})$. Cong is incomparable to the other domains but usually too weak by itself. For this reason, \ikoscc also implements a combination (\emph{reduced product}) of Int with Cong (Int $\times$ Cong). A key principle of the Abstract Interpretation framework is to build complex abstract domains from the combination of simpler ones via reduced product or functor domains. For this, \ikoscc provides support for building reduced product of multiple abstract domains. For instance, combinations of DBM or Oct with Cong or even better, reduced products of DBM or Oct with Int $\times$ Cong can be implemented in a straightforward manner.\footnote{Although DBM and octagons are strictly more expressive than intervals, non-linear operations such bitwise and logical operations can be still reasonably modelled using intervals but not using DBM or octagons. For this reason, it is often more recommendable to reduce first interval with congruences and then with DBM or octagons.} \emph{Variable packing} techniques (e.g.,~\cite{VenetB04,octagons,Bouaziz12}) are not currently implemented. % %We have not implemented these cases since they have not been necessary %for any of avionics programs analyzed so far. Similarly, for more %expressive domains such as \emph{Two Variables per %Inequality}~\cite{SimonK10} or \emph{Convex %Polyhedra}~\cite{Cousot_Halbwachs_POPL78}. More expressive relational domains such as \emph{Two Variables per Inequality}~\cite{SimonK10} or \emph{Convex Polyhedral}~\cite{Cousot_Halbwachs_POPL78} are also possible. Finally, and for accuracy reasons, the value analysis also keeps track of two important pieces of information: whether a pointer may be null (Null) and whether a variable might be uninitialized (Init). The Null domain models if a pointer is definitely null, definitely non-null or otherwise, may be null. The Init domain models is a variable is definitely initialized, definitely uninitialized or may be initialized. \subsection{Analyses} %\vspace{2mm} \noindent \textbf{Analyses.} Once we have described all the main components we are ready to describe in more details each of the analyses implemented in \ikoscc. For each analysis the user can choose the base numerical abstract domain as well as the level of precision. %% Our experimental evaluation %% in Section~\ref{sec:results} shows the most suitable options for the %% kind of applications we target here. % During the analysis phase, each analysis uses the same value analysis and the only difference among them is during the check phase. Therefore, each analysis keeps track of of the same numerical invariants as well as nullity and uninitialized information. The reason for this is that analyses such as \textsf{boa}, \textsf{dbz}, or \textsf{prove} can benefit from nullity information because it can increase precision by detecting infeasible paths through reasoning whether a pointer is null. On the other hand, \textsf{null} or \textsf{uva} might benefit from numerical invariants because they can also be more precise after detecting infeasible paths due to numerical constraints. Upon competition of the analysis phase we can assume that the value analysis has computed the following functions ($\mathcal{V}$ is the set of program variables): \begin{itemize} \item a function $R: \mathcal{V} \mapsto (\{-\infty \} \cup {\mathbb{Z}}) \times (\{+\infty \} \cup {\mathbb{Z}})$. % We use the notation $R(x) = [l,u]$ to represent that $l \leq x \leq u$\footnote{Note that all the base domains implemented in \ikos pose an operation that converts from their representations to intervals. E.g., in the DBM abstract domain given the constraints $C \equiv x - y \leq 0 \wedge y -x \leq 0 \wedge y \leq 5 \wedge -y \leq -5$ the result of $R(x)$ can be computed by $\exists y. C \equiv x\leq 5 \wedge -x \leq -5 \equiv x = [5,5]$. Existential quantifier elimination is a common operation in abstract domains commonly named as \textsf{forget}.}. The symbol $\top$ represents the interval $[-\infty, +\infty]$. \item a function $I: \mathcal{V} \mapsto \{initialized, uninitialized, \top\}$, and \item a function $N: \mathcal{V} \mapsto \{null, nonnull, \top\}$. \end{itemize} \noindent The function $R$ maps each program variable to a range (i.e., interval). The function $I$ maps a program variable to whether it is initialized or not, and the function $N$ maps a variable to whether is null or not. The symbol $\top$ refers to a complete lack of information. We describe next the main operations that each analysis performs during the check phase. \subsubsection{Buffer overflow (\textsf{boa})} This analysis proves that there is no out-of-bounds array accesses. That consists of checking each \texttt{load} or \texttt{store} instruction that reads from or write to pointer $p$. In that case, the value analysis has kept track of two variables $p_{o}$ and $p_{s}$ where \begin{itemize} \item $p_{o}$ is the offset from the base address of the object that contains $p$. \item $p_{s}$ is the actual size in bytes of the allocated memory for $p$ (including padding and alignment). \end{itemize} \noindent Assume that $R(p_{s}) = [x,y]$ and the symbol $a \sqsubseteq b$ returns true iff the interval $a$ is included in the interval $b$ (i.e., $ a \equiv [x_1,y_1] \sqsubseteq b \equiv [x_2,y_2]$ iff $x_1 \geq x_2$ and $y_1 \leq y_2$). Then, given a pointer $p$ we perform an \emph{overflow check}: \begin{itemize} \item if $R(p_{o}) \sqsubseteq [-\infty, y -1]$ then safe. \item else if $R(p_{o}) \sqsubseteq [y, +\infty]$ then error. \item otherwise, warning. \end{itemize} \noindent as well as an \emph{underflow check}: \begin{itemize} \item if $R(p_{o}) \sqsubseteq [0, +\infty]$ then safe. \item else if $R(p_{o}) \sqsubseteq [-\infty, -1]$ then error. \item otherwise, warning. \end{itemize} \noindent Therefore, note that an access to $p$ can be only considered safe if both overflow and underflow conditions hold. That is, $R(p_{o}) \sqsubseteq [-\infty, y -1]$ and $R(p_{o}) \sqsubseteq [0, +\infty]$ which is equivalent to say that $R(p_{o}) \sqsubseteq [0, y -1]$. The buffer overflow analysis also checks for memory intrinsics such as \texttt{memcopy}, \texttt{memmove} and \texttt{memset}. %The default base numerical domain is Int $\times$ Cong. A minimum %level of precision of \textsf{L2} (scalar and pointers) produces often %a low warning rate but modelling of the heap (\textsf{L3}) produces %even better results with a small overhead. \subsubsection{Division by zero (\textsf{dbz})} This analysis proves that there is no integer division by zero. For each integer (signed or unsigned) division $x / y$ such that $R[y] = [l,b]$: \begin{itemize} \item if $l=0$ and $u=0$ then error \item else if $[0,0] \sqsubseteq [l,b]$ then warning \item otherwise, safe. \end{itemize} %We have observed that after \ikospp simplifies the LLVM bitcode %division operations require often very local reasoning and involving %only integer scalars. Therefore, using Int with \textsf{L1} is usually %enough. \subsubsection{Null dereference (\textsf{null})} This analysis proves that all the memory writes and reads cannot de-reference a null pointer. For each memory access (i.e., \texttt{load} and \texttt{store}) through pointer $p$: \begin{itemize} \item if $N(p)$ is $nonnull$ then safe \item else if $N(p)$ is $null$ then error \item otherwise, warning \end{itemize} \subsubsection{Read uninitialized variables (\textsf{uva})} This analysis proves that any used integer variable has been previously initialized. For each used integer variable $v$: \begin{itemize} \item if $I(v)$ is $initialized$ then safe \item else if $I(v)$ is $uninitialized$ then error \item otherwise, warning \end{itemize} %% \item Prover of user-definable assertions (\textsf{prove}). To allow %% users to annotate the program with richer assertions we use a %% relational domain such as DBM with \textsf{L3}. Common to all analyses a \emph{liveness analysis} is run as pre-analysis step. The purpose is to infer which variables are definitely \emph{dead} at the exit of each CFG node so we can \emph{forget} those variables from $Post^{\#}$ before it is propagated to the successor's $Pre^{\#}$. We observed that the impact on using liveness information is mostly negligible for non-relational domains but it can be very significant in the case of relational domains. Finally, all the analyses can be used in an \emph{intra-procedural} or \emph{inter-procedural} manner. In the former, each function is analyzed ignoring its call context. In the latter, fully context-sensitivity is achieved by inlining all program functions. We have observed that inlining is a reasonable solution due to two main reasons: (a) recursive functions are very rare in avionics software, and (b) the exponential worst-case behavior has not been observed after programs are pre-processed using \ikospp. %From the above %analyses, only division by zero (\textsf{dbz}) is executed %intra-procedurally. \ignore{ \subsection{Implementation Details} \label{subsec:implementation} % efficient fixpoint based on WTO % separate domain for non-relational domains % finite domain implementation } \section{Usage} \label{sec:usage} Compiling multiple C files with LLVM requires modifying the Makefile used to build the application so that the compiler tools invoked are those provided by LLVM. This usually amounts to changing the settings for the Makefile variables CC, LD and AR to \texttt{llvm-gcc}, \texttt{llvm-link}, and \texttt{llvm-ar}. It is very important to run \texttt{llvm-gcc} with options \texttt{-c -emit-llvm} to generate LLVM bitcode rather than binary executables. % Once we have obtained a single LLVM bitcode file, we provide a python script to analyze the bitcode in a very simple way. The options for running the analyzer are: \begin{small} \begin{verbatim} ikos_cc [--cpu=CPU] [--mem=MEM] [--ikos-pp] INPUT -a ANALYSIS \end{verbatim} \end{small} \noindent where \texttt{CPU} is the CPU time limit in seconds, \texttt{MEM} is the memory limit in MB, \texttt{ikos-pp} runs \ikospp, \texttt{INPUT} is a LLVM bitcode file (or alternatively, a C file), and \texttt{ANALYSIS} is one of the following: boa, dbz, uva, prover, and nullity. Upon termination, \ikoscc dumps all the checks into an external database. The format of the checks is: \begin{small} \begin{verbatim} name line number callstring status \end{verbatim} \end{small} \noindent where \texttt{name} is a name for the check (e.g., buffer overflow, buffer underflow, division by zero, etc), \texttt{line} and \texttt{number} is the location of the check in the C file, \texttt{callstring} is the call stack at the time of the check (empty if intra-procedural analysis), and \texttt{status} is either: \texttt{safe} (definitely safe), \texttt{unreachable} (definitely safe because the check is dead code), \texttt{error} (definitely unsafe), or \texttt{warning} (may be unsafe). % Note that if the analysis is inter-procedural then it can have multiple checks at the same \texttt{line} and \texttt{number} but with a different \texttt{callstring} \section{Experimental Evaluation} \label{sec:results} We have evaluated \ikoscc with several open-source autopilot control software as well as software used in several NASA missions. % \textsf{paparazzi}~\cite{paparazzi} (20K LOC) and \textsf{mnav}~\cite{mnav} (160K LOC) are both versatile autopilot control software for a fixed-wing aircrafts and multi-copters. \textsf{mnav} is fully implemented in C but \textsf{paparazzi} is a mix of OCaml and C. For our experiments, we only analyzed the C part. \textsf{gen2} (13K LOC) is automatically code generated for several Simulink models\todo{Say which models?}. \textsf{SporeSat} is an autonomous, free-flying three unit spacecraft. We analyzed one of its components\todo{We analyzed only the file \texttt{/1/sporesat2\_app\_spore}. Give description and size}. Neither the code for \textsf{gen2} or \textsf{SporeSat} is publicly available. % All experiments have been carried out on an Red Hat Enterprise Workstation machine with a 2.4 GHz AMD Opteron(TM) Processor 6136 and 8GB RAM. %\floatsetup[figure]{style=plain,subcapbesideposition=top} \begin{table}[tbh] \begin{center} \subfloat[Modelling integer and pointer scalars using intervals with \ikospp]{ \setlength{\tabcolsep}{1pt} \begin{tabular}{|l|c|c|c||c|c|c||c|c|c||c|c|c|} \hline \textsf{Program} & \multicolumn{3}{|c||}{\textsc{boa}} & \multicolumn{3}{|c||}{\textsc{uva}} & \multicolumn{3}{|c||}{\textsc{nul}} & \multicolumn{3}{|c|}{\textsc{dbz}} \\ \hline & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ \\ \hline \hline \textsf{paparazzi} & $908$ & $0$ & $24$ & $1181$ & $649$ & $25$ & $454$ & $0$ & $25$ & $3$ & $0$ & $6$ \\ \hline \textsf{mnav} & $5998$ & $2302$ & $59$ & $5860$ & $1232$ & $58$ & $2696$ & $895$ & $59$ & $1$ & $0$ & $6$ \\ \hline \textsf{gen2} & $10114$ & $264$ & $62$ & $1931$ & $420$ & $58$ & $5034$ & $51$ & $60$ & $2$ & $0$ & $14$ \\ \hline \textsf{sporeSat} & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD \\ % TSS \hline \end{tabular} } \\ \subfloat[Modelling integer and pointer scalars and memory contents using intervals with \ikospp]{ \setlength{\tabcolsep}{1pt} \begin{tabular}{|l|c|c|c||c|c|c||c|c|c||c|c|c|} \hline \textsf{Program} & \multicolumn{3}{|c||}{\textsc{boa}} & \multicolumn{3}{|c||}{\textsc{uva}} & \multicolumn{3}{|c||}{\textsc{nul}} & \multicolumn{3}{|c|}{\textsc{dbz}} \\ \hline & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ \\ \hline \hline \textsf{paparazzi} & $890$ & $0$ & $30$ & $1152$ & $23$ & $30$ & $445$ & $0$ & $30$ & \multicolumn{3}{c|}{} \\ \cline{1-10} \textsf{mnav} & $4730$ & $1343$ & $65$ & $4663$ & $838$ & $65$ & $2169$ & $492$ & $65$ & \multicolumn{3}{c|}{} \\ \cline{1-10} \textsf{gen2} & $10114$ & $264$ & $73$ & $1931$ & $420$ & $73$ & $5034$ & $51$ & $73$ & \multicolumn{3}{c|}{} \\ \hline \textsf{sporeSat} & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD & TBD \\ % TSS \hline \end{tabular} } \\ \subfloat[Modelling integer and pointer scalars and memory contents using intervals without \ikospp]{ \setlength{\tabcolsep}{1pt} \begin{tabular}{|l|c|c|c||c|c|c||c|c|c||c|c|c|} \hline \textsf{Program} & \multicolumn{3}{|c||}{\textsc{boa}} & \multicolumn{3}{|c||}{\textsc{uva}} & \multicolumn{3}{|c||}{\textsc{nul}} & \multicolumn{3}{|c|}{\textsc{dbz}} \\ \hline & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ & $\mathsf{C}$ & $\mathsf{W}$ & $\mathsf{T}$ \\ \hline \hline \textsf{paparazzi} & $14890$ & $84$ & $12886$ & $2395$ & $107$ & $12795$ & $7417$ & $28$ & $12575$ & $25$ &$1$ &$85$ \\ \hline \textsf{mnav} & TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD \\ \hline \textsf{gen2} & TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD \\ \hline \textsf{sporeSat} & TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD &TBD \\ % TSS \hline \end{tabular} } \end{center} \caption{\label{table:res}Analyses results on flight control software and NASA mission software} \end{table} Tables~\ref{table:res}(a)-(c) show the results of our evaluation. For each program we ran the four analyses currently implemented in \ikoscc: \textsc{boa} (buffer overflow analysis), \textsc{uva} (use of uninitialized integer variable analysis), \textsc{nul} (null pointer dereference analysis), and \textsc{dbz} (integer division by zero). % For each analysis we counted the total number of checks ($\mathsf{C}$), the total number of warnings ($\mathsf{W}$), and the total time ($\mathsf{T}$) in seconds. \ikoscc did not find any definite error for any of the programs and hence, we do not show that number. % For all experiments we always ran \textsc{boa}, \textsc{uva}, and \textsc{null} in an inter-procedural manner and only \textsc{dbz} in an intra-procedural manner. The reason is that unlike the other analyses division by zero checks involve often very local reasoning and hence, there is no need to run a much costly inter-procedural analysis. Table~\ref{table:res}(a) shows the results of modelling integer and pointer scalars using the interval domain and Table~\ref{table:res}(b) shows the results of a similar configuration but modelling also pointer contents. In both cases we ran \ikospp to optimize the LLVM bitecode. Table~\ref{table:res}(c) uses the same configuration that Table~\ref{table:res}(b) but after disabling the use of \ikospp. In that way, we measure the effect of running the LLVM bitecode pre-processor prior to any analysis. First, \ikoscc was able to prove absence of integer division by zero for \textsf{paparazzi}, \textsf{mnav}, and \textsf{gen2} as well absence of buffer overflow and null pointer de-reference for \textsf{paparazzi}. For other programs, such as \textsf{gen2}, the number of warnings was very low for some analyses (e.g., \textsc{boa} and \textsc{nul}) which allowed us to analyze it manually and determine the main causes of those warnings (see Section~\ref{sec:sec:warnings} for more details). \todo{Analysis of \textsf{sporeSat} is missing.} % Unlike for these programs, the results of \textsc{boa}, \textsc{nul}, and \textsc{uva} for \textsf{mnav} were less successful. We refer to Section~\ref{sec:sec:warnings} for details. % The modelling of pointer contents (Table~\ref{table:res}(b)) shows that it usually pays off in terms of precision with a reasonable increase in analysis time. %% As expected, the precision gains are more %% significant with analyses such as \textsc{uva} since there it is %% crucial to model more precisely whether pointer contents are %% initialized or not. For other analyses such as \textsc{boa} although %% the modelling of pointers is also very important it might play a less %% vital role since array indexes are less often stored in pointer %% contents. % Finally, Table~\ref{table:res}(c) shows the dramatic impact of \ikospp, described in Section~\ref{sec:preprocessor}, in terms of precision as well as analysis time. The main reasons are that \ikospp can lower many global C \texttt{struct}'s and variables to scalars, reducing significantly the number of \emph{cells} that our value domain needs to model. Similarly, \ikospp reduces significantly the number of scalar variables which is also vital to keep the scalability of the base numerical domains. \textbf{TODO:} We should try with $Int \times Cong$. We will probably get similar results. We would like to try with a relational domain, such as DBMs, but currently we cannot since \emph{variable packing} is not implemented and hence, DBMs run quickly out of resources. \subsection{Causes of Warnings} \label{sec:sec:warnings} We have manually inspected some of our benchmarks and searching for the possible causes of warnings returned by \ikoscc. We list here some (but not all) of the reasons: \begin{itemize} \item In \textsf{gen2}, some numerical invariants are not expressible by \ikoscc abstract domains: \begin{small} \begin{verbatim} float*A, float*B; for (i=0; i < 10; i++) *p *= (*A++) * (*B++); \end{verbatim} \end{small} \noindent For \textsc{boa}, we need to produce invariants $A_{o} = 4 \times i \wedge B_{o} = 4 \times i \wedge 0 \leq i \leq 9$ where $A_{0}$ and $B_{0}$ are the offsets of $A$ and $B$, respectively, and $4$ is the size of an integer in bytes. However, the invariants required by $A_{o}$ or $B_{o}$ cannot be expressed with octagons, our most expressive domain. For this kind of invariants we would need TVPI~\cite{SimonK10} but it might be quite expensive. \todo{I think the Gauge domain~\cite{Gauge} would produce these invariants} \item In \textsf{gen2}, current \ikoscc fixpoint iterator is not powerful enough with binary search-based lookups: \todo{This example is more complicated. There is an assumption that $\mathtt{x[bottom]} < u < \mathtt{x[top]}$ and also \texttt{u} is non-negative.} \begin{small} \begin{verbatim} bottom = some constant; top = some constant; for (;;) { idx = (bottom + top)/2; if (u <= x[idx]) top = idx - 1; else if (u > x[idx+1]) bottom = idx + 1; else { retValue = idx; break; } } \end{verbatim} \end{small} \noindent To prove that \texttt{x} cannot be accessed out of bounds we need to infer that $\mathtt{bottom} \leq \mathtt{idx} \leq \mathtt{top}$. However, note that $\mathtt{idx}$ is both incremented and decremented in the loop. Therefore, widening will have effect on both lower and upper bound of $\mathtt{idx}$ producing $-\infty \leq \mathtt{idx} \leq \infty$. Narrowing does not improve the results. \item In function \texttt{rtGetMinusInf} (\textsf{gen2}) floating point computation exploiting IEEE representation in the same spirit that the example in~\cite{Mine12}.\todo{Need to confirm this} \item In \textsf{mnav}, the navigator component relies on a matrix library that creates matrices by allocating dynamic memory inside loops (\texttt{\_mat\_creat}): \begin{small} \begin{verbatim} typedef struct { int row; int col; } MATHEAD; typedef struct { MATHEAD head; double *matrix; // double } MATBODY; typedef double **MATRIX;// double #define Mathead(a) ((MATHEAD *)((MATHEAD *)(a) - 1)) #define MatRow(a) (Mathead(a)->row) #define MatCol(a) (Mathead(a)->col) MATRIX _mat_creat(int row, int col) { MATBODY *mat; int i; if ((mat = (MATBODY *)malloc( sizeof(MATHEAD) + sizeof(double *) * row)) == 0) { return NULL; }; for (i=0; imatrix) + i) = (double *)malloc(sizeof(double) * col)) == 0) { return NULL); } } mat->head.row = row; mat->head.col = col; return (&(mat->matrix)); } \end{verbatim} \end{small} \noindent Here, our value domain is not powerful enough to model \texttt{malloc}'s inside loops. Nevertheless, the traversal of those matrices (e.g., \texttt{mat\_copy}) is quite regular: \begin{small} \begin{verbatim} MATRIX mat_copy(MATRIX A, MATRIX C) { int i, j; for (i=0; i< MatRow(A); i++) for (j=0; j< MatCol(A); j++) { C[i][j] = A[i][j]; } return(C); } \end{verbatim} \end{small} \noindent For \textsc{boa}, we would need the invariants for \texttt{MatRow(A)} and \texttt{MatCol(A)} and the allocated size for \texttt{A} and \texttt{B} but unfortunately we cannot infer any of them. \item \textsf{sporeSat} is significantly more complicated and different from standard avionics software we have seen so far. % The global state is quite large. There many global arrays and linked-lists that stores mutexes, message queues, etc. Memory management is also more complicated than usual: there is a pool of memory blocks which are already allocated. Each time there is a request for a new memory block there is a loop that traverses all the free memory blocks in the pool and returns the one with smallest size that it is sufficient for the requested size \todo{This is just some of the problems. We need a much more detailed analysis}. \end{itemize} \ignore{ \section{Related Work} \label{sec:related} In a previous work, authors presented Ikos~\cite{ikos} a framework for developing static analysis based on abstract interpretation. This framework consists of two main components: \arbos to represent succinctly CFGs from C programs and a library of fixpoint iterators and abstract domains. % The work we propose here can be seen as an instantiation of this framework. As a proof of concept, \cite{ikos} implemented only a buffer overflow analysis and although its results on a set of avionics benchmarks were impressive it did not modelled memory. Therefore, the closest related work comes from more mature tools relying on the abstract interpretation framework, namely C Global Surveyor (\cgs~\cite{VenetB04}), CodeHawk~\cite{CodeHawk}, Astr\'{e}e~\cite{AstreeESOP05}, PolySpace Verifier~\cite{polyspace}, and Frama-C~\cite{frama-c}. \astree focuses on safety-critical software while \ikoscc focuses on on unmanned aerial flight control. %, on-board network management,etc? Both \astree and \ikoscc implement the same value analysis~\cite{Mine06} but \astree does not deal with \texttt{malloc}'s at all while \ikoscc deals with arrays and linked-lists to store pointers to semaphores, message queues, etc as well as dynamically-allocated matrices that implement the logic of the UAVs \todo{\ikoscc neither at this point but we would like to}. On the other hand, \astree implements more sophisticated abstract domains that allow modelling more precisely devices such as filters while \ikoscc do not. \cgs is very limited also with \texttt{malloc}s and it does not model precisely dynamic memory inside loops. On the other hand, \cgs implements a more compositional inter-procedural algorithm. \cgs uses the reduced product of linear equalities~\cite{Karr76} with intervals as the base numerical domain. \textbf{TODO:} \begin{itemize} \item Similar to us, \framac relies on a value analysis based on~\cite{Mine06}. We should investigate if an experimental comparison is possible. \item More recent abstract intepreters such as \textsc{Pagai}~\cite{pagai}: a path-sensitive abstract interpreter based on SMT. \end{itemize} } \section{Limitations and Future Extensions} \label{sec:future} Finally, we describe here some current limitations of the static analyzer as well as some interesting future extensions. At the level of front-end, our tool relies on unsupported legacy tools (such as \texttt{llvm-gcc} and LLVM version 2.9), thus it is difficult to maintain and extend. For instance, \texttt{llvm-2.9} cannot be compiled with GNU compiler versions newer than \texttt{4.6} and there is no \texttt{llvm-gcc} version for Windows machines. We would like to replace \texttt{llvm-gcc} with \texttt{clang}\footnote{\textbf{Author's note:} Historically, the reason of using \texttt{llvm-gcc} over \texttt{clang} has been that there is NASA software that cannot be compiled by \texttt{clang}. We need to review this claim because we tried with all the benchmarks we have and \texttt{clang} compiled all. \texttt{clang} is a very dynamic project so it has significantly improved over the years.} which would also allow us replacing LLVM version 2.9 with a newer one (e.g., version 3.6), or alternatively to use directly \texttt{gcc} via \texttt{DragonEgg}~\cite{dragonegg}. \vspace{2mm} At the level of the analysis some of our current limitations are: \begin{itemize} \item all recursive calls are safely ignored. \item inter-procedural analysis is done via inlining which might be prohibitive with large programs. \item limited reasoning about dynamic memory allocation: \ikoscc does not distinguish between different instances of \texttt{malloc} in a loop. \item \ikoscc does not model pointer accesses with more than one level of indirection (e.g., \texttt{int **p; *p = q;} cannot be modelled precisely). \item no reasoning about floating points (e.g.,~\cite{Mine12}): all floating point variables are safely ignored. \item no machine arithmetic (e.g.,~\cite{Mine12,wrapped}) \end{itemize} Note that not all of these analysis limitations have a real impact when analyzing avionics software, and in fact, some of these absences might have facilitated the design of our tool. For example, the use of recursive call is a prohibited practice when implementing avionics software. Therefore, it suffices for \ikoscc to analyze them in a sound manner although imprecisely. As a future work we plan to combine a \emph{position-sensitive} pointer analysis (e.g.,~\cite{Venet04}) with our value analysis presented in Section~\ref{sec:analysis}. This would allow us to reason more precisely about dynamic memory allocation, in particular, with deeper (i.e., multiple levels of indirection) memory accesses. % and when we need to distinguish between different \texttt{malloc} %instances in a loop. We would like also to support \cpp. The design of a precise static analyzer for \cpp is not trivial and it might require some re-design in our tool. Our medium-term goal is to be able to analyze full \cpp in a sound manner. Finally, we would like to emphasize that \ikoscc has been carefully crafted for being effective for certification of avionics software. It has not been, however, designed for being a code style checker or modelling syntax-oriented properties. Note that this is true even if \ikospp is not used since LLVM bitcode lacks already of some information such as signedness and some passes (e.g.,\texttt{-mem2reg}) required before the translation to AR form can apply already some transformations such as dead code elimination. We also suggest to read the appendix in Section~\ref{sec:undefined} for details about undefinedness in C programs. To avoid all these issues, we would need to implement a new tool at the front-end (e.g., \texttt{clang} or \llvmgcc) which is far beyond the scope of this project. \ignore{ \section{Conclusions} TODO } \bibliographystyle{plain} \bibliography{biblio} \newpage \appendix \section{Notes about Undefined Behaviour in C} \label{sec:undefined} In this section, we recapitulate well-known consequences of undefined behaviour in C programs and how they affect to the soundness of static analyzers. In C programs, erroneous (buggy) operations such as null dereference, or signed integer overflow are said to trigger \emph{undefined behaviour}. Although the presence of undefined behaviour indicates a bug in the program, compilers are not forced to report an error or even a warning. In fact, quoting the C FAQ compilers are completely free to decide how to deal with undefined behaviour: \begin{quote} \emph{Anything at all can happen; the Standard imposes no requirements. The program may fail to compile, or it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended}. \end{quote} Although it might seem a bit surprising from the static analysis point of view, the reason why the C Standard allows the existence of undefined behaviour is to allow C being a very efficient low-level programming language. % For instance, \emph{use of uninitialized variables} is a common example of undefined behaviour. This avoids compilers requiring all variables must be zero initialized when they are in scope. This can have a very positive impact on performance in presence of large stack arrays and dynamically allocated memory. Another common example is \emph{signed integer overflow}. For instance, assuming that $\mathtt{INT\_MAX} + 1$ is undefined allows transforming $x + 1 > x$ into true. Note that this simplification is not possible if we would assume that $\mathtt{INT\_MAX} + 1 = \mathtt{INT\_MIN}$. Another very important example is \emph{out of bounds array} accesses. The reason why out of bound accesses are left undefined is that it avoids instrumenting programs with expensive runtime checks ensuring that all accesses are in range. Therefore, it should be clear that the reason why undefined behaviour exists is to allow compilers being smart and avoid dealing with otherwise very costly situations. Similar rationale applies to other cases such as \emph{division by zero}, \emph{null dereference}, \emph{oversized shift amounts} (shifting an 32 bit unsigned number by 32 bits or more), and \emph{violation of typing rules} (e.g., cast an int* to float* and then dererefence it). However, it should be obvious that compiler optimizations might have negative effects on static analyzers that take as input compiler optimized code rather than source code like in the case of \ikoscc. These optimizations might hide bugs that \ikoscc will not be able to find. In other words, \ikoscc can report a program to be safe even if there is a bug. To exemplify this phenomenon Figure~\ref{fig:undefined-ex} shows two buggy programs that \ikoscc will report as safe. % The program in Figure~\ref{fig:undefined-ex}(a) has an use of an uninitialized variable since $z$ is assigned to $5$ only if $argc$ is greater than $2$. Among others, \ikoscc executes the following commands: % \begin{enumerate} \item \texttt{llvm-gcc test-1.c -c -emit-llvm -o test-1.bc} \item \texttt{opt test-1.bc -mem2reg -o test-1.pp.bc} \end{enumerate} % \noindent where command (1) is used to generate LLVM bitecode and (2) is a requirement for \arbos. During the transformation \texttt{mem2reg} the compiler notices that $z$ can be uninitialized but instead of reporting an error or warning, it decides to assign always $5$ to $z$ regardless the outcome of the comparison $(argc > 2)$. The program in Figure~\ref{fig:undefined-ex}(b) is buggy because the assignment \texttt{a[i] = i} after the loop is writing in the array $a$ at index $10$ but the array has been only allocated for indexes between $0$ and $9$. % Perhaps, a bit surprising is that if we would execute the command \texttt{llvm-gcc -O1 test-2.c -c -emit-llvm -o test-2.bc} we would see that the program \texttt{test-2.bc} consists of one single statement \texttt{return 0} so that \ikoscc claims the program to be trivially safe since no checks are found. The reason for this is that the compiler optimizations (triggered by flag \texttt{-O1}) can infer that the loop is bounded and in fact, since the loop does not have any side effects the compiler removes completely the loop. Moreover, the compiler replaces the assignment \texttt{a[i] = i} with \texttt{a[10] = 10} and it realizes that the array write is out of bounds. Instead of reporting an error or warning the compiler decides to remove the array assignment. We refer readers to~\cite{regehr-undefined,llvm-undefined} for more examples and discussions describing how compiler optimizations can make analysis tools unsound by taking advantage of the existence of undefined behaviour in C programs. \begin{figure}[t] \centering \begin{tabular}[h]{cc} \begin{minipage}[t]{0.5\linewidth} \begin{tabbing} xx \= xx \= xx \= \kill int main (int argc, char **argv) \\ $\{$ \\ \> int z, y; \\ \> \textbf{if} (argc > 2) \\ \> \> z = 5; \\ \> \textbf{for} (y=0 ; y<5 ; y++) $\{$ \\ \> \> z = z + 1; \\ \> $\}$ \\ \> \textbf{return} z; \\ $\}$ \end{tabbing} \end{minipage} & \begin{minipage}[t]{0.5\linewidth} \begin{tabbing} xx \= xx \= xx \= \kill int main (int argc, char **argv) \\ $\{$ \\ \> int i, a[10]; \\ \> \textbf{for} (i=0 ; i<10 ; i++) $\{$ \\ \> \> a[i] = i; \\ \> $\}$ \\ \> a[i] = i;\\ \> \textbf{return} 0; \\ $\}$ \end{tabbing} \end{minipage} \\ \mbox{(a) \texttt{test-1.c}} & \mbox{(b) \texttt{test-2.c}} \\ \end{tabular} \caption{Examples of buggy programs that compilers can make them safe} \label{fig:undefined-ex} \end{figure} The most obvious solution to this problem is to ensure that all compiler optimizations are disabled. Considering our architecture illustrated in Figure~\ref{fig:architecture} this would imply the following steps: \begin{enumerate} \item Ensure that C programs are compiled by \llvmgcc without using any optimization (i.e., compilation flag \texttt{-O0}). \item Disable all \llvmopt transformations described in Figure~\ref{fig:architecture} such as \texttt{mem2reg} and \texttt{lowerswitch}. \item Disable the use of \ikospp. \end{enumerate} Step (1) might not be feasible in real situations. Avionics software is usually deployed in very restricted environments in terms of hardware resources. Therefore, it might be mandatory to highly optimize (even \texttt{-O3}) the code before its deployment. Step (2) is also hard to satisfy since these \llvmopt optimizations are required to ensure the correctness of \arbos and hence, they cannot be currently lifted. Finally, step (3) is the easiest to perform since the use of \ikospp is optional. In this way, users can limit the effect of compiler optimizations at the expense of longer analysis time and less precise results as reported in Section~\ref{sec:results}. % Therefore, unless we relax the requirements for \arbos and the physical environment makes realistic to disable all compiler optimizations \ikoscc users must account for the possibility that compiler optimizations may hide bugs. However, based on our experience the situation is not as bad as it might seem. Source code-based analyzers\footnote{\llvmgcc provides, for instance, flags such as \texttt{Wuninitialized} to report users about uninitialized variables. We tried with \texttt{test-1.c} but we did not get any warning.} can be used as a preliminary step before using \ikoscc. This would allow to catch bugs that might be otherwise eliminated by the compiler. Moreover, real avionics software does not often contain so obvious examples like those illustrated in Figure~\ref{fig:undefined-ex}. That is, bugs are often much more subtle and compilers do not often encounter undefined behaviour in this kind of applications. \end{document} NASA-SW-VnV-ikos-1d98c65/analyzer/include/000077500000000000000000000000001473507761200200665ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/000077500000000000000000000000001473507761200210335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/000077500000000000000000000000001473507761200226605ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/000077500000000000000000000000001473507761200245035ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/aggregate_literal.hpp000066400000000000000000000275251473507761200306710ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Data structures for aggregates (struct, array). * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Literal for aggregate types (struct, array) template < typename VariableRef, typename MemoryLocationRef > class AggregateLiteral { public: /// \brief Scalar literal type using ScalarLiteral = core::Literal< VariableRef, MemoryLocationRef >; /// \brief Field of an aggregate struct Field { MachineInt offset; ScalarLiteral value; MachineInt size; bool operator==(const Field& o) const { return offset == o.offset && value == o.value && size == o.size; } }; /// \brief List of fields using Fields = std::vector< Field >; private: /// \brief Constant aggregate literal struct CstLit { Fields fields; bool operator==(const CstLit& o) const { return fields == o.fields; } }; /// \brief Zero aggregate literal struct ZeroLit { bool operator==(const ZeroLit&) const { return true; } }; /// \brief Undefined aggregate literal struct UndefinedLit { bool operator==(const UndefinedLit&) const { return true; } }; /// \brief Variable aggregate literal struct VarLit { VariableRef var; bool operator==(const VarLit& o) const { return var == o.var; } }; private: /// \brief Union type for aggregate literals using Lit = boost::variant< CstLit, ZeroLit, UndefinedLit, VarLit >; private: /// \brief Literal value Lit _lit; /// \brief Size (in bytes) MachineInt _size; private: AggregateLiteral(Lit lit, MachineInt size) : _lit(std::move(lit)), _size(std::move(size)) {} public: /// \brief No default constructor AggregateLiteral() = delete; /// \brief Copy constructor AggregateLiteral(const AggregateLiteral&) = default; /// \brief Move constructor AggregateLiteral(AggregateLiteral&&) = default; /// \brief Copy assignment operator AggregateLiteral& operator=(const AggregateLiteral&) = default; /// \brief Move assignment operator AggregateLiteral& operator=(AggregateLiteral&&) = default; /// \brief Destructor ~AggregateLiteral() = default; /// \brief Comparison of aggregate literals bool operator==(const AggregateLiteral& other) const { return this->_lit == other._lit && this->_size == other._size; } /// \brief Comparison of aggregate literals bool operator!=(const AggregateLiteral& other) const { return !this->operator==(other); } /// \brief Create a constant aggregate literal static AggregateLiteral cst(Fields fields, MachineInt size) { return AggregateLiteral(Lit(CstLit{fields}), size); } /// \brief Create a zero-initialized aggregate literal static AggregateLiteral zero(MachineInt size) { return AggregateLiteral(Lit(ZeroLit{}), size); } /// \brief Create an undefined aggregate literal static AggregateLiteral undefined(MachineInt size) { return AggregateLiteral(Lit(UndefinedLit{}), size); } /// \brief Create a variable aggregate literal static AggregateLiteral var(VariableRef v, MachineInt size) { return AggregateLiteral(Lit(VarLit{v}), size); } /// \brief Return the size of the literal, in bytes const MachineInt& size() const { return this->_size; } private: /// \brief Visitor that checks if the given literal has the given type template < typename LiteralType > struct IsType : public boost::static_visitor< bool > { template < typename T > bool operator()(const T&) const { return std::is_same< T, LiteralType >::value; } }; public: /// \brief Return true if it's a constant aggregate literal bool is_cst() const { return boost::apply_visitor(IsType< CstLit >(), this->_lit); } /// \brief Return true if it's a zero-initialized aggregate literal bool is_zero() const { return boost::apply_visitor(IsType< ZeroLit >(), this->_lit); } /// \brief Return true if it's an undefined aggregate literal bool is_undefined() const { return boost::apply_visitor(IsType< UndefinedLit >(), this->_lit); } /// \brief Return true if it's a variable aggregate literal bool is_var() const { return boost::apply_visitor(IsType< VarLit >(), this->_lit); } private: /// \brief Visitor that returns the fields struct GetFields : public boost::static_visitor< const Fields& > { const Fields& operator()(const CstLit& lit) const { return lit.fields; } const Fields& operator()(const ZeroLit&) const { ikos_unreachable("trying to call fields() on literal zero"); } const Fields& operator()(const UndefinedLit&) const { ikos_unreachable("trying to call fields() on literal undefined"); } const Fields& operator()(const VarLit&) const { ikos_unreachable("trying to call fields() on a variable"); } }; public: /// \brief Get the set of fields const Fields& fields() const { #if BOOST_VERSION == 105800 // Workaround for https://svn.boost.org/trac10/ticket/11285 GetFields vis; return this->_lit.apply_visitor(vis); #else return boost::apply_visitor(GetFields(), this->_lit); #endif } private: /// \brief Visitor that returns the variable struct GetVar : public boost::static_visitor< VariableRef > { VariableRef operator()(const CstLit&) const { ikos_unreachable("trying to call var() on a constant"); } VariableRef operator()(const ZeroLit&) const { ikos_unreachable("trying to call var() on literal zero"); } VariableRef operator()(const UndefinedLit&) const { ikos_unreachable("trying to call var() on literal undefined"); } VariableRef operator()(const VarLit& lit) const { return lit.var; } }; public: /// \brief Get the variable VariableRef var() const { return boost::apply_visitor(GetVar(), this->_lit); } public: /// \brief Aggregate literal visitor /// /// Visitors should implement the following methods: /// /// R cst(const Fields& fields, const MachineInt& size); /// R zero(const MachineInt& size); /// R undefined(const MachineInt& size); /// R var(VariableRef variable, const MachineInt& size); template < typename R = void > class Visitor { public: using ResultType = R; }; // end class Visitor private: template < typename Visitor > struct VariantVisitor : public boost::static_visitor< typename Visitor::ResultType > { using ResultType = typename Visitor::ResultType; Visitor& v; const MachineInt& size; VariantVisitor(Visitor& v_, const MachineInt& size_) : v(v_), size(size_) {} ResultType operator()(const CstLit& lit) { return v.cst(lit.fields, size); } ResultType operator()(const ZeroLit&) { return v.zero(size); } ResultType operator()(const UndefinedLit&) { return v.undefined(size); } ResultType operator()(const VarLit& lit) { return v.var(lit.var, size); } }; template < typename Visitor > struct ConstVariantVisitor : public boost::static_visitor< typename Visitor::ResultType > { using ResultType = typename Visitor::ResultType; const Visitor& v; const MachineInt& size; ConstVariantVisitor(const Visitor& v_, const MachineInt& size_) : v(v_), size(size_) {} ResultType operator()(const CstLit& lit) const { return v.cst(lit.fields, size); } ResultType operator()(const ZeroLit&) const { return v.zero(size); } ResultType operator()(const UndefinedLit&) const { return v.undefined(size); } ResultType operator()(const VarLit& lit) const { return v.var(lit.var, size); } }; public: /// \brief Visit the aggregate literal template < typename Visitor, typename = typename std::enable_if_t< std::is_base_of< AggregateLiteral::Visitor< typename Visitor::ResultType >, Visitor >::value > > typename Visitor::ResultType apply_visitor(Visitor& v) const { VariantVisitor< Visitor > vis(v); return boost::apply_visitor(vis, this->_lit); } /// \brief Visit the aggregate literal template < typename Visitor, typename = typename std::enable_if_t< std::is_base_of< AggregateLiteral::Visitor< typename Visitor::ResultType >, Visitor >::value > > typename Visitor::ResultType apply_visitor(const Visitor& v) const { ConstVariantVisitor< Visitor > vis(v); return boost::apply_visitor(vis, this->_lit); } private: /// \brief Visitor that dumps the literal on a stream struct Dumper : public boost::static_visitor<> { std::ostream& o; explicit Dumper(std::ostream& _o) : o(_o) {} void operator()(const CstLit& lit) const { o << "cst_aggregate{fields="; for (auto it = lit.fields.begin(), et = lit.fields.end(); it != et;) { o << "(offset=" << it->offset << ", value=" << it->value << ", size=" << it->size << ")"; if (++it != et) { o << ", "; } } } void operator()(const ZeroLit&) const { o << "zero_aggregate{"; } void operator()(const UndefinedLit&) const { o << "undefined_aggregate{"; } void operator()(const VarLit& lit) const { o << "var_aggregate{var="; core::DumpableTraits< VariableRef >::dump(o, lit.var); } }; public: /// \brief Dump the literal on a stream, for debugging purpose void dump(std::ostream& o) const { Dumper dumper(o); boost::apply_visitor(dumper, this->_lit); o << ", size=" << this->_size << "}"; } }; // end class AggregateLiteral /// \brief Write an aggregate literal on a stream template < typename VariableRef, typename MemoryLocationRef > std::ostream& operator<<( std::ostream& o, const AggregateLiteral< VariableRef, MemoryLocationRef >& l) { l.dump(o); return o; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/call_context.hpp000066400000000000000000000126311473507761200276760ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief CallContext and CallContextFactory * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Represents a calling context class CallContext { private: /// \brief Parent call context CallContext* _parent = nullptr; /// \brief Call statement ar::CallBase* _call = nullptr; private: /// \brief Create an empty call context CallContext() = default; /// \brief Create a call context CallContext(CallContext* parent, ar::CallBase* call) : _parent(parent), _call(call) { ikos_assert(this->_parent != nullptr); ikos_assert(this->_call != nullptr); } public: /// \brief No copy constructor CallContext(const CallContext&) = delete; /// \brief No move constructor CallContext(CallContext&&) = delete; /// \brief No copy assignment operator CallContext& operator=(const CallContext&) = delete; /// \brief No move assignment operator CallContext& operator=(CallContext&&) = delete; /// \brief Destructor ~CallContext() = default; /// \brief Return true if this is an empty calling context bool empty() const { return this->_parent == nullptr; } /// \brief Return true if the calling context has a parent context bool has_parent() const { return this->_parent != nullptr; } /// \brief Return the parent calling context CallContext* parent() const { ikos_assert_msg(!this->empty(), "call context is empty"); return this->_parent; } /// \brief Return the call statement leading to this context ar::CallBase* call() const { ikos_assert_msg(!this->empty(), "call context is empty"); return this->_call; } /// \brief Return true if the given function is within the call context bool contains(ar::Function* fun) const { const CallContext* context = this; for (; context->_parent != nullptr; context = context->_parent) { if (context->_call->code()->function_or_null() == fun) { return true; } } return false; } private: friend class CallContextFactory; }; // end class CallContext /// \brief Management of calling contexts class CallContextFactory { private: boost::shared_mutex _mutex; llvm::DenseMap< std::pair< CallContext*, ar::CallBase* >, std::unique_ptr< CallContext > > _map; std::unique_ptr< CallContext > _empty_call_context; public: /// \brief Constructor CallContextFactory(); /// \brief No copy constructor CallContextFactory(const CallContextFactory&) = delete; /// \brief No move constructor CallContextFactory(CallContextFactory&&) = delete; /// \brief No copy assignment operator CallContextFactory& operator=(const CallContextFactory&) = delete; /// \brief No move assignment operator CallContextFactory& operator=(CallContextFactory&&) = delete; /// \brief Destructor ~CallContextFactory(); /// \brief Get the empty call context CallContext* get_empty() { return this->_empty_call_context.get(); } /// \brief Get or Create the call context with the given parameters /// /// \param parent Parent call context /// \param call Call statement CallContext* get_context(CallContext* parent, ar::CallBase* call); }; // end class CallContextFactory } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/context.hpp000066400000000000000000000112101473507761200266730ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Global analysis context * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace analyzer { // forward declarations class OutputDatabase; class MemoryFactory; class VariableFactory; class LiteralFactory; class CallContextFactory; class LivenessAnalysis; class FunctionPointerAnalysis; class PointerAnalysis; class FixpointParameters; /// \brief Global analysis context /// /// Class holding all the global state of the analyses class Context { public: /// \brief Input program ar::Bundle* bundle; /// \brief Analysis options const AnalysisOptions opts; /// \brief Working directory boost::filesystem::path wd; /// \brief Output database OutputDatabase* output_db; /// \brief Memory location factory MemoryFactory* mem_factory; /// \brief Variable factory VariableFactory* var_factory; /// \brief Literal factory LiteralFactory* lit_factory; /// \brief Call context factory CallContextFactory* call_context_factory; /// \brief Fixpoint parameters FixpointParameters* fixpoint_parameters; /// \brief Liveness analysis, or null LivenessAnalysis* liveness; /// \brief Function pointer analysis, or null FunctionPointerAnalysis* function_pointer; /// \brief Pointer analysis, or null PointerAnalysis* pointer; public: /// \brief Constructor Context(ar::Bundle* bundle_, AnalysisOptions opts_, boost::filesystem::path wd_, OutputDatabase& output_db_, MemoryFactory& mem_factory_, VariableFactory& var_factory_, LiteralFactory& lit_factory_, CallContextFactory& call_context_factory_, FixpointParameters& fixpoint_parameters_) : bundle(bundle_), opts(std::move(opts_)), wd(std::move(wd_)), output_db(&output_db_), mem_factory(&mem_factory_), var_factory(&var_factory_), lit_factory(&lit_factory_), call_context_factory(&call_context_factory_), fixpoint_parameters(&fixpoint_parameters_), liveness(nullptr), function_pointer(nullptr), pointer(nullptr) {} /// \brief No copy constructor Context(const Context&) = delete; /// \brief No move constructor Context(Context&&) = delete; /// \brief No copy assignment operator Context& operator=(const Context&) = delete; /// \brief No move assignment operator Context& operator=(Context&&) = delete; /// \brief Destructor ~Context() = default; }; // end class Context } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/execution_engine/000077500000000000000000000000001473507761200300335ustar00rootroot00000000000000concurrent_inliner.hpp000066400000000000000000000410241473507761200343700ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/execution_engine/******************************************************************************* * * \file * \brief Concurrent dynamic inlining call semantic * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Concurrent inliner of function calls /// /// The inlining of a function is done dynamically by matching formal and actual /// parameters and analyzing recursively the callee (FunctionFixpoint) and after /// the callee returns by simulating call-by-ref and updating the return value /// at the call site. The inlining also supports function pointers by resolving /// first the set of possible callees and joining the results. template < typename FunctionFixpoint, typename AbstractDomain > class ConcurrentInlineCallExecutionEngine final : public CallExecutionEngine { public: using InlineCallExecutionEngineT = ConcurrentInlineCallExecutionEngine< FunctionFixpoint, AbstractDomain >; using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; using FixpointCacheT = FixpointCache< FunctionFixpoint, AbstractDomain >; private: /// \brief Analysis context Context& _ctx; /// \brief Numerical execution engine NumericalExecutionEngineT& _engine; /// \brief Function analyzer of the caller FunctionFixpoint& _caller; /// \brief Function fixpoint cache of callees FixpointCacheT& _callees_cache; /// \brief True to check properties on the callees bool _check_callees; public: /// \brief Constructor ConcurrentInlineCallExecutionEngine(Context& ctx, NumericalExecutionEngineT& engine, FunctionFixpoint& caller, FixpointCacheT& callees_cache) : _ctx(ctx), _engine(engine), _caller(caller), _callees_cache(callees_cache), _check_callees(false) {} /// \brief Mark to check the callees void mark_check_callees() { this->_check_callees = true; } /// \brief Exit a function /// /// This is called whenever we reach the exit node (if there is one). /// /// Note that this is different from exec(ar::Returnvalue*) if there is /// exceptions. This can be used to catch the invariant, including pending /// exceptions. void exec_exit(ar::Function* fun) override { this->_engine.deallocate_local_variables(fun->local_variable_begin(), fun->local_variable_end()); this->_caller.set_exit_invariant(this->_engine.inv()); } /// \brief Execute a ReturnValue statement void exec(ar::ReturnValue* s) override { this->_caller.set_return_stmt(s); } /// \brief Execute a Call statement void exec(ar::Call* s) override { // Execute the call base statement this->exec(cast< ar::CallBase >(s)); // Exceptions aren't caught, propagate them this->inv().merge_caught_in_propagated_exceptions(); } /// \brief Execute an Invoke statement void exec(ar::Invoke* s) override { // Execute the call base statement this->exec(cast< ar::CallBase >(s)); // Exceptions are caught. // Nothing to do here. // see NumericalExecutionEngine::exec_edge() } private: /// \brief Return a non-const reference on the current invariant AbstractDomain& inv() { return this->_engine.inv(); } /// \brief Analysis on a callee class CalleeAnalysis { public: ar::Function* callee; std::unique_ptr< FunctionFixpoint > fixpoint; public: /// \brief Constructor explicit CalleeAnalysis(ar::Function* callee_) : callee(callee_), fixpoint(nullptr) {} /// \brief No copy constructor CalleeAnalysis(const CalleeAnalysis&) = delete; /// \brief Move constructor CalleeAnalysis(CalleeAnalysis&&) = default; /// \brief No copy assignment operator CalleeAnalysis& operator=(const CalleeAnalysis&) = delete; /// \brief No move assignment operator CalleeAnalysis& operator=(CalleeAnalysis&&) = delete; /// \brief Destructor ~CalleeAnalysis() = default; }; // end class CalleeAnalysis /// \brief Worker on a callee for tbb::parallel_reduce class CalleeWorker { private: /// \brief Analysis context Context& _ctx; /// \brief Caller numerical execution engine const NumericalExecutionEngineT& _engine; /// \brief Function analyzer of the caller FunctionFixpoint& _caller; /// \brief Function fixpoint cache of callees FixpointCacheT& _callees_cache; /// \brief Call statement ar::CallBase* _call; /// \brief Analyses on callees std::vector< CalleeAnalysis >& _callee_analyses; /// \brief Post invariant llvm::Optional< AbstractDomain > _post; public: /// \brief Constructor CalleeWorker(Context& ctx, const NumericalExecutionEngineT& engine, FunctionFixpoint& caller, FixpointCacheT& callees_cache, ar::CallBase* call, std::vector< CalleeAnalysis >& callee_analyses, AbstractDomain post) : _ctx(ctx), _engine(engine), _caller(caller), _callees_cache(callees_cache), _call(call), _callee_analyses(callee_analyses), _post(std::move(post)) {} /// \brief Split constructor CalleeWorker(CalleeWorker& parent, tbb::split) : _ctx(parent._ctx), _engine(parent._engine), _caller(parent._caller), _callees_cache(parent._callees_cache), _call(parent._call), _callee_analyses(parent._callee_analyses), _post(llvm::None) {} /// \brief No copy constructor CalleeWorker(const CalleeWorker&) = delete; /// \brief No move constructor CalleeWorker(CalleeWorker&&) = delete; /// \brief No copy assignment operator CalleeWorker& operator=(const CalleeWorker&) = delete; /// \brief No move assignment operator CalleeWorker& operator=(CalleeWorker&&) = delete; /// \brief Destructor ~CalleeWorker() = default; void operator()(const tbb::blocked_range< size_t >& r) { for (auto i = r.begin(); i != r.end(); i++) { this->operator()(this->_callee_analyses[i]); } } /// \brief Analyze a callee void operator()(CalleeAnalysis& analysis) { NumericalExecutionEngineT engine = this->_engine.fork(); // Do not propagate exceptions from the caller to the callee engine.inv().ignore_exceptions(); // Assign parameters engine.match_down(this->_call, analysis.callee); analysis.fixpoint = nullptr; if (_ctx.opts.use_fixpoint_cache && this->_caller.converged()) { // Try to fetch the previously computed fix-point analysis.fixpoint = this->_callees_cache.try_fetch(this->_call, analysis.callee); } if (analysis.fixpoint == nullptr) { if (_ctx.opts.use_fixpoint_cache) { // Erase the previous fix-point on the callee this->_callees_cache.erase(this->_call, analysis.callee); } // Create a fixpoint on the callee analysis.fixpoint = std::make_unique< FunctionFixpoint >(_ctx, this->_caller, this->_call, analysis.callee); // Run analysis on callee analysis.fixpoint->run(std::move(engine.inv())); } // Return statement in the callee, or null ar::ReturnValue* return_stmt = analysis.fixpoint->return_stmt(); engine.set_inv(analysis.fixpoint->exit_invariant()); // Merge exceptions in caught_exceptions, in case it's an invoke engine.inv().merge_propagated_in_caught_exceptions(); if (engine.inv().is_normal_flow_bottom()) { // Collect the exception states this->post_join(std::move(engine.inv())); return; } engine.match_up(this->_call, return_stmt); this->post_join(std::move(engine.inv())); } /// \brief Join two workers void join(CalleeWorker& other) { if (other._post) { this->post_join(std::move(*other._post)); } } /// \brief Join the post invariant void post_join(AbstractDomain&& inv) { if (this->_post) { (*this->_post).join_with(std::move(inv)); } else { this->_post = std::move(inv); } } /// \brief Join the post invariant void post_join(const AbstractDomain& inv) { if (this->_post) { (*this->_post).join_with(inv); } else { this->_post = inv; } } /// \brief Return the post invariant AbstractDomain& post() { ikos_assert(this->_post); return *this->_post; } }; // end class CalleeWorker /// \brief Execute any call statement void exec(ar::CallBase* call) { this->inv().normal().normalize(); if (this->inv().is_normal_flow_bottom()) { return; } // // Collect potential callees // auto callees = PointsToSet::bottom(); ar::Value* called = call->called(); if (isa< ar::UndefinedConstant >(called)) { // Call on undefined pointer: error this->inv().set_normal_flow_to_bottom(); return; } else if (isa< ar::NullConstant >(called)) { // Call on null pointer: error this->inv().set_normal_flow_to_bottom(); return; } else if (auto cst = dyn_cast< ar::FunctionPointerConstant >(called)) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(called)) { // Call to assembly this->_engine.exec_unknown_extern_call(call); return; } else if (isa< ar::GlobalVariable >(called)) { // Call to global variable: error this->inv().set_normal_flow_to_bottom(); return; } else if (isa< ar::LocalVariable >(called)) { // Call to local variable: error this->inv().set_normal_flow_to_bottom(); return; } else if (auto ptr = dyn_cast< ar::InternalVariable >(called)) { // Indirect call through a function pointer Variable* ptr_var = _ctx.var_factory->get_internal(ptr); // Assert `ptr != null` this->inv().normal().nullity_assert_non_null(ptr_var); // Reduction between value and pointer analysis const PointerInfo* pointer_info = this->_engine.pointer_info(); if (pointer_info != nullptr) { PointsToSet points_to = pointer_info->get(ptr_var).points_to(); // Pointer analysis and value analysis can be inconsistent if (!points_to.is_bottom() && !points_to.is_top()) { this->inv().normal().pointer_refine(ptr_var, points_to); } } this->inv().normal().normalize(); if (this->inv().is_normal_flow_bottom()) { return; } // Get the callees callees = this->inv().normal().pointer_to_points_to(ptr_var); } else { ikos_unreachable("unexpected called operand"); } // // Check callees // ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference this->inv().set_normal_flow_to_bottom(); return; } else if (callees.is_top()) { // No points-to information // ASSUMPTION: the callee has no side effects. // Just set lhs and all actual parameters of pointer type to TOP. this->_engine.exec_unknown_extern_call(call); return; } // // Compute the post invariant // // By default, propagate the exception states AbstractDomain post = this->inv(); post.set_normal_flow_to_bottom(); // Analyses on callees std::vector< CalleeAnalysis > callee_analyses; // For each callee for (MemoryLocation* mem : callees) { if (!isa< FunctionMemoryLocation >(mem)) { // Not a call to a function memory location continue; } ar::Function* callee = cast< FunctionMemoryLocation >(mem)->function(); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call // // This could be because of an imprecision of the pointer analysis. continue; } if (callee->is_declaration()) { // Call to an extern function // // ASSUMPTION: if this is a call to an extern non-intrinsic function, // treat it as a function call that has no side effects. NumericalExecutionEngineT engine = this->_engine.fork(); engine.inv().ignore_exceptions(); engine.exec_extern_call(call, callee); engine.inv().merge_propagated_in_caught_exceptions(); post.join_with(std::move(engine.inv())); continue; } ikos_assert(callee->is_definition()); if (this->_caller.function() == callee || this->_caller.call_context()->contains(callee)) { // Recursive function call // // TODO(jnavas): we can be more precise by making top only lhs of // call_stmt, actual parameters of pointer type and any global variable // that might be touched by the recursive function. this->_engine.exec_unknown_intern_call(call); return; } // // Analyze recursively the callee // callee_analyses.push_back(CalleeAnalysis(callee)); } CalleeWorker worker(this->_ctx, this->_engine, this->_caller, this->_callees_cache, call, callee_analyses, std::move(post)); tbb::blocked_range< size_t > range(0, callee_analyses.size()); tbb::parallel_reduce(range, worker); // Non-thread safe for (CalleeAnalysis& analysis : callee_analyses) { if (this->_check_callees) { // Run the checks on the callee analysis.fixpoint->run_checks(); } if (_ctx.opts.use_fixpoint_cache) { // Save the fix-point for later this->_callees_cache.store(call, analysis.callee, std::move(analysis.fixpoint)); } } this->_engine.set_inv(std::move(worker.post())); } }; // end class ConcurrentInlineCallExecutionEngine } // end namespace analyzer } // end namespace ikos context_insensitive.hpp000066400000000000000000000106551473507761200346000ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/execution_engine/****************************************************************************** * * \file * \brief Context insensitive call semantic * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Context insensitive call semantic /// /// It safely ignores function calls, except for direct intrinsic calls. /// /// Some assumptions are made about the program, see /// NumericalExecutionEngine::exec_unknown_intern_call() for more info. template < typename AbstractDomain > class ContextInsensitiveCallExecutionEngine final : public CallExecutionEngine { public: using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; private: /// \brief Numerical execution engine NumericalExecutionEngineT& _engine; public: /// \brief Constructor explicit ContextInsensitiveCallExecutionEngine( NumericalExecutionEngineT& engine) : _engine(engine) {} /// \brief Exit a function /// /// This is called whenever we reach the exit node (if there is one). /// /// Note that this is different from exec(ar::Returnvalue*) if there is /// exceptions. This can be used to catch the invariant, including pending /// exceptions. void exec_exit(ar::Function*) override {} /// \brief Execute any call statement void exec(ar::CallBase* call) { if (auto cst = dyn_cast< ar::FunctionPointerConstant >(call->called())) { // Direct call ar::Function* fun = cst->function(); if (fun->is_declaration()) { // Extern function this->_engine.exec_extern_call(call, fun); return; } } // Otherwise this->_engine.exec_unknown_intern_call(call); } /// \brief Execute a Call statement void exec(ar::Call* s) override { // Execute the call statement this->exec(cast< ar::CallBase >(s)); // Exceptions aren't caught, propagate them this->_engine.inv().merge_caught_in_propagated_exceptions(); } /// \brief Execute an Invoke statement void exec(ar::Invoke* s) override { // Execute the call base statement this->exec(cast< ar::CallBase >(s)); // Exceptions are caught. // Nothing to do here. // see NumericalExecutionEngine::exec_edge() } /// \brief Execute a ReturnValue statement void exec(ar::ReturnValue*) override {} }; // end class ContextInsensitiveCallExecutionEngine } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/execution_engine/engine.hpp000066400000000000000000000233271473507761200320200ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for executing statements * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Execution engine for AR (Abstract Representation) statements /// /// This is the base class for execution engines. /// /// This has to be used together with a `CallExecutionEngine` to execute /// function calls and return statements. This allows to have different /// inter-procedural strategies (e.g., inlining, summaries-based, /// intra-procedural, etc). class ExecutionEngine { public: /// \brief Execution engine options enum ExecutionEngineOption : unsigned { NoOption = 0x0, /// \brief Update the allocation size variable UpdateAllocSizeVar = 0x1, }; /// \brief Execution engine options using ExecutionEngineOptions = Flags< ExecutionEngineOption >; public: /// \brief Constructor ExecutionEngine() noexcept = default; /// \brief Copy constructor ExecutionEngine(const ExecutionEngine&) noexcept = default; /// \brief Move constructor ExecutionEngine(ExecutionEngine&&) noexcept = default; /// \brief Copy assignment operator ExecutionEngine& operator=(const ExecutionEngine&) noexcept = default; /// \brief Move assignment operator ExecutionEngine& operator=(ExecutionEngine&&) noexcept = default; /// \brief Destructor virtual ~ExecutionEngine() = default; /// \brief Enter a basic block virtual void exec_enter(ar::BasicBlock* bb) = 0; /// \brief Leave a basic block virtual void exec_leave(ar::BasicBlock* bb) = 0; /// \brief Execute an edge from `src` to `dest` virtual void exec_edge(ar::BasicBlock* src, ar::BasicBlock* dest) = 0; /// \brief Execute an Assignment statement virtual void exec(ar::Assignment* s) = 0; /// \brief Execute an UnaryOperation statement virtual void exec(ar::UnaryOperation* s) = 0; /// \brief Execute a BinaryOperation statement virtual void exec(ar::BinaryOperation* s) = 0; /// \brief Execute a Comparison statement virtual void exec(ar::Comparison* s) = 0; /// \brief Execute an Unreachable statement virtual void exec(ar::Unreachable* s) = 0; /// \brief Execute an Allocate statement virtual void exec(ar::Allocate* s) = 0; /// \brief Execute a PointerShift statement virtual void exec(ar::PointerShift* s) = 0; /// \brief Execute a Load statement virtual void exec(ar::Load* s) = 0; /// \brief Execute a Store statement virtual void exec(ar::Store* s) = 0; /// \brief Execute an ExtractElement statement virtual void exec(ar::ExtractElement* s) = 0; /// \brief Execute an InsertElement statement virtual void exec(ar::InsertElement* s) = 0; /// \brief Execute a ShuffleVector statement virtual void exec(ar::ShuffleVector* s) = 0; /// \brief Execute a LandingPad statement virtual void exec(ar::LandingPad* s) = 0; /// \brief Execute a Resume statement virtual void exec(ar::Resume* s) = 0; /// \brief Execute a call to the given extern function virtual void exec_extern_call(ar::CallBase* call, ar::Function* fun) = 0; /// \brief Execute a call to the given intrinsic function virtual void exec_intrinsic_call(ar::CallBase* call, ar::Intrinsic::ID) = 0; /// \brief Execute a call to an unknown extern function virtual void exec_unknown_extern_call(ar::CallBase* call) = 0; /// \brief Execute a call to an unknown internal function virtual void exec_unknown_intern_call(ar::CallBase* call) = 0; /// \brief Execute a call to an unknown function /// /// \param call /// The call statement /// \param may_write_params /// True if the function call might write on a pointer parameter /// \param ignore_unknown_write /// True to ignore writes on unknown pointer parameters (unsound) /// \param may_write_globals /// True if the function call might update a global variable /// \param may_throw_exc /// True if the function call might throw an exception virtual void exec_unknown_call(ar::CallBase* call, bool may_write_params, bool ignore_unknown_write, bool may_write_globals, bool may_throw_exc) = 0; /// \brief Assign formal parameters to the actual arguments of a function call virtual void match_down(ar::CallBase* call, ar::Function* called) = 0; /// \brief Assign the return value of a function call virtual void match_up(ar::CallBase* call, ar::ReturnValue* ret) = 0; }; // end class ExecutionEngine /// \brief Execution engine for Call statements /// /// This is used to execute function calls and return statements, based on /// different inter-procedural strategies (e.g., inlining, summaries-based, /// intra-procedural, etc). class CallExecutionEngine { public: /// \brief Constructor CallExecutionEngine() noexcept = default; /// \brief Copy constructor CallExecutionEngine(const CallExecutionEngine&) noexcept = default; /// \brief Move constructor CallExecutionEngine(CallExecutionEngine&&) noexcept = default; /// \brief Copy assignment operator CallExecutionEngine& operator=(const CallExecutionEngine&) noexcept = default; /// \brief Move assignment operator CallExecutionEngine& operator=(CallExecutionEngine&&) noexcept = default; /// \brief Destructor virtual ~CallExecutionEngine() = default; /// \brief Exit a function /// /// This is called whenever we reach the exit node (if there is one). /// /// Note that this is different from exec(ar::Returnvalue*) if there is /// exceptions. This can be used to catch the invariant, including pending /// exceptions. virtual void exec_exit(ar::Function*) = 0; /// \brief Execute a Call statement virtual void exec(ar::Call* s) = 0; /// \brief Execute an Invoke statement virtual void exec(ar::Invoke* s) = 0; /// \brief Execute a ReturnValue statement virtual void exec(ar::ReturnValue* s) = 0; }; // end class CallExecutionEngine /// \brief Execute the transfert function for a Statement template < typename ExecEngine, typename CallExecEngine > inline void transfer_function(ExecEngine& exec_engine, CallExecEngine& call_exec_engine, ar::Statement* stmt) { struct StatementVisitor { using ResultType = void; ExecEngine& exec_engine; CallExecEngine& call_exec_engine; void operator()(ar::Assignment* s) { exec_engine.exec(s); } void operator()(ar::UnaryOperation* s) { exec_engine.exec(s); } void operator()(ar::BinaryOperation* s) { exec_engine.exec(s); } void operator()(ar::Comparison* s) { exec_engine.exec(s); } void operator()(ar::ReturnValue* s) { call_exec_engine.exec(s); } void operator()(ar::Unreachable* s) { exec_engine.exec(s); } void operator()(ar::Allocate* s) { exec_engine.exec(s); } void operator()(ar::PointerShift* s) { exec_engine.exec(s); } void operator()(ar::Load* s) { exec_engine.exec(s); } void operator()(ar::Store* s) { exec_engine.exec(s); } void operator()(ar::ExtractElement* s) { exec_engine.exec(s); } void operator()(ar::InsertElement* s) { exec_engine.exec(s); } void operator()(ar::ShuffleVector* s) { exec_engine.exec(s); } void operator()(ar::Call* s) { call_exec_engine.exec(s); } void operator()(ar::Invoke* s) { call_exec_engine.exec(s); } void operator()(ar::LandingPad* s) { exec_engine.exec(s); } void operator()(ar::Resume* s) { exec_engine.exec(s); } }; StatementVisitor visitor{exec_engine, call_exec_engine}; ar::apply_visitor(visitor, stmt); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/execution_engine/fixpoint_cache.hpp000066400000000000000000000115321473507761200335310ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Function fixpoint cache for dynamic inlining * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Function fixpoint cache for dynamic inlining /// /// This class stores computed function fixpoints for a given call site template < typename FunctionFixpoint, typename AbstractDomain > class FixpointCache { private: /// \brief Map from callee function to FunctionFixpoint using CalleeMap = boost::container::flat_map< ar::Function*, std::unique_ptr< FunctionFixpoint > >; /// \brief Map from call statement to CalleeMap using CallMap = llvm::DenseMap< ar::CallBase*, CalleeMap >; private: std::mutex _mutex; CallMap _call_map; public: /// \brief Constructor FixpointCache() = default; /// \brief No copy constructor FixpointCache(const FixpointCache&) = delete; /// \brief No move constructor FixpointCache(FixpointCache&&) = delete; /// \brief No copy assignment operator FixpointCache& operator=(const FixpointCache&) = delete; /// \brief No move assignment operator FixpointCache& operator=(FixpointCache&&) = delete; /// \brief Destructor ~FixpointCache() = default; /// \brief Try to fetch a fixpoint for a given call site and callee function std::unique_ptr< FunctionFixpoint > try_fetch(ar::CallBase* call, ar::Function* callee) { std::lock_guard< std::mutex > lock(this->_mutex); auto call_it = this->_call_map.find(call); if (call_it == this->_call_map.end()) { return nullptr; } CalleeMap& callee_map = call_it->second; auto callee_it = callee_map.find(callee); if (callee_it == callee_map.end()) { return nullptr; } return std::move(callee_it->second); } /// \brief Erase the fixpoint for a given call site and callee function void erase(ar::CallBase* call, ar::Function* callee) { std::lock_guard< std::mutex > lock(this->_mutex); auto call_it = this->_call_map.find(call); if (call_it == this->_call_map.end()) { return; } CalleeMap& callee_map = call_it->second; auto callee_it = callee_map.find(callee); if (callee_it == callee_map.end()) { return; } callee_it->second.reset(); } /// \brief Store a fixpoint for a given call site and callee function void store(ar::CallBase* call, ar::Function* callee, std::unique_ptr< FunctionFixpoint > fixpoint) { std::lock_guard< std::mutex > lock(this->_mutex); this->_call_map[call][callee] = std::move(fixpoint); } }; // end class FixpointCache } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/execution_engine/inliner.hpp000066400000000000000000000303411473507761200322050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Dynamic inlining call semantic * * Author: Maxime Arthaud * * Contributors: Jorge A. Navas * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Inliner of function calls /// /// The inlining of a function is done dynamically by matching formal and actual /// parameters and analyzing recursively the callee (FunctionFixpoint) and after /// the callee returns by simulating call-by-ref and updating the return value /// at the call site. The inlining also supports function pointers by resolving /// first the set of possible callees and joining the results. template < typename FunctionFixpoint, typename AbstractDomain > class InlineCallExecutionEngine final : public CallExecutionEngine { public: using InlineCallExecutionEngineT = InlineCallExecutionEngine< FunctionFixpoint, AbstractDomain >; using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; using FixpointCacheT = FixpointCache< FunctionFixpoint, AbstractDomain >; private: /// \brief Analysis context Context& _ctx; /// \brief Numerical execution engine NumericalExecutionEngineT& _engine; /// \brief Function analyzer of the caller FunctionFixpoint& _caller; /// \brief Function fixpoint cache of callees FixpointCacheT& _callees_cache; /// \brief True to check properties on the callees bool _check_callees; public: /// \brief Constructor InlineCallExecutionEngine(Context& ctx, NumericalExecutionEngineT& engine, FunctionFixpoint& caller, FixpointCacheT& callees_cache) : _ctx(ctx), _engine(engine), _caller(caller), _callees_cache(callees_cache), _check_callees(false) {} /// \brief Mark to check the callees void mark_check_callees() { this->_check_callees = true; } /// \brief Exit a function /// /// This is called whenever we reach the exit node (if there is one). /// /// Note that this is different from exec(ar::Returnvalue*) if there is /// exceptions. This can be used to catch the invariant, including pending /// exceptions. void exec_exit(ar::Function* fun) override { this->_engine.deallocate_local_variables(fun->local_variable_begin(), fun->local_variable_end()); this->_caller.set_exit_invariant(this->_engine.inv()); } /// \brief Execute a ReturnValue statement void exec(ar::ReturnValue* s) override { this->_caller.set_return_stmt(s); } /// \brief Execute a Call statement void exec(ar::Call* s) override { // Execute the call base statement this->exec(cast< ar::CallBase >(s)); // Exceptions aren't caught, propagate them this->inv().merge_caught_in_propagated_exceptions(); } /// \brief Execute an Invoke statement void exec(ar::Invoke* s) override { // Execute the call base statement this->exec(cast< ar::CallBase >(s)); // Exceptions are caught. // Nothing to do here. // see NumericalExecutionEngine::exec_edge() } private: /// \brief Return a non-const reference on the current invariant AbstractDomain& inv() { return this->_engine.inv(); } /// \brief Execute any call statement void exec(ar::CallBase* call) { this->inv().normal().normalize(); if (this->inv().is_normal_flow_bottom()) { return; } // // Collect potential callees // auto callees = PointsToSet::bottom(); ar::Value* called = call->called(); if (isa< ar::UndefinedConstant >(called)) { // Call on undefined pointer: error this->inv().set_normal_flow_to_bottom(); return; } else if (isa< ar::NullConstant >(called)) { // Call on null pointer: error this->inv().set_normal_flow_to_bottom(); return; } else if (auto cst = dyn_cast< ar::FunctionPointerConstant >(called)) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(called)) { // Call to assembly this->_engine.exec_unknown_extern_call(call); return; } else if (isa< ar::GlobalVariable >(called)) { // Call to global variable: error this->inv().set_normal_flow_to_bottom(); return; } else if (isa< ar::LocalVariable >(called)) { // Call to local variable: error this->inv().set_normal_flow_to_bottom(); return; } else if (auto ptr = dyn_cast< ar::InternalVariable >(called)) { // Indirect call through a function pointer Variable* ptr_var = _ctx.var_factory->get_internal(ptr); // Assert `ptr != null` this->inv().normal().nullity_assert_non_null(ptr_var); // Reduction between value and pointer analysis const PointerInfo* pointer_info = this->_engine.pointer_info(); if (pointer_info != nullptr) { PointsToSet points_to = pointer_info->get(ptr_var).points_to(); // Pointer analysis and value analysis can be inconsistent if (!points_to.is_bottom() && !points_to.is_top()) { this->inv().normal().pointer_refine(ptr_var, points_to); } } this->inv().normal().normalize(); if (this->inv().is_normal_flow_bottom()) { return; } // Get the callees callees = this->inv().normal().pointer_to_points_to(ptr_var); } else { ikos_unreachable("unexpected called operand"); } // // Check callees // ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference this->inv().set_normal_flow_to_bottom(); return; } else if (callees.is_top()) { // No points-to information // ASSUMPTION: the callee has no side effects. // Just set lhs and all actual parameters of pointer type to TOP. this->_engine.exec_unknown_extern_call(call); return; } // // Compute the post invariant // // By default, propagate the exception states AbstractDomain post = this->inv(); post.set_normal_flow_to_bottom(); // For each callee for (MemoryLocation* mem : callees) { if (!isa< FunctionMemoryLocation >(mem)) { // Not a call to a function memory location continue; } ar::Function* callee = cast< FunctionMemoryLocation >(mem)->function(); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call // // This could be because of an imprecision of the pointer analysis. continue; } if (callee->is_declaration()) { // Call to an extern function // // ASSUMPTION: if this is a call to an extern non-intrinsic function, // treat it as a function call that has no side effects. NumericalExecutionEngineT engine = this->_engine.fork(); engine.inv().ignore_exceptions(); engine.exec_extern_call(call, callee); engine.inv().merge_propagated_in_caught_exceptions(); post.join_with(std::move(engine.inv())); continue; } ikos_assert(callee->is_definition()); if (this->_caller.function() == callee || this->_caller.call_context()->contains(callee)) { // Recursive function call // // TODO(jnavas): we can be more precise by making top only lhs of // call_stmt, actual parameters of pointer type and any global variable // that might be touched by the recursive function. this->_engine.exec_unknown_intern_call(call); return; } NumericalExecutionEngineT engine = this->_engine.fork(); // Do not propagate exceptions from the caller to the callee engine.inv().ignore_exceptions(); // Assign parameters engine.match_down(call, callee); // // Analyze recursively the callee // std::unique_ptr< FunctionFixpoint > callee_fixpoint = nullptr; if (_ctx.opts.use_fixpoint_cache && this->_caller.converged()) { // Try to fetch the previously computed fix-point callee_fixpoint = this->_callees_cache.try_fetch(call, callee); } if (callee_fixpoint == nullptr) { if (_ctx.opts.use_fixpoint_cache) { // Erase the previous fix-point on the callee this->_callees_cache.erase(call, callee); } // Create a fixpoint on the callee callee_fixpoint = std::make_unique< FunctionFixpoint >(_ctx, this->_caller, call, callee); // Run analysis on callee log::debug("Analyzing function '" + demangle(callee->name()) + "'"); callee_fixpoint->run(std::move(engine.inv())); } if (this->_check_callees) { // Run the checks on the callee callee_fixpoint->run_checks(); } // Return statement in the callee, or null ar::ReturnValue* return_stmt = callee_fixpoint->return_stmt(); engine.set_inv(callee_fixpoint->exit_invariant()); if (_ctx.opts.use_fixpoint_cache) { // Save the fix-point for later this->_callees_cache.store(call, callee, std::move(callee_fixpoint)); } else { // Delete the callee fix-point callee_fixpoint.reset(); } // Merge exceptions in caught_exceptions, in case it's an invoke engine.inv().merge_propagated_in_caught_exceptions(); if (engine.inv().is_normal_flow_bottom()) { // Collect the exception states post.join_with(std::move(engine.inv())); continue; } engine.match_up(call, return_stmt); post.join_with(std::move(engine.inv())); } this->_engine.set_inv(std::move(post)); } }; // end class InlineCallExecutionEngine } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/execution_engine/numerical.hpp000066400000000000000000004205021473507761200325260ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Numerical execution engine * * Author: Maxime Arthaud * * Contributors: Jorge A. Navas * Clement Decoodt * Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Numerical execution engine /// /// This class performs the transfer function on each AR (Abstract /// Representation) statement with different levels of precision. /// /// It relies on an abstract domain. /// /// The abstract domain must implement the exception abstract domain interface /// to handle exception propagation correctly. /// /// The exception abstract domain must provide an underlying abstract domain /// that must implement the memory abstract domain interface to handle scalar /// variables and memory operations. template < typename AbstractDomain > class NumericalExecutionEngine final : public ExecutionEngine { public: static_assert(core::exception::IsAbstractDomain< AbstractDomain >::value, "AbstractDomain must implement exception::AbstractDomain"); static_assert(core::memory::IsAbstractDomain< typename AbstractDomain::UnderlyingDomainT, Variable*, MemoryLocation* >::value, "AbstractDomain::UnderlyingDomainT must implement " "memory::AbstractDomain"); private: using IntInterval = core::machine_int::Interval; using IntIntervalCongruence = core::machine_int::IntervalCongruence; using IntVariable = core::VariableExpression< MachineInt, Variable* >; using IntLinearExpression = core::LinearExpression< MachineInt, Variable* >; using IntLinearConstraint = core::LinearConstraint< MachineInt, Variable* >; using IntLinearConstraintSystem = core::LinearConstraintSystem< MachineInt, Variable* >; using Nullity = core::Nullity; using Uninitialized = core::Uninitialized; using Lifetime = core::Lifetime; using IntUnaryOperator = core::machine_int::UnaryOperator; using IntBinaryOperator = core::machine_int::BinaryOperator; using IntPredicate = core::machine_int::Predicate; using PointerPredicate = core::pointer::Predicate; private: /// \brief Current invariant AbstractDomain _inv; /// \brief Analysis context Context& _ctx; /// \brief Memory location factory MemoryFactory& _mem_factory; /// \brief Variable factory VariableFactory& _var_factory; /// \brief Literal factory LiteralFactory& _lit_factory; /// \brief Data layout const ar::DataLayout& _data_layout; /// \brief Call context CallContext* _call_context; /// \brief Execution engine options ExecutionEngineOptions _opts; /// \brief Optional liveness information const LivenessAnalysis* _liveness; /// \brief Optional pointer information const PointerInfo* _pointer_info; public: /// \brief Constructor /// /// \param inv Initial invariant /// \param ctx Analysis context /// \param call_context Calling context /// \param opts Execution engine options /// \param liveness Liveness analysis, or null /// \param pointer_info Pointer information, or null NumericalExecutionEngine(AbstractDomain inv, Context& ctx, CallContext* call_context, ExecutionEngineOptions opts, const LivenessAnalysis* liveness = nullptr, const PointerInfo* pointer_info = nullptr) : _inv(std::move(inv)), _ctx(ctx), _mem_factory(*ctx.mem_factory), _var_factory(*ctx.var_factory), _lit_factory(*ctx.lit_factory), _data_layout(ctx.bundle->data_layout()), _call_context(call_context), _opts(opts), _liveness(liveness), _pointer_info(pointer_info) {} private: /// \brief Private copy constructor NumericalExecutionEngine(const NumericalExecutionEngine&) = default; public: /// \brief Public move constructor NumericalExecutionEngine(NumericalExecutionEngine&&) noexcept( std::is_nothrow_move_constructible< AbstractDomain >::value) = default; /// \brief No copy assignment operator NumericalExecutionEngine& operator=(const NumericalExecutionEngine&) = delete; /// \brief No move assignment operator NumericalExecutionEngine& operator=(NumericalExecutionEngine&&) = delete; /// \brief Destructor ~NumericalExecutionEngine() override = default; /// \brief Create a fresh numerical execution engine, with its own abstract /// domain NumericalExecutionEngine fork() const { return *this; } /// \brief Return the current invariant AbstractDomain& inv() { return this->_inv; } /// \brief Return the current invariant const AbstractDomain& inv() const { return this->_inv; } /// \brief Update the current invariant void set_inv(const AbstractDomain& inv) { this->_inv = inv; } /// \brief Update the current invariant void set_inv(AbstractDomain&& inv) { this->_inv = std::move(inv); } /// \brief Return the liveness analysis used, or null const LivenessAnalysis* liveness() const { return this->_liveness; } /// \brief Return the pointer information, or null const PointerInfo* pointer_info() const { return this->_pointer_info; } public: /// \name Helpers to allocate memory /// @{ /// \brief Initial value for a memory block enum class MemoryInitialValue { // Memory is initialized with zeros Zero, // Memory is uninitialized, reading it is an error Uninitialized, // Memory is unknown, reading it returns a non-deterministic value Unknown, }; /// \brief Allocate a new memory object `addr` with unknown size /// /// We consider as a memory object an alloca (i.e., stack variables), global /// variables, malloc-like allocation sites, function pointers, and /// destination of inttoptr instructions. Also, variables whose address might /// have been taken are translated to global variables by the front-end. void allocate_memory(Variable* ptr, MemoryLocation* addr, Nullity nullity, Lifetime lifetime, MemoryInitialValue init_val) { // Update pointer this->_inv.normal().pointer_assign(ptr, addr, nullity); // Update memory location lifetime this->_inv.normal().lifetime_set(addr, lifetime); // Update memory value if (init_val == MemoryInitialValue::Zero) { this->_inv.normal().mem_zero_reachable(ptr); } else if (init_val == MemoryInitialValue::Uninitialized) { this->_inv.normal().mem_uninitialize_reachable(ptr); } else if (init_val == MemoryInitialValue::Unknown) { this->_inv.normal().mem_forget_reachable(ptr); } else { ikos_unreachable("unreachable"); } } /// \brief Allocate a new memory object `addr` of size `alloc_size` (in bytes) void allocate_memory(Variable* ptr, MemoryLocation* addr, Nullity nullity, Lifetime lifetime, MemoryInitialValue init_val, const MachineInt& alloc_size) { // Update pointer, lifetime and initial value for the memory location this->allocate_memory(ptr, addr, nullity, lifetime, init_val); if (init_val == MemoryInitialValue::Uninitialized) { // When the size of the allocation is known (like it is here) // we mark the storage as uninitialized by assigning it // the undefined value. this->_inv.normal().mem_write(ptr, ScalarLit::undefined(), alloc_size); } if (this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { // Update allocation size var Variable* alloc_size_var = this->_var_factory.get_alloc_size(addr); this->_inv.normal().int_assign(alloc_size_var, alloc_size); } } /// \brief Allocate a new memory object `addr` of size `alloc_size` (in bytes) void allocate_memory(Variable* ptr, MemoryLocation* addr, Nullity nullity, Lifetime lifetime, MemoryInitialValue init_val, Variable* alloc_size) { // Update pointer, lifetime and initial value for the memory location this->allocate_memory(ptr, addr, nullity, lifetime, init_val); if (this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { // Update allocation size var Variable* alloc_size_var = this->_var_factory.get_alloc_size(addr); this->_inv.normal().uninit_assert_initialized(alloc_size); this->_inv.normal().int_assign(alloc_size_var, alloc_size); } } private: /// @} /// \name Internal helpers /// @{ /// \brief Initialize a global variable or function pointer operand /// /// Global variables and constant function pointers are not stored in the /// initial invariant, so it is necessary to initialize them on the fly when /// we need them. void init_global_operand(ar::Value* value) { if (auto gv = dyn_cast< ar::GlobalVariable >(value)) { this->_inv.normal().pointer_assign(this->_var_factory.get_global(gv), this->_mem_factory.get_global(gv), Nullity::non_null()); } else if (auto fun_ptr = dyn_cast< ar::FunctionPointerConstant >(value)) { auto fun = fun_ptr->function(); this->_inv.normal().pointer_assign(this->_var_factory.get_function_ptr( fun), this->_mem_factory.get_function(fun), Nullity::non_null()); } else if (auto struct_cst = dyn_cast< ar::StructConstant >(value)) { for (auto it = struct_cst->field_begin(), et = struct_cst->field_end(); it != et; ++it) { this->init_global_operand(it->value); } } else if (auto seq_cst = dyn_cast< ar::SequentialConstant >(value)) { for (auto it = seq_cst->element_begin(), et = seq_cst->element_end(); it != et; ++it) { this->init_global_operand(*it); } } } /// \brief Initialize global variables and function pointer operands void init_global_operands(ar::Statement* s) { for (auto it = s->op_begin(), et = s->op_end(); it != et; ++it) { this->init_global_operand(*it); } } /// \brief Prepare a memory access (read/write) on the given pointer /// /// Return true if the memory access can be performed, i.e the pointer is /// non-null and well defined bool prepare_mem_access(const ScalarLit& ptr) { if (ptr.is_undefined()) { // Undefined pointer dereference this->_inv.set_normal_flow_to_bottom(); return false; } else if (ptr.is_null()) { // Null pointer dereference this->_inv.set_normal_flow_to_bottom(); return false; } ikos_assert_msg(ptr.is_pointer_var(), "unexpected parameter"); // Reduction between value and pointer analysis this->refine_addresses_offset(ptr.var()); // Assert `ptr != null` this->_inv.normal().nullity_assert_non_null(ptr.var()); this->_inv.normal().normalize(); // Ready for read/write return !this->_inv.is_normal_flow_bottom(); } /// \brief Normalize the nullity domain /// /// Check if the given pointer variable points to AbsoluteZeroMemoryLocation. /// If so, check if the offset interval contains zero, and update the nullity /// domain accordingly. void normalize_absolute_zero_nullity(Variable* p) { auto nullity = this->_inv.normal().nullity_to_nullity(p); if (nullity.is_bottom() || nullity.is_top()) { return; } PointsToSet addrs = this->_inv.normal().pointer_to_points_to(p); if (addrs.contains(this->_mem_factory.get_absolute_zero())) { IntIntervalCongruence offset = this->_inv.normal().pointer_offset_to_interval_congruence(p); auto zero = MachineInt::zero(offset.bit_width(), offset.sign()); if (offset.is_bottom()) { return; } else if (addrs.singleton()) { if (offset.singleton() == boost::optional< MachineInt >(zero)) { // Pointer is definitely null (base is zero, offset = 0) this->_inv.normal().nullity_set(p, Nullity::null()); } else if (!offset.contains(zero)) { // Pointer is definitely non-null (base is zero, offset != 0) this->_inv.normal().nullity_set(p, Nullity::non_null()); } else { // Pointer might be null (base is zero, offset contains zero) this->_inv.normal().nullity_set(p, Nullity::top()); } } else if (offset.contains(zero)) { // Pointer might be null (base might be zero, offset contains zero) this->_inv.normal().nullity_set(p, Nullity::top()); } } } /// \brief Refine the addresses of `ptr` using information from an external /// pointer analysis void refine_addresses(Variable* ptr) { if (!this->_pointer_info) { return; } PointerAbsValue value = this->_pointer_info->get(ptr); this->_inv.normal().pointer_refine(ptr, value.points_to()); } /// \brief Refine the addresses and offset of `ptr` using information from an /// external pointer analysis void refine_addresses_offset(Variable* ptr) { if (!this->_pointer_info) { return; } PointerAbsValue value = this->_pointer_info->get(ptr); this->_inv.normal().pointer_refine(ptr, value); } private: /// @} /// \name Helpers for assignments /// @{ /// \brief Integer variable assignment class IntegerAssign : public ScalarLit::template Visitor<> { private: Variable* _lhs; AbstractDomain& _inv; public: IntegerAssign(Variable* lhs, AbstractDomain& inv) : _lhs(lhs), _inv(inv) {} void machine_int(const MachineInt& rhs) { this->_inv.normal().int_assign(this->_lhs, rhs); } void floating_point(const DummyNumber&) { ikos_unreachable("unreachable"); } void memory_location(MemoryLocation*) { ikos_unreachable("unreachable"); } void null() { ikos_unreachable("unreachable"); } void undefined() { this->_inv.normal().int_assign_undef(this->_lhs); } void machine_int_var(Variable* rhs) { this->_inv.normal().int_assign(this->_lhs, rhs); } void floating_point_var(Variable*) { ikos_unreachable("unreachable"); } void pointer_var(Variable*) { ikos_unreachable("unreachable"); } }; // end class IntegerAssign /// \brief Floating point variable assignment class FloatingPointAssign : public ScalarLit::template Visitor<> { private: Variable* _lhs; AbstractDomain& _inv; public: FloatingPointAssign(Variable* lhs, AbstractDomain& inv) : _lhs(lhs), _inv(inv) {} void machine_int(const MachineInt&) { ikos_unreachable("unreachable"); } void floating_point(const DummyNumber&) { this->_inv.normal().float_assign_nondet(this->_lhs); } void memory_location(MemoryLocation*) { ikos_unreachable("unreachable"); } void null() { ikos_unreachable("unreachable"); } void undefined() { this->_inv.normal().float_assign_undef(this->_lhs); } void machine_int_var(Variable*) { ikos_unreachable("unreachable"); } void floating_point_var(Variable* rhs) { this->_inv.normal().float_assign(this->_lhs, rhs); } void pointer_var(Variable*) { ikos_unreachable("unreachable"); } }; // end class FloatingPointAssign /// \brief Pointer variable assignment class PointerAssign : public ScalarLit::template Visitor<> { private: Variable* _lhs; AbstractDomain& _inv; public: PointerAssign(Variable* lhs, AbstractDomain& inv) : _lhs(lhs), _inv(inv) {} void machine_int(const MachineInt&) { ikos_unreachable("unreachable"); } void floating_point(const DummyNumber&) { ikos_unreachable("unreachable"); } void memory_location(MemoryLocation* addr) { this->_inv.normal().pointer_assign(this->_lhs, addr, Nullity::non_null()); } void null() { this->_inv.normal().pointer_assign_null(this->_lhs); } void undefined() { this->_inv.normal().pointer_assign_undef(this->_lhs); } void machine_int_var(Variable*) { ikos_unreachable("unreachable"); } void floating_point_var(Variable*) { ikos_unreachable("unreachable"); } void pointer_var(Variable* rhs) { this->_inv.normal().pointer_assign(this->_lhs, rhs); } }; // end class PointerAssign /// \brief Scalar assignment `lhs = rhs` /// /// Requires that `lhs` and `rhs` have the same type. /// Propagates uninitialized variables. void assign(const ScalarLit& lhs, const ScalarLit& rhs) { if (lhs.is_machine_int_var()) { IntegerAssign v(lhs.var(), this->_inv); rhs.apply_visitor(v); } else if (lhs.is_floating_point_var()) { FloatingPointAssign v(lhs.var(), this->_inv); rhs.apply_visitor(v); } else if (lhs.is_pointer_var()) { PointerAssign v(lhs.var(), this->_inv); rhs.apply_visitor(v); } else { ikos_unreachable("left hand side is not a variable"); } } private: /// @} /// \name Helpers for implicit bitcasts /// @{ /// \brief Integer variable implicit bitcast class IntegerImplicitBitcast : public ScalarLit::template Visitor<> { private: Variable* _lhs; ar::IntegerType* _type; AbstractDomain& _inv; public: IntegerImplicitBitcast(Variable* lhs, AbstractDomain& inv) : _lhs(lhs), _type(ar::cast< ar::IntegerType >(lhs->type())), _inv(inv) {} void machine_int(const MachineInt& rhs) { ikos_assert(this->_type->bit_width() == rhs.bit_width()); if (this->_type->sign() == rhs.sign()) { this->_inv.normal().int_assign(this->_lhs, rhs); } else { this->_inv.normal().int_assign(this->_lhs, rhs.sign_cast(this->_type->sign())); } } void floating_point(const DummyNumber&) { ikos_unreachable("unreachable"); } void memory_location(MemoryLocation*) { ikos_unreachable("unreachable"); } void null() { ikos_unreachable("unreachable"); } void undefined() { this->_inv.set_normal_flow_to_bottom(); } void machine_int_var(Variable* rhs) { auto rhs_type = ar::cast< ar::IntegerType >(rhs->type()); ikos_assert(this->_type->bit_width() == rhs_type->bit_width()); if (this->_type->sign() == rhs_type->sign()) { this->_inv.normal().uninit_assert_initialized(rhs); this->_inv.normal().int_assign(this->_lhs, rhs); } else { this->_inv.normal().int_apply(IntUnaryOperator::SignCast, this->_lhs, rhs); } } void floating_point_var(Variable*) { ikos_unreachable("unreachable"); } void pointer_var(Variable*) { ikos_unreachable("unreachable"); } }; // end class IntegerImplicitBitcast /// \brief Floating point variable implement bitcast class FloatingPointImplicitBitcast : public ScalarLit::template Visitor<> { private: Variable* _lhs; AbstractDomain& _inv; public: FloatingPointImplicitBitcast(Variable* lhs, AbstractDomain& inv) : _lhs(lhs), _inv(inv) {} void machine_int(const MachineInt&) { ikos_unreachable("unreachable"); } void floating_point(const DummyNumber&) { this->_inv.normal().float_assign_nondet(this->_lhs); } void memory_location(MemoryLocation*) { ikos_unreachable("unreachable"); } void null() { ikos_unreachable("unreachable"); } void undefined() { this->_inv.set_normal_flow_to_bottom(); } void machine_int_var(Variable*) { ikos_unreachable("unreachable"); } void floating_point_var(Variable* rhs) { this->_inv.normal().uninit_assert_initialized(rhs); this->_inv.normal().float_assign(this->_lhs, rhs); } void pointer_var(Variable*) { ikos_unreachable("unreachable"); } }; // end class FloatingPointImplicitBitcast /// \brief Pointer variable implicit bitcast class PointerImplicitBitcast : public ScalarLit::template Visitor<> { private: Variable* _lhs; AbstractDomain& _inv; public: PointerImplicitBitcast(Variable* lhs, AbstractDomain& inv) : _lhs(lhs), _inv(inv) {} void machine_int(const MachineInt&) { ikos_unreachable("unreachable"); } void floating_point(const DummyNumber&) { ikos_unreachable("unreachable"); } void memory_location(MemoryLocation* addr) { this->_inv.normal().pointer_assign(this->_lhs, addr, Nullity::non_null()); } void null() { this->_inv.normal().pointer_assign_null(this->_lhs); } void undefined() { this->_inv.set_normal_flow_to_bottom(); } void machine_int_var(Variable*) { ikos_unreachable("unreachable"); } void floating_point_var(Variable*) { ikos_unreachable("unreachable"); } void pointer_var(Variable* rhs) { this->_inv.normal().uninit_assert_initialized(rhs); this->_inv.normal().pointer_assign(this->_lhs, rhs); } }; // end class PointerImplicitBitcast /// \brief Implicit bitcast `lhs = rhs` /// /// Requires either one of: /// - `lhs` and `rhs` have the same type /// - `lhs` and `rhs` are integers of same bit-width (signed <-> unsigned) /// - `lhs` and `rhs` are pointer types (ie., A* <-> B*) /// /// Implicit bitcast on an uninitialized variable is an error. void implicit_bitcast(const ScalarLit& lhs, const ScalarLit& rhs) { if (lhs.is_machine_int_var()) { IntegerImplicitBitcast v(lhs.var(), this->_inv); rhs.apply_visitor(v); } else if (lhs.is_floating_point_var()) { FloatingPointImplicitBitcast v(lhs.var(), this->_inv); rhs.apply_visitor(v); } else if (lhs.is_pointer_var()) { PointerImplicitBitcast v(lhs.var(), this->_inv); rhs.apply_visitor(v); } else { ikos_unreachable("left hand side is not a variable"); } } private: /// @} /// \name Helpers for aggregate (struct, array) statements /// @{ /// \brief Return the type void* ar::Type* void_ptr_type() const { ar::Context& ctx = _ctx.bundle->context(); return ar::PointerType::get(ctx, ar::VoidType::get(ctx)); } /// \brief Initialize an aggregate memory location /// /// Internal variables of aggregate types are modeled as if they were in /// memory, at a symbolic location. /// /// Returns a pointer to the symbolic location of the aggregate in memory. Variable* init_aggregate_memory(const AggregateLit& aggregate) { ikos_assert_msg(aggregate.is_var(), "aggregate is not a variable"); auto var = cast< InternalVariable >(aggregate.var()); this->allocate_memory(var, this->_mem_factory.get_aggregate(var->internal_var()), Nullity::non_null(), Lifetime::top(), MemoryInitialValue::Zero); return var; } /// \brief Return a pointer to the symbolic location of the aggregate in /// memory Variable* aggregate_pointer(const AggregateLit& aggregate) { ikos_assert_msg(aggregate.is_var(), "aggregate is not a variable"); auto var = cast< InternalVariable >(aggregate.var()); this->_inv.normal().pointer_assign(var, this->_mem_factory.get_aggregate( var->internal_var()), Nullity::non_null()); return var; } /// \brief Write an aggregate in the memory void mem_write_aggregate(Variable* ptr, const AggregateLit& aggregate) { if (aggregate.size().is_zero()) { return; // Nothing to do } else if (aggregate.is_cst()) { // Pointer to write the aggregate in the memory Variable* write_ptr = this->_var_factory.get_named_shadow(this->void_ptr_type(), "shadow.mem_write_aggregate.ptr"); for (const auto& field : aggregate.fields()) { this->_inv.normal().pointer_assign(write_ptr, ptr, field.offset); this->_inv.normal().mem_write(write_ptr, field.value, field.size); } // Clean-up this->_inv.normal().pointer_forget(write_ptr); } else if (aggregate.is_zero() || aggregate.is_undefined()) { // aggregate.size() is in bytes, compute bit-width, and check // if the bit-width fits in an unsigned int // XXX: We should use mem_zero_reachable and mem_uninitialize_reachable bool overflow; MachineInt eight(8, aggregate.size().bit_width(), Unsigned); MachineInt bit_width = mul(aggregate.size(), eight, overflow); if (overflow || !bit_width.fits< uint64_t >()) { // Too big for a cell this->_inv.normal().mem_forget_reachable(ptr); } else if (aggregate.is_zero()) { MachineInt zero(0, bit_width.to< uint64_t >(), Signed); this->_inv.normal().mem_write(ptr, ScalarLit::machine_int(zero), aggregate.size()); } else if (aggregate.is_undefined()) { this->_inv.normal().mem_write(ptr, ScalarLit::undefined(), aggregate.size()); } else { ikos_unreachable("unreachable"); } } else if (aggregate.is_var()) { Variable* aggregate_ptr = this->aggregate_pointer(aggregate); this->_inv.normal().mem_copy(ptr, aggregate_ptr, ScalarLit::machine_int(aggregate.size())); } else { ikos_unreachable("unreachable"); } } /// \brief Aggregate assignment `lhs = rhs` /// /// Propagates uninitialized variables. void assign(const AggregateLit& lhs, const AggregateLit& rhs) { ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); Variable* ptr = this->init_aggregate_memory(lhs); this->mem_write_aggregate(ptr, rhs); } /// \brief Assignment `lhs = rhs` /// /// Requires that `lhs` and `rhs` have the same type. /// Propagates uninitialized variables. void assign(const Literal& lhs, const Literal& rhs) { if (lhs.is_scalar()) { ikos_assert_msg(rhs.is_scalar(), "unexpected right hand side"); this->assign(lhs.scalar(), rhs.scalar()); } else if (lhs.is_aggregate()) { ikos_assert_msg(rhs.is_aggregate(), "unexpected right hand side"); this->assign(lhs.aggregate(), rhs.aggregate()); } else { ikos_unreachable("unreachable"); } } /// \brief Implicit bitcast `lhs = rhs` /// /// Requires either one of: /// - `lhs` and `rhs` have the same type /// - `lhs` and `rhs` are integers of same bit-width (signed <-> unsigned) /// - `lhs` and `rhs` are pointer types (ie., A* <-> B*) /// /// Implicit bitcast on an uninitialized variable is an error. void implicit_bitcast(const Literal& lhs, const Literal& rhs) { if (lhs.is_scalar()) { ikos_assert_msg(rhs.is_scalar(), "unexpected right hand side"); this->implicit_bitcast(lhs.scalar(), rhs.scalar()); } else if (lhs.is_aggregate()) { ikos_assert_msg(rhs.is_aggregate(), "unexpected right hand side"); this->assign(lhs.aggregate(), rhs.aggregate()); } else { ikos_unreachable("unreachable"); } } /// \brief Randomly throw unknown exceptions with the current invariant /// /// Equivalent to if (rand()) { throw rand(); } void throw_unknown_exceptions() { this->_inv.caught_exceptions().join_with(this->_inv.normal()); } public: /// \brief Deallocate the memory for the given local variables void deallocate_local_variables(ar::Function::LocalVariableIterator begin, ar::Function::LocalVariableIterator end) { for (auto it = begin; it != end; ++it) { LocalVariable* var = this->_var_factory.get_local(*it); MemoryLocation* addr = this->_mem_factory.get_local(*it); // Forget local variable pointer this->_inv.normal().pointer_forget(var); this->_inv.caught_exceptions().pointer_forget(var); this->_inv.propagated_exceptions().pointer_forget(var); // Forget the memory content this->_inv.normal().mem_forget(addr); this->_inv.caught_exceptions().mem_forget(addr); this->_inv.propagated_exceptions().mem_forget(addr); // Set the memory location lifetime to deallocated this->_inv.normal().lifetime_assign_deallocated(addr); this->_inv.caught_exceptions().lifetime_assign_deallocated(addr); this->_inv.propagated_exceptions().lifetime_assign_deallocated(addr); if (this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { // Forget the allocation size variable AllocSizeVariable* alloc_size_var = this->_var_factory.get_alloc_size(addr); this->_inv.normal().int_forget(alloc_size_var); this->_inv.caught_exceptions().int_forget(alloc_size_var); this->_inv.propagated_exceptions().int_forget(alloc_size_var); } } } public: /// @} /// \name Implement ExecutionEngine /// @{ /// \brief Enter a basic block void exec_enter(ar::BasicBlock*) override {} /// \brief Leave a basic block /// /// Use the liveness analysis to remove dead variables void exec_leave(ar::BasicBlock* bb) override { if (this->_liveness == nullptr) { return; } boost::optional< const LivenessAnalysis::VariableRefList& > dead = this->_liveness->dead_at_end(bb); if (!dead) { return; } // Do not remove the returned variable Variable* returned_var = nullptr; if (!bb->empty() && isa< ar::ReturnValue >(bb->back())) { auto ret = cast< ar::ReturnValue >(bb->back()); if (ret->has_operand()) { const Literal& v = this->_lit_factory.get(ret->operand()); if (v.is_var()) { returned_var = v.var(); } } } for (Variable* var : *dead) { if (var == returned_var) { // Ignore continue; } // Special case for aggregate internal variables: Clean-up the memory if (auto iv = dyn_cast< InternalVariable >(var)) { ar::InternalVariable* ar_iv = iv->internal_var(); if (ar_iv->type()->is_aggregate()) { MemoryLocation* addr = this->_mem_factory.get_aggregate(ar_iv); this->_inv.normal().mem_forget(addr); this->_inv.caught_exceptions().mem_forget(addr); this->_inv.propagated_exceptions().mem_forget(addr); } } // Clean-up scalars this->_inv.normal().scalar_forget(var); this->_inv.caught_exceptions().scalar_forget(var); this->_inv.propagated_exceptions().scalar_forget(var); } } /// \brief Execute an edge from `src` to `dest` void exec_edge(ar::BasicBlock* src, ar::BasicBlock* dest) override { // Check if the source block ends with an invoke if (src->empty()) { return; } ar::Statement* stmt = src->back(); if (!isa< ar::Invoke >(stmt)) { return; } auto invoke = cast< ar::Invoke >(stmt); if (invoke->normal_dest() == dest) { this->_inv.enter_normal(); } else if (invoke->exception_dest() == dest) { this->_inv.enter_catch(); } else { ikos_unreachable("unreachable"); } } /// \brief Execute an Assignment statement /// /// Unlike most statements, this propagates uninitialized variables. void exec(ar::Assignment* s) override { this->init_global_operands(s); this->assign(this->_lit_factory.get(s->result()), this->_lit_factory.get(s->operand())); } /// \brief Execute an UnaryOperation statement void exec(ar::UnaryOperation* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const Literal& lhs = this->_lit_factory.get(s->result()); const Literal& rhs = this->_lit_factory.get(s->operand()); switch (s->op()) { case ar::UnaryOperation::UTrunc: case ar::UnaryOperation::STrunc: { this->exec_int_conv(IntUnaryOperator::Trunc, lhs.scalar(), rhs.scalar()); } break; case ar::UnaryOperation::ZExt: case ar::UnaryOperation::SExt: { this->exec_int_conv(IntUnaryOperator::Ext, lhs.scalar(), rhs.scalar()); } break; case ar::UnaryOperation::FPTrunc: case ar::UnaryOperation::FPExt: { this->exec_float_conv(lhs.scalar(), rhs.scalar()); } break; case ar::UnaryOperation::FPToUI: case ar::UnaryOperation::FPToSI: { this->exec_float_to_int_conv(lhs.scalar(), rhs.scalar()); } break; case ar::UnaryOperation::UIToFP: case ar::UnaryOperation::SIToFP: { this->exec_int_to_float_conv(lhs.scalar(), rhs.scalar()); } break; case ar::UnaryOperation::PtrToUI: case ar::UnaryOperation::PtrToSI: { this->exec_ptr_to_int_conv(lhs.scalar(), rhs.scalar()); } break; case ar::UnaryOperation::UIToPtr: case ar::UnaryOperation::SIToPtr: { this->exec_int_to_ptr_conv(lhs.scalar(), rhs.scalar()); } break; case ar::UnaryOperation::Bitcast: { this->exec_bitcast(s, lhs, rhs); } break; } } private: /// \brief Execute an integer conversion void exec_int_conv(IntUnaryOperator op, const ScalarLit& lhs, const ScalarLit& rhs) { ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); if (rhs.is_machine_int()) { auto type = cast< ar::IntegerType >(lhs.var()->type()); this->_inv.normal() .int_assign(lhs.var(), core::machine_int::apply_unary_operator(op, rhs.machine_int(), type->bit_width(), type->sign())); } else if (rhs.is_machine_int_var()) { this->_inv.normal().int_apply(op, lhs.var(), rhs.var()); } else { ikos_unreachable("unexpected arguments"); } } /// \brief Execute a floating point conversion void exec_float_conv(const ScalarLit& lhs, const ScalarLit& rhs) { ikos_assert_msg(lhs.is_floating_point_var(), "left hand side is not a floating point variable"); if (rhs.is_floating_point_var()) { this->_inv.normal().uninit_assert_initialized(rhs.var()); } this->_inv.normal().float_assign_nondet(lhs.var()); } /// \brief Execute a conversion from floating point to integer void exec_float_to_int_conv(const ScalarLit& lhs, const ScalarLit& rhs) { ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); if (rhs.is_floating_point_var()) { this->_inv.normal().uninit_assert_initialized(rhs.var()); } this->_inv.normal().int_assign_nondet(lhs.var()); } /// \brief Execute a conversion from integer to floating point void exec_int_to_float_conv(const ScalarLit& lhs, const ScalarLit& rhs) { ikos_assert_msg(lhs.is_floating_point_var(), "left hand side is not a floating point variable"); if (rhs.is_machine_int_var()) { this->_inv.normal().uninit_assert_initialized(rhs.var()); } this->_inv.normal().float_assign_nondet(lhs.var()); } /// \brief Execute a conversion from pointer to integer void exec_ptr_to_int_conv(const ScalarLit& lhs, const ScalarLit& rhs) { ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); if (rhs.is_null()) { auto type = cast< ar::IntegerType >(lhs.var()->type()); auto zero = MachineInt::zero(type->bit_width(), type->sign()); this->_inv.normal().int_assign(lhs.var(), zero); } else if (rhs.is_pointer_var()) { this->_inv.normal() .scalar_pointer_to_int(lhs.var(), rhs.var(), this->_mem_factory.get_absolute_zero()); } else { ikos_unreachable("unreachable"); } } /// \brief Execute a conversion from integer to pointer void exec_int_to_ptr_conv(const ScalarLit& lhs, const ScalarLit& rhs) { if (rhs.is_machine_int()) { MachineInt addr = rhs.machine_int(); if (addr.is_zero()) { this->_inv.normal().pointer_assign_null(lhs.var()); } else { addr = addr.cast(this->_data_layout.pointers.bit_width, Unsigned); this->_inv.normal() .pointer_assign(lhs.var(), this->_mem_factory.get_absolute_zero(), Nullity::non_null()); this->_inv.normal().pointer_assign(lhs.var(), lhs.var(), addr); } } else if (rhs.is_machine_int_var()) { this->_inv.normal() .scalar_int_to_pointer(lhs.var(), rhs.var(), this->_mem_factory.get_absolute_zero()); } else { ikos_unreachable("unexpected operand"); } } /// \brief Execute a bitcast /// /// Valid bitcasts are: /// * pointer casts: A* to B* /// * primitive type casts with the same bit-width /// /// A primitive type is either an integer, a floating point or a vector /// of integers or floating points. void exec_bitcast(ar::UnaryOperation* s, const Literal& lhs, const Literal& rhs) { if (rhs.is_var()) { this->_inv.normal().uninit_assert_initialized(rhs.var()); } if (lhs.is_scalar()) { this->exec_bitcast(s, lhs.scalar(), rhs); } else if (lhs.is_aggregate()) { this->exec_bitcast(s, lhs.aggregate(), rhs); } else { ikos_unreachable("unreachable"); } } /// \brief Execute a bitcast with a scalar left hand side void exec_bitcast(ar::UnaryOperation* s, const ScalarLit& lhs, const Literal& rhs) { if (lhs.is_pointer_var()) { // Pointer cast: A* to B* this->assign(lhs, rhs.scalar()); } else if (lhs.is_machine_int_var()) { if (rhs.is_scalar() && rhs.scalar().is_machine_int()) { // Sign cast: (u|s)iN to (u|s)iN auto type = ar::cast< ar::IntegerType >(s->result()->type()); this->_inv.normal() .int_assign(lhs.var(), rhs.scalar().machine_int().cast(type->bit_width(), type->sign())); } else if (rhs.is_scalar() && rhs.scalar().is_machine_int_var()) { // Sign cast: (u|s)iN to (u|s)iN this->_inv.normal().int_apply(IntUnaryOperator::SignCast, lhs.var(), rhs.scalar().var()); } else { this->_inv.normal().int_assign_nondet(lhs.var()); } } else { ikos_unreachable("unexpected left hand side"); } } /// \brief Execute a bitcast with an aggregate left hand side void exec_bitcast(ar::UnaryOperation* /*s*/, const AggregateLit& lhs, const Literal& rhs) { ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); if (rhs.is_scalar()) { Variable* ptr = this->init_aggregate_memory(lhs); this->_inv.normal().mem_forget_reachable(ptr); } else if (rhs.is_aggregate()) { this->assign(lhs, rhs.aggregate()); } else { ikos_unreachable("unreachable"); } } public: /// \brief Execute a BinaryOperation statement void exec(ar::BinaryOperation* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } if (s->result()->type()->is_vector()) { this->exec_vector_bin_operation(s); return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(s->result()); const ScalarLit& left = this->_lit_factory.get_scalar(s->left()); const ScalarLit& right = this->_lit_factory.get_scalar(s->right()); switch (s->op()) { case ar::BinaryOperation::UAdd: case ar::BinaryOperation::SAdd: { this->exec_int_bin_operation(lhs, s->has_no_wrap() ? IntBinaryOperator::AddNoWrap : IntBinaryOperator::Add, left, right); } break; case ar::BinaryOperation::USub: case ar::BinaryOperation::SSub: { this->exec_int_bin_operation(lhs, s->has_no_wrap() ? IntBinaryOperator::SubNoWrap : IntBinaryOperator::Sub, left, right); } break; case ar::BinaryOperation::UMul: case ar::BinaryOperation::SMul: { this->exec_int_bin_operation(lhs, s->has_no_wrap() ? IntBinaryOperator::MulNoWrap : IntBinaryOperator::Mul, left, right); } break; case ar::BinaryOperation::UDiv: case ar::BinaryOperation::SDiv: { this->exec_int_bin_operation(lhs, s->is_exact() ? IntBinaryOperator::DivExact : IntBinaryOperator::Div, left, right); } break; case ar::BinaryOperation::URem: case ar::BinaryOperation::SRem: { this->exec_int_bin_operation(lhs, IntBinaryOperator::Rem, left, right); } break; case ar::BinaryOperation::UShl: case ar::BinaryOperation::SShl: { this->exec_int_bin_operation(lhs, s->has_no_wrap() ? IntBinaryOperator::ShlNoWrap : IntBinaryOperator::Shl, left, right); } break; case ar::BinaryOperation::ULShr: case ar::BinaryOperation::SLShr: { this->exec_int_bin_operation(lhs, s->is_exact() ? IntBinaryOperator::LShrExact : IntBinaryOperator::LShr, left, right); } break; case ar::BinaryOperation::UAShr: case ar::BinaryOperation::SAShr: { this->exec_int_bin_operation(lhs, s->is_exact() ? IntBinaryOperator::AShrExact : IntBinaryOperator::AShr, left, right); } break; case ar::BinaryOperation::UAnd: case ar::BinaryOperation::SAnd: { this->exec_int_bin_operation(lhs, IntBinaryOperator::And, left, right); } break; case ar::BinaryOperation::UOr: case ar::BinaryOperation::SOr: { this->exec_int_bin_operation(lhs, IntBinaryOperator::Or, left, right); } break; case ar::BinaryOperation::UXor: case ar::BinaryOperation::SXor: { this->exec_int_bin_operation(lhs, IntBinaryOperator::Xor, left, right); } break; case ar::BinaryOperation::FAdd: case ar::BinaryOperation::FSub: case ar::BinaryOperation::FMul: case ar::BinaryOperation::FDiv: case ar::BinaryOperation::FRem: { this->exec_float_bin_operation(lhs, left, right); } break; default: { ikos_unreachable("unreachable"); } } } private: /// \brief Execute an integer binary operation void exec_int_bin_operation(const ScalarLit& lhs, IntBinaryOperator op, const ScalarLit& left, const ScalarLit& right) { ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); if (left.is_machine_int()) { if (right.is_machine_int()) { this->_inv.normal().int_assign(lhs.var(), left.machine_int()); this->_inv.normal().int_apply(op, lhs.var(), lhs.var(), right.machine_int()); } else if (right.is_machine_int_var()) { this->_inv.normal().int_apply(op, lhs.var(), left.machine_int(), right.var()); } else { ikos_unreachable("unexpected right operand"); } } else if (left.is_machine_int_var()) { if (right.is_machine_int()) { this->_inv.normal().int_apply(op, lhs.var(), left.var(), right.machine_int()); } else if (right.is_machine_int_var()) { this->_inv.normal().int_apply(op, lhs.var(), left.var(), right.var()); } else { ikos_unreachable("unexpected right operand"); } } else { ikos_unreachable("unexpected left operand"); } } /// \brief Execute a floating point binary operation void exec_float_bin_operation(const ScalarLit& lhs, const ScalarLit& left, const ScalarLit& right) { ikos_assert_msg(lhs.is_floating_point_var(), "left hand side is not a floating point variable"); // TODO(marthaud): add floating point reasoning if (left.is_floating_point_var()) { this->_inv.normal().uninit_assert_initialized(left.var()); } if (right.is_floating_point_var()) { this->_inv.normal().uninit_assert_initialized(right.var()); } this->_inv.normal().float_assign_nondet(lhs.var()); } /// \brief Execute a vector binary operation void exec_vector_bin_operation(ar::BinaryOperation* s) { const AggregateLit& lhs = this->_lit_factory.get_aggregate(s->result()); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); // Ignore the semantic while being sound Variable* ptr = this->init_aggregate_memory(lhs); this->_inv.normal().mem_forget_reachable(ptr); } public: /// \brief Execute a Comparison statement void exec(ar::Comparison* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const ScalarLit& left = this->_lit_factory.get_scalar(s->left()); const ScalarLit& right = this->_lit_factory.get_scalar(s->right()); switch (s->predicate()) { case ar::Comparison::UIEQ: case ar::Comparison::SIEQ: { this->exec_int_comparison(IntPredicate::EQ, left, right); } break; case ar::Comparison::UINE: case ar::Comparison::SINE: { this->exec_int_comparison(IntPredicate::NE, left, right); } break; case ar::Comparison::UIGT: case ar::Comparison::SIGT: { this->exec_int_comparison(IntPredicate::GT, left, right); } break; case ar::Comparison::UIGE: case ar::Comparison::SIGE: { this->exec_int_comparison(IntPredicate::GE, left, right); } break; case ar::Comparison::UILT: case ar::Comparison::SILT: { this->exec_int_comparison(IntPredicate::LT, left, right); } break; case ar::Comparison::UILE: case ar::Comparison::SILE: { this->exec_int_comparison(IntPredicate::LE, left, right); } break; case ar::Comparison::FOEQ: case ar::Comparison::FOGT: case ar::Comparison::FOGE: case ar::Comparison::FOLT: case ar::Comparison::FOLE: case ar::Comparison::FONE: case ar::Comparison::FORD: case ar::Comparison::FUNO: case ar::Comparison::FUEQ: case ar::Comparison::FUGT: case ar::Comparison::FUGE: case ar::Comparison::FULT: case ar::Comparison::FULE: case ar::Comparison::FUNE: { this->exec_float_comparison(left, right); } break; case ar::Comparison::PEQ: { this->exec_ptr_comparison(PointerPredicate::EQ, left, right); } break; case ar::Comparison::PNE: { this->exec_ptr_comparison(PointerPredicate::NE, left, right); } break; case ar::Comparison::PGT: { this->exec_ptr_comparison(PointerPredicate::GT, left, right); } break; case ar::Comparison::PGE: { this->exec_ptr_comparison(PointerPredicate::GE, left, right); } break; case ar::Comparison::PLT: { this->exec_ptr_comparison(PointerPredicate::LT, left, right); } break; case ar::Comparison::PLE: { this->exec_ptr_comparison(PointerPredicate::LE, left, right); } break; default: { ikos_unreachable("unreachable"); } } } private: /// \brief Execute an integer comparison void exec_int_comparison(IntPredicate pred, const ScalarLit& left, const ScalarLit& right) { if (left.is_machine_int()) { if (right.is_machine_int()) { if (!compare(pred, left.machine_int(), right.machine_int())) { this->_inv.set_normal_flow_to_bottom(); } } else if (right.is_machine_int_var()) { this->_inv.normal().int_add(pred, left.machine_int(), right.var()); } else { ikos_unreachable("unexpected right operand"); } } else if (left.is_machine_int_var()) { if (right.is_machine_int()) { this->_inv.normal().int_add(pred, left.var(), right.machine_int()); } else if (right.is_machine_int_var()) { this->_inv.normal().int_add(pred, left.var(), right.var()); } else { ikos_unreachable("unexpected right operand"); } } else { ikos_unreachable("unexpected left operand"); } } /// \brief Execute a floating point comparison void exec_float_comparison(const ScalarLit& left, const ScalarLit& right) { // TODO(marthaud): add floating point reasoning if (left.is_floating_point_var()) { this->_inv.normal().uninit_assert_initialized(left.var()); } if (right.is_floating_point_var()) { this->_inv.normal().uninit_assert_initialized(right.var()); } } /// \brief Execute a pointer comparison void exec_ptr_comparison(PointerPredicate pred, const ScalarLit& left, const ScalarLit& right) { if (left.is_null()) { if (right.is_null()) { // Compare `null pred null` if (pred == PointerPredicate::NE || pred == PointerPredicate::GT || pred == PointerPredicate::LT) { this->_inv.set_normal_flow_to_bottom(); } } else if (right.is_pointer_var()) { // Compare `null pred p` this->refine_addresses(right.var()); if (pred == PointerPredicate::EQ) { this->_inv.normal().nullity_assert_null(right.var()); } else if (pred == PointerPredicate::NE || pred == PointerPredicate::GT || pred == PointerPredicate::LT) { this->_inv.normal().nullity_assert_non_null(right.var()); } else { this->_inv.normal().uninit_assert_initialized(right.var()); } } else { ikos_unreachable("unexpected right operand"); } } else if (left.is_pointer_var()) { if (right.is_null()) { // Compare `p pred null` this->refine_addresses(left.var()); if (pred == PointerPredicate::EQ) { this->_inv.normal().nullity_assert_null(left.var()); } else if (pred == PointerPredicate::NE || pred == PointerPredicate::GT || pred == PointerPredicate::LT) { this->_inv.normal().nullity_assert_non_null(left.var()); } else { this->_inv.normal().uninit_assert_initialized(left.var()); } } else if (right.is_pointer_var()) { // Compare `p pred q` // Reduction with the external pointer analysis this->refine_addresses_offset(left.var()); this->refine_addresses_offset(right.var()); this->_inv.normal().pointer_add(pred, left.var(), right.var()); } else { ikos_unreachable("unexpected right operand"); } } else { ikos_unreachable("unexpected left operand"); } } public: /// \brief Execute an Unreachable statement void exec(ar::Unreachable*) override { // Unreachable propagates exceptions this->_inv.set_normal_flow_to_bottom(); } /// \brief Execute an Allocate statement void exec(ar::Allocate* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(s->result()); const ScalarLit& array_size = this->_lit_factory.get_scalar(s->array_size()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); // Allocate the memory MemoryLocation* addr = this->_mem_factory.get_local(s->result()); this->allocate_memory(lhs.var(), addr, Nullity::non_null(), Lifetime::allocated(), MemoryInitialValue::Uninitialized); if (this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { // Set the allocation size variable Variable* alloc_size_var = this->_var_factory.get_alloc_size(addr); auto element_size = MachineInt(this->_data_layout.alloc_size_in_bytes( s->allocated_type()), this->_data_layout.pointers.bit_width, Unsigned); if (array_size.is_machine_int()) { bool overflow; MachineInt alloc_size_int = mul(array_size.machine_int(), element_size, overflow); if (overflow) { this->_inv.set_normal_flow_to_bottom(); // undefined behavior } else { this->_inv.normal().int_assign(alloc_size_var, alloc_size_int); // When the size of the allocation is known (like it is here) // we mark the storage as uninitialized by assigning it // the undefined value. this->_inv.normal().mem_write(lhs.var(), ScalarLit::undefined(), alloc_size_int); } } else if (array_size.is_machine_int_var()) { this->_inv.normal().int_apply(IntBinaryOperator::MulNoWrap, alloc_size_var, array_size.var(), element_size); } else { ikos_unreachable("unexpected array size parameter"); } } } /// \brief Execute a PointerShift statement void exec(ar::PointerShift* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const ScalarLit& lhs = this->_lit_factory.get_scalar(s->result()); const ScalarLit& base = this->_lit_factory.get_scalar(s->pointer()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); ikos_assert_msg(base.is_null() || base.is_pointer_var(), "unexpected base operand"); // Build a linear expression of the operands uint64_t bit_width = this->_data_layout.pointers.bit_width; auto zero = MachineInt::zero(bit_width, Unsigned); auto offset_expr = IntLinearExpression(zero); for (auto it = s->term_begin(), et = s->term_end(); it != et; ++it) { auto term = *it; const ScalarLit& offset = this->_lit_factory.get_scalar(term.second); if (offset.is_machine_int()) { offset_expr.add( mul(term.first, offset.machine_int().cast(bit_width, Unsigned))); } else if (offset.is_machine_int_var()) { offset_expr.add(term.first, offset.var()); } else { ikos_unreachable("unexpected offset operand"); } } if (base.is_null()) { this->_inv.normal().pointer_assign(lhs.var(), this->_mem_factory.get_absolute_zero(), Nullity::null()); this->_inv.normal().pointer_assign(lhs.var(), lhs.var(), offset_expr); } else { this->_inv.normal().pointer_assign(lhs.var(), base.var(), offset_expr); } this->normalize_absolute_zero_nullity(lhs.var()); } /// \brief Execute a Load statement /// /// Reading uninitialized memory is an error. void exec(ar::Load* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const ScalarLit& ptr = this->_lit_factory.get_scalar(s->operand()); if (!this->prepare_mem_access(ptr)) { return; } const Literal& result = this->_lit_factory.get(s->result()); auto size = MachineInt(this->_data_layout.store_size_in_bytes(s->result()->type()), this->_data_layout.pointers.bit_width, Unsigned); if (result.is_scalar()) { const ScalarLit& lhs = result.scalar(); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); if (!s->is_volatile()) { // Perform memory read in the value domain this->_inv.normal().mem_read(lhs, ptr.var(), size); } else { this->_inv.normal().scalar_assign_nondet(lhs.var()); } // Reduction between value and pointer analysis if (lhs.is_pointer_var()) { this->refine_addresses_offset(lhs.var()); } } else if (result.is_aggregate()) { const AggregateLit& lhs = result.aggregate(); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); Variable* lhs_ptr = this->init_aggregate_memory(lhs); if (!s->is_volatile()) { // Perform memory read in the value domain this->_inv.normal().mem_copy(lhs_ptr, ptr.var(), ScalarLit::machine_int(size)); } else { this->_inv.normal().mem_forget_reachable(lhs_ptr); } } else { ikos_unreachable("unexpected left hand side"); } } /// \brief Execute a Store statement /// /// Writing an uninitialized variable is an error. void exec(ar::Store* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const ScalarLit& ptr = this->_lit_factory.get_scalar(s->pointer()); if (!this->prepare_mem_access(ptr)) { return; } if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore memory write, analysis could be unsound. // See CheckKind::IgnoredStore return; } const Literal& val = this->_lit_factory.get(s->value()); auto size = MachineInt(this->_data_layout.store_size_in_bytes(s->value()->type()), this->_data_layout.pointers.bit_width, Unsigned); if (val.is_scalar()) { const ScalarLit& rhs = val.scalar(); if (rhs.is_pointer_var()) { this->refine_addresses_offset(rhs.var()); } // Perform memory write in the value domain this->_inv.normal().mem_write(ptr.var(), rhs, size); } else if (val.is_aggregate()) { this->mem_write_aggregate(ptr.var(), val.aggregate()); } else { ikos_unreachable("unexpected right hand side"); } } /// \brief Execute an ExtractElement statement void exec(ar::ExtractElement* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const Literal& lhs = this->_lit_factory.get(s->result()); const AggregateLit& rhs = this->_lit_factory.get_aggregate(s->aggregate()); const ScalarLit& offset = this->_lit_factory.get_scalar(s->offset()); ikos_assert_msg(rhs.is_var(), "right hand side is not a variable"); Variable* rhs_ptr = this->aggregate_pointer(rhs); Variable* read_ptr = this->_var_factory.get_named_shadow(this->void_ptr_type(), "shadow.extract_element.ptr"); if (offset.is_machine_int_var()) { this->_inv.normal().pointer_assign(read_ptr, rhs_ptr, offset.var()); } else if (offset.is_machine_int()) { this->_inv.normal().pointer_assign(read_ptr, rhs_ptr, offset.machine_int()); } else { ikos_unreachable("unexpected offset operand"); } auto size = MachineInt(this->_data_layout.store_size_in_bytes(s->result()->type()), this->_data_layout.pointers.bit_width, Unsigned); if (lhs.is_scalar()) { ikos_assert_msg(lhs.scalar().is_var(), "left hand side is not a variable"); this->_inv.normal().mem_read(lhs.scalar(), read_ptr, size); } else if (lhs.is_aggregate()) { ikos_assert_msg(lhs.aggregate().is_var(), "left hand side is not a variable"); Variable* lhs_ptr = this->init_aggregate_memory(lhs.aggregate()); this->_inv.normal().mem_copy(lhs_ptr, read_ptr, ScalarLit::machine_int(size)); } else { ikos_unreachable("unexpected left hand side"); } // Clean-up this->_inv.normal().pointer_forget(read_ptr); } /// \brief Execute an InsertElement statement /// /// Unlike most statements, this accepts undefined aggregate operands void exec(ar::InsertElement* s) override { if (s->offset()->is_undefined_constant() || s->element()->is_undefined_constant()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const AggregateLit& lhs = this->_lit_factory.get_aggregate(s->result()); const AggregateLit& rhs = this->_lit_factory.get_aggregate(s->aggregate()); const ScalarLit& offset = this->_lit_factory.get_scalar(s->offset()); const Literal& element = this->_lit_factory.get(s->element()); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); Variable* lhs_ptr = this->init_aggregate_memory(lhs); // First, copy the aggregate value this->mem_write_aggregate(lhs_ptr, rhs); // Then, insert the element Variable* write_ptr = this->_var_factory.get_named_shadow(this->void_ptr_type(), "shadow.insert_element.ptr"); if (offset.is_machine_int_var()) { this->_inv.normal().pointer_assign(write_ptr, lhs_ptr, offset.var()); } else if (offset.is_machine_int()) { this->_inv.normal().pointer_assign(write_ptr, lhs_ptr, offset.machine_int()); } else { ikos_unreachable("unexpected offset operand"); } auto size = MachineInt(this->_data_layout.store_size_in_bytes(s->element()->type()), this->_data_layout.pointers.bit_width, Unsigned); if (element.is_scalar()) { this->_inv.normal().mem_write(write_ptr, element.scalar(), size); } else if (element.is_aggregate()) { this->mem_write_aggregate(write_ptr, element.aggregate()); } else { ikos_unreachable("unexpected element operand"); } // Clean-up this->_inv.normal().pointer_forget(write_ptr); } /// \brief Execute a ShuffleVector statement void exec(ar::ShuffleVector* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->init_global_operands(s); const AggregateLit& lhs = this->_lit_factory.get_aggregate(s->result()); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); // Ignore the semantic while being sound Variable* ptr = this->init_aggregate_memory(lhs); this->_inv.normal().mem_forget_reachable(ptr); } /// \brief Execute a LandingPad statement void exec(ar::LandingPad*) override {} /// \brief Execute a Resume statement void exec(ar::Resume* s) override { if (s->has_undefined_constant_operand()) { this->_inv.set_normal_flow_to_bottom(); return; } this->_inv.resume_exception(); } /// @} /// \name Execute call statements /// @{ /// \brief Execute a call to the given extern function void exec_extern_call(ar::CallBase* call, ar::Function* fun) override { ikos_assert(fun->is_declaration()); ikos_assert(ar::TypeVerifier::is_valid_call(call, fun->type())); if (fun->is_intrinsic()) { this->exec_intrinsic_call(call, fun->intrinsic_id()); } else { this->exec_unknown_extern_call(call); } } /// \brief Execute a call to the given intrinsic function void exec_intrinsic_call(ar::CallBase* call, ar::Intrinsic::ID id) override { this->_inv.normal().normalize(); if (this->_inv.is_normal_flow_bottom()) { return; } if (id == ar::Intrinsic::IkosPartitioningVar) { // Unlike most functions, it propagates uninitialized variables this->exec_ikos_partitioning_var(call); return; } // Check for uninitialized variables for (auto it = call->op_begin(), et = call->op_end(); it != et; ++it) { ar::Value* op = *it; if (isa< ar::UndefinedConstant >(op)) { this->_inv.set_normal_flow_to_bottom(); return; } else if (auto iv = dyn_cast< ar::InternalVariable >(op)) { Variable* var = this->_var_factory.get_internal(iv); this->_inv.normal().uninit_assert_initialized(var); } } this->_inv.normal().normalize(); if (this->_inv.is_normal_flow_bottom()) { return; } switch (id) { case ar::Intrinsic::MemoryCopy: case ar::Intrinsic::MemoryMove: { this->exec_memcpy_or_memmove(call); } break; case ar::Intrinsic::MemorySet: { this->exec_memset(call); } break; case ar::Intrinsic::VarArgStart: case ar::Intrinsic::VarArgEnd: case ar::Intrinsic::VarArgGet: case ar::Intrinsic::VarArgCopy: { this->exec_unknown_call(call, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::StackSave: case ar::Intrinsic::StackRestore: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LifetimeStart: case ar::Intrinsic::LifetimeEnd: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::EhTypeidFor: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::Trap: { this->exec_abort(call); } break; // case ar::Intrinsic::IkosAssert: case ar::Intrinsic::IkosAssume: case ar::Intrinsic::IkosNonDet: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::IkosCounterInit: { this->exec_ikos_counter_init(call); } break; case ar::Intrinsic::IkosCounterIncr: { this->exec_ikos_counter_incr(call); } break; case ar::Intrinsic::IkosCheckMemAccess: case ar::Intrinsic::IkosCheckStringAccess: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::IkosAssumeMemSize: { this->exec_ikos_assume_mem_size(call); } break; case ar::Intrinsic::IkosForgetMemory: { this->exec_ikos_forget_memory(call); } break; case ar::Intrinsic::IkosAbstractMemory: { this->exec_ikos_abstract_memory(call); } break; case ar::Intrinsic::IkosWatchMemory: { this->exec_ikos_watch_memory(call); } break; case ar::Intrinsic::IkosPartitioningVar: { this->exec_ikos_partitioning_var(call); } break; case ar::Intrinsic::IkosPartitioningJoin: { this->exec_ikos_partitioning_join(call); } break; case ar::Intrinsic::IkosPartitioningDisable: { this->exec_ikos_partitioning_disable(call); } break; case ar::Intrinsic::IkosPrintInvariant: case ar::Intrinsic::IkosPrintValues: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; // case ar::Intrinsic::LibcMalloc: { this->exec_malloc(call); } break; case ar::Intrinsic::LibcCalloc: { this->exec_calloc(call); } break; case ar::Intrinsic::LibcValloc: { this->exec_valloc(call); } break; case ar::Intrinsic::LibcAlignedAlloc: { this->exec_aligned_alloc(call); } break; case ar::Intrinsic::LibcRealloc: { this->exec_realloc(call); } break; case ar::Intrinsic::LibcFree: { this->exec_free(call); } break; case ar::Intrinsic::LibcAbs: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcRand: case ar::Intrinsic::LibcSrand: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcExit: { this->exec_exit(call); } break; case ar::Intrinsic::LibcAbort: { this->exec_abort(call); } break; // case ar::Intrinsic::LibcErrnoLocation: { this->exec_errno_location(call); } break; // case ar::Intrinsic::LibcOpen: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; // case ar::Intrinsic::LibcClose: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcRead: { this->exec_read(call); } break; case ar::Intrinsic::LibcWrite: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; // case ar::Intrinsic::LibcGets: { this->exec_gets(call); } break; case ar::Intrinsic::LibcFgets: { this->exec_fgets(call); } break; case ar::Intrinsic::LibcGetc: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFgetc: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcGetchar: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcPuts: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFputs: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcPutc: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFputc: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcPrintf: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFprintf: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcSprintf: { this->exec_sprintf(call); } break; case ar::Intrinsic::LibcSnprintf: { this->exec_snprintf(call); } break; case ar::Intrinsic::LibcScanf: { this->exec_unknown_call(call, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFscanf: { this->exec_unknown_call(call, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcSscanf: { this->exec_unknown_call(call, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFopen: { this->exec_fopen(call); } break; case ar::Intrinsic::LibcFclose: { this->exec_fclose(call); } break; case ar::Intrinsic::LibcFflush: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; // case ar::Intrinsic::LibcStrlen: { this->exec_strlen(call); } break; case ar::Intrinsic::LibcStrnlen: { this->exec_strnlen(call); } break; case ar::Intrinsic::LibcStrcpy: { this->exec_strcpy(call); } break; case ar::Intrinsic::LibcStrncpy: { this->exec_strncpy(call); } break; case ar::Intrinsic::LibcStrcat: { this->exec_strcat(call); } break; case ar::Intrinsic::LibcStrncat: { this->exec_strncat(call); } break; case ar::Intrinsic::LibcStrcmp: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcStrncmp: { this->exec_unknown_call(call, /* may_write_params = */ false, /* ignore_unknown_write = */ false, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcStrstr: { this->exec_strstr(call); } break; case ar::Intrinsic::LibcStrchr: { this->exec_strchr(call); } break; case ar::Intrinsic::LibcStrdup: { this->exec_strdup(call); } break; case ar::Intrinsic::LibcStrndup: { this->exec_strndup(call); } break; case ar::Intrinsic::LibcStrcpyCheck: { this->exec_strcpy(call); } break; case ar::Intrinsic::LibcMemoryCopyCheck: { this->exec_memcpy_or_memmove(call); } break; case ar::Intrinsic::LibcMemoryMoveCheck: { this->exec_memcpy_or_memmove(call); } break; case ar::Intrinsic::LibcMemorySetCheck: { this->exec_memset(call); } break; case ar::Intrinsic::LibcStrcatCheck: { this->exec_strcat(call); } break; case ar::Intrinsic::LibcppNew: case ar::Intrinsic::LibcppNewArray: { this->exec_new(call); } break; case ar::Intrinsic::LibcppDelete: { this->exec_free(call); } break; case ar::Intrinsic::LibcppDeleteArray: { // TODO(marthaud): delete[] also calls the destructor on each element this->exec_free(call); } break; case ar::Intrinsic::LibcppAllocateException: { this->exec_allocate_exception(call); } break; case ar::Intrinsic::LibcppFreeException: { this->exec_free(call); } break; case ar::Intrinsic::LibcppThrow: { this->exec_throw(call); } break; case ar::Intrinsic::LibcppBeginCatch: { this->exec_begin_catch(call); } break; case ar::Intrinsic::LibcppEndCatch: { this->exec_end_catch(call); } break; default: { ikos_unreachable("unreachable"); } break; } } /// \brief Execute a call to an unknown extern function void exec_unknown_extern_call(ar::CallBase* call) override { this->exec_unknown_call(call, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ true); } /// \brief Execute a call to an unknown internal function void exec_unknown_intern_call(ar::CallBase* call) override { this->exec_unknown_call(call, /* may_write_params = */ true, /* ignore_unknown_write = */ false, /* may_write_globals = */ true, /* may_throw_exc = */ true); } /// \brief Execute a call to an unknown function /// /// \param call /// The call statement /// \param may_write_params /// True if the function call might write on a pointer parameter /// \param ignore_unknown_write /// True to ignore writes on unknown pointer parameters (unsound) /// \param may_write_globals /// True if the function call might update a global variable /// \param may_throw_exc /// True if the function call might throw an exception void exec_unknown_call(ar::CallBase* call, bool may_write_params, bool ignore_unknown_write, bool may_write_globals, bool may_throw_exc) override { this->_inv.normal().normalize(); if (this->_inv.is_normal_flow_bottom()) { return; } // Check for uninitialized variables for (auto it = call->op_begin(), et = call->op_end(); it != et; ++it) { ar::Value* op = *it; if (isa< ar::UndefinedConstant >(op)) { this->_inv.set_normal_flow_to_bottom(); return; } else if (auto iv = dyn_cast< ar::InternalVariable >(op)) { Variable* var = this->_var_factory.get_internal(iv); this->_inv.normal().uninit_assert_initialized(var); } } this->_inv.normal().normalize(); if (this->_inv.is_normal_flow_bottom()) { return; } if (may_write_globals) { // Forget all memory contents this->_inv.normal().mem_forget_all(); } else if (may_write_params) { // Forget all memory contents pointed by pointer parameters for (auto it = call->arg_begin(), et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; if (!isa< ar::InternalVariable >(arg) || !isa< ar::PointerType >(arg->type())) { continue; } auto iv = cast< ar::InternalVariable >(arg); Variable* ptr = this->_var_factory.get_internal(iv); this->init_global_operand(arg); this->refine_addresses(ptr); if (this->_inv.normal().nullity_is_null(ptr)) { continue; // Safe } else if (ignore_unknown_write && this->_inv.normal().pointer_to_points_to(ptr).is_top()) { // Ignore side effect on the memory // See CheckKind::IgnoredCallSideEffectOnPointerParameter continue; } else { this->_inv.normal().mem_forget_reachable(ptr); } } } if (may_throw_exc) { // The call can throw exceptions this->throw_unknown_exceptions(); } // ASSUMPTION: // The claim about the correctness of the program under analysis can be // made only if all calls to unavailable code are assumed to be correct // and without side-effects. We will assume that the lhs of an external // call site is always initialized. However, in case of a pointer, we do // not assume that a non-null pointer is returned. if (call->has_result()) { // Forget the result const Literal& ret = this->_lit_factory.get(call->result()); if (ret.is_scalar()) { ikos_assert_msg(ret.scalar().is_var(), "left hand side is not a variable"); this->_inv.normal().scalar_assign_nondet(ret.scalar().var()); } else if (ret.is_aggregate()) { ikos_assert_msg(ret.aggregate().is_var(), "left hand side is not a variable"); Variable* ret_ptr = this->aggregate_pointer(ret.aggregate()); this->_inv.normal().mem_forget_reachable(ret_ptr); } else { ikos_unreachable("unexpected left hand side"); } } } private: /// @} /// \name Execution of intrinsic functions /// @{ /// \brief Execute a call to memcpy(dest, src, len) or memmove(dest, src, len) void exec_memcpy_or_memmove(ar::CallBase* call) { this->init_global_operands(call); // Both src and dest must be already allocated in memory so offsets and // sizes for both src and dest are already part of the invariants const ScalarLit& dest = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& src = this->_lit_factory.get_scalar(call->argument(1)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(2)); if (!this->prepare_mem_access(src)) { return; } if (!this->prepare_mem_access(dest)) { return; } if (this->_inv.normal().pointer_to_points_to(dest.var()).is_top()) { // Ignore memory copy/move, analysis could be unsound. // See CheckKind::IgnoredMemoryCopy, CheckKind::IgnoredMemoryMove } else if (cast< ar::IntegerConstant >(call->argument(5))->value() == 0) { // Non-volatile this->_inv.normal().mem_copy(dest.var(), src.var(), size); } else { // Volatile if (size.is_machine_int()) { this->_inv.normal().mem_forget_reachable(dest.var(), size.machine_int()); } else if (size.is_machine_int_var()) { IntInterval size_intv = this->_inv.normal().int_to_interval(size.var()); this->_inv.normal().mem_forget_reachable(dest.var(), size_intv.ub()); } else { ikos_unreachable("unreachable"); } } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->assign(lhs, dest); } } /// \brief Execute a call to memset(dest, byte, len) void exec_memset(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& dest = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& value = this->_lit_factory.get_scalar(call->argument(1)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(2)); ikos_assert_msg(value.is_machine_int_var() || value.is_machine_int(), "unexpected value operand"); ikos_assert_msg(size.is_machine_int_var() || size.is_machine_int(), "unexpected size operand"); if (!this->prepare_mem_access(dest)) { return; } if (this->_inv.normal().pointer_to_points_to(dest.var()).is_top()) { // Ignore memory set, analysis could be unsound. // See CheckKind::IgnoredMemorySet } else { this->_inv.normal().mem_set(dest.var(), value, size); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->assign(lhs, dest); } } /// \brief Execute a call to ikos.counter.init void exec_ikos_counter_init(ar::CallBase* call) { ikos_assert(call->has_result()); ikos_assert(call->num_arguments() == 1); const ScalarLit& ret = this->_lit_factory.get_scalar(call->result()); const ScalarLit& init = this->_lit_factory.get_scalar(call->argument(0)); ikos_assert_msg(ret.is_machine_int_var(), "left hand side is not an integer variable"); ikos_assert_msg(init.is_machine_int(), "operand is not a machine integer"); this->_inv.normal().counter_init(ret.var(), init.machine_int()); } /// \brief Execute a call to ikos.counter.incr void exec_ikos_counter_incr(ar::CallBase* call) { ikos_assert(call->has_result()); ikos_assert(call->num_arguments() == 2); ikos_assert(call->result() == call->argument(0)); const ScalarLit& ret = this->_lit_factory.get_scalar(call->result()); const ScalarLit& incr = this->_lit_factory.get_scalar(call->argument(1)); ikos_assert_msg(ret.is_machine_int_var(), "left hand side is not an integer variable"); ikos_assert_msg(incr.is_machine_int(), "operand is not a machine integer"); this->_inv.normal().counter_incr(ret.var(), incr.machine_int()); } /// \brief Execute a call to ikos.assume_mem_size void exec_ikos_assume_mem_size(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(ptr)) { return; } if (!this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { return; } PointsToSet addrs = this->_inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_bottom()) { return; } else if (addrs.is_top()) { // Ignore (this is sound) return; } for (auto addr : addrs) { Variable* alloc_size_var = this->_var_factory.get_alloc_size(addr); if (size.is_machine_int()) { this->_inv.normal().int_assign(alloc_size_var, size.machine_int()); } else if (size.is_machine_int_var()) { this->_inv.normal().int_assign(alloc_size_var, size.var()); } else { ikos_unreachable("unreachable"); } } } /// \brief Execute a call to ikos.forget_memory void exec_ikos_forget_memory(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(ptr)) { return; } if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore ikos.forget_memory, analysis could be unsound. // See CheckKind::UnknownMemoryAccess } else if (size.is_machine_int()) { this->_inv.normal().mem_forget_reachable(ptr.var(), size.machine_int()); } else if (size.is_machine_int_var()) { IntInterval size_intv = this->_inv.normal().int_to_interval(size.var()); this->_inv.normal().mem_forget_reachable(ptr.var(), size_intv.ub()); } else { ikos_unreachable("unreachable"); } } /// \brief Execute a call to ikos.abstract_memory void exec_ikos_abstract_memory(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(ptr)) { return; } if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore ikos.abstract_memory, analysis could be unsound. // See CheckKind::UnknownMemoryAccess } else if (size.is_machine_int()) { this->_inv.normal().mem_abstract_reachable(ptr.var(), size.machine_int()); } else if (size.is_machine_int_var()) { IntInterval size_intv = this->_inv.normal().int_to_interval(size.var()); this->_inv.normal().mem_abstract_reachable(ptr.var(), size_intv.ub()); } else { ikos_unreachable("unreachable"); } } /// \brief Execute a call to ikos.watch_memory void exec_ikos_watch_memory(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(ptr)) { return; } // Save the watched pointer Variable* watch_mem_ptr = this->_var_factory.get_named_shadow(this->void_ptr_type(), "shadow.watch_mem.ptr"); this->_inv.normal().pointer_assign(watch_mem_ptr, ptr.var()); // Save the watched size Variable* watch_mem_size = this->_var_factory.get_named_shadow(ar::IntegerType::size_type( this->_ctx.bundle), "shadow.watch_mem.size"); if (size.is_machine_int()) { this->_inv.normal().int_assign(watch_mem_size, size.machine_int()); } else if (size.is_machine_int_var()) { this->_inv.normal().int_assign(watch_mem_size, size.var()); } else { ikos_unreachable("unexpected size parameter"); } } /// \brief Execute a call to ikos.partitioning.var.si32 void exec_ikos_partitioning_var(ar::CallBase* call) { const ScalarLit& arg = this->_lit_factory.get_scalar(call->argument(0)); if (arg.is_var()) { this->_inv.normal().partitioning_set_variable(arg.var()); } } /// \brief Execute a call to ikos.partitioning.join void exec_ikos_partitioning_join(ar::CallBase*) { this->_inv.normal().partitioning_join(); } /// \brief Execute a call to ikos.partitioning.disable void exec_ikos_partitioning_disable(ar::CallBase*) { this->_inv.normal().partitioning_disable(); } /// \brief Execute a dynamic allocation void exec_dynamic_alloc(ar::CallBase* call, ar::Value* size, bool may_return_null, bool may_throw_exc, MemoryInitialValue init_val) { if (may_throw_exc) { this->throw_unknown_exceptions(); } if (!call->has_result()) { return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); const ScalarLit& size_l = this->_lit_factory.get_scalar(size); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); auto nullity = may_return_null ? Nullity::top() : Nullity::non_null(); MemoryLocation* addr = this->_mem_factory.get_dyn_alloc(call, this->_call_context); if (size_l.is_machine_int_var()) { this->allocate_memory(lhs.var(), addr, nullity, Lifetime::allocated(), init_val, size_l.var()); } else if (size_l.is_machine_int()) { this->allocate_memory(lhs.var(), addr, nullity, Lifetime::allocated(), init_val, size_l.machine_int()); } else { ikos_unreachable("unexpected size operand"); } } /// \brief Execute a call to libc malloc /// /// #include /// void* malloc(size_t size); /// /// The malloc() function returns a pointer to a newly allocated block size /// bytes long, or a null pointer if the block could not be allocated. void exec_malloc(ar::CallBase* call) { this->exec_dynamic_alloc(call, call->argument(0), /* may_return_null = */ true, /* may_throw_exc = */ false, MemoryInitialValue::Uninitialized); } /// \brief Execute a call to libc calloc /// /// #include /// void* calloc(size_t count, size_t size); /// /// The calloc() function contiguously allocates enough space for count /// objects that are size bytes of memory each and returns a pointer to the /// allocated memory. The allocated memory is filled with bytes of value zero. void exec_calloc(ar::CallBase* call) { if (!call->has_result()) { return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); const ScalarLit& count = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); // Allocate the memory MemoryLocation* addr = this->_mem_factory.get_dyn_alloc(call, this->_call_context); this->allocate_memory(lhs.var(), addr, Nullity::top(), Lifetime::allocated(), MemoryInitialValue::Zero); if (!this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { return; } // Set the allocation size variable Variable* alloc_size_var = this->_var_factory.get_alloc_size(addr); if (count.is_machine_int()) { if (size.is_machine_int()) { bool overflow; MachineInt alloc_size_int = mul(count.machine_int(), size.machine_int(), overflow); if (overflow) { this->_inv.set_normal_flow_to_bottom(); // Undefined behavior } else { this->_inv.normal().int_assign(alloc_size_var, alloc_size_int); } } else if (size.is_machine_int_var()) { this->_inv.normal().int_apply(IntBinaryOperator::MulNoWrap, alloc_size_var, count.machine_int(), size.var()); } else { ikos_unreachable("unexpected size parameter"); } } else if (count.is_machine_int_var()) { if (size.is_machine_int()) { this->_inv.normal().int_apply(IntBinaryOperator::MulNoWrap, alloc_size_var, count.var(), size.machine_int()); } else if (size.is_machine_int_var()) { this->_inv.normal().int_apply(IntBinaryOperator::MulNoWrap, alloc_size_var, count.var(), size.var()); } else { ikos_unreachable("unexpected size parameter"); } } else { ikos_unreachable("unexpected count parameter"); } } /// \brief Execute a call to libc valloc /// /// #include /// void* valloc(size_t size); /// /// The valloc() function allocates size bytes of memory and returns a pointer /// to the allocated memory. The allocated memory is aligned on a page /// boundary. void exec_valloc(ar::CallBase* call) { this->exec_dynamic_alloc(call, call->argument(0), /* may_return_null = */ true, /* may_throw_exc = */ false, MemoryInitialValue::Uninitialized); } /// \brief Execute a call to libc aligned_alloc /// /// #include /// void* aligned_alloc(size_t alignment, size_t size); /// /// The function posix_memalign() allocates size bytes and places the address /// of the allocated memory in *memptr. The address of the allocated memory /// will be a multiple of alignment, which must be a power of two and a /// multiple of sizeof(void *). If size is 0, then posix_memalign() returns /// either NULL, or a unique pointer value that can later be successfully /// passed to free(3). /// /// The function aligned_alloc() is the same as memalign(), except for the /// added restriction that size should be a multiple of alignment. void exec_aligned_alloc(ar::CallBase* call) { this->exec_dynamic_alloc(call, call->argument(1), /* may_return_null = */ true, /* may_throw_exc = */ false, MemoryInitialValue::Uninitialized); } /// \brief Execute a call to libc realloc /// /// #include /// void* realloc(void* ptr, size_t size); /// /// The realloc() function tries to change the size of the allocation pointed /// to by ptr to size, and returns ptr. If there is not enough room to /// enlarge the memory allocation pointed to by ptr, realloc() creates a new /// allocation, copies as much of the old data pointed to by ptr as will fit /// to the new allocation, frees the old allocation, and returns a pointer to /// the allocated memory. If ptr is NULL, realloc() is identical to a call to /// malloc() for size bytes. If size is zero and ptr is not NULL, a new, /// minimum sized object is allocated and the original object is freed. When /// extending a region allocated with calloc(3), realloc(3) does not guarantee /// that the additional memory is also zero-filled. void exec_realloc(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); // Allocate the memory if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); MemoryLocation* addr = this->_mem_factory.get_dyn_alloc(call, this->_call_context); if (size.is_machine_int_var()) { this->allocate_memory(lhs.var(), addr, Nullity::top(), Lifetime::allocated(), MemoryInitialValue::Uninitialized, size.var()); } else if (size.is_machine_int()) { this->allocate_memory(lhs.var(), addr, Nullity::top(), Lifetime::allocated(), MemoryInitialValue::Uninitialized, size.machine_int()); } else { ikos_unreachable("unexpected size operand"); } } // Copy data if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); if (ptr.is_pointer_var() && !this->_inv.normal().nullity_is_null(ptr.var())) { // This should be the size of `ptr` instead of `size` this->_inv.normal().mem_copy(lhs.var(), ptr.var(), size); } } this->_inv.normal().normalize(); if (this->_inv.is_normal_flow_bottom()) { // If the mem_copy generated an error return; } // Free the pointer this->exec_free(call); } /// \brief Execute a call to libc free, libc++ delete or delete[], etc. /// /// #include /// void free(void* ptr); /// /// The free() function deallocates the memory allocation pointed to by ptr. /// If ptr is a NULL pointer, no operation is performed. void exec_free(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); if (ptr.is_null()) { // This is safe, according to C standards return; } ikos_assert_msg(ptr.is_pointer_var(), "unexpected parameter"); if (this->_inv.normal().nullity_is_null(ptr.var())) { // This is safe, according to C standards return; } // Reduction between value and pointer analysis this->refine_addresses(ptr.var()); PointsToSet addrs = this->_inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_bottom()) { return; } else if (addrs.is_top()) { // Ignored memory deallocation, analysis could be unsound. // See CheckKind::IgnoredFree return; } // Forget memory contents this->_inv.normal().mem_forget_reachable(ptr.var()); // Forget the allocation size and set the new lifetime for (auto addr : addrs) { if (!isa< DynAllocMemoryLocation >(addr)) { if (addrs.size() == 1) { // This is an error this->_inv.set_normal_flow_to_bottom(); return; } else { continue; } } if (addrs.size() == 1) { this->_inv.normal().lifetime_assign_deallocated(addr); } else { this->_inv.normal().lifetime_forget(addr); } if (this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { Variable* alloc_size_var = this->_var_factory.get_alloc_size(addr); this->_inv.normal().int_forget(alloc_size_var); } } } /// \brief Execute a call to libc exit /// /// #include /// void exit(int status); /// /// The exit() functions terminate a process. /// /// It also performs the following functions in the order listed: /// 1. Call the functions registered with the atexit(3) function, in the /// reverse order of their registration. /// 2. Flush all open output streams. /// 3. Close all open streams. /// 4. Unlink all files created with the tmpfile(3) function. void exec_exit(ar::CallBase* /*call*/) { // TODO(marthaud): analyze functions registered by atexit() this->_inv.set_normal_flow_to_bottom(); } /// \brief Execute a call to libc abort /// /// #include /// void abort(void); /// /// The abort() function causes abnormal program termination to occur, unless /// the signal SIGABRT is being caught and the signal handler does not return. void exec_abort(ar::CallBase* /*call*/) { this->_inv.set_normal_flow_to_bottom(); } /// \brief Execute a call to libc errno_location /// /// #include /// int* __errno_location(void); /// /// The __errno_location() function returns a pointer to the errno variable. void exec_errno_location(ar::CallBase* call) { // Forget the current value of errno MemoryLocation* addr = this->_mem_factory.get_libc_errno(); this->_inv.normal().mem_forget(addr); // Assign the result if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->_inv.normal().pointer_assign(lhs.var(), addr, Nullity::non_null()); } } /// \brief Execute a call to libc read /// /// #include /// ssize_t read(int handle, void* buffer, size_t nbyte); /// /// The read() function attempts to read nbytes from the file associated with /// handle, and places the characters read into buffer. If the file is opened /// using O_TEXT, it removes carriage returns and detects the end of the file. /// /// The function returns the number of bytes read. On end-of-file, 0 is /// returned, on error it returns -1, setting errno to indicate the type of /// error that occurred. void exec_read(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(1)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(2)); if (!this->prepare_mem_access(ptr)) { return; } if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore read, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else if (size.is_machine_int()) { this->_inv.normal().mem_abstract_reachable(ptr.var(), size.machine_int()); } else if (size.is_machine_int_var()) { IntInterval size_intv = this->_inv.normal().int_to_interval(size.var()); this->_inv.normal().mem_abstract_reachable(ptr.var(), size_intv.ub()); } else { ikos_unreachable("unreachable"); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); this->_inv.normal().int_assign_nondet(lhs.var()); } } /// \brief Execute a call to libc gets /// /// #include /// char* gets(char* str); /// /// The gets() function is equivalent to fgets() with an infinite size and a /// stream of stdin, except that the newline character (if any) is not stored /// in the string. It is the caller's responsibility to ensure that the input /// line, if any, is sufficiently short to fit in the string. void exec_gets(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); if (!this->prepare_mem_access(ptr)) { return; } if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore gets, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else { this->_inv.normal().mem_abstract_reachable(ptr.var()); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->_inv.normal().pointer_assign(lhs.var(), ptr.var()); this->_inv.normal().nullity_set(lhs.var(), Nullity::top()); // Returns null on errors } } /// \brief Execute a call to libc fgets /// /// #include /// char* fgets(char* str, int size, FILE* stream); /// /// The fgets() function reads at most one less than the number of characters /// specified by size from the given stream and stores them in the string str. /// Reading stops when a newline character is found, at end-of-file or error. /// The newline, if any, is retained. If any characters are read and there is /// no error, a `\0' character is appended to end the string. void exec_fgets(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(ptr)) { return; } // Size is a ui32, convert it to a size_t auto size_type = ar::IntegerType::size_type(this->_ctx.bundle); if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore fgets, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else if (size.is_machine_int()) { this->_inv.normal() .mem_abstract_reachable(ptr.var(), size.machine_int() .cast(size_type->bit_width(), ar::Unsigned)); } else if (size.is_machine_int_var()) { IntInterval size_intv = this->_inv.normal() .int_to_interval(size.var()) .cast(size_type->bit_width(), ar::Unsigned); this->_inv.normal().mem_abstract_reachable(ptr.var(), size_intv.ub()); } else { ikos_unreachable("unreachable"); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->_inv.normal().pointer_assign(lhs.var(), ptr.var()); this->_inv.normal().nullity_set(lhs.var(), Nullity::top()); // Returns null on errors } } /// \brief Execute a call to libc sprintf /// /// #include /// int sprintf(char* str, const char* format, ...); /// /// The snprintf() and vsnprintf() functions will write at most size-1 of the /// characters printed into the output string (the size'th character then gets /// the terminating `\0'); if the return value is greater than or equal to the /// size argument, the string was too short and some of the printed characters /// were discarded. The output is always null-terminated, unless size is 0. /// /// The sprintf() and vsprintf() functions effectively assume a size of /// INT_MAX + 1. void exec_sprintf(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); if (!this->prepare_mem_access(ptr)) { return; } if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore sprintf, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else { this->_inv.normal().mem_abstract_reachable(ptr.var()); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); this->_inv.normal().int_assign_nondet(lhs.var()); } } /// \brief Execute a call to libc snprintf /// /// #include /// int snprintf(char* str, size_t size, const char* format, ...); /// /// The snprintf() and vsnprintf() functions will write at most size-1 of the /// characters printed into the output string (the size'th character then gets /// the terminating `\0'); if the return value is greater than or equal to the /// size argument, the string was too short and some of the printed characters /// were discarded. The output is always null-terminated, unless size is 0. void exec_snprintf(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(1)); // Calling snprintf with zero bufsz and null pointer buffer can be used to // determine the buffer size needed to contain the output. That case is // allowed. Otherwise, check first argument. bool checkPointer = !(size.is_machine_int() && size.machine_int().is_zero()); if (checkPointer) { if (!this->prepare_mem_access(ptr)) { return; } if (this->_inv.normal().pointer_to_points_to(ptr.var()).is_top()) { // Ignore snprintf, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else if (size.is_machine_int()) { this->_inv.normal().mem_abstract_reachable(ptr.var(), size.machine_int()); } else if (size.is_machine_int_var()) { IntInterval size_intv = this->_inv.normal().int_to_interval(size.var()); this->_inv.normal().mem_abstract_reachable(ptr.var(), size_intv.ub()); } else { ikos_unreachable("unreachable"); } } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); this->_inv.normal().int_assign_nondet(lhs.var()); } } /// \brief Execute a call to libc fopen /// /// #include /// FILE* fopen(const char* path, const char* mode); /// /// The fopen() function opens the file whose name is the string pointed to by /// path and associates a stream with it. void exec_fopen(ar::CallBase* call) { if (!call->has_result()) { return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); MemoryLocation* addr = this->_mem_factory.get_dyn_alloc(call, this->_call_context); this->allocate_memory(lhs.var(), addr, Nullity::top(), Lifetime::allocated(), MemoryInitialValue::Unknown); } /// \brief Execute a call to libc fclose /// /// #include /// int fclose(FILE* stream); /// /// The fclose() function dissociates the named stream from its underlying /// file or set of functions. If the stream was being used for output, any /// buffered data is written first, using fflush(3). void exec_fclose(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& ptr = this->_lit_factory.get_scalar(call->argument(0)); // fclose(NULL) is undefined behavior if (!this->prepare_mem_access(ptr)) { return; } this->exec_free(call); if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); this->_inv.normal().int_assign_nondet(lhs.var()); } } /// \brief Execute a call to libc strlen /// /// #include /// size_t strlen(const char* s); /// /// The strlen() function computes the length of the string s. /// /// The strlen() function returns the number of characters that precede the /// terminating NULL character. void exec_strlen(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& str = this->_lit_factory.get_scalar(call->argument(0)); if (!this->prepare_mem_access(str)) { return; } if (!call->has_result()) { return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); // lhs is in [0, size - 1] this->_inv.normal().int_assign_nondet(lhs.var()); PointsToSet addrs = this->_inv.normal().pointer_to_points_to(str.var()); if (addrs.is_top()) { return; } boost::optional< AbstractDomain > inv = boost::none; for (MemoryLocation* addr : addrs) { AbstractDomain tmp = this->_inv; if (auto gv = dyn_cast< GlobalMemoryLocation >(addr)) { auto alloc_size = MachineInt(this->_data_layout.store_size_in_bytes( gv->global_var()->type()->pointee()), this->_data_layout.pointers.bit_width, Unsigned); tmp.normal().int_add(IntPredicate::LT, lhs.var(), alloc_size); } else { Variable* size_var = this->_var_factory.get_alloc_size(addr); tmp.normal().int_add(IntPredicate::LT, lhs.var(), size_var); } if (!inv) { inv = std::move(tmp); } else { inv->join_with(tmp); } } if (!inv) { this->_inv.set_to_bottom(); } else { this->_inv = std::move(*inv); } } /// \brief Execute a call to libc strlen /// /// #include /// size_t strnlen(const char* s, size_t maxlen); /// /// The strnlen() function attempts to compute the length of s, but never /// scans beyond the first maxlen bytes of s. /// /// The strnlen() function returns either the same result as strlen() or /// maxlen, whichever is smaller. void exec_strnlen(ar::CallBase* call) { this->exec_strlen(call); if (!call->has_result()) { return; } // lhs <= maxlen const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); const ScalarLit& maxlen = this->_lit_factory.get_scalar(call->argument(1)); ikos_assert_msg(lhs.is_machine_int_var(), "left hand side is not an integer variable"); if (maxlen.is_machine_int()) { this->_inv.normal().int_add(IntPredicate::LE, lhs.var(), maxlen.machine_int()); } else if (maxlen.is_machine_int_var()) { this->_inv.normal().int_add(IntPredicate::LE, lhs.var(), maxlen.var()); } else { ikos_unreachable("unexpected maxlen parameter"); } } /// \brief Execute a call to libc strcpy /// /// #include /// char* strcpy(char* dst, const char* src); /// /// The strcpy() function copies the string src to dst (including the /// terminating `\0' character). /// /// The strcpy() function returns dst. void exec_strcpy(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& dest = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& src = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(dest)) { return; } if (!this->prepare_mem_access(src)) { return; } if (this->_inv.normal().pointer_to_points_to(dest.var()).is_top()) { // Ignore strcpy, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else { // Do not keep track of the content this->_inv.normal().mem_abstract_reachable(dest.var()); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->assign(lhs, dest); } } /// \brief Execute a call to libc strncpy /// /// #include /// char* strncpy(char* dst, const char* src, size_t n); /// /// The strncpy() function copies at most n characters from src into dst. /// If src is less than n characters long, the remainder of dst is filled with /// `\0' characters. Otherwise, dst is not terminated. /// /// The strncpy() function returns dst. void exec_strncpy(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& dest = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& src = this->_lit_factory.get_scalar(call->argument(1)); const ScalarLit& size = this->_lit_factory.get_scalar(call->argument(2)); if (!this->prepare_mem_access(dest)) { return; } if (!this->prepare_mem_access(src)) { return; } if (this->_inv.normal().pointer_to_points_to(dest.var()).is_top()) { // Ignore strncpy, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else if (size.is_machine_int()) { this->_inv.normal().mem_abstract_reachable(dest.var(), size.machine_int()); } else if (size.is_machine_int_var()) { IntInterval size_intv = this->_inv.normal().int_to_interval(size.var()); this->_inv.normal().mem_abstract_reachable(dest.var(), size_intv.ub()); } else { ikos_unreachable("unreachable"); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->assign(lhs, dest); } } /// \brief Execute a call to libc strcat /// /// #include /// char* strcat(char* s1, const char* s2); /// /// The strcat() function appends a copy of the null-terminated string s2 to /// the end of the null-terminated string s1, then add a terminating \0. The /// string s1 must have sufficient space to hold the result. /// /// The strcat() function returns the pointer s1. void exec_strcat(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& s1 = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& s2 = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(s1)) { return; } if (!this->prepare_mem_access(s2)) { return; } if (this->_inv.normal().pointer_to_points_to(s1.var()).is_top()) { // Ignore strcat, analysis could be unsound. // See CheckKind::IgnoredCallSideEffectOnPointerParameter } else { // Do not keep track of the content this->_inv.normal().mem_abstract_reachable(s1.var()); } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->assign(lhs, s1); } } /// \brief Execute a call to libc strcat /// /// #include /// char* strncat(char* s1, const char* s2, size_t n); /// /// The strncat() function appends a copy of the null-terminated string s2 to /// the end of the null-terminated string s1, then add a terminating `\0'. The /// string s1 must have sufficient space to hold the result. /// /// The strncat() function appends not more than n characters from s2, and /// then adds a terminating `\0'. /// /// The strncat() function returns the pointer s1. void exec_strncat(ar::CallBase* call) { this->exec_strcat(call); } /// \brief Execute a call to libc strstr /// /// #include /// char* strstr(const char* haystack, const char* needle); /// /// The strstr() function locates the first occurrence of the null-terminated /// string needle in the null-terminated string haystack. void exec_strstr(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& haystack = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& needle = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(haystack)) { return; } if (!this->prepare_mem_access(needle)) { return; } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->_inv.normal().pointer_assign(lhs.var(), haystack.var()); this->_inv.normal().nullity_set(lhs.var(), Nullity::top()); this->_inv.normal().pointer_forget_offset(lhs.var()); } } /// \brief Execute a call to libc strchr /// /// #include /// char* strchr(const char* s, int c); /// /// The strchr() function locates the first occurrence of c (converted to a /// char) in the string pointed to by s. The terminating null character is /// considered to be part of the string; therefore if c is `\0', the functions /// locate the terminating `\0'. void exec_strchr(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& s = this->_lit_factory.get_scalar(call->argument(0)); if (!this->prepare_mem_access(s)) { return; } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); this->_inv.normal().pointer_assign(lhs.var(), s.var()); this->_inv.normal().nullity_set(lhs.var(), Nullity::top()); this->_inv.normal().pointer_forget_offset(lhs.var()); } } /// \brief Execute a call to libc strdup /// /// #include /// char* strdup(const char* s1); /// /// The strdup() function allocates sufficient memory for a copy of the string /// s1, does the copy, and returns a pointer to it. The pointer may /// subsequently be used as an argument to the function free(3). void exec_strdup(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& s = this->_lit_factory.get_scalar(call->argument(0)); if (!this->prepare_mem_access(s)) { return; } if (call->has_result()) { const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); MemoryLocation* addr = this->_mem_factory.get_dyn_alloc(call, this->_call_context); this->allocate_memory(lhs.var(), addr, Nullity::top(), Lifetime::allocated(), MemoryInitialValue::Unknown); } } /// \brief Execute a call to libc strndup /// /// #include /// char* strndup(const char* s1, size_t n); /// /// The strndup() function copies at most n characters from the string s1 /// always NUL terminating the copied string. void exec_strndup(ar::CallBase* call) { this->init_global_operands(call); const ScalarLit& s = this->_lit_factory.get_scalar(call->argument(0)); const ScalarLit& n = this->_lit_factory.get_scalar(call->argument(1)); if (!this->prepare_mem_access(s)) { return; } if (!call->has_result()) { return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); MemoryLocation* addr = this->_mem_factory.get_dyn_alloc(call, this->_call_context); this->allocate_memory(lhs.var(), addr, Nullity::top(), Lifetime::allocated(), MemoryInitialValue::Unknown); if (this->_opts.test(ExecutionEngine::UpdateAllocSizeVar)) { // sizeof(addr) <= n Variable* alloc_size_var = this->_var_factory.get_alloc_size(addr); if (n.is_machine_int()) { this->_inv.normal().int_add(IntPredicate::LE, alloc_size_var, n.machine_int()); } else if (n.is_machine_int_var()) { this->_inv.normal().int_add(IntPredicate::LE, alloc_size_var, n.var()); } else { ikos_unreachable("unexpected size operand"); } } } /// \brief Execute a call to libc++ new or new[] /// /// operator new(size_t) /// operator new[](size_t) /// /// Allocates requested number of bytes. These allocation functions are called /// by new-expressions to allocate memory in which new object would then be /// initialized. They may also be called using regular function call syntax. void exec_new(ar::CallBase* call) { this->exec_dynamic_alloc(call, call->argument(0), /* may_return_null = */ false, /* may_throw_exc = */ true, MemoryInitialValue::Uninitialized); } /// \brief Execute a call to libc++ allocate exception /// /// void* __cxa_allocate_exception(size_t thrown_size) noexcept; /// /// Allocates memory to hold the exception to be thrown. thrown_size is the /// size of the exception object. Can allocate additional memory to hold /// private data. If memory can not be allocated, call std::terminate(). void exec_allocate_exception(ar::CallBase* call) { this->exec_dynamic_alloc(call, call->argument(0), /* may_return_null = */ false, /* may_throw_exc = */ false, MemoryInitialValue::Uninitialized); } /// \brief Execute a call to libc++ throw /// /// __cxa_throw(void* exception, std::type_info* tinfo, void (*dest)(void*)) /// /// After constructing the exception object with the throw argument value, the /// generated code calls the __cxa_throw runtime library routine. This routine /// never returns. void exec_throw(ar::CallBase* /*call*/) { this->_inv.throw_exception(); } /// \brief Execute a call to libc++ begin catch /// /// void* __cxa_begin_catch(void* exc_obj) noexcept; /// /// When entering a catch scope, __cxa_begin_catch is called with the /// exception object `exc_obj`. This routine returns the adjusted pointer to /// the exception object. /// /// Assume that it returns `exc_obj` unchanged. void exec_begin_catch(ar::CallBase* call) { if (!call->has_result()) { return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(call->result()); const ScalarLit& exc_obj = this->_lit_factory.get_scalar(call->argument(0)); this->assign(lhs, exc_obj); } /// \brief Execute a call to libc++ end catch /// /// void __cxa_end_catch(); /// /// Locates the most recently caught exception and decrements its handler /// count. Removes the exception from the caughtÓexception stack, if the /// handler count goes to zero. Destroys the exception if the handler count /// goes to zero, and the exception was not re-thrown by throw. Collaboration /// between __cxa_rethrow() and __cxa_end_catch() is necessary to handle the /// last point. Though implementation-defined, one possibility is for /// __cxa_rethrow() to set a flag in the handlerCount member of the exception /// header to mark an exception being rethrown. void exec_end_catch(ar::CallBase* /*call*/) {} /// @} public: void match_down(ar::CallBase* call, ar::Function* called) override { ikos_assert(called->is_definition()); ikos_assert(ar::TypeVerifier::is_valid_call(call, called->type())); auto param_it = called->param_begin(); auto param_et = called->param_end(); auto arg_it = call->arg_begin(); auto arg_et = call->arg_end(); for (; param_it != param_et && arg_it != arg_et; ++param_it, ++arg_it) { this->init_global_operand(*arg_it); this->implicit_bitcast(this->_lit_factory.get(*param_it), this->_lit_factory.get(*arg_it)); } } void match_up(ar::CallBase* call, ar::ReturnValue* ret) override { if (ret == nullptr || !ret->has_operand()) { // No return value return; } const Literal& return_value = this->_lit_factory.get(ret->operand()); if (call->has_result()) { // Assign the result variable const Literal& result = this->_lit_factory.get(call->result()); this->init_global_operand(ret->operand()); this->implicit_bitcast(result, return_value); if (return_value.is_var()) { // If the current partitioning is based on the return variable, // we automatically update it to the result variable. auto partitioning_var = this->_inv.normal().partitioning_variable(); if (partitioning_var && *partitioning_var == return_value.var()) { this->_inv.normal().partitioning_set_variable(result.var()); } } } // Clean-up the invariant if (!return_value.is_var()) { return; } else if (return_value.is_scalar()) { this->_inv.normal().scalar_forget(return_value.var()); } else if (return_value.is_aggregate()) { this->_inv.normal().mem_forget_reachable(return_value.var()); this->_inv.normal().scalar_forget(return_value.var()); } else { ikos_unreachable("unreachable"); } } }; // end class NumericalExecutionEngine } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/fixpoint_parameters.hpp000066400000000000000000000152421473507761200313030ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Fixpoint parameters * * Author: Thomas Bailleux * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Widening hints for a control flow graph class WideningHints { private: /// \brief Map of widening hints associated to a given cycle head using Map = llvm::DenseMap< ar::BasicBlock*, MachineInt >; private: Map _map; public: /// \brief Iterator over the widening hints using Iterator = Map::const_iterator; public: /// \brief Constructor WideningHints() = default; /// \brief Copy constructor WideningHints(const WideningHints&) = default; /// \brief Move constructor WideningHints(WideningHints&&) = default; /// \brief Copy assignment operator WideningHints& operator=(const WideningHints&) = default; /// \brief Move assignment operator WideningHints& operator=(WideningHints&&) = default; /// \brief Destructor ~WideningHints() = default; /// \brief Return the widening hint for the given cycle head, if any boost::optional< const MachineInt& > get(ar::BasicBlock* head) const; /// \brief Add a widening hint for the given cycle head void add(ar::BasicBlock* head, const MachineInt& hint); /// \brief Begin iterator over the list of widening hints Iterator begin() const { return this->_map.begin(); } /// \brief End iterator over the list of widening hints Iterator end() const { return this->_map.end(); } }; // end class WideningHints /// \brief Fixpoint parameters for a control flow graph class CodeFixpointParameters { public: /// \brief Strategy for the increasing iterations (before reaching a fixpoint) WideningStrategy widening_strategy; /// \brief Strategy for the decreasing iterations (after reaching a fixpoint) NarrowingStrategy narrowing_strategy; /// \brief Number of loop iterations before applying the widening strategy unsigned widening_delay; /// \brief Number of loop iterations between each widening unsigned widening_period; /// \brief Fixed number of narrowing iterations to perform /// /// boost::none to perform narrowing iterations until convergence boost::optional< unsigned > narrowing_iterations; /// \brief Widening hints WideningHints widening_hints; public: /// \brief Constructor CodeFixpointParameters(WideningStrategy widening_strategy_, NarrowingStrategy narrowing_strategy_, unsigned widening_delay_, unsigned widening_period_, boost::optional< unsigned > narrowing_iterations_); /// \brief Copy constructor CodeFixpointParameters(const CodeFixpointParameters&) = default; /// \brief Move constructor CodeFixpointParameters(CodeFixpointParameters&&) = default; /// \brief Copy assignment operator CodeFixpointParameters& operator=(const CodeFixpointParameters&) = default; /// \brief Move assignment operator CodeFixpointParameters& operator=(CodeFixpointParameters&&) = default; /// \brief Destructor ~CodeFixpointParameters() = default; }; // end class CodeFixpointParameters /// \brief Fixpoint parameters for the whole program class FixpointParameters { private: /// \brief Default fixpoint parameters CodeFixpointParameters _default_params; /// \brief Map that associates a function to fixpoint parameters llvm::DenseMap< ar::Function*, std::unique_ptr< CodeFixpointParameters > > _map; public: /// \brief Constructor explicit FixpointParameters(const AnalysisOptions& opts); /// \brief No copy constructor FixpointParameters(const FixpointParameters&) = delete; /// \brief No move constructor FixpointParameters(FixpointParameters&&) = delete; /// \brief No copy assignment operator FixpointParameters& operator=(const FixpointParameters&) = delete; /// \brief No move assignment operator FixpointParameters& operator=(FixpointParameters&&) = delete; /// \brief Destructor ~FixpointParameters(); /// \brief Default fixpoint parameters for a control flow graph const CodeFixpointParameters& default_params() const { return this->_default_params; } /// \brief Get or create the fixpoint parameters for the given function CodeFixpointParameters& get(ar::Function*); /// \brief Get the fixpoint parameters for the given function const CodeFixpointParameters& get(ar::Function*) const; /// \brief Dump the fixpoint parameters, for debugging purpose void dump(std::ostream& o) const; }; // end class FixpointParameters } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/hardware_addresses.hpp000066400000000000000000000132511473507761200310500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Hardware addresses utility for the analyzer * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Class that handles a set of readable/writable addresses /// /// We can declare hardware addresses with an argument or by giving a file class HardwareAddresses { private: using Interval = core::machine_int::Interval; private: /// \brief Range of hardware addresses std::vector< Interval > _address_ranges; const ar::DataLayout& _data_layout; public: /// \brief Constructor HardwareAddresses( ar::Bundle* bundle, const llvm::cl::list< std::string >& hardware_addresses, const llvm::cl::opt< std::string >& hardware_addresses_file); /// \brief Add a range from a string void add_range(StringRef); /// \brief Add a range from a file void add_range_from_file(const std::string&); /// \brief Get all the ranges const std::vector< Interval >& ranges() const { return this->_address_ranges; } /// \brief Check if a range is included in one of the hardware addresses bool geq(const Interval& other) const; /// \brief Check if all hardware ranges don't meet with the given range bool is_meet_bottom(const Interval& other) const; /// \brief Dump the object, for debugging purpose void dump(std::ostream& o) const; private: /// \brief Add a range void add_range(Interval); }; // end class HardwareAddresses /// \brief Exception for HardwareAddresses class HardwareAddressesException : public analyzer::Exception { public: /// \brief Enum of all kind of exception enum HardwareAddressesExceptionKind { InvalidFormatKind, InvalidRangeKind, CannotOpenFileKind, }; private: /// \brief Line number if it applies uint64_t _n_line; /// \brief Explanatory string std::shared_ptr< const std::string > _errstr; /// \brief Kind of exception HardwareAddressesExceptionKind _kind; public: /// \brief Constructor /// /// \param pattern The pattern which is parsed /// \param kind Kind of exception explicit HardwareAddressesException(StringRef pattern, HardwareAddressesExceptionKind kind); /// \brief Constructor /// /// \param pattern The pattern which is parsed /// \param n_line Line number /// \param kind Kind of exception explicit HardwareAddressesException(StringRef pattern, HardwareAddressesExceptionKind kind, uint64_t n_line); /// \brief No default constructor HardwareAddressesException() = delete; /// \brief Copy constructor HardwareAddressesException(const HardwareAddressesException&) noexcept = default; /// \brief Move constructor HardwareAddressesException(HardwareAddressesException&&) noexcept = default; /// \brief Copy assignment operator HardwareAddressesException& operator=( const HardwareAddressesException&) noexcept = default; /// \brief Move assignment operator HardwareAddressesException& operator=(HardwareAddressesException&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override; /// \brief Destructor ~HardwareAddressesException() override; private: /// \brief Create the explanatory string void create_errstr(StringRef pattern); }; // end class HardwareAddressesException } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/literal.hpp000066400000000000000000000275621473507761200266640ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate AR operands to a symbolic representation * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Scalar literal using ScalarLit = core::Literal< Variable*, MemoryLocation* >; /// \brief Aggregate literal using AggregateLit = AggregateLiteral< Variable*, MemoryLocation* >; /// \brief Any literal class Literal { private: /// \brief Union type for scalar and aggregate literals using Lit = boost::variant< ScalarLit, AggregateLit >; private: Lit _lit; public: /// Create a scalar literal explicit Literal(ScalarLit lit) : _lit(std::move(lit)) {} /// \brief Create an aggregate literal explicit Literal(AggregateLit lit) : _lit(std::move(lit)) {} /// \brief Copy constructor Literal(const Literal&) = default; /// \brief Move constructor Literal(Literal&&) = default; /// \brief Copy assignment operator Literal& operator=(const Literal&) = default; /// \brief Move assignment operator Literal& operator=(Literal&&) = default; /// \brief Destructor ~Literal() = default; /// \brief Comparison of literals bool operator==(const Literal& other) const { return this->_lit == other._lit; } /// \brief Comparison of literals bool operator!=(const Literal& other) const { return !this->operator==(other); } private: /// \brief Visitor that checks if the given literal has the given type template < typename LiteralType > struct IsType : public boost::static_visitor< bool > { template < typename T > bool operator()(const T&) const { return std::is_same< T, LiteralType >::value; } }; public: /// \brief Return true if it's a scalar literal bool is_scalar() const { return boost::apply_visitor(IsType< ScalarLit >(), this->_lit); } /// \brief Return true if it's an aggregate literal bool is_aggregate() const { return boost::apply_visitor(IsType< AggregateLit >(), this->_lit); } private: /// \brief Visitor that returns the scalar literal struct GetScalarLit : public boost::static_visitor< const ScalarLit& > { const ScalarLit& operator()(const ScalarLit& lit) const { return lit; } const ScalarLit& operator()(const AggregateLit&) const { ikos_unreachable("trying to call scalar() on an aggregate literal"); } }; public: /// \brief Return the scalar literal const ScalarLit& scalar() const { #if BOOST_VERSION == 105800 // Workaround for https://svn.boost.org/trac10/ticket/11285 GetScalarLit vis; return this->_lit.apply_visitor(vis); #else return boost::apply_visitor(GetScalarLit(), this->_lit); #endif } private: /// \brief Visitor that returns the aggregate literal struct GetAggregateLit : public boost::static_visitor< const AggregateLit& > { const AggregateLit& operator()(const ScalarLit&) const { ikos_unreachable("trying to call aggregate() on a scalar literal"); } const AggregateLit& operator()(const AggregateLit& lit) const { return lit; } }; public: /// \brief Return the aggregate literal const AggregateLit& aggregate() const { #if BOOST_VERSION == 105800 // Workaround for https://svn.boost.org/trac10/ticket/11285 GetAggregateLit vis; return this->_lit.apply_visitor(vis); #else return boost::apply_visitor(GetAggregateLit(), this->_lit); #endif } private: /// \brief Visitor that returns true if the literal is a variable struct IsVariableLit : public boost::static_visitor< bool > { bool operator()(const ScalarLit& lit) const { return lit.is_var(); } bool operator()(const AggregateLit& lit) const { return lit.is_var(); } }; public: // \brief Return true if the literal is a variable bool is_var() const { return boost::apply_visitor(IsVariableLit(), this->_lit); } private: /// \brief Visitor that returns the variable struct GetVariable : public boost::static_visitor< Variable* > { Variable* operator()(const ScalarLit& lit) const { return lit.var(); } Variable* operator()(const AggregateLit& lit) const { return lit.var(); } }; public: /// \brief Get the variable Variable* var() const { return boost::apply_visitor(GetVariable(), this->_lit); } public: /// \brief Literal visitor /// /// Visitors should implement the following methods: /// /// R operator()(const ScalarLit&); /// R operator()(const AggregateLit&); template < typename R = void > class Visitor { public: using ResultType = R; }; // end class Visitor private: template < typename Visitor > struct VariantVisitor : public boost::static_visitor< typename Visitor::ResultType > { using ResultType = typename Visitor::ResultType; Visitor& v; explicit VariantVisitor(Visitor& v_) : v(v_) {} ResultType operator()(const ScalarLit& lit) { return v(lit); } ResultType operator()(const AggregateLit& lit) { return v(lit); } }; template < typename Visitor > struct ConstVariantVisitor : public boost::static_visitor< typename Visitor::ResultType > { using ResultType = typename Visitor::ResultType; const Visitor& v; explicit ConstVariantVisitor(const Visitor& v_) : v(v_) {} ResultType operator()(const ScalarLit& lit) const { return v(lit); } ResultType operator()(const AggregateLit& lit) const { return v(lit); } }; public: /// \brief Visit the literal template < typename Visitor, typename = typename std::enable_if_t< std::is_base_of< Literal::Visitor< typename Visitor::ResultType >, Visitor >::value > > typename Visitor::ResultType apply_visitor(Visitor& v) const { VariantVisitor< Visitor > vis(v); return boost::apply_visitor(vis, this->_lit); } /// \brief Visit the literal template < typename Visitor, typename = typename std::enable_if_t< std::is_base_of< Literal::Visitor< typename Visitor::ResultType >, Visitor >::value > > typename Visitor::ResultType apply_visitor(const Visitor& v) const { ConstVariantVisitor< Visitor > vis(v); return boost::apply_visitor(vis, this->_lit); } private: /// \brief Visitor that dumps the literal on a stream struct Dumper : public boost::static_visitor<> { std::ostream& o; explicit Dumper(std::ostream& _o) : o(_o) {} void operator()(const ScalarLit& lit) const { lit.dump(o); } void operator()(const AggregateLit& lit) const { lit.dump(o); } }; public: /// \brief Dump the literal on a stream, for debugging purpose void dump(std::ostream& o) const { boost::apply_visitor(Dumper(o), this->_lit); } }; // end class Literal /// \brief Write a literal on a stream inline std::ostream& operator<<(std::ostream& o, const Literal& l) { l.dump(o); return o; } /// \brief Exception for unexpected literals /// /// This is raised when calling lfac[value] and an AggregateLit is found class UnexpectedLiteralError : public LogicError { public: /// \brief Constructor explicit UnexpectedLiteralError(const std::string& msg) : LogicError(msg) {} }; // end class UnexpectedLiteralError class ScalarLiteralError : public UnexpectedLiteralError { private: const ScalarLit& _lit; public: explicit ScalarLiteralError(const ScalarLit& lit) : UnexpectedLiteralError("literal factory: unexpected scalar literal"), _lit(lit) {} const ScalarLit& lit() const { return this->_lit; } }; // end class ScalarLiteralError class AggregateLiteralError : public UnexpectedLiteralError { private: const AggregateLit& _lit; public: explicit AggregateLiteralError(const AggregateLit& lit) : UnexpectedLiteralError("literal factory: unexpected aggregate literal"), _lit(lit) {} const AggregateLit& lit() const { return _lit; } }; // end class AggregateLiteralError /// \brief Create literals from AR values class LiteralFactory { private: /// \brief Map from ar::Value* to Literal /// /// Must be a data structure that does not invalidate references on /// insertions. using Map = std::unordered_map< ar::Value*, Literal >; private: /// \brief Mutex boost::shared_mutex _mutex; /// \brief Variable factory VariableFactory& _vfac; /// \brief Data layout const ar::DataLayout& _data_layout; /// \brief Map from ar::Value* to Literal Map _map; public: /// \brief Constructor LiteralFactory(VariableFactory& vfac, const ar::DataLayout& data_layout); /// \brief No copy constructor LiteralFactory(const LiteralFactory&) = delete; /// \brief No move constructor LiteralFactory(LiteralFactory&&) = delete; /// \brief No copy assignment operator LiteralFactory& operator=(const LiteralFactory&) = delete; /// \brief No move assignment operator LiteralFactory& operator=(LiteralFactory&&) = delete; /// \brief Destructor ~LiteralFactory(); /// \brief Translate an ar::Value* into a scalar literal /// /// \throw AggregateLiteralError or VoidVarLiteralError const ScalarLit& get_scalar(ar::Value* value); /// \brief Translate an ar::Value* into an aggregate literal /// /// \throw ScalarLiteralError or VoidVarLiteralError const AggregateLit& get_aggregate(ar::Value* value); /// \brief Translate an ar::Value* into a literal /// /// This also adds the translation into the cache const Literal& get(ar::Value* value); private: /// \brief Translate an ar::Value* into a Literal Literal create_literal(ar::Value* value); }; // end class LiteralFactory } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/liveness.hpp000066400000000000000000000107071473507761200270510ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Liveness variable analysis * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Compute liveness of variables for a whole bundle class LivenessAnalysis { public: /// \brief List of variables using VariableRefList = std::vector< Variable* >; private: /// \brief Map from basic block to a list of variables using VariableRefMap = llvm::DenseMap< ar::BasicBlock*, VariableRefList >; private: /// \brief Analysis context Context& _ctx; /// \brief List of live variables at the entry of a basic block VariableRefMap _live_at_entry_map; /// \brief List of dead variables at the end of a basic block VariableRefMap _dead_at_end_map; public: /// \brief Constructor explicit LivenessAnalysis(Context& ctx); /// \brief No copy constructor LivenessAnalysis(const LivenessAnalysis&) = delete; /// \brief No move constructor LivenessAnalysis(LivenessAnalysis&&) = delete; /// \brief No copy assignment operator LivenessAnalysis& operator=(const LivenessAnalysis&) = delete; /// \brief No move assignment operator LivenessAnalysis& operator=(LivenessAnalysis&&) = delete; /// \brief Destructor ~LivenessAnalysis(); /// \brief Return a list of live variables at the entry of the given block /// /// Returns boost::none if we have no information boost::optional< const VariableRefList& > live_at_entry( ar::BasicBlock* bb) const; /// \brief Return a list of dead variables at the end of the given block /// /// Returns boost::none if we have no information boost::optional< const VariableRefList& > dead_at_end( ar::BasicBlock* bb) const; /// \brief Run the analysis void run(); private: /// \brief Run the analysis on the given code void run(ar::Code* code); public: /// \brief Dump the liveness analysis results, for debugging purpose void dump(std::ostream& o) const; private: /// \brief Dump the liveness analysis results for the given code void dump(std::ostream& o, ar::Code* code) const; /// \brief Dump a VariableRefList static void dump(std::ostream& o, const VariableRefList& vars); }; // end class LivenessAnalysis } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/memory_location.hpp000066400000000000000000000304161473507761200304200ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief MemoryLocation types and MemoryFactory used by the analyses * * Author: Clement Decoodt * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Represents a location in memory /// /// MemoryLocation is an implementation of the MemoryLocation generic object in /// the core. /// /// See ikos/core/semantic/memory_location.hpp /// It must be indexable (see ikos/core/semantic/indexable.hpp) /// Is must be dumpable (see ikos/core/semantic/dumpable.hpp) class MemoryLocation { public: /// \brief kind of the memory location enum MemoryLocationKind { LocalMemoryKind, GlobalMemoryKind, FunctionMemoryKind, AggregateMemoryKind, AbsoluteZeroMemoryKind, ArgvMemoryKind, LibcErrnoMemoryKind, DynAllocMemoryKind, }; protected: /// \brief Kind of the memory location MemoryLocationKind _kind; protected: /// \brief Protected constructor explicit MemoryLocation(MemoryLocationKind kind); public: /// \brief No copy constructor MemoryLocation(const MemoryLocation&) = delete; /// \brief No move constructor MemoryLocation(MemoryLocation&&) = delete; /// \brief No copy assignment operator MemoryLocation& operator=(const MemoryLocation&) = delete; /// \brief No move assignment operator MemoryLocation& operator=(MemoryLocation&&) = delete; /// \brief Destructor virtual ~MemoryLocation(); /// \brief Return the kind of the object MemoryLocationKind kind() const { return this->_kind; } /// \brief Dump the memory location, for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class MemoryLocation /// \brief Local memory location class LocalMemoryLocation final : public MemoryLocation { private: /// \brief AR Local Variable ar::LocalVariable* _var; public: /// \brief Default constructor explicit LocalMemoryLocation(ar::LocalVariable* var); /// \brief Get the ar::LocalVariable* ar::LocalVariable* local_var() const { return this->_var; } /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == LocalMemoryKind; } }; // end class LocalMemoryLocation /// \brief Global memory location class GlobalMemoryLocation final : public MemoryLocation { private: /// \brief AR Global Variable ar::GlobalVariable* _var; public: /// \brief Default constructor explicit GlobalMemoryLocation(ar::GlobalVariable* var); /// \brief Get the ar::GlobalVariable* ar::GlobalVariable* global_var() const { return this->_var; } /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == GlobalMemoryKind; } }; // end class GlobalMemoryLocation /// \brief Function memory location class FunctionMemoryLocation final : public MemoryLocation { private: /// \brief Function ar::Function* _fun; public: /// \brief Default constructor explicit FunctionMemoryLocation(ar::Function* fun); /// \brief Get the ar::Function* ar::Function* function() const { return this->_fun; } /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == FunctionMemoryKind; } }; // end class FunctionMemoryLocation /// \brief Aggregate memory location class AggregateMemoryLocation final : public MemoryLocation { private: /// \brief AR Aggregate Internal Variable ar::InternalVariable* _var; public: /// \brief Default constructor explicit AggregateMemoryLocation(ar::InternalVariable* var); /// \brief Get the ar::InternalVariable* ar::InternalVariable* internal_var() const { return this->_var; } /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == AggregateMemoryKind; } }; // end class AggregateMemoryLocation /// \brief Absolute zero memory location class AbsoluteZeroMemoryLocation final : public MemoryLocation { public: /// \brief Default constructor AbsoluteZeroMemoryLocation(); /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == AbsoluteZeroMemoryKind; } }; // end class AbsoluteZeroMemoryLocation /// \brief Argv memory location class ArgvMemoryLocation final : public MemoryLocation { public: /// \brief Default constructor ArgvMemoryLocation(); /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == ArgvMemoryKind; } }; // end class ArgvMemoryLocation /// \brief Libc errno memory location class LibcErrnoMemoryLocation final : public MemoryLocation { public: /// \brief Default constructor LibcErrnoMemoryLocation(); /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == LibcErrnoMemoryKind; } }; // end class LibcErrnoMemoryLocation /// \brief Dynamic alloc memory location class DynAllocMemoryLocation final : public MemoryLocation { private: /// \brief Call statement to the allocator (malloc, calloc, etc.) ar::CallBase* _call; /// \brief Call context CallContext* _context; public: /// \brief Default constructor explicit DynAllocMemoryLocation(ar::CallBase* call, CallContext* context); /// \brief Return the call statement ar::CallBase* call() const { return this->_call; } /// \brief Return the call context CallContext* context() const { return this->_context; } /// \brief Dump the memory location, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const MemoryLocation* ml) { return ml->kind() == DynAllocMemoryKind; } }; // end class DynAllocMemoryLocation /// \brief Management of memory locations class MemoryFactory { private: boost::shared_mutex _local_memory_mutex; llvm::DenseMap< ar::LocalVariable*, std::unique_ptr< LocalMemoryLocation > > _local_memory_map; boost::shared_mutex _global_memory_mutex; llvm::DenseMap< ar::GlobalVariable*, std::unique_ptr< GlobalMemoryLocation > > _global_memory_map; boost::shared_mutex _function_memory_mutex; llvm::DenseMap< ar::Function*, std::unique_ptr< FunctionMemoryLocation > > _function_memory_map; boost::shared_mutex _aggregate_memory_mutex; llvm::DenseMap< ar::InternalVariable*, std::unique_ptr< AggregateMemoryLocation > > _aggregate_memory_map; std::unique_ptr< AbsoluteZeroMemoryLocation > _absolute_zero; std::unique_ptr< ArgvMemoryLocation > _argv; std::unique_ptr< LibcErrnoMemoryLocation > _libc_errno; boost::shared_mutex _dyn_alloc_mutex; llvm::DenseMap< std::pair< ar::CallBase*, CallContext* >, std::unique_ptr< DynAllocMemoryLocation > > _dyn_alloc_map; public: /// \brief Default constructor MemoryFactory(); /// \brief No copy constructor MemoryFactory(const MemoryFactory&) = delete; /// \brief No move constructor MemoryFactory(MemoryFactory&&) = delete; /// \brief No copy assignment operator MemoryFactory& operator=(const MemoryFactory&) = delete; /// \brief No move assignment operator MemoryFactory& operator=(MemoryFactory&&) = delete; /// \brief Destructor ~MemoryFactory(); public: /// \brief Get or create a LocalMemoryLocation LocalMemoryLocation* get_local(ar::LocalVariable* var); /// \brief Get or create a GlobalMemoryLocation GlobalMemoryLocation* get_global(ar::GlobalVariable* var); /// \brief Get or Create a FunctionMemoryLocation FunctionMemoryLocation* get_function(ar::Function* fun); /// \brief Get or Create a FunctionMemoryLocation FunctionMemoryLocation* get_function(ar::FunctionPointerConstant* cst); /// \brief Get or create a AggregateMemoryLocation AggregateMemoryLocation* get_aggregate(ar::InternalVariable* var); /// \brief Get or create a AbsoluteZeroMemoryLocation AbsoluteZeroMemoryLocation* get_absolute_zero(); /// \brief Get or create a ArgvMemoryLocation ArgvMemoryLocation* get_argv(); /// \brief Get or create a LibcErrnoMemoryLocation LibcErrnoMemoryLocation* get_libc_errno(); /// \brief Get or create a DynAllocMemoryLocation DynAllocMemoryLocation* get_dyn_alloc(ar::CallBase* call, CallContext* context); }; // end class MemoryFactory } // end namespace analyzer } // end namespace ikos namespace ikos { namespace core { /// \brief Implement IndexableTraits for MemoryLocation* /// /// The index of MemoryLocation* is the address of the pointer template <> struct IndexableTraits< analyzer::MemoryLocation* > { static Index index(const analyzer::MemoryLocation* m) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast< Index >(m); } }; /// \brief Implement DumpableTraits for MemoryLocation* template <> struct DumpableTraits< analyzer::MemoryLocation* > { static void dump(std::ostream& o, const analyzer::MemoryLocation* m) { m->dump(o); } }; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/option.hpp000066400000000000000000000260261473507761200265320ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Analyses options * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { // forward declaration class SettingsTable; /// \brief Machine integer abstract domain enum class MachineIntDomainOption { Interval, Congruence, IntervalCongruence, DBM, VarPackDBM, VarPackDBMCongruence, Gauge, GaugeIntervalCongruence, ApronInterval, ApronOctagon, ApronPolkaPolyhedra, ApronPolkaLinearEqualities, ApronPplPolyhedra, ApronPplLinearCongruences, ApronPkgridPolyhedraLinearCongruences, VarPackApronOctagon, VarPackApronPolkaPolyhedra, VarPackApronPolkaLinearEqualities, VarPackApronPplPolyhedra, VarPackApronPplLinearCongruences, VarPackApronPkgridPolyhedraLinearCongruences, }; /// \brief Return a string representing a MachineIntDomainOption inline const char* machine_int_domain_option_str(MachineIntDomainOption d) { switch (d) { case MachineIntDomainOption::Interval: return "interval"; case MachineIntDomainOption::Congruence: return "congruence"; case MachineIntDomainOption::IntervalCongruence: return "interval-congruence"; case MachineIntDomainOption::DBM: return "dbm"; case MachineIntDomainOption::VarPackDBM: return "var-pack-dbm"; case MachineIntDomainOption::VarPackDBMCongruence: return "var-pack-dbm-congruence"; case MachineIntDomainOption::Gauge: return "gauge"; case MachineIntDomainOption::GaugeIntervalCongruence: return "gauge-interval-congruence"; case MachineIntDomainOption::ApronInterval: return "apron-interval"; case MachineIntDomainOption::ApronOctagon: return "apron-octagon"; case MachineIntDomainOption::ApronPolkaPolyhedra: return "apron-polka-polyhedra"; case MachineIntDomainOption::ApronPolkaLinearEqualities: return "apron-polka-linear-equalities"; case MachineIntDomainOption::ApronPplPolyhedra: return "apron-ppl-polyhedra"; case MachineIntDomainOption::ApronPplLinearCongruences: return "apron-ppl-linear-congruences"; case MachineIntDomainOption::ApronPkgridPolyhedraLinearCongruences: return "apron-pkgrid-polyhedra-lin-cong"; case MachineIntDomainOption::VarPackApronOctagon: return "var-pack-apron-octagon"; case MachineIntDomainOption::VarPackApronPolkaPolyhedra: return "var-pack-apron-polka-polyhedra"; case MachineIntDomainOption::VarPackApronPolkaLinearEqualities: return "var-pack-apron-polka-linear-equalities"; case MachineIntDomainOption::VarPackApronPplPolyhedra: return "var-pack-apron-ppl-polyhedra"; case MachineIntDomainOption::VarPackApronPplLinearCongruences: return "var-pack-apron-ppl-linear-congruences"; case MachineIntDomainOption::VarPackApronPkgridPolyhedraLinearCongruences: return "var-pack-apron-pkgrid-polyhedra-lin-cong"; default: { ikos_unreachable("unreachable"); } } } /// \brief Either Interprocedural or Intraprocedural enum class Procedural { /// \brief Analyzes function by taking into account other functions Interprocedural, /// \brief Analyze function independently Intraprocedural, }; /// \brief Return a string representing a Procedural inline const char* procedural_str(Procedural proc) { switch (proc) { case Procedural::Interprocedural: return "interprocedural"; case Procedural::Intraprocedural: return "intraprocedural"; default: { ikos_unreachable("unreachable"); } } } /// \brief Strategy for the increasing iterations (before reaching a fixpoint) enum class WideningStrategy { /// \brief Widening operator Widen, /// \brief Join operator Join, }; /// \brief Return a string representing a WideningStrategy inline const char* widening_strategy_str(WideningStrategy widening_strategy) { switch (widening_strategy) { case WideningStrategy::Widen: return "widen"; case WideningStrategy::Join: return "join"; default: { ikos_unreachable("unreachable"); } } } /// \brief Strategy for the decreasing iterations (after reaching a fixpoint) enum class NarrowingStrategy { /// \brief Narrowing operator Narrow, /// \brief Meet operator Meet, }; /// \brief Return a string representing a NarrowingStrategy inline const char* narrowing_strategy_str( NarrowingStrategy narrowing_strategy) { switch (narrowing_strategy) { case NarrowingStrategy::Narrow: return "narrow"; case NarrowingStrategy::Meet: return "meet"; default: { ikos_unreachable("unreachable"); } } } /// \brief Return a string representing the hardware addresses inline std::string hardware_addresses_str(const HardwareAddresses& hwa) { JsonList json_intervals; for (const auto& interval : hwa.ranges()) { json_intervals.add(JsonList{interval.lb(), interval.ub()}); } return json_intervals.str(); } /// \brief Policy of initialization for global variables /// /// This is mostly used to avoid losing time initializing big strings enum class GlobalsInitPolicy { /// \brief Initialize all global variables All, /// \brief Initialize all global variables except arrays with more than 100 /// elements SkipBigArrays, /// \brief Initialize all global variables except strings ([n x si8]*) SkipStrings, /// \brief Do not initialize any global variable None, }; /// \brief Return a string representing a GlobalsInitPolicy inline const char* globals_init_policy_str(GlobalsInitPolicy p) { switch (p) { case GlobalsInitPolicy::All: return "all"; case GlobalsInitPolicy::SkipBigArrays: return "skip-big-arrays"; case GlobalsInitPolicy::SkipStrings: return "skip-strings"; case GlobalsInitPolicy::None: return "none"; default: { ikos_unreachable("unreachable"); } } } /// \brief Progress report option enum class ProgressOption { /// \brief Interactive if output is a TTY, otherwise None Auto, /// \brief Interactive progress Interactive, /// \brief Linear progress Linear, /// \brief No progress None, }; /// \brief Display option enum class DisplayOption { /// \brief Display all All, /// \brief Display failed Fail, /// \brief Display nothing None, }; /// \brief Hold all the analysis options struct AnalysisOptions { public: /// \brief List of checkers std::vector< CheckerName > analyses; /// \brief List of entry points std::vector< ar::Function* > entry_points; /// \brief List of entry points that start with uninitialized global variables std::vector< ar::Function* > no_init_globals; /// \brief Machine integer abstract domain MachineIntDomainOption machine_int_domain; /// \brief Is the analysis interprocedural or intraprocedural Procedural procedural; /// \brief Number of threads int num_threads; /// \brief Strategy for the increasing iterations (before reaching a fixpoint) WideningStrategy widening_strategy; /// \brief Strategy for the decreasing iterations (after reaching a fixpoint) NarrowingStrategy narrowing_strategy; /// \brief Number of loop iterations before applying the widening strategy unsigned widening_delay; /// \brief Widening delay for specific functions boost::container::flat_map< ar::Function*, unsigned > widening_delay_functions; /// \brief Number of loop iterations between each widening unsigned widening_period; /// \brief Fixed number of narrowing iterations to perform /// /// boost::none to perform narrowing iterations until convergence boost::optional< unsigned > narrowing_iterations; /// \brief Wether we should use a liveness analysis or not bool use_liveness; /// \brief Wether we should use a pointer analysis or not bool use_pointer; /// \brief Wether we should use widening hints or not bool use_widening_hints; /// \brief Wether we should use the partitioning abstract domain or not bool use_partitioning_domain; /// \brief Wether we should save fixpoints on called functions or not bool use_fixpoint_cache; /// \brief Wether we should perform checks or not bool use_checks; /// \brief Whether to trace states during analysis bool trace_ar_statements; /// \brief Policy of initialization for global variables GlobalsInitPolicy globals_init_policy; /// \brief Option to show the progress of the analysis ProgressOption progress; /// \brief Option to display the invariants DisplayOption display_invariants; /// \brief Option to display the checks DisplayOption display_checks; /// \brief Hardware addresses HardwareAddresses hardware_addresses; /// \brief Value of argc, or boost::none boost::optional< int > argc; public: /// \brief Save the options in the output database void save(SettingsTable&); }; // end class AnalysisOptions } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/pointer/000077500000000000000000000000001473507761200261635ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/pointer/constraint.hpp000066400000000000000000000774041473507761200310740ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Pointer constraints generation * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Pointer constraint using PointerConstraint = core::pointer::Constraint< Variable*, MemoryLocation* >; /// \brief System of pointer constraints class PointerConstraints { private: /// \brief System of pointer constraints core::pointer::ConstraintSystem< Variable*, MemoryLocation* > _system; public: /// \brief Constructor explicit PointerConstraints(const ar::DataLayout& dl); /// \brief No copy constructor PointerConstraints(const PointerConstraints&) = delete; /// \brief No move constructor PointerConstraints(PointerConstraints&&) = delete; /// \brief No copy assignment operator PointerConstraints& operator=(const PointerConstraints&) = delete; /// \brief No move assignment operator PointerConstraints& operator=(PointerConstraints&&) = delete; /// \brief Destructor ~PointerConstraints(); /// \brief Add a pointer constraint void add(std::unique_ptr< PointerConstraint > cst); /// \brief Solve pointer constraints void solve(); /// \brief Export results void results(PointerInfo&) const; /// \brief Dump the pointer constraints, for debugging purpose void dump(std::ostream&) const; }; // end class PointerConstraints /// \brief Generate points-to constraints for a given ar::Code* template < typename CodeInvariants > class PointerConstraintsGenerator { private: using AbstractDomainT = typename CodeInvariants::AbstractDomainT; private: using MachineIntLinearExpression = core::LinearExpression< MachineInt, Variable* >; using VarOp = core::pointer::VariableOperand< Variable*, MemoryLocation* >; using AddrOp = core::pointer::AddressOperand< Variable*, MemoryLocation* >; using AssignCst = core::pointer::AssignConstraint< Variable*, MemoryLocation* >; using StoreCst = core::pointer::StoreConstraint< Variable*, MemoryLocation* >; using LoadCst = core::pointer::LoadConstraint< Variable*, MemoryLocation* >; private: /// \brief Analysis context Context& _ctx; /// \brief Data layout const ar::DataLayout& _data_layout; /// \brief System of pointer constraints PointerConstraints& _csts; /// \brief Information about function pointers, or null const PointerInfo* _function_pointer; public: /// \brief Constructor PointerConstraintsGenerator(Context& ctx, PointerConstraints& csts, const PointerInfo* function_pointer = nullptr) : _ctx(ctx), _data_layout(ctx.bundle->data_layout()), _csts(csts), _function_pointer(function_pointer) {} /// \brief Add pointer constraints for a function definition /// /// \param function The function /// \param invariants Numerical invariants for each basic block void process_function_def(ar::Function* function, const CodeInvariants& invariants) { this->process_function_decl(function); for (ar::BasicBlock* bb : *function->body()) { BasicBlockVisitor vis(this->_ctx, this->_csts, this->_function_pointer, invariants, invariants.entry(bb)); vis.process(bb); } } /// \brief Add pointer constraints for a function declaration void process_function_decl(ar::Function* function) { Variable* fun_ptr = _ctx.var_factory->get_function_ptr(function); MemoryLocation* fun_addr = _ctx.mem_factory->get_function(function); this->_csts.add( AssignCst::create(fun_ptr, AddrOp::create(fun_addr, zero()))); } /// \brief Add pointer constraints for a global variable definition /// /// \param gv The global variable /// \param invariants Numerical invariants for each basic block void process_global_var_def(ar::GlobalVariable* gv, const CodeInvariants& invariants) { this->process_global_var_decl(gv); for (ar::BasicBlock* bb : *gv->initializer()) { BasicBlockVisitor vis(this->_ctx, this->_csts, this->_function_pointer, invariants, invariants.entry(bb)); vis.process(bb); } } /// \brief Add pointer constraints for a global variable declaration void process_global_var_decl(ar::GlobalVariable* gv) { Variable* gv_ptr = _ctx.var_factory->get_global(gv); MemoryLocation* gv_addr = _ctx.mem_factory->get_global(gv); this->_csts.add(AssignCst::create(gv_ptr, AddrOp::create(gv_addr, zero()))); } private: /// \name Implementation /// @{ /// \brief Return the interval [0, 0] MachineIntInterval zero() const { return MachineIntInterval( MachineInt::zero(this->_data_layout.pointers.bit_width, Unsigned)); } /// \brief Visit all statements of an ar::BasicBlock* class BasicBlockVisitor { private: /// \brief Analysis context Context& _ctx; /// \brief Data layout const ar::DataLayout& _data_layout; /// \brief Literal factory LiteralFactory& _lit_factory; /// \brief System of pointer constraints PointerConstraints& _csts; /// \brief Information about function pointers const PointerInfo* _function_pointer; /// \brief Numerical invariants before for each basic block const CodeInvariants& _invariants; /// \brief Current invariant AbstractDomainT _inv; public: /// \brief Constructor BasicBlockVisitor(Context& ctx, PointerConstraints& csts, const PointerInfo* function_pointer, const CodeInvariants& invariants, AbstractDomainT inv) : _ctx(ctx), _data_layout(ctx.bundle->data_layout()), _lit_factory(*ctx.lit_factory), _csts(csts), _function_pointer(function_pointer), _invariants(invariants), _inv(std::move(inv)) {} /// \brief Return the interval [0, 0] MachineIntInterval zero() const { return MachineIntInterval( MachineInt::zero(this->_data_layout.pointers.bit_width, Unsigned)); } /// \brief Generate points-to constraint for the given basic block void process(ar::BasicBlock* bb) { for (ar::Statement* stmt : *bb) { // Generate pointer constraints for the statement ar::apply_visitor(*this, stmt); // Propagate the invariant this->_inv = this->_invariants.analyze_statement(stmt, std::move(this->_inv)); } } private: /// \brief Perform a memory copy from `src` to `dest` void mem_copy(Variable* dest, Variable* src) { // Create a temporary variable ar::PointerType* void_ptr_ty = ar::PointerType::get(_ctx.bundle->context(), ar::VoidType::get(_ctx.bundle->context())); Variable* tmp = _ctx.var_factory->create_unnamed_shadow(void_ptr_ty); // tmp = *src this->_csts.add(LoadCst::create(tmp, VarOp::create(src, zero()))); // *dest = tmp this->_csts.add(StoreCst::create(dest, VarOp::create(tmp, zero()))); } /// \brief Assign `lhs = rhs` void assign(const ScalarLit& lhs, const ScalarLit& rhs) { if (!lhs.is_pointer_var()) { return; } if (rhs.is_machine_int()) { ikos_unreachable("assignment from integer to pointer"); } else if (rhs.is_floating_point()) { ikos_unreachable("assignment from float to pointer"); } else if (rhs.is_null() || rhs.is_undefined()) { return; } else if (rhs.is_machine_int_var()) { ikos_unreachable("assignment from integer to pointer"); } else if (rhs.is_floating_point_var()) { ikos_unreachable("assignment from float to pointer"); } else if (rhs.is_pointer_var()) { this->_csts.add( AssignCst::create(lhs.var(), VarOp::create(rhs.var(), zero()))); } else { ikos_unreachable("unreachable"); } } private: /// @} /// \name Helpers for aggregate (struct,array) statements /// @{ /// \brief Return a pointer to the symbolic location of the aggregate in /// memory InternalVariable* aggregate_pointer(const AggregateLit& aggregate) { ikos_assert_msg(aggregate.is_var(), "aggregate is not a variable"); auto var = cast< InternalVariable >(aggregate.var()); auto addr = _ctx.mem_factory->get_aggregate(var->internal_var()); this->_csts.add(AssignCst::create(var, AddrOp::create(addr, zero()))); return var; } /// \brief Write an aggregate in the memory void mem_write_aggregate(Variable* ptr, const AggregateLit& aggregate) { if (aggregate.is_cst()) { // In theory, we should add stores at `ptr + field.offset` instead of // `ptr`, but the pointer analysis ignores offsets. for (const auto& field : aggregate.fields()) { if (field.value.is_var()) { this->_csts.add( StoreCst::create(ptr, VarOp::create(field.value.var(), zero()))); } } } else if (aggregate.is_zero() || aggregate.is_undefined()) { return; // nothing to do } else if (aggregate.is_var()) { this->mem_copy(ptr, this->aggregate_pointer(aggregate)); } else { ikos_unreachable("unreachable"); } } private: /// \brief Aggregate assignment `lhs = rhs` void assign(const AggregateLit& lhs, const AggregateLit& rhs) { ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); this->mem_write_aggregate(this->aggregate_pointer(lhs), rhs); } /// \brief Assignment `lhs = rhs` void assign(const Literal& lhs, const Literal& rhs) { if (lhs.is_scalar()) { ikos_assert_msg(rhs.is_scalar(), "unexpected right hand side"); this->assign(lhs.scalar(), rhs.scalar()); } else if (lhs.is_aggregate()) { ikos_assert_msg(rhs.is_aggregate(), "unexpected right hand side"); this->assign(lhs.aggregate(), rhs.aggregate()); } else { ikos_unreachable("unreachable"); } } public: // Statement visitor using ResultType = void; void operator()(ar::Assignment* s) { this->assign(this->_lit_factory.get(s->result()), this->_lit_factory.get(s->operand())); } void operator()(ar::UnaryOperation* s) { switch (s->op()) { case ar::UnaryOperation::UIToPtr: case ar::UnaryOperation::SIToPtr: { // Cast from int to ptr (for instance: int x = 5; int *px = x;) uint64_t bit_width = this->_data_layout.pointers.bit_width; const ScalarLit& lhs = this->_lit_factory.get_scalar(s->result()); const ScalarLit& rhs = this->_lit_factory.get_scalar(s->operand()); if (rhs.is_machine_int()) { auto offset = rhs.machine_int().cast(bit_width, Unsigned); AssignCst::create(lhs.var(), AddrOp::create(_ctx.mem_factory ->get_absolute_zero(), MachineIntInterval(offset))); } else if (rhs.is_machine_int_var()) { auto offset_intv = this->_inv.normal().int_to_interval(rhs.var()).cast(bit_width, Unsigned); AssignCst::create(lhs.var(), AddrOp::create(_ctx.mem_factory ->get_absolute_zero(), offset_intv)); } else { ikos_unreachable("unexpected operand"); } } break; case ar::UnaryOperation::Bitcast: { if (s->result()->type()->is_pointer()) { // Pointer cast ikos_assert(s->operand()->type()->is_pointer()); this->assign(this->_lit_factory.get_scalar(s->result()), this->_lit_factory.get_scalar(s->operand())); } } break; default: break; } } void operator()(ar::BinaryOperation*) {} void operator()(ar::Comparison*) {} void operator()(ar::ReturnValue* s) { if (!s->has_operand()) { return; } Variable* ret_var = _ctx.var_factory->get_return(s->code()->function()); const Literal& rhs = this->_lit_factory.get(s->operand()); if (rhs.is_scalar()) { if (rhs.scalar().is_pointer_var()) { this->_csts.add( AssignCst::create(ret_var, VarOp::create(rhs.scalar().var(), zero()))); } } else if (rhs.is_aggregate()) { this->mem_write_aggregate(ret_var, rhs.aggregate()); } else { ikos_unreachable("unreachable"); } } void operator()(ar::Unreachable*) {} void operator()(ar::Allocate* s) { Variable* local_var = _ctx.var_factory->get_local(s->result()); MemoryLocation* local_addr = _ctx.mem_factory->get_local(s->result()); this->_csts.add( AssignCst::create(local_var, AddrOp::create(local_addr, zero()))); } void operator()(ar::PointerShift* s) { const ScalarLit& lhs = this->_lit_factory.get_scalar(s->result()); const ScalarLit& base = this->_lit_factory.get_scalar(s->pointer()); ikos_assert_msg(lhs.is_pointer_var(), "left hand side is not a pointer variable"); if (base.is_undefined()) { return; } uint64_t bit_width = this->_data_layout.pointers.bit_width; MachineIntLinearExpression offset_expr( MachineInt::zero(bit_width, Unsigned)); for (auto it = s->term_begin(), et = s->term_end(); it != et; ++it) { auto term = *it; const ScalarLit& offset = this->_lit_factory.get_scalar(term.second); if (offset.is_undefined()) { return; } else if (offset.is_machine_int()) { offset_expr.add( mul(term.first, offset.machine_int().cast(bit_width, Unsigned))); } else if (offset.is_machine_int_var()) { offset_expr.add(term.first, offset.var()); } else { ikos_unreachable("unreachable"); } } MachineIntInterval offset_intv = this->_inv.normal().int_to_interval(offset_expr); if (base.is_null()) { this->_csts.add( AssignCst::create(lhs.var(), AddrOp::create(_ctx.mem_factory ->get_absolute_zero(), offset_intv))); } else { this->_csts.add( AssignCst::create(lhs.var(), VarOp::create(base.var(), offset_intv))); } } void operator()(ar::Load* s) { const ScalarLit& ptr = this->_lit_factory.get_scalar(s->operand()); const Literal& result = this->_lit_factory.get(s->result()); if (!ptr.is_pointer_var()) { return; } if (result.is_scalar()) { const ScalarLit& lhs = result.scalar(); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); if (lhs.is_pointer_var()) { this->_csts.add( LoadCst::create(lhs.var(), VarOp::create(ptr.var(), zero()))); } } else if (result.is_aggregate()) { const AggregateLit& lhs = result.aggregate(); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); this->mem_copy(this->aggregate_pointer(lhs), ptr.var()); } else { ikos_unreachable("unexpected left hand side"); } } void operator()(ar::Store* s) { const ScalarLit& ptr = this->_lit_factory.get_scalar(s->pointer()); const Literal& val = this->_lit_factory.get(s->value()); if (!ptr.is_pointer_var()) { return; } if (val.is_scalar()) { const ScalarLit& rhs = val.scalar(); if (rhs.is_pointer_var()) { this->_csts.add( StoreCst::create(ptr.var(), VarOp::create(rhs.var(), zero()))); } } else if (val.is_aggregate()) { this->mem_write_aggregate(ptr.var(), val.aggregate()); } else { ikos_unreachable("unexpected right hand side"); } } void operator()(ar::ExtractElement* s) { const Literal& lhs = this->_lit_factory.get(s->result()); const AggregateLit& rhs = this->_lit_factory.get_aggregate(s->aggregate()); ikos_assert_msg(rhs.is_var(), "right hand side is not a variable"); Variable* rhs_ptr = this->aggregate_pointer(rhs); if (lhs.is_scalar()) { ikos_assert_msg(lhs.scalar().is_var(), "left hand side is not a variable"); if (lhs.scalar().is_pointer_var()) { this->_csts.add(LoadCst::create(lhs.scalar().var(), VarOp::create(rhs_ptr, zero()))); } } else if (lhs.is_aggregate()) { ikos_assert_msg(lhs.aggregate().is_var(), "left hand side is not a variable"); Variable* lhs_ptr = this->aggregate_pointer(lhs.aggregate()); this->mem_copy(lhs_ptr, rhs_ptr); } else { ikos_unreachable("unexpected left hand side"); } } void operator()(ar::InsertElement* s) { const AggregateLit& lhs = this->_lit_factory.get_aggregate(s->result()); const AggregateLit& rhs = this->_lit_factory.get_aggregate(s->aggregate()); const Literal& element = this->_lit_factory.get(s->element()); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); Variable* lhs_ptr = this->aggregate_pointer(lhs); // first, copy the aggregate value this->mem_write_aggregate(lhs_ptr, rhs); // then insert the element if (element.is_scalar()) { if (element.scalar().is_pointer_var()) { this->_csts.add( StoreCst::create(lhs_ptr, VarOp::create(element.scalar().var(), zero()))); } } else if (element.is_aggregate()) { this->mem_write_aggregate(lhs_ptr, element.aggregate()); } else { ikos_unreachable("unexpected element operand"); } } void operator()(ar::ShuffleVector* s) { const AggregateLit& lhs = this->_lit_factory.get_aggregate(s->result()); const AggregateLit& left = this->_lit_factory.get_aggregate(s->left()); const AggregateLit& right = this->_lit_factory.get_aggregate(s->right()); ikos_assert_msg(lhs.is_var(), "left hand side is not a variable"); Variable* lhs_ptr = this->aggregate_pointer(lhs); this->mem_write_aggregate(lhs_ptr, left); this->mem_write_aggregate(lhs_ptr, right); } void operator()(ar::LandingPad*) {} void operator()(ar::Resume*) {} void operator()(ar::CallBase* s) { // Collect potential callees std::vector< MemoryLocation* > callees; ar::Value* called = s->called(); if (auto ptr = dyn_cast< ar::InternalVariable >(called)) { Variable* ptr_var = _ctx.var_factory->get_internal(ptr); if (!this->_function_pointer) { return; } PointsToSet points_to = this->_function_pointer->get(ptr_var).points_to(); if (points_to.is_top() || points_to.is_bottom()) { return; } std::copy(points_to.begin(), points_to.end(), std::back_inserter(callees)); } else if (auto cst = dyn_cast< ar::FunctionPointerConstant >(called)) { callees.push_back(_ctx.mem_factory->get_function(cst->function())); } else { // undefined, null, inline asm, global or local variable return; } // Add pointer constraints for each possible callee for (MemoryLocation* mem : callees) { // Check if the callee is a function if (!isa< FunctionMemoryLocation >(mem)) { continue; } ar::Function* fun = cast< FunctionMemoryLocation >(mem)->function(); if (!ar::TypeVerifier::is_valid_call(s, fun->type())) { // Ill-formed function call, ignore callee. // This could be because of an imprecision of the pointer analysis. continue; } if (fun->is_declaration()) { // External call this->process_extern_call(s, fun); } else if (fun->is_definition()) { this->process_intern_call(s, fun); } else { ikos_unreachable("unreachable"); } } } void process_extern_call(ar::CallBase* s, ar::Function* fun) { if (fun->is_intrinsic()) { this->process_intrinsic_call(s, fun->intrinsic_id()); } else { // nothing to do } } void process_intrinsic_call(ar::CallBase* s, ar::Intrinsic::ID id) { switch (id) { case ar::Intrinsic::MemoryCopy: case ar::Intrinsic::MemoryMove: { this->process_mem_copy(s); } break; case ar::Intrinsic::MemorySet: case ar::Intrinsic::VarArgStart: case ar::Intrinsic::VarArgEnd: case ar::Intrinsic::VarArgGet: case ar::Intrinsic::VarArgCopy: case ar::Intrinsic::StackSave: case ar::Intrinsic::StackRestore: case ar::Intrinsic::LifetimeStart: case ar::Intrinsic::LifetimeEnd: case ar::Intrinsic::EhTypeidFor: case ar::Intrinsic::Trap: break; // do nothing // case ar::Intrinsic::IkosAssert: case ar::Intrinsic::IkosAssume: case ar::Intrinsic::IkosNonDet: case ar::Intrinsic::IkosCounterInit: case ar::Intrinsic::IkosCounterIncr: case ar::Intrinsic::IkosCheckMemAccess: case ar::Intrinsic::IkosCheckStringAccess: case ar::Intrinsic::IkosAssumeMemSize: case ar::Intrinsic::IkosForgetMemory: case ar::Intrinsic::IkosAbstractMemory: case ar::Intrinsic::IkosWatchMemory: case ar::Intrinsic::IkosPartitioningVar: case ar::Intrinsic::IkosPartitioningJoin: case ar::Intrinsic::IkosPartitioningDisable: case ar::Intrinsic::IkosPrintInvariant: case ar::Intrinsic::IkosPrintValues: break; // do nothing // case ar::Intrinsic::LibcMalloc: case ar::Intrinsic::LibcCalloc: case ar::Intrinsic::LibcValloc: case ar::Intrinsic::LibcAlignedAlloc: case ar::Intrinsic::LibcRealloc: { this->process_dyn_alloc(s); } break; case ar::Intrinsic::LibcFree: case ar::Intrinsic::LibcAbs: case ar::Intrinsic::LibcRand: case ar::Intrinsic::LibcSrand: case ar::Intrinsic::LibcExit: case ar::Intrinsic::LibcAbort: break; // do nothing // case ar::Intrinsic::LibcErrnoLocation: { this->process_errno_location(s); } break; // case ar::Intrinsic::LibcOpen: break; // do nothing // case ar::Intrinsic::LibcClose: case ar::Intrinsic::LibcRead: case ar::Intrinsic::LibcWrite: break; // do nothing // case ar::Intrinsic::LibcGets: case ar::Intrinsic::LibcFgets: { this->assign_call_result(s, s->argument(0)); } break; case ar::Intrinsic::LibcGetc: case ar::Intrinsic::LibcFgetc: case ar::Intrinsic::LibcGetchar: case ar::Intrinsic::LibcPuts: case ar::Intrinsic::LibcFputs: case ar::Intrinsic::LibcPutc: case ar::Intrinsic::LibcFputc: case ar::Intrinsic::LibcPrintf: case ar::Intrinsic::LibcFprintf: case ar::Intrinsic::LibcSprintf: case ar::Intrinsic::LibcSnprintf: case ar::Intrinsic::LibcScanf: case ar::Intrinsic::LibcFscanf: case ar::Intrinsic::LibcSscanf: break; // do nothing case ar::Intrinsic::LibcFopen: { this->process_dyn_alloc(s); } break; case ar::Intrinsic::LibcFclose: case ar::Intrinsic::LibcFflush: break; // do nothing // case ar::Intrinsic::LibcStrlen: case ar::Intrinsic::LibcStrnlen: break; // do nothing case ar::Intrinsic::LibcStrcpy: case ar::Intrinsic::LibcStrncpy: case ar::Intrinsic::LibcStrcat: case ar::Intrinsic::LibcStrncat: { this->assign_call_result(s, s->argument(0)); } break; case ar::Intrinsic::LibcStrcmp: case ar::Intrinsic::LibcStrncmp: break; // do nothing case ar::Intrinsic::LibcStrstr: case ar::Intrinsic::LibcStrchr: { this->process_string_search(s); } break; case ar::Intrinsic::LibcStrdup: case ar::Intrinsic::LibcStrndup: { this->process_dyn_alloc(s); } break; case ar::Intrinsic::LibcStrcpyCheck: { this->assign_call_result(s, s->argument(0)); } break; case ar::Intrinsic::LibcMemoryCopyCheck: case ar::Intrinsic::LibcMemoryMoveCheck: { this->process_mem_copy(s); this->assign_call_result(s, s->argument(0)); } break; case ar::Intrinsic::LibcMemorySetCheck: case ar::Intrinsic::LibcStrcatCheck: { this->assign_call_result(s, s->argument(0)); } break; case ar::Intrinsic::LibcppNew: case ar::Intrinsic::LibcppNewArray: { this->process_dyn_alloc(s); } break; case ar::Intrinsic::LibcppDelete: case ar::Intrinsic::LibcppDeleteArray: break; // do nothing case ar::Intrinsic::LibcppAllocateException: { this->process_dyn_alloc(s); } break; case ar::Intrinsic::LibcppFreeException: case ar::Intrinsic::LibcppThrow: break; // do nothing case ar::Intrinsic::LibcppBeginCatch: { this->assign_call_result(s, s->argument(0)); } break; case ar::Intrinsic::LibcppEndCatch: break; // do nothing default: { ikos_unreachable("unreachable"); } break; } } void process_mem_copy(ar::CallBase* s) { const ScalarLit& dest = this->_lit_factory.get_scalar(s->argument(0)); const ScalarLit& src = this->_lit_factory.get_scalar(s->argument(1)); if (!src.is_pointer_var() || !dest.is_pointer_var()) { return; } this->mem_copy(dest.var(), src.var()); } void process_dyn_alloc(ar::CallBase* s) { if (!s->has_result()) { return; } // This analysis is context insensitive CallContext* context = _ctx.call_context_factory->get_empty(); MemoryLocation* dyn_addr = _ctx.mem_factory->get_dyn_alloc(s, context); Variable* var = _ctx.var_factory->get_internal(s->result()); this->_csts.add(AssignCst::create(var, AddrOp::create(dyn_addr, zero()))); } void assign_call_result(ar::CallBase* s, ar::Value* operand) { if (!s->has_result()) { return; } this->assign(this->_lit_factory.get(s->result()), this->_lit_factory.get(operand)); } void process_string_search(ar::CallBase* s) { if (!s->has_result()) { return; } const ScalarLit& lhs = this->_lit_factory.get_scalar(s->result()); const ScalarLit& ptr = this->_lit_factory.get_scalar(s->argument(0)); if (!lhs.is_pointer_var() || !ptr.is_pointer_var()) { return; } auto top = MachineIntInterval::top(this->_data_layout.pointers.bit_width, Unsigned); this->_csts.add( AssignCst::create(lhs.var(), VarOp::create(ptr.var(), top))); } void process_errno_location(ar::CallBase* s) { if (!s->has_result()) { return; } MemoryLocation* addr = _ctx.mem_factory->get_libc_errno(); Variable* var = _ctx.var_factory->get_internal(s->result()); this->_csts.add(AssignCst::create(var, AddrOp::create(addr, zero()))); } void process_intern_call(ar::CallBase* s, ar::Function* fun) { // Handle parameters auto param_it = fun->param_begin(); auto param_et = fun->param_end(); auto arg_it = s->arg_begin(); auto arg_et = s->arg_end(); for (; param_it != param_et && arg_it != arg_et; ++param_it, ++arg_it) { this->assign(this->_lit_factory.get(*param_it), this->_lit_factory.get(*arg_it)); } // Handle result if (!s->has_result()) { return; } Variable* ret_var = _ctx.var_factory->get_return(fun); const Literal& lhs = this->_lit_factory.get(s->result()); if (lhs.is_scalar()) { if (lhs.scalar().is_pointer_var()) { this->_csts.add(AssignCst::create(lhs.scalar().var(), VarOp::create(ret_var, zero()))); } } else if (lhs.is_aggregate()) { Variable* lhs_ptr = this->aggregate_pointer(lhs.aggregate()); this->_csts.add( AssignCst::create(ret_var, VarOp::create(lhs_ptr, zero()))); } else { ikos_unreachable("unreachable"); } } }; // end class BasicBlockVisitor /// @} }; // end class PointerConstraintsGenerator } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/pointer/function.hpp000066400000000000000000000071231473507761200305240ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Function pointer analysis * * This pass is intended to be used as a pre-step for other analyses. * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Compute points-to set of function pointers for a whole bundle /// /// This pass is intended to be used as a pre-step for other analyses. class FunctionPointerAnalysis { private: /// \brief Analysis context Context& _ctx; /// \brief Pointer information PointerInfo _info; public: /// \brief Constructor explicit FunctionPointerAnalysis(Context& ctx); /// \brief No copy constructor FunctionPointerAnalysis(const FunctionPointerAnalysis&) = delete; /// \brief No move constructor FunctionPointerAnalysis(FunctionPointerAnalysis&&) = delete; /// \brief No copy assignment operator FunctionPointerAnalysis& operator=(const FunctionPointerAnalysis&) = delete; /// \brief No move assignment operator FunctionPointerAnalysis& operator=(FunctionPointerAnalysis&&) = delete; /// \brief Destructor ~FunctionPointerAnalysis(); /// \brief Run the analysis void run(); /// \brief Dump the function pointer analysis results, for debugging purpose void dump(std::ostream& o) const; /// \brief Return the result of the analysis const PointerInfo& results() const { return this->_info; } }; // end class FunctionPointerAnalysis } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/pointer/pointer.hpp000066400000000000000000000102051473507761200303520ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Pointer analysis * * This pass is intended to be used as a pre-step for other analyses. * It computes first intra-procedurally numerical invariants for each function. * Then, it generates nonuniform points-to constraints in a flow-insensitive * manner, solves them, and finally stores the results for subsequent analyses. * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace analyzer { /// \brief Pointer analysis for a whole bundle /// /// This pass is intended to be used as a pre-step for other analyses. It /// computes first intra-procedurally numerical invariants for each function. /// Then, it generates nonuniform points-to constraints in a flow-insensitive /// manner, solves them, and finally stores the results for subsequent analyses. class PointerAnalysis { private: /// \brief Analysis context Context& _ctx; /// \brief Previously computed function pointer analysis const FunctionPointerAnalysis& _function_pointer; /// \brief Pointer information PointerInfo _info; public: /// \brief Constructor PointerAnalysis(Context& ctx, const FunctionPointerAnalysis& function_pointer); /// \brief No copy constructor PointerAnalysis(const PointerAnalysis&) = delete; /// \brief No move constructor PointerAnalysis(PointerAnalysis&&) = delete; /// \brief No copy assignment operator PointerAnalysis& operator=(const PointerAnalysis&) = delete; /// \brief No move assignment operator PointerAnalysis& operator=(PointerAnalysis&&) = delete; /// \brief Destructor ~PointerAnalysis(); /// \brief Run the analysis void run(); /// \brief Dump the pointer analysis results, for debugging purpose void dump(std::ostream& o) const; /// \brief Return the result of the analysis const PointerInfo& results() const { return this->_info; } }; // end class PointerAnalysis } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/pointer/value.hpp000066400000000000000000000100761473507761200300140ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Pointer abstractions * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Set of memory locations using PointsToSet = core::PointsToSet< MemoryLocation* >; /// \brief Machine integer interval using MachineIntInterval = core::machine_int::Interval; /// \brief Pointer abstraction using a points-to set and an interval using PointerAbsValue = core::PointerAbsValue< MemoryLocation* >; /// \brief Hold pointer information class PointerInfo { private: /// \brief Map from variable to pointer value using PointerMap = std::unordered_map< Variable*, PointerAbsValue >; private: /// \brief Map from variables to pointer abstract values PointerMap _map; /// \brief Data layout const ar::DataLayout& _data_layout; public: /// \brief Constructor explicit PointerInfo(const ar::DataLayout& data_layout); /// \brief No copy constructor PointerInfo(const PointerInfo&) = delete; /// \brief No move constructor PointerInfo(PointerInfo&&) = delete; /// \brief No copy assignment operator PointerInfo& operator=(const PointerInfo&) = delete; /// \brief No move assignment operator PointerInfo& operator=(PointerInfo&&) = delete; /// \brief Destructor ~PointerInfo(); /// \brief Clear all information void clear(); /// \brief Return information about the given pointer PointerAbsValue get(Variable* v) const; /// \brief Insert an information about a pointer void insert(Variable* v, const PointerAbsValue&); /// \brief Dump the pointer constraints, for debugging purpose void dump(std::ostream&) const; }; // end class PointerInfo } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/result.hpp000066400000000000000000000053251473507761200265370ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Result type definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Represents the result of an analysis enum class Result { Ok, Warning, Error, Unreachable }; /// \brief Return a string representing a result inline const char* result_str(Result result) { switch (result) { case Result::Ok: return "ok"; case Result::Warning: return "warning"; case Result::Error: return "error"; case Result::Unreachable: return "unreachable"; default: { ikos_unreachable("unreachable"); } } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/000077500000000000000000000000001473507761200256175ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/abstract_domain.hpp000066400000000000000000000057611473507761200314730ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Abstract domain for the value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { /// \brief Memory abstract domain for the value analysis using MemoryAbstractDomain = core::memory::PolymorphicDomain< Variable*, MemoryLocation* >; /// \brief Abstract domain for the value analysis using AbstractDomain = core::exception::ExceptionDomain< MemoryAbstractDomain >; /// \brief Create the bottom abstract value AbstractDomain make_bottom_abstract_value(Context& ctx); /// \brief Create the initial abstract value AbstractDomain make_initial_abstract_value(Context& ctx); } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/global_variable.hpp000066400000000000000000000075201473507761200314410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Helpers for global variables for the value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { /// \brief Return true if the given global variable should be initialized, /// according to the given policy bool is_initialized(ar::GlobalVariable* gv, GlobalsInitPolicy policy); /// \brief Return the global constructors, in call order, given the /// ar.global_ctors variable std::vector< std::pair< ar::Function*, MachineInt > > global_ctors( ar::GlobalVariable* gv); /// \brief Return the global destructors, in call order, given the /// ar.global_dtors variable std::vector< std::pair< ar::Function*, MachineInt > > global_dtors( ar::GlobalVariable* gv); /// \brief Call execution engine for global variable initializer class GlobalVarCallExecutionEngine final : public CallExecutionEngine { public: ikos_attribute_unused void exec_exit(ar::Function* /*fun*/) override {} ikos_attribute_noreturn void exec(ar::Call* /*call*/) override { ikos_unreachable("call statement in global variable initializer"); } ikos_attribute_noreturn void exec(ar::Invoke* /*invoke*/) override { ikos_unreachable("invoke statement in global variable initializer"); } ikos_attribute_noreturn void exec(ar::ReturnValue* /*ret*/) override { ikos_unreachable("return statement in global variable initializer"); } }; // end class GlobalVarCallExecutionEngine } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/000077500000000000000000000000001473507761200310215ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/concurrent/000077500000000000000000000000001473507761200332035ustar00rootroot00000000000000analysis.hpp000066400000000000000000000061671473507761200354720ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/concurrent/******************************************************************************* * * \file * \brief Concurrent interprocedural value analysis * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace concurrent { /// \brief Concurrent interprocedural value analysis /// /// Performs a top-down analysis with a memory abstract domain. class Analysis { private: /// \brief Analysis context Context& _ctx; public: /// \brief Constructor explicit Analysis(Context& ctx); /// \brief No copy constructor Analysis(const Analysis&) = delete; /// \brief No move constructor Analysis(Analysis&&) = delete; /// \brief No copy assignment operator Analysis& operator=(const Analysis&) = delete; /// \brief No move assignment operator Analysis& operator=(Analysis&&) = delete; /// \brief Destructor ~Analysis(); /// \brief Run the analysis void run(); }; // end class Analysis } // end namespace concurrent } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.hpp000066400000000000000000000170311473507761200374040ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/concurrent/******************************************************************************* * * \file * \brief Concurrent fixpoint on a function body * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace concurrent { /// \brief Concurrent interprocedural fixpoint on a function body class FunctionFixpoint final : public core::InterleavedConcurrentFwdFixpointIterator< ar::Code*, AbstractDomain > { private: /// \brief Parent class using FwdFixpointIterator = core::InterleavedConcurrentFwdFixpointIterator< ar::Code*, AbstractDomain >; /// \brief Function fixpoint cache of callees using FixpointCacheT = FixpointCache< FunctionFixpoint, AbstractDomain >; private: /// \brief Analysis context Context& _ctx; /// \brief Analyzed function ar::Function* _function; /// \brief Current call context CallContext* _call_context; /// \brief Fixpoint parameters const CodeFixpointParameters& _fixpoint_parameters; /// \brief List of property checks to run const std::vector< std::unique_ptr< Checker > >& _checkers; /// \brief Mutex for _exit_invariant and _return_stmt std::mutex _mutex; /// \brief Invariant at the end of the function AbstractDomain _exit_invariant; /// \brief Return statement, or null ar::ReturnValue* _return_stmt; /// \brief Function fixpoint cache of callees FixpointCacheT _callees_cache; public: /// \brief Constructor for an entry point /// /// \param ctx Analysis context /// \param checkers List of checkers to run /// \param entry_point Function to analyze FunctionFixpoint(Context& ctx, const std::vector< std::unique_ptr< Checker > >& checkers, ar::Function* entry_point); /// \brief Constructor for a callee /// /// \param ctx Analysis context /// \param caller Parent function fixpoint /// \param call Call statement /// \param callee Called function FunctionFixpoint(Context& ctx, const FunctionFixpoint& caller, ar::CallBase* call, ar::Function* callee); /// \brief Compute the fixpoint void run(AbstractDomain inv) override; /// \brief Extrapolate the new state after an increasing iteration AbstractDomain extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Refine the new state after a decreasing iteration AbstractDomain refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Check if the decreasing iterations fixpoint is reached bool is_decreasing_iterations_fixpoint(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Propagate the invariant through the basic block AbstractDomain analyze_node(ar::BasicBlock* bb, AbstractDomain pre) override; /// \brief Propagate the invariant through an edge AbstractDomain analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) override; /// \brief Process the computed abstract value for a node void process_pre(ar::BasicBlock* bb, const AbstractDomain& pre) override; /// \brief Process the computed abstract value for a node void process_post(ar::BasicBlock* bb, const AbstractDomain& post) override; /// \brief Run the checks with the previously computed fix-point void run_checks(); /// \name Required by InlineCallExecutionEngine /// @{ /// \brief Return the function ar::Function* function() const { return this->_function; } /// \brief Return the call context CallContext* call_context() const { return this->_call_context; } /// \brief Return the exit invariant, or bottom const AbstractDomain& exit_invariant() const { return this->_exit_invariant; } /// \brief Set the exit invariant void set_exit_invariant(AbstractDomain invariant) { invariant.normalize(); std::lock_guard< std::mutex > lock(this->_mutex); this->_exit_invariant = std::move(invariant); } /// \brief Return the return statement, or null ar::ReturnValue* return_stmt() const { return this->_return_stmt; } /// \brief Set the return statement void set_return_stmt(ar::ReturnValue* s) { std::lock_guard< std::mutex > lock(this->_mutex); ikos_assert_msg(this->_return_stmt == nullptr || this->_return_stmt == s, "code has more than one return statement"); this->_return_stmt = s; } /// @} }; // end class FunctionFixpoint } // end namespace concurrent } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos init_invariant.hpp000066400000000000000000000051761473507761200345020ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/******************************************************************************* * * \file * \brief Initial invariant for the interprocedural value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { /// \brief Initialize argc and argv AbstractDomain init_main_invariant(Context& ctx, ar::Function* main, AbstractDomain inv); } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/sequential/000077500000000000000000000000001473507761200331735ustar00rootroot00000000000000analysis.hpp000066400000000000000000000061331473507761200354530ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/sequential/******************************************************************************* * * \file * \brief Sequential interprocedural value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { /// \brief Sequential interprocedural value analysis /// /// Performs a top-down analysis with a memory abstract domain. class Analysis { private: /// \brief Analysis context Context& _ctx; public: /// \brief Constructor explicit Analysis(Context& ctx); /// \brief No copy constructor Analysis(const Analysis&) = delete; /// \brief No move constructor Analysis(Analysis&&) = delete; /// \brief No copy assignment operator Analysis& operator=(const Analysis&) = delete; /// \brief No move assignment operator Analysis& operator=(Analysis&&) = delete; /// \brief Destructor ~Analysis(); /// \brief Run the analysis void run(); }; // end class Analysis } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.hpp000066400000000000000000000176751473507761200374120ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/sequential/******************************************************************************* * * \file * \brief Sequential interprocedural fixpoint on a function body * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include "ikos/ar/format/namer.hpp" #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { /// \brief Sequential interprocedural fixpoint on a function body class FunctionFixpoint final : public core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomain > { private: /// \brief Parent class using FwdFixpointIterator = core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomain >; /// \brief Function fixpoint cache of callees using FixpointCacheT = FixpointCache< FunctionFixpoint, AbstractDomain >; private: /// \brief Analysis context Context& _ctx; /// \brief Analyzed function ar::Function* _function; /// \brief Current call context CallContext* _call_context; /// \brief Fixpoint parameters const CodeFixpointParameters& _fixpoint_parameters; /// \brief List of property checks to run const std::vector< std::unique_ptr< Checker > >& _checkers; /// \brief Invariant at the end of the function AbstractDomain _exit_invariant; /// \brief Return statement, or null ar::ReturnValue* _return_stmt; /// \brief Function fixpoint cache of callees FixpointCacheT _callees_cache; /// \brief Progress logger ProgressLogger& _logger; std::unique_ptr< ar::Namer > _namer; public: /// \brief Constructor for an entry point /// /// \param ctx Analysis context /// \param checkers List of checkers to run /// \param entry_point Function to analyze FunctionFixpoint(Context& ctx, const std::vector< std::unique_ptr< Checker > >& checkers, ProgressLogger& logger, ar::Function* entry_point); /// \brief Constructor for a callee /// /// \param ctx Analysis context /// \param caller Parent function fixpoint /// \param call Call statement /// \param callee Called function FunctionFixpoint(Context& ctx, const FunctionFixpoint& caller, ar::CallBase* call, ar::Function* callee); virtual ~FunctionFixpoint() override; /// \brief Compute the fixpoint void run(AbstractDomain inv) override; /// \brief Extrapolate the new state after an increasing iteration AbstractDomain extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Refine the new state after a decreasing iteration AbstractDomain refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Check if the decreasing iterations fixpoint is reached bool is_decreasing_iterations_fixpoint(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Propagate the invariant through the basic block AbstractDomain analyze_node(ar::BasicBlock* bb, AbstractDomain pre) override; /// \brief Propagate the invariant through an edge AbstractDomain analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) override; /// \brief Notify the beginning of the analysis of a cycle void notify_enter_cycle(ar::BasicBlock* head) override; /// \brief Notify the beginning of an iteration on a cycle void notify_cycle_iteration(ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) override; /// \brief Notify the end of the analysis of a cycle void notify_leave_cycle(ar::BasicBlock* head) override; /// \brief Process the computed abstract value for a node void process_pre(ar::BasicBlock* bb, const AbstractDomain& pre) override; /// \brief Process the computed abstract value for a node void process_post(ar::BasicBlock* bb, const AbstractDomain& post) override; /// \brief Run the checks with the previously computed fix-point void run_checks(); /// \name Required by InlineCallExecutionEngine /// @{ /// \brief Return the function ar::Function* function() const { return this->_function; } /// \brief Return the call context CallContext* call_context() const { return this->_call_context; } /// \brief Return the exit invariant, or bottom const AbstractDomain& exit_invariant() const { return this->_exit_invariant; } /// \brief Set the exit invariant void set_exit_invariant(AbstractDomain invariant) { invariant.normalize(); this->_exit_invariant = std::move(invariant); } /// \brief Return the return statement, or null ar::ReturnValue* return_stmt() const { return this->_return_stmt; } /// \brief Set the return statement void set_return_stmt(ar::ReturnValue* s) { ikos_assert_msg(this->_return_stmt == nullptr || this->_return_stmt == s, "code has more than one return statement"); this->_return_stmt = s; } /// @} }; // end class FunctionFixpoint } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos global_init_fixpoint.hpp000066400000000000000000000103501473507761200400270ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/sequential/******************************************************************************* * * \file * \brief Fixpoint on a global variable initializer * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { /// \brief Fixpoint on a global variable initializer class GlobalVarInitializerFixpoint final : public core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomain > { private: /// \brief Parent class using FwdFixpointIterator = core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomain >; /// \brief Numerical execution engine using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; private: /// \brief Global variable ar::GlobalVariable* _gv; /// \brief Analysis context Context& _ctx; /// \brief Empty call context CallContext* _empty_call_context; public: /// \brief Constructor GlobalVarInitializerFixpoint(Context& ctx, ar::GlobalVariable* gv); /// \brief Compute the fixpoint void run(AbstractDomain inv) override; /// \brief Propagate the invariant through the basic block AbstractDomain analyze_node(ar::BasicBlock* bb, AbstractDomain pre) override; /// \brief Propagate the invariant through an edge AbstractDomain analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) override; /// \brief Process the computed abstract value for a node void process_pre(ar::BasicBlock* bb, const AbstractDomain& pre) override; /// \brief Process the computed abstract value for a node void process_post(ar::BasicBlock* bb, const AbstractDomain& post) override; /// \brief Return the invariant at the end of the exit node const AbstractDomain& exit_invariant() const; }; // end class GlobalVarInitializerFixpoint } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos progress.hpp000066400000000000000000000247611473507761200355030ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/interprocedural/sequential/******************************************************************************* * * \file * \brief Progress logging utilities for the interprocedural value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { /// \brief Base class for interprocedural value analysis progress loggers class ProgressLogger : public Logger { protected: /// \brief Analysis context Context& _ctx; public: /// \brief Constructor ProgressLogger(std::ostream& out, Context& ctx); /// \brief Start analyzing a cycle /// /// \param head Head of the cycle virtual void start_cycle(ar::BasicBlock* head) = 0; /// \brief Start a cycle iteration /// /// \param head Head of the cycle /// \param iteration Number of iteration /// \param kind Increasing or Decreasing virtual void start_cycle_iter(ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) = 0; /// \brief End analyzing a cycle /// /// \param head Head of the cycle virtual void end_cycle(ar::BasicBlock* head) = 0; /// \brief Start analyzing a called function virtual void start_callee(CallContext* call_context, ar::Function* fun) = 0; /// \brief End analyzing a called function virtual void end_callee(CallContext* call_context, ar::Function* fun) = 0; }; // end class ProgressLogger /// \brief Interactive interprocedural value analysis progress logger class InteractiveProgressLogger final : public ProgressLogger { private: /// \brief Refresh rate of the stack frame static constexpr const std::chrono::seconds RefreshRate = std::chrono::seconds(2); private: /// \brief Represents a call frame struct CallFrame { CallContext* call_context; ar::Function* function; bool operator==(const CallFrame& o) const { return this->call_context == o.call_context && this->function == o.function; } }; /// \brief Represents a cycle frame struct CycleFrame { ar::BasicBlock* head; unsigned iteration; core::FixpointIterationKind kind; bool operator==(const CycleFrame& o) const { return this->head == o.head && this->iteration == o.iteration && this->kind == o.kind; } }; /// \brief Represents a frame using Frame = boost::variant< CallFrame, CycleFrame >; private: /// \brief Number of columns in the output stream std::size_t _out_columns; /// \brief Thread that displays the current progress on a regular basis std::thread _thread; /// \brief Whether the thread is running std::atomic_bool _running; /// \brief Condition variable to notify the thread to stop running std::condition_variable _event; /// \brief Mutex std::mutex _mutex; /// \brief Current stack frame std::vector< Frame > _current_stack_frame; /// \brief Displayed stack frame std::vector< Frame > _displayed_stack_frame; public: /// \brief Constructor /// /// \param out Output stream /// \param ctx Analysis context /// \param out_columns Number of columns in the output stream InteractiveProgressLogger(std::ostream& out, Context& ctx, std::size_t out_columns); /// \brief No copy constructor InteractiveProgressLogger(const InteractiveProgressLogger&) = delete; /// \brief No move constructor InteractiveProgressLogger(InteractiveProgressLogger&&) = delete; /// \brief No copy assignment operator InteractiveProgressLogger& operator=(const InteractiveProgressLogger&) = delete; /// \brief No move assignment operator InteractiveProgressLogger& operator=(InteractiveProgressLogger&&) = delete; /// \brief Destructor ~InteractiveProgressLogger() override; /// \brief Start analyzing a cycle void start_cycle(ar::BasicBlock* head) override; /// \brief Start a cycle iteration void start_cycle_iter(ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) override; /// \brief End analyzing a cycle void end_cycle(ar::BasicBlock* head) override; /// \brief Start analyzing a called function void start_callee(CallContext* call_context, ar::Function* fun) override; /// \brief End analyzing a called function void end_callee(CallContext* call_context, ar::Function* fun) override; /// \brief This is called once when the logger becomes active void start_logger() override; /// \brief This is called once when the logger becomes inactive void end_logger() override; /// \brief This is called once before writing a log message void start_message() override; /// \brief This is called once after writing a log message void end_message() override; private: /// \brief Run in a thread void run(); /// \brief Print the current stack frame /// /// Precondition: the current thread owns the mutex void print_stack_frame(); /// \brief Print a frame /// /// Precondition: the current thread owns the mutex void print_frame(const Frame& frame); /// \brief Clear the displayed stack frame /// /// Precondition: the current thread owns the mutex void clear_displayed_stack_frame(); }; // end class InteractiveProgressLogger /// \brief Linear interprocedural value analysis progress logger class LinearProgressLogger final : public ProgressLogger { public: /// \brief Constructor LinearProgressLogger(std::ostream& out, Context& ctx); /// \brief Start analyzing a cycle void start_cycle(ar::BasicBlock* head) override; /// \brief Start a cycle iteration void start_cycle_iter(ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) override; /// \brief End analyzing a cycle void end_cycle(ar::BasicBlock* head) override; /// \brief Start analyzing a called function void start_callee(CallContext* call_context, ar::Function* fun) override; /// \brief End analyzing a called function void end_callee(CallContext* call_context, ar::Function* fun) override; /// \brief This is called once when the logger becomes active void start_logger() override; /// \brief This is called once when the logger becomes inactive void end_logger() override; /// \brief This is called once before writing a log message void start_message() override; /// \brief This is called once after writing a log message void end_message() override; }; // end class LinearProgressLogger /// \brief Progress logger that discards progress status class NoProgressLogger final : public ProgressLogger { public: /// \brief Constructor NoProgressLogger(std::ostream& out, Context& ctx); /// \brief Start analyzing a cycle void start_cycle(ar::BasicBlock* head) override; /// \brief Start a cycle iteration void start_cycle_iter(ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) override; /// \brief End analyzing a cycle void end_cycle(ar::BasicBlock* head) override; /// \brief Start analyzing a called function void start_callee(CallContext* call_context, ar::Function* fun) override; /// \brief End analyzing a called function void end_callee(CallContext* call_context, ar::Function* fun) override; /// \brief This is called once when the logger becomes active void start_logger() override; /// \brief This is called once when the logger becomes inactive void end_logger() override; /// \brief This is called once before writing a log message void start_message() override; /// \brief This is called once after writing a log message void end_message() override; }; // end class NoProgressLogger /// \brief Create a progress logger /// /// \param ctx Analysis context /// \param opt Progress option /// \param level Log level std::unique_ptr< ProgressLogger > make_progress_logger(Context& ctx, ProgressOption opt, LogLevel level); } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/intraprocedural/000077500000000000000000000000001473507761200310155ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/intraprocedural/concurrent/000077500000000000000000000000001473507761200331775ustar00rootroot00000000000000analysis.hpp000066400000000000000000000060631473507761200354610ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/intraprocedural/concurrent/******************************************************************************* * * \file * \brief Concurrent intraprocedural value analysis * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace concurrent { /// \brief Concurrent intraprocedural value analysis class Analysis { private: /// \brief Analysis context Context& _ctx; public: /// \brief Constructor explicit Analysis(Context& ctx); /// \brief No copy constructor Analysis(const Analysis&) = delete; /// \brief No move constructor Analysis(Analysis&&) = delete; /// \brief No copy assignment operator Analysis& operator=(const Analysis&) = delete; /// \brief No move assignment operator Analysis& operator=(Analysis&&) = delete; /// \brief Destructor ~Analysis(); /// \brief Run the analysis void run(); }; // end class Analysis } // end namespace concurrent } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.hpp000066400000000000000000000125211473507761200373770ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/intraprocedural/concurrent/******************************************************************************* * * \file * \brief Concurrent intraprocedural fixpoint on a function body * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace concurrent { /// \brief Sequential intraprocedural fixpoint on a function body class FunctionFixpoint final : public core::InterleavedConcurrentFwdFixpointIterator< ar::Code*, AbstractDomain > { private: /// \brief Parent class using FwdFixpointIterator = core::InterleavedConcurrentFwdFixpointIterator< ar::Code*, AbstractDomain >; private: /// \brief Analysis context Context& _ctx; /// \brief Empty call context CallContext* _empty_call_context; /// \brief Fixpoint parameters const CodeFixpointParameters& _fixpoint_parameters; public: /// \brief Create a function fixpoint iterator FunctionFixpoint(Context& ctx, ar::Function* function); /// \brief Compute the fixpoint void run(AbstractDomain inv) override; /// \brief Extrapolate the new state after an increasing iteration AbstractDomain extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Refine the new state after a decreasing iteration AbstractDomain refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Check if the decreasing iterations fixpoint is reached bool is_decreasing_iterations_fixpoint(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Propagate the invariant through the basic block AbstractDomain analyze_node(ar::BasicBlock* bb, AbstractDomain pre) override; /// \brief Propagate the invariant through an edge AbstractDomain analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) override; /// \brief Process the computed abstract value for a node void process_pre(ar::BasicBlock* bb, const AbstractDomain& pre) override; /// \brief Process the computed abstract value for a node void process_post(ar::BasicBlock* bb, const AbstractDomain& post) override; /// \brief Run the checks with the previously computed fix-point void run_checks(const std::vector< std::unique_ptr< Checker > >& checkers); }; // end class FunctionFixpoint } // end namespace concurrent } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/intraprocedural/sequential/000077500000000000000000000000001473507761200331675ustar00rootroot00000000000000analysis.hpp000066400000000000000000000060271473507761200354510ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/intraprocedural/sequential/******************************************************************************* * * \file * \brief Sequential intraprocedural value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace sequential { /// \brief Sequential intraprocedural value analysis class Analysis { private: /// \brief Analysis context Context& _ctx; public: /// \brief Constructor explicit Analysis(Context& ctx); /// \brief No copy constructor Analysis(const Analysis&) = delete; /// \brief No move constructor Analysis(Analysis&&) = delete; /// \brief No copy assignment operator Analysis& operator=(const Analysis&) = delete; /// \brief No move assignment operator Analysis& operator=(Analysis&&) = delete; /// \brief Destructor ~Analysis(); /// \brief Run the analysis void run(); }; // end class Analysis } // end namespace sequential } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.hpp000066400000000000000000000122361473507761200373720ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/intraprocedural/sequential/******************************************************************************* * * \file * \brief Sequential intraprocedural fixpoint on a function body * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace sequential { /// \brief Sequential intraprocedural fixpoint on a function body class FunctionFixpoint final : public core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomain > { private: /// \brief Parent class using FwdFixpointIterator = core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomain >; private: /// \brief Analysis context Context& _ctx; /// \brief Empty call context CallContext* _empty_call_context; /// \brief Fixpoint parameters const CodeFixpointParameters& _fixpoint_parameters; public: /// \brief Create a function fixpoint iterator FunctionFixpoint(Context& ctx, ar::Function* function); /// \brief Compute the fixpoint void run(AbstractDomain inv) override; /// \brief Extrapolate the new state after an increasing iteration AbstractDomain extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Refine the new state after a decreasing iteration AbstractDomain refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Check if the decreasing iterations fixpoint is reached bool is_decreasing_iterations_fixpoint(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) override; /// \brief Propagate the invariant through the basic block AbstractDomain analyze_node(ar::BasicBlock* bb, AbstractDomain pre) override; /// \brief Propagate the invariant through an edge AbstractDomain analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) override; /// \brief Process the computed abstract value for a node void process_pre(ar::BasicBlock* bb, const AbstractDomain& pre) override; /// \brief Process the computed abstract value for a node void process_post(ar::BasicBlock* bb, const AbstractDomain& post) override; /// \brief Run the checks with the previously computed fix-point void run_checks(const std::vector< std::unique_ptr< Checker > >& checkers); }; // end class FunctionFixpoint } // end namespace sequential } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/value/machine_int_domain.hpp000066400000000000000000000140321473507761200321350ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Machine integer abstract domain used by the value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace analyzer { namespace value { /// \brief Machine integer abstract domain used for the value analysis using MachineIntAbstractDomain = core::machine_int::PolymorphicDomain< Variable* >; /// \name Constructors of machine integer abstract domains /// @{ MachineIntAbstractDomain make_top_machine_int_interval(); MachineIntAbstractDomain make_bottom_machine_int_interval(); MachineIntAbstractDomain make_top_machine_int_congruence(); MachineIntAbstractDomain make_bottom_machine_int_congruence(); MachineIntAbstractDomain make_top_machine_int_interval_congruence(); MachineIntAbstractDomain make_bottom_machine_int_interval_congruence(); MachineIntAbstractDomain make_top_machine_int_dbm(); MachineIntAbstractDomain make_bottom_machine_int_dbm(); MachineIntAbstractDomain make_top_machine_int_var_pack_dbm(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_dbm(); MachineIntAbstractDomain make_top_machine_int_var_pack_dbm_congruence(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_dbm_congruence(); MachineIntAbstractDomain make_top_machine_int_gauge(); MachineIntAbstractDomain make_bottom_machine_int_gauge(); MachineIntAbstractDomain make_top_machine_int_gauge_interval_congruence(); MachineIntAbstractDomain make_bottom_machine_int_gauge_interval_congruence(); MachineIntAbstractDomain make_top_machine_int_apron_interval(); MachineIntAbstractDomain make_bottom_machine_int_apron_interval(); MachineIntAbstractDomain make_top_machine_int_apron_octagon(); MachineIntAbstractDomain make_bottom_machine_int_apron_octagon(); MachineIntAbstractDomain make_top_machine_int_apron_polka_polyhedra(); MachineIntAbstractDomain make_bottom_machine_int_apron_polka_polyhedra(); MachineIntAbstractDomain make_top_machine_int_apron_polka_linear_equalities(); MachineIntAbstractDomain make_bottom_machine_int_apron_polka_linear_equalities(); MachineIntAbstractDomain make_top_machine_int_apron_ppl_polyhedra(); MachineIntAbstractDomain make_bottom_machine_int_apron_ppl_polyhedra(); MachineIntAbstractDomain make_top_machine_int_apron_ppl_linear_congruences(); MachineIntAbstractDomain make_bottom_machine_int_apron_ppl_linear_congruences(); MachineIntAbstractDomain make_top_machine_int_apron_pkgrid_polyhedra_lin_cong(); MachineIntAbstractDomain make_bottom_machine_int_apron_pkgrid_polyhedra_lin_cong(); MachineIntAbstractDomain make_top_machine_int_var_pack_apron_octagon(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_octagon(); MachineIntAbstractDomain make_top_machine_int_var_pack_apron_polka_polyhedra(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_polka_polyhedra(); MachineIntAbstractDomain make_top_machine_int_var_pack_apron_polka_linear_equalities(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_polka_linear_equalities(); MachineIntAbstractDomain make_top_machine_int_var_pack_apron_ppl_polyhedra(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_ppl_polyhedra(); MachineIntAbstractDomain make_top_machine_int_var_pack_apron_ppl_linear_congruences(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_ppl_linear_congruences(); MachineIntAbstractDomain make_top_machine_int_var_pack_apron_pkgrid_polyhedra_lin_cong(); MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_pkgrid_polyhedra_lin_cong(); /// @} /// \brief Create the top machine integer abstract value of the given choice MachineIntAbstractDomain make_top_machine_int_abstract_value( MachineIntDomainOption domain); /// \brief Create the bottom machine integer abstract value of the given choice MachineIntAbstractDomain make_bottom_machine_int_abstract_value( MachineIntDomainOption domain); } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/variable.hpp000066400000000000000000000532451473507761200270120ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Variable types and VariableFactory used by the analyses * * Author: Clement Decoodt * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Represents a variable, with a reference on the AR representation /// /// Variable is an abstract class, and implementation of the Variable generic /// object in the core. /// /// See ikos/core/semantic/variable.hpp /// It must be indexable (see ikos/core/semantic/indexable.hpp) /// It must be dumpable (see ikos/core/semantic/dumpable.hpp) /// It must implement machine_int::VariableTraits, /// see ikos/core/semantic/machine_int/variable.hpp /// It must implement scalar::VariableTraits, /// see ikos/core/semantic/scalar/variable.hpp /// It must implement memory::CellVariableTraits, /// see ikos/core/semantic/memory/value/cell_variable.hpp /// /// Variable has a 'kind', which is the type of variable it represents. /// The 'kind' is an element of VariableKind. /// /// Variable* should be passed everywhere. The factory that creates the Variable /// owns the pointer, so you don't need to free it. class Variable { public: /// \brief Kind of the variable enum VariableKind { _BeginArVariableKind, LocalVariableKind, GlobalVariableKind, InternalVariableKind, InlineAssemblyPointerVariableKind, FunctionPointerVariableKind, _EndArVariableKind, _BeginShadowVariableKind, CellVariableKind, OffsetVariableKind, AllocSizeVariableKind, ReturnVariableKind, NamedShadowVariableKind, UnnamedShadowVariableKind, _EndShadowVariableKind, }; protected: /// \brief Kind of the variable VariableKind _kind; /// \brief Type of the variable ar::Type* _type; /// \brief The offset variable, or nullptr if it is not a pointer std::unique_ptr< Variable > _offset_var; protected: /// \brief Protected constructor Variable(VariableKind kind, ar::Type* type); public: /// \brief No copy constructor Variable(const Variable&) = delete; /// \brief No move constructor Variable(Variable&&) = delete; /// \brief No copy assignment operator Variable& operator=(const Variable&) = delete; /// \brief No move assignment operator Variable& operator=(Variable&&) = delete; /// \brief Destructor virtual ~Variable(); /// \brief Return the kind of the object VariableKind kind() const { return this->_kind; } /// \brief Return the type of the variable ar::Type* type() const { return this->_type; } /// \brief Return the offset variable, or nullptr if it is not a pointer Variable* offset_var() const { return this->_offset_var.get(); } /// \brief Set the offset variable void set_offset_var(std::unique_ptr< Variable > offset_var) { this->_offset_var = std::move(offset_var); } /// \brief Dump the variable, for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class Variable /// \brief Local variable class LocalVariable final : public Variable { protected: /// \brief AR Local Variable ar::LocalVariable* _var; public: /// \brief Default constructor explicit LocalVariable(ar::LocalVariable* var); /// \brief Get the ar::LocalVariable* ar::LocalVariable* local_var() const { return this->_var; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == LocalVariableKind; } }; // end class LocalVariableKind /// \brief Global variable class GlobalVariable final : public Variable { protected: /// \brief AR Global Variable ar::GlobalVariable* _var; public: /// \brief Default constructor explicit GlobalVariable(ar::GlobalVariable* var); /// \brief Get the ar::GlobalVariable* ar::GlobalVariable* global_var() const { return this->_var; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == GlobalVariableKind; } }; // end class GlobalVariable /// \brief Internal variable class InternalVariable final : public Variable { protected: /// \brief AR Internal Variable ar::InternalVariable* _var; public: /// \brief Default constructor explicit InternalVariable(ar::InternalVariable* var); /// \brief Get the ar::InternalVariable* ar::InternalVariable* internal_var() const { return this->_var; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == InternalVariableKind; } }; // end class InternalVariable /// \brief Inline assembly pointer variable class InlineAssemblyPointerVariable final : public Variable { private: /// \brief Inline Assembly ar::InlineAssemblyConstant* _inline_asm; public: /// \brief Default constructor explicit InlineAssemblyPointerVariable( ar::InlineAssemblyConstant* inline_asm); /// \brief Get the ar::InlineAssemblyConstant* ar::InlineAssemblyConstant* inline_asm() const { return this->_inline_asm; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == InlineAssemblyPointerVariableKind; } }; // end class InlineAssemblyPointerVariable /// \brief Function pointer variable class FunctionPointerVariable final : public Variable { private: /// \brief Function ar::Function* _fun; public: /// \brief Default constructor explicit FunctionPointerVariable(ar::Function* fun); /// \brief Get the ar::Function* ar::Function* function() const { return this->_fun; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == FunctionPointerVariableKind; } }; // end class FunctionPointerVariable /// \brief Cell variable /// /// Symbolic variable representing the value at a specific memory location class CellVariable final : public Variable { private: /// \brief Base address MemoryLocation* _address; /// \brief Offset (in bytes) MachineInt _offset; /// \brief Size (in bytes) MachineInt _size; public: /// \brief Default constructor CellVariable(ar::Type* type, MemoryLocation* address, MachineInt offset, MachineInt size); /// \brief Get the MemoryLocation* the cell refers to MemoryLocation* address() const { return this->_address; } /// \brief Get the offset of the cell const MachineInt& offset() const { return this->_offset; } /// \brief Get the size of the cell const MachineInt& size() const { return this->_size; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == CellVariableKind; } }; // end class CellVariable /// \brief Offset variable /// /// Symbolic variable representing the offset of a pointer variable class OffsetVariable final : public Variable { private: /// \brief Parent variable Variable* _pointer; public: /// \brief Default constructor OffsetVariable(ar::Type* type, Variable* pointer); /// \brief Get the pointer variable Variable* pointer() const { return this->_pointer; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == OffsetVariableKind; } }; // end class OffsetVariable /// \brief Allocation size variable /// /// Symbolic variable representing the size of a memory location class AllocSizeVariable final : public Variable { private: /// \brief Base address MemoryLocation* _address; public: /// \brief Default constructor AllocSizeVariable(ar::Type* type, MemoryLocation* address); /// \brief Get the base address MemoryLocation* address() const { return this->_address; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == AllocSizeVariableKind; } }; // end class AllocSizeVariable /// \brief Return variable of a function /// /// Symbolic variable representing the return variable of a function class ReturnVariable final : public Variable { private: /// \brief Function ar::Function* _fun; public: /// \brief Default constructor explicit ReturnVariable(ar::Function* fun); /// \brief Get the ar::Function* ar::Function* function() const { return this->_fun; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == ReturnVariableKind; } }; // end class ReturnVariable /// \brief Named shadow variable /// /// Variable with a unique name, used to represents values unrelated to AR. class NamedShadowVariable final : public Variable { private: std::string _name; public: /// \brief Default constructor NamedShadowVariable(ar::Type* type, std::string name); /// \brief Get the variable name const std::string& name() const { return this->_name; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == NamedShadowVariableKind; } }; // end class NamedShadowVariable /// \brief Unnamed shadow variable /// /// Temporary unnamed variable, used to represents values unrelated to AR. class UnnamedShadowVariable final : public Variable { private: std::size_t _id; public: /// \brief Default constructor UnnamedShadowVariable(ar::Type* type, std::size_t id); /// \brief Dump the variable, for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Variable* v) { return v->kind() == UnnamedShadowVariableKind; } }; // end class UnnamedShadowVariable /// \brief Management of variables class VariableFactory { private: /// \brief Hash function for _cell_map struct CellMapKeyHash { std::size_t operator()( const std::tuple< MemoryLocation*, MachineInt, MachineInt >& k) const { std::size_t hash = 0; boost::hash_combine(hash, std::get< 0 >(k)); boost::hash_combine(hash, std::get< 1 >(k)); boost::hash_combine(hash, std::get< 2 >(k)); return hash; } }; private: /// \brief The AR context ar::Context& _ar_context; /// \brief Represents the type of an offset or a size (similar to std::size_t) /// /// This is an unsigned integer with the bit-width of a pointer ar::IntegerType* _size_type; boost::shared_mutex _local_variable_mutex; llvm::DenseMap< ar::LocalVariable*, std::unique_ptr< LocalVariable > > _local_variable_map; boost::shared_mutex _global_variable_mutex; llvm::DenseMap< ar::GlobalVariable*, std::unique_ptr< GlobalVariable > > _global_variable_map; boost::shared_mutex _internal_variable_mutex; llvm::DenseMap< ar::InternalVariable*, std::unique_ptr< InternalVariable > > _internal_variable_map; boost::shared_mutex _inline_asm_pointer_mutex; llvm::DenseMap< ar::InlineAssemblyConstant*, std::unique_ptr< InlineAssemblyPointerVariable > > _inline_asm_pointer_map; boost::shared_mutex _function_pointer_mutex; llvm::DenseMap< ar::Function*, std::unique_ptr< FunctionPointerVariable > > _function_pointer_map; boost::shared_mutex _cell_mutex; std::unordered_map< std::tuple< MemoryLocation*, MachineInt, MachineInt >, std::unique_ptr< CellVariable >, CellMapKeyHash > _cell_map; boost::shared_mutex _alloc_size_mutex; llvm::DenseMap< MemoryLocation*, std::unique_ptr< AllocSizeVariable > > _alloc_size_map; boost::shared_mutex _return_variable_mutex; llvm::DenseMap< ar::Function*, std::unique_ptr< ReturnVariable > > _return_variable_map; boost::shared_mutex _named_shadow_variable_mutex; llvm::StringMap< std::unique_ptr< NamedShadowVariable > > _named_shadow_variable_map; boost::mutex _unnamed_shadow_variable_mutex; std::vector< std::unique_ptr< UnnamedShadowVariable > > _unnamed_shadow_variable_vec; public: /// \brief Constructor explicit VariableFactory(ar::Bundle* bundle); /// \brief No copy constructor VariableFactory(const VariableFactory&) = delete; /// \brief No move constructor VariableFactory(VariableFactory&&) = delete; /// \brief No copy assignment operator VariableFactory& operator=(const VariableFactory&) = delete; /// \brief No move assignment operator VariableFactory& operator=(VariableFactory&&) = delete; /// \brief Destructor ~VariableFactory(); public: /// \brief Get or Create a LocalVariable LocalVariable* get_local(ar::LocalVariable* var); /// \brief Get or Create a GlobalVariable GlobalVariable* get_global(ar::GlobalVariable* var); /// \brief Get or Create an InternalVariable InternalVariable* get_internal(ar::InternalVariable* var); /// \brief Get or Create a InlineAssemblyPointerVariable InlineAssemblyPointerVariable* get_asm_ptr(ar::InlineAssemblyConstant* cst); /// \brief Get or Create a FunctionPointerVariable FunctionPointerVariable* get_function_ptr(ar::Function* fun); /// \brief Get or Create a FunctionPointerVariable FunctionPointerVariable* get_function_ptr(ar::FunctionPointerConstant* cst); /// \brief Get or Create a CellVariable CellVariable* get_cell(MemoryLocation* address, const MachineInt& offset, const MachineInt& size, Signedness sign); /// \brief Get or Create an AllocSizeVariable AllocSizeVariable* get_alloc_size(MemoryLocation* address); /// \brief Get or Create a ReturnVariable ReturnVariable* get_return(ar::Function* fun); /// \brief Get or Create a NamedShadowVariable NamedShadowVariable* get_named_shadow(ar::Type* type, llvm::StringRef name); /// \brief Create a new UnnamedShadowVariable UnnamedShadowVariable* create_unnamed_shadow(ar::Type* type); }; // end class VariableFactory } // end namespace analyzer } // end namespace ikos namespace ikos { namespace core { /// \brief Implement IndexableTraits for Variable* /// /// The index of Variable* is the address of the pointer. template <> struct IndexableTraits< analyzer::Variable* > { static Index index(const analyzer::Variable* v) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast< Index >(v); } }; /// \brief Implement DumpableTraits for Variable* template <> struct DumpableTraits< analyzer::Variable* > { static void dump(std::ostream& o, const analyzer::Variable* v) { v->dump(o); } }; namespace machine_int { /// \brief Implement machine_int::VariableTraits for Variable* template <> struct VariableTraits< analyzer::Variable* > { /// \brief Return the bit width of the given variable static uint64_t bit_width(const analyzer::Variable* v) { ikos_assert_msg(v->type()->is_integer(), "variable is not an integer"); return ar::cast< ar::IntegerType >(v->type())->bit_width(); } /// \brief Return the sign of the given variable static Signedness sign(const analyzer::Variable* v) { ikos_assert_msg(v->type()->is_integer(), "variable is not an integer"); return ar::cast< ar::IntegerType >(v->type())->sign(); } }; } // end namespace machine_int namespace scalar { /// \brief Implement scalar::VariableTraits for Variable* template <> struct VariableTraits< analyzer::Variable* > { /// \brief Return true if the given variable is a machine integer variable static bool is_int(const analyzer::Variable* v) { return !analyzer::isa< analyzer::CellVariable >(v) && v->type()->is_integer(); } /// \brief Return true if the given variable is a floating point variable static bool is_float(const analyzer::Variable* v) { return !analyzer::isa< analyzer::CellVariable >(v) && v->type()->is_float(); } /// \brief Return true if the given variable is a pointer variable static bool is_pointer(const analyzer::Variable* v) { // Aggregate variables are treated as pointers for the analysis return !analyzer::isa< analyzer::CellVariable >(v) && (v->type()->is_pointer() || v->type()->is_aggregate()); } /// \brief Return true if the given variable is a dynamically typed variable static bool is_dynamic(const analyzer::Variable* v) { return analyzer::isa< analyzer::CellVariable >(v); } /// \brief Return the machine integer offset variable of the given pointer static analyzer::Variable* offset_var(const analyzer::Variable* v) { ikos_assert_msg(v->offset_var() != nullptr, "variable is not a pointer"); return v->offset_var(); } }; } // end namespace scalar namespace memory { /// \brief Implement memory::CellVariableTraits for Variable* template <> struct CellVariableTraits< analyzer::Variable*, analyzer::MemoryLocation* > { /// \brief Return true if the given variable is a memory cell variable static bool is_cell(const analyzer::Variable* v) { return analyzer::isa< analyzer::CellVariable >(v); } /// \brief Return the base memory location of the given cell static analyzer::MemoryLocation* base(const analyzer::Variable* v) { return analyzer::cast< analyzer::CellVariable >(v)->address(); } /// \brief Return the offset of the given cell static const MachineInt& offset(const analyzer::Variable* v) { return analyzer::cast< analyzer::CellVariable >(v)->offset(); } /// \brief Return the size of the given cell static const MachineInt& size(const analyzer::Variable* v) { return analyzer::cast< analyzer::CellVariable >(v)->size(); } }; /// \brief Implement memory::CellFactoryTraits for VariableFactory template <> struct CellFactoryTraits< analyzer::Variable*, analyzer::MemoryLocation*, analyzer::VariableFactory* > { /// \brief Get or create the cell with the given base address, offset and size static analyzer::Variable* cell(analyzer::VariableFactory* vfac, analyzer::MemoryLocation* base, const MachineInt& offset, const MachineInt& size, Signedness sign) { return vfac->get_cell(base, offset, size, sign); } }; } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/analysis/widening_hint.hpp000066400000000000000000000070771473507761200300550ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Widening hint analysis * * Author: Thomas Bailleux * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Widening hint analysis /// /// This analysis is intended to be used before the computation of any fixpoint. /// /// It detect widening hints to help the fixpoint computation. It basically /// iterates on the cycles in the code and looks for constants which could be /// involved in the loop guard. /// /// For instance, if we have the following code: /// /// \code{.c} /// for (int i = 0; i < 10; i++) { /// do_something(); /// } /// \endcode /// /// It will mark the constant '10' as a widening hint. class WideningHintAnalysis { private: /// \brief Analysis context Context& _ctx; public: /// \brief Constructor explicit WideningHintAnalysis(Context& ctx); /// \brief No copy constructor WideningHintAnalysis(const WideningHintAnalysis&) = delete; /// \brief No move constructor WideningHintAnalysis(WideningHintAnalysis&&) = delete; /// \brief No copy assignment operator WideningHintAnalysis& operator=(const WideningHintAnalysis&) = delete; /// \brief No move assignment operator WideningHintAnalysis& operator=(WideningHintAnalysis&&) = delete; /// \brief Destructor ~WideningHintAnalysis(); /// \brief Run the analysis void run(); private: /// \brief Run the analysis on the given function void run(ar::Function*); }; // end class WideningHintAnalysis } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/000077500000000000000000000000001473507761200242645ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/assert_prover.hpp000066400000000000000000000063641473507761200277040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Assertion prover checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Assertion prover checker class AssertProverChecker final : public Checker { private: using IntInterval = core::machine_int::Interval; public: /// \brief Constructor explicit AssertProverChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; }; /// \brief Check an assert call CheckResult check_assert(ar::IntrinsicCall* call, const value::AbstractDomain& inv); private: /// \brief Dispay the check for the given assert(), if requested llvm::Optional< LogMessage > display_assert_check( Result result, ar::IntrinsicCall* call) const; }; // end class AssertProverChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/buffer_overflow.hpp000066400000000000000000000254451473507761200302030ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Buffer overflow checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace analyzer { /// \brief Buffer overflow checker class BufferOverflowChecker final : public Checker { private: using PointsToSet = core::PointsToSet< MemoryLocation* >; using IntPredicate = core::machine_int::Predicate; using IntUnaryOperator = core::machine_int::UnaryOperator; using IntBinaryOperator = core::machine_int::BinaryOperator; using IntInterval = core::machine_int::Interval; using IntVariable = core::VariableExpression< MachineInt, Variable* >; using IntLinearExpression = core::LinearExpression< MachineInt, Variable* >; private: //// \brief The AR context ar::Context& _ar_context; /// \brief The data layout const ar::DataLayout& _data_layout; /// \brief The unsigned integer type with the bit-width of a pointer ar::IntegerType* _size_type; /// \brief The integer constant 0 of type size_t ar::IntegerConstant* _size_zero; /// \brief The integer constant 1 of type size_t ar::IntegerConstant* _size_one; public: enum class BufferOverflowCheckKind { /// \brief Check for a memory access on a function memory location Function = 0, /// \brief Check for a memory access on a deallocated dynamic allocated /// memory UseAfterFree = 1, /// \brief Check for a memory access on a dangling stack pointer UseAfterReturn = 2, /// \brief Check for a memory access on a hardware address HardwareAddresses = 3, // \brief Check for an out of bound memory access OutOfBound = 4, }; public: /// \brief Constructor explicit BufferOverflowChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; llvm::SmallVector< ar::Value*, 2 > operands; JsonDict info; }; /// \brief Memory location check result struct MemoryLocationCheckResult { BufferOverflowCheckKind kind; Result result; }; /// \brief Check a function call std::vector< CheckResult > check_call(ar::CallBase* call, const value::AbstractDomain& inv); /// \brief Check an intrinsic function call std::vector< CheckResult > check_intrinsic_call( ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check a memory access (read/write) for buffer overflow /// /// \returns The analysis check result (Ok, Warning, Error, Unreachable) /// /// The method checks that the memory access to /// [offset, offset + access_size - 1] is valid. /// /// It checks the following property: /// addrs_set(ptr) != TOP && /// ∀a ∈ addrs_set(ptr), ∀o ∈ offset, o + access_size <= a.size /// /// \param stmt The statement /// \param pointer The pointer operand /// \param access_size The access size operand (in bytes) /// \param if_null Result if the pointer is null /// \param inv The invariant CheckResult check_mem_access(ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, Result if_null, value::AbstractDomain inv); /// \brief Check a memory access (read/write) at the given memory location /// /// The method is called by check_mem_access, and performs the analysis /// of the memory location access. /// /// \returns A pair which contains the result and the kind of the check /// /// \param stmt The statement /// \param pointer The pointer operand /// \param access_size The access size operand (in bytes) /// \param inv The invariant /// \param addr The memory location /// \param size_var The allocation size variable /// \param offset_var The pointer offset variable /// \param offset_plus_size The shadow variable equal to offset + access size /// \param offset_intv The pointer offset interval /// \param block_info JSON dictionary to add extra information MemoryLocationCheckResult check_memory_location_access( ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, const value::AbstractDomain& inv, MemoryLocation* addr, AllocSizeVariable* size_var, Variable* offset_var, Variable* offset_plus_size, const IntInterval& offset_intv, JsonDict& block_info); /// \brief Check a string access (read/write) for buffer overflow /// /// \returns The analysis check result (Ok, Warning, Error, Unreachable) /// /// \param stmt The statement /// \param pointer The pointer string operand /// \param if_null Result if the pointer is null /// \param inv The invariant CheckResult check_string_access(ar::Statement* stmt, ar::Value* pointer, Result if_null, const value::AbstractDomain& inv); /// \brief Check a string access (read/write) for buffer overflow /// /// \returns The analysis check result (Ok, Warning, Error, Unreachable) /// /// \param stmt The statement /// \param pointer The pointer string operand /// \param max_access_size The maximum access size, in bytes /// \param if_null Result if the pointer is null /// \param inv The invariant CheckResult check_string_access(ar::Statement* stmt, ar::Value* pointer, ar::Value* max_access_size, Result if_null, const value::AbstractDomain& inv); /// \brief Check a `va_list` access (read/write) for buffer overflow /// /// \returns The analysis check result (Ok, Warning, Error, Unreachable) /// /// \param stmt The statement /// \param pointer The pointer operand /// \param inv The invariant CheckResult check_va_list_access(ar::Statement* stmt, ar::Value* pointer, const value::AbstractDomain& inv); /// \brief Check a call to realloc for buffer overflow /// /// \returns The analysis check result (Ok, Warning, Error, Unreachable) /// /// \param call The call statement /// \param pointer The pointer operand /// \param inv The invariant CheckResult check_realloc(ar::CallBase* call, ar::Value* pointer, const value::AbstractDomain& inv); /// \brief Check a `FILE*` access (read/write) for buffer overflow /// /// \returns The analysis check result (Ok, Warning, Error, Unreachable) /// /// \param stmt The statement /// \param pointer The pointer operand /// \param if_null Result if the pointer is null /// \param inv The invariant CheckResult check_file_access(ar::Statement* stmt, ar::Value* pointer, Result if_null, const value::AbstractDomain& inv); /// \brief Return the store size for the given type, as an integer constant ar::IntegerConstant* store_size(ar::Type*) const; /// \brief Initialize global variable pointers and function pointers void init_global_ptr(value::AbstractDomain& inv, ar::Value* value) const; /// \brief Initialize global variable sizes and function sizes void init_global_alloc_size(value::AbstractDomain& inv, MemoryLocation* addr, AllocSizeVariable* size_var) const; /// \brief Check whether a memory access is an array access /// /// \returns the size of an array element boost::optional< MachineInt > is_array_access( ar::Statement* stmt, const value::AbstractDomain& inv, const IntInterval& offset_intv, const PointsToSet& addrs) const; /// \brief Display a memory access check, if requested llvm::Optional< LogMessage > display_mem_access_check( Result result, ar::Statement* stmt) const; /// \brief Display a memory access check, if requested llvm::Optional< LogMessage > display_mem_access_check( Result result, ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size) const; /// \brief Display a memory access check, if requested llvm::Optional< LogMessage > display_mem_access_check( Result result, ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, MemoryLocation* addr) const; }; // end class BufferOverflowChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/checker.hpp000066400000000000000000000146061473507761200264100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Base class for property checkers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Base class for property checkers class Checker { protected: /// \brief Analysis context Context& _ctx; /// \brief Literal factory LiteralFactory& _lit_factory; /// \brief Checks table ChecksTable& _checks; /// \brief Option to display the invariants DisplayOption _display_invariants; /// \brief Option to display the checks DisplayOption _display_checks; protected: /// \brief Constructor explicit Checker(Context& ctx) : _ctx(ctx), _lit_factory(*ctx.lit_factory), _checks(ctx.output_db->checks), _display_invariants(ctx.opts.display_invariants), _display_checks(ctx.opts.display_checks) {} public: /// \brief No copy constructor Checker(const Checker&) = delete; /// \brief Move constructor Checker(Checker&&) noexcept = default; /// \brief No copy assignment operator Checker& operator=(const Checker&) = delete; /// \brief No move assignment operator Checker& operator=(Checker&&) = delete; /// \brief Destructor virtual ~Checker() = default; /// \brief Get the checker name virtual CheckerName name() const = 0; /// \brief Get the checker short name const char* short_name() const { return checker_short_name(this->name()); } /// \brief Get the checker long name const char* long_name() const { return checker_long_name(this->name()); } /// \brief Get the checker description virtual const char* description() const = 0; /// \brief Check a statement virtual void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) = 0; protected: // Helpers to display checks and invariants /// \brief Return true if the invariant should be displayed inline bool display_invariant(Result result) const { return this->_display_invariants == DisplayOption::All || (this->_display_invariants == DisplayOption::Fail && (result == Result::Error || result == Result::Warning || result == Result::Unreachable)); } // \brief Display the invariant for the given statement, if requested /// /// \return a log message if the invariant should be displayed inline llvm::Optional< LogMessage > display_invariant( Result result, ar::Statement* stmt, const value::AbstractDomain& inv) const { if (this->display_invariant(result)) { LogMessage msg = log::msg(); this->display_stmt_location(msg, stmt); msg << "Invariant:\n"; inv.dump(msg.stream()); msg << "\n"; return std::move(msg); } else { return llvm::None; } } /// \brief Return true if the check should be displayed inline bool display_check(Result result) const { return this->_display_checks == DisplayOption::All || (this->_display_checks == DisplayOption::Fail && (result == Result::Error || result == Result::Warning || result == Result::Unreachable)); } /// \brief Display the check for the given statement, if requested /// /// \return a log message if the check should be displayed inline llvm::Optional< LogMessage > display_check(Result result, ar::Statement* stmt) const { if (this->display_check(result)) { LogMessage msg = log::msg(); this->display_stmt_location(msg, stmt); this->display_result(msg, result); return std::move(msg); } else { return llvm::None; } } /// \brief Display a statement location void display_stmt_location(LogMessage& msg, ar::Statement* s) const; /// \brief Display a check result void display_result(LogMessage& msg, Result result) const; }; // end class Checker /// \brief Create a checker, given its name std::unique_ptr< Checker > make_checker(Context& ctx, CheckerName name); } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/dead_code.hpp000066400000000000000000000073361473507761200266750ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Dead code checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Dead code checker class DeadCodeChecker final : public Checker { private: /// \brief Previous statement for each basic block currently analyzed /// /// Since we cannot get the previous statement of an `ar::Statement` in O(1), /// we use this map to store the previously analyzed statement. llvm::DenseMap< ar::BasicBlock*, ar::Statement* > _prev_stmts; public: /// \brief Constructor explicit DeadCodeChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Return the previous statement ar::Statement* previous_statement(ar::Statement* stmt) const; /// \brief Save the current statement void save_current_statement(ar::Statement* stmt); /// \brief Return true if we need to skip the check for the given statement static bool skip_check(ar::Statement* stmt); /// \brief Return true if we need a check for the current statement, /// given the previous statement (or null) and the current basic block static bool needs_check(ar::Statement* prev_stmt, ar::BasicBlock* bb); /// \brief Dispay a dead code check, if requested void display_dead_code_check(Result result, ar::Statement* stmt) const; }; // end class DeadCodeChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/debug.hpp000066400000000000000000000060461473507761200260710ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Debug checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Debug checker class DebugChecker final : public Checker { public: /// \brief Constructor explicit DebugChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Execute an __ikos_print_invariant call void exec_print_invariant(ar::IntrinsicCall* call, const value::AbstractDomain& inv); /// \brief Execute an __ikos_print_values call void exec_print_values(ar::IntrinsicCall* call, const value::AbstractDomain& inv); }; // end class DebugChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/division_by_zero.hpp000066400000000000000000000064231473507761200303570ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Division by zero checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Division by zero checker class DivisionByZeroChecker final : public Checker { private: using IntInterval = core::machine_int::Interval; public: /// \brief Constructor explicit DivisionByZeroChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; JsonDict info; }; /// \brief Check a division CheckResult check_division(ar::BinaryOperation* stmt, const value::AbstractDomain& inv); private: /// \brief Dispay the check for the given division, if requested llvm::Optional< LogMessage > display_division_check( Result result, ar::BinaryOperation* stmt) const; }; // end class DivisionByZeroChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/double_free.hpp000066400000000000000000000103701473507761200272510ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Double free checker * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace analyzer { /// \brief Double free checker class DoubleFreeChecker final : public Checker { private: using PointsToSet = core::PointsToSet< MemoryLocation* >; public: /// \brief Constructor explicit DoubleFreeChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; llvm::SmallVector< ar::Value*, 2 > operands; JsonDict info; }; /// \brief Check a function call std::vector< CheckResult > check_call(ar::CallBase* call, const value::AbstractDomain& inv); /// \brief Check an intrinsic function call boost::optional< CheckResult > check_intrinsic_call( ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check a function call to free on the given pointer CheckResult check_double_free(ar::CallBase* call, ar::Value* pointer, const value::AbstractDomain& inv); /// \brief Check for a double free call on a memory location Result check_memory_location_free(ar::CallBase* call, const value::AbstractDomain& inv, MemoryLocation* addr); /// \brief Display the double free check, if requested llvm::Optional< LogMessage > display_double_free_check( Result result, ar::Statement* stmt) const; /// \brief Display the double free check, if requested, with a memory location llvm::Optional< LogMessage > display_double_free_check( Result result, ar::CallBase* call, MemoryLocation* addr) const; }; // end class DoubleFreeChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/function_call.hpp000066400000000000000000000070411473507761200276170ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Function call checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Function call checker class FunctionCallChecker final : public Checker { private: using PointsToSet = core::PointsToSet< MemoryLocation* >; public: enum class FunctionCallCheckKind { /// \brief Callee is not a function NotFunction, /// \brief Callee has a wrong signature WrongSignature, /// \brief Callee is safe Ok, }; public: /// \brief Constructor explicit FunctionCallChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; llvm::SmallVector< ar::Value*, 1 > operands; JsonDict info; }; /// \brief Check a function call CheckResult check_call(ar::CallBase* call, const value::AbstractDomain& inv); /// \brief Dispay a function call check, if requested llvm::Optional< LogMessage > display_call_check(Result result, ar::CallBase* call) const; }; // end class FunctionCallChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/int_overflow_base.hpp000066400000000000000000000071471473507761200305150ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Base for integer overflow checker * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Base for integer overflow checker class IntOverflowCheckerBase : public Checker { private: using IntInterval = core::machine_int::Interval; using ZInterval = core::numeric::Interval< ZNumber >; using ZBound = core::Bound< ZNumber >; public: /// \brief Constructor explicit IntOverflowCheckerBase(Context& ctx); protected: /// \brief Check an integer overflow and insert the checks in the database void check_integer_overflow(ar::BinaryOperation* stmt, const value::AbstractDomain& inv, CallContext* call_context); private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; llvm::SmallVector< ar::Value*, 2 > operands; JsonDict info; }; /// \brief Check an integer overflow llvm::SmallVector< CheckResult, 2 > check_integer_overflow( ar::BinaryOperation* stmt, const value::AbstractDomain& inv); private: /// \brief Display info about the check llvm::Optional< LogMessage > display_int_overflow_check( Result result, ar::BinaryOperation* stmt) const; /// \brief CheckKind for integer underflow virtual CheckKind underflow_check_kind() const = 0; /// \brief CheckKind for integer overflow virtual CheckKind overflow_check_kind() const = 0; }; // end class IntOverflowCheckerBase } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/kind.hpp000066400000000000000000000116461473507761200257320ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Check kind * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once namespace ikos { namespace analyzer { /// \brief List of checks enum class CheckKind { /// \brief Check for an unreachable statement Unreachable, /// \brief Check for an unexpected operand of a statement UnexpectedOperand, /// \brief Check for an uninitialized variable of a statement UninitializedVariable, /// \brief Check for an assertion Assert, /// \brief Check for a division by zero DivisionByZero, /// \brief Check for an invalid shift count ShiftCount, _BeginIntOverflow, /// \brief Check for an underflow on a signed integer operation SignedIntUnderflow, /// \brief Check for an overflow on a signed integer operation SignedIntOverflow, /// \brief Check for an underflow on an unsigned integer operation UnsignedIntUnderflow, /// \brief Check for an overflow on an unsigned integer operation UnsignedIntOverflow, _EndIntOverflow, /// \brief Check for a memory access on a null pointer NullPointerDereference, /// \brief Check for a null pointer comparison NullPointerComparison, /// \brief Check for a pointer comparison on an invalid pointer (points-to set /// is empty) InvalidPointerComparison, /// \brief Check for an invalid pointer comparison PointerComparison, /// \brief Check for a pointer computation overflow PointerOverflow, /// \brief Check for a memory access on an invalid pointer (points-to set is /// empty) InvalidPointerDereference, /// \brief Check for an unknown memory access (points-to set is top) UnknownMemoryAccess, /// \brief Check for the alignment of a pointer on a memory access UnalignedPointer, _BeginBufferOverflow, /// \brief Check for a call to gets() BufferOverflowGets, /// \brief Check for a buffer overflow BufferOverflow, _EndBufferOverflow, _BeginSoundness, /// \brief Ignored memory store on an unknown pointer IgnoredStore, /// \brief Ignored memory copy on an unknown pointer IgnoredMemoryCopy, /// \brief Ignored memory move on an unknown pointer IgnoredMemoryMove, /// \brief Ignored memory set on an unknown pointer IgnoredMemorySet, /// \brief Ignored free on an unknown pointer IgnoredFree, /// \brief Ignored side effect of a call with an unknown pointer parameter IgnoredCallSideEffectOnPointerParameter, /// \brief Ignored side effect of a function call IgnoredCallSideEffect, /// \brief Check for a recursive function call RecursiveFunctionCall, _EndSoundness, _BeginFunctionCall, /// \brief Check for a function call to inline assembly FunctionCallInlineAssembly, /// \brief Check for a function call on an unknown pointer UnknownFunctionCallPointer, /// \brief Check a function call FunctionCall, _EndFunctionCall, /// \brief Check for a memory deallocation (e.g, free) Free, }; } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/memory_watch.hpp000066400000000000000000000142521473507761200274770ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Memory watch checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Memory watch checker class MemoryWatchChecker final : public Checker { private: using PointsToSet = core::PointsToSet< MemoryLocation* >; using IntPredicate = core::machine_int::Predicate; using IntUnaryOperator = core::machine_int::UnaryOperator; using IntBinaryOperator = core::machine_int::BinaryOperator; private: //// \brief The AR context ar::Context& _ar_context; /// \brief The data layout const ar::DataLayout& _data_layout; /// \brief The unsigned integer type with the bit-width of a pointer ar::IntegerType* _size_type; /// \brief Watched pointer variable Variable* _watch_mem_ptr; /// \brief Watched size variable Variable* _watch_mem_size; public: /// \brief Constructor explicit MemoryWatchChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check a store void check_store(ar::Store* store, const value::AbstractDomain& inv); /// \brief Check a function call void check_call(ar::CallBase* call, const value::AbstractDomain& inv, CallContext* call_context); /// \brief Check a recursive function call void check_recursive_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check an intrinsic function call void check_intrinsic_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check a call to an unknown extern function void check_unknown_extern_call(ar::CallBase* call, const value::AbstractDomain& inv); /// \brief Check a call to an unknown function /// /// Check if the given function call might write on a watched memory location /// /// \param call /// The call statement /// \param inv /// The invariant /// \param may_write_params /// True if the function call might write on a pointer parameter /// \param ignore_unknown_write /// True to ignore writes on unknown pointer parameters (unsound) /// \param may_write_globals /// True if the function call might update a global variable /// \param may_throw_exc /// True if the function call might throw an exception void check_unknown_call(ar::CallBase* call, value::AbstractDomain inv, bool may_write_params, bool ignore_unknown_write, bool may_write_globals, bool may_throw_exc); /// \brief Check a memory write /// /// Check if the given statement might write on a watched memory location /// /// \param stmt The statement /// \param pointer The pointer operand /// \param access_size The access size operand (in bytes) /// \param inv The invariant void check_mem_write(ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, value::AbstractDomain inv); /// \brief Check a memory write /// /// Check if the given statement might write on a watched memory location /// /// \param stmt The statement /// \param pointer The pointer operand /// \param inv The invariant void check_mem_write(ar::Statement* stmt, ar::Value* pointer, value::AbstractDomain inv); /// \brief Initialize global variable pointers and function pointers void init_global_ptr(value::AbstractDomain& inv, ar::Value* value) const; /// \brief Return the store size for the given type, as an integer constant ar::IntegerConstant* store_size(ar::Type*) const; }; // end class MemoryWatchChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/name.hpp000066400000000000000000000123571473507761200257250ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Checker names * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief List of available checkers enum class CheckerName { BufferOverflow, DivisionByZero, NullPointerDereference, AssertProver, UnalignedPointer, UninitializedVariable, SignedIntOverflow, UnsignedIntOverflow, ShiftCount, PointerOverflow, PointerCompare, Soundness, FunctionCall, DeadCode, DoubleFree, Debug, MemoryWatch, }; /// \brief Return the long name of the given checker inline const char* checker_long_name(CheckerName checker) { switch (checker) { case CheckerName::BufferOverflow: return "Buffer Overflow Analysis"; case CheckerName::DivisionByZero: return "Division by Zero Analysis"; case CheckerName::NullPointerDereference: return "Null Pointer Dereference Analysis"; case CheckerName::AssertProver: return "Assertion Prover"; case CheckerName::UnalignedPointer: return "Unaligned Pointer Analysis"; case CheckerName::UninitializedVariable: return "Uninitialized Variable Analysis"; case CheckerName::SignedIntOverflow: return "Signed Integer Overflow Analysis"; case CheckerName::UnsignedIntOverflow: return "Unsigned Integer Overflow Analysis"; case CheckerName::ShiftCount: return "Shift Count Analysis"; case CheckerName::PointerOverflow: return "Pointer Overflow Analysis"; case CheckerName::PointerCompare: return "Pointer Comparison Analysis"; case CheckerName::Soundness: return "Soundness Analysis"; case CheckerName::FunctionCall: return "Function Call Analysis"; case CheckerName::DeadCode: return "Dead Code Analysis"; case CheckerName::DoubleFree: return "Double Free Analysis"; case CheckerName::Debug: return "Debugger"; case CheckerName::MemoryWatch: return "Memory Watcher"; default: { ikos_unreachable("unreachable"); } } } /// \brief Return the short name of the given checker inline const char* checker_short_name(CheckerName checker) { switch (checker) { case CheckerName::BufferOverflow: return "boa"; case CheckerName::DivisionByZero: return "dbz"; case CheckerName::NullPointerDereference: return "nullity"; case CheckerName::AssertProver: return "prover"; case CheckerName::UnalignedPointer: return "upa"; case CheckerName::UninitializedVariable: return "uva"; case CheckerName::SignedIntOverflow: return "sio"; case CheckerName::UnsignedIntOverflow: return "uio"; case CheckerName::ShiftCount: return "shc"; case CheckerName::PointerOverflow: return "poa"; case CheckerName::PointerCompare: return "pcmp"; case CheckerName::Soundness: return "sound"; case CheckerName::FunctionCall: return "fca"; case CheckerName::DeadCode: return "dca"; case CheckerName::DoubleFree: return "dfa"; case CheckerName::Debug: return "dbg"; case CheckerName::MemoryWatch: return "watch"; default: { ikos_unreachable("unreachable"); } } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/null_dereference.hpp000066400000000000000000000100411473507761200302720ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Null dereference checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace analyzer { /// \brief Null dereference checker class NullDereferenceChecker final : public Checker { private: using PointsToSet = core::PointsToSet< MemoryLocation* >; public: /// \brief Constructor explicit NullDereferenceChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; llvm::SmallVector< ar::Value*, 2 > operands; }; /// \brief Check a function call std::vector< CheckResult > check_call(ar::CallBase* call, const value::AbstractDomain& inv); /// \brief Check an intrinsic function call std::vector< CheckResult > check_intrinsic_call( ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check a null dereference CheckResult check_null(ar::Statement* stmt, ar::Value* operand, const value::AbstractDomain& inv); private: /// \brief Dispay a null dereference check, if requested llvm::Optional< LogMessage > display_null_check(Result result, ar::Statement* stmt) const; /// \brief Dispay a null dereference check, if requested llvm::Optional< LogMessage > display_null_check(Result result, ar::Statement* stmt, ar::Value* operand) const; }; // end class NullDereferenceChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/pointer_alignment.hpp000066400000000000000000000105671473507761200305240ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer alignment checker * * Author: Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Pointer alignment checker class PointerAlignmentChecker final : public Checker { private: using PointsToSet = core::PointsToSet< MemoryLocation* >; using Congruence = core::machine_int::Congruence; private: /// \brief The data layout const ar::DataLayout& _data_layout; public: /// \brief Constructor explicit PointerAlignmentChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check a pointer alignment and insert the check in the database void check_alignment(ar::Statement* stmt, ar::Value* operand, uint64_t alignment_req, const value::AbstractDomain& inv, CallContext* call_context); /// \brief Check result struct CheckResult { CheckKind kind; Result result; JsonDict info; }; /// \brief Check a pointer alignment and insert the check in the database CheckResult check_alignment(ar::Statement* stmt, ar::Value* operand, uint64_t alignment_req, const value::AbstractDomain& inv); /// \brief Check the alignment of a memory location Result check_memory_location_alignment(MemoryLocation* memloc, const Congruence& offset_c, const Congruence& alignment_req_c, JsonDict& block_info); /// \brief Return the congruence aZ+b on pointer offsets Congruence to_congruence(uint64_t a, uint64_t b) const; private: /// \brief Dispay the pointer alignment check, if requested llvm::Optional< LogMessage > display_alignment_check( Result result, ar::Statement* stmt, ar::Value* operand) const; }; // end class PointerAlignmentChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/pointer_compare.hpp000066400000000000000000000066531473507761200301750ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer compare checker * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Pointer compare checker class PointerCompareChecker final : public Checker { private: using IntInterval = core::machine_int::Interval; using PointsToSet = core::PointsToSet< MemoryLocation* >; public: /// \brief Constructor explicit PointerCompareChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; llvm::SmallVector< ar::Value*, 2 > operands; JsonDict info; }; /// \brief Check a pointer comparison CheckResult check_pointer_compare(ar::Comparison* stmt, const value::AbstractDomain& inv); /// \brief Display the pointer comparison check, if requested llvm::Optional< LogMessage > display_pointer_compare_check( Result result, ar::Comparison* stmt) const; }; // end class PointerCompareChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/pointer_overflow.hpp000066400000000000000000000067461473507761200304150ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer overflow checker * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Pointer overflow checker class PointerOverflowChecker final : public Checker { private: using IntInterval = core::machine_int::Interval; using ZInterval = core::numeric::Interval< ZNumber >; using ZBound = core::Bound< ZNumber >; private: /// \brief The data layout const ar::DataLayout& _data_layout; public: /// \brief Constructor explicit PointerOverflowChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; std::vector< ar::Value* > operands; }; /// \brief Check a pointer overflow CheckResult check_pointer_overflow(ar::PointerShift* stmt, const value::AbstractDomain& inv); /// \brief Display the pointer overflow check, if requested llvm::Optional< LogMessage > display_pointer_overflow_check( Result result, ar::PointerShift* stmt) const; }; // end class PointerOverflowChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/shift_count.hpp000066400000000000000000000063651473507761200273340ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Shift count checker * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Shift count checker class ShiftCountChecker final : public Checker { private: using IntInterval = core::machine_int::Interval; public: /// \brief Constructor explicit ShiftCountChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; JsonDict info; }; /// \brief Check a shift count CheckResult check_shift_count(ar::BinaryOperation* stmt, const value::AbstractDomain& inv); /// \brief Display a shift count check, if requested llvm::Optional< LogMessage > display_shift_count_check( Result result, ar::BinaryOperation* stmt) const; }; // end class ShiftCountChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/signed_int_overflow.hpp000066400000000000000000000060041473507761200310430ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Signed integer overflow checker * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Signed integer overflow checker class SignedIntOverflowChecker final : public IntOverflowCheckerBase { public: /// \brief Constructor explicit SignedIntOverflowChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief CheckKind for integer underflow CheckKind underflow_check_kind() const override; /// \brief CheckKind for integer overflow CheckKind overflow_check_kind() const override; }; // end class SignedIntOverflowChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/soundness.hpp000066400000000000000000000125351473507761200270240ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Soundness checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace analyzer { /// \brief Soundness checker /// /// Warn about any statement that could make the analysis unsound. class SoundnessChecker final : public Checker { private: using PointsToSet = core::PointsToSet< MemoryLocation* >; public: /// \brief Constructor explicit SoundnessChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check result struct CheckResult { CheckKind kind; Result result; llvm::SmallVector< ar::Value*, 2 > operands; JsonDict info; }; /// \brief Check a function call std::vector< CheckResult > check_call(ar::CallBase* call, const value::AbstractDomain& inv, CallContext* call_context); /// \brief Check for a recursive function call /// /// Warn about RecursiveFunctionCall. CheckResult check_recursive_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check an intrinsic function call std::vector< CheckResult > check_intrinsic_call( ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check a call to an unknown extern function /// /// Warn about IgnoredCallSideEffect. CheckResult check_unknown_extern_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv); /// \brief Check a memory write on an unknown pointer /// /// Check if the points-to set of the pointer is top. /// /// Warn about IgnoredStore, IgnoredMemoryCopy, IgnoredMemoryMove and /// IgnoredMemorySet. boost::optional< CheckResult > check_mem_write( ar::Statement* stmt, ar::Value* pointer, CheckKind access_kind, const value::AbstractDomain& inv); /// \brief Check a call for unknown pointer parameters /// /// Check if the points-to set of any given pointer is top. /// /// Warn about IgnoredCallSideEffectOnPointerParameter. std::vector< CheckResult > check_call_pointer_params( ar::CallBase* call, ar::Function* fun, const std::vector< ar::Value* >& pointers, const value::AbstractDomain& inv); /// \brief Check a call to free() /// /// Check if the points-to set of the given pointer is top. /// /// Warn about IgnoredFree. boost::optional< CheckResult > check_free(ar::CallBase* call, ar::Value* pointer, const value::AbstractDomain& inv); /// \brief Dispay a soundness check, if requested llvm::Optional< LogMessage > display_soundness_check( Result result, ar::Statement* stmt) const; }; // end class SoundnessChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/uninitialized_variable.hpp000066400000000000000000000070041473507761200315130ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Uninitialized variable checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Uninitialized variable checker class UninitializedVariableChecker final : public Checker { public: /// \brief Constructor explicit UninitializedVariableChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief Check an operand and save the result void check_initialized(ar::Statement* stmt, ar::Value* operand, const value::AbstractDomain& inv, CallContext* call_context); /// \brief Check an operand and return a result boost::optional< Result > check_initialized(ar::Value* operand, const value::AbstractDomain& inv); private: /// \brief Dispay a uninitialized variable check, if requested void display_initialized_check(Result result, ar::Statement* stmt, ar::Value* operand) const; }; // end class UninitializedVariableChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/checker/unsigned_int_overflow.hpp000066400000000000000000000060161473507761200314110ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Unsigned integer overflow checker * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Unsigned integer overflow checker class UnsignedIntOverflowChecker final : public IntOverflowCheckerBase { public: /// \brief Constructor explicit UnsignedIntOverflowChecker(Context& ctx); /// \brief Get the checker name CheckerName name() const override; /// \brief Get the checker description const char* description() const override; /// \brief Check a statement void check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) override; private: /// \brief CheckKind for integer underflow CheckKind underflow_check_kind() const override; /// \brief CheckKind for integer overflow CheckKind overflow_check_kind() const override; }; // end class UnsignedIntOverflowChecker } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/000077500000000000000000000000001473507761200244245ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/output.hpp000066400000000000000000000062321473507761200265000ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Output database * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Output database class OutputDatabase { public: sqlite::DbConnection& db; SettingsTable settings; TimesTable times; FilesTable files; FunctionsTable functions; StatementsTable statements; OperandsTable operands; CallContextsTable call_contexts; MemoryLocationsTable memory_locations; ChecksTable checks; public: /// \brief Constructor explicit OutputDatabase(sqlite::DbConnection& db_); }; // end class OutputDatabase } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/sqlite.hpp000066400000000000000000000257511473507761200264500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Simple wrapper classes for SQLite3 database * * Authors: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace sqlite { /// \brief Database error class DbError : public analyzer::Exception { private: /// \brief Error code int _code; /// \brief Context messagge /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _context; /// \brief Computed message for what() method /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _what; public: /// \brief No default constructor DbError() = delete; /// \brief Constructor /// /// \param code SQLite error code explicit DbError(int code); /// \brief Constructor /// /// \param code SQLite error code /// \param context Context message DbError(int code, const std::string& context); /// \brief Copy constructor DbError(const DbError&) noexcept = default; /// \brief Move constructor DbError(DbError&&) noexcept = default; /// \brief Copy assignment operator DbError& operator=(const DbError&) noexcept = default; /// \brief Move assignment operator DbError& operator=(DbError&&) noexcept = default; /// \brief Return the error code int error_code() const noexcept { return this->_code; } /// \brief Return the context message const char* context() const noexcept { return this->_context->c_str(); } /// \brief SQLite error message const char* error_msg() const noexcept; /// \brief Get the explanatory string const char* what() const noexcept override; /// \brief Destructor ~DbError() override; }; // end class DbError /// \brief Integer type for SQLite using DbInt64 = sqlite3_int64; /// \brief Double type for SQLite using DbDouble = double; /// \brief Column type enum class DbColumnType { Text, Integer, Real, Blob }; /// \brief Return the string representation of a column type const char* column_type_str(DbColumnType t); /// \brief Journal mode enum class JournalMode { Delete, Truncate, Persist, Memory, WAL, Off }; /// \brief Synchronous mode enum class SynchronousFlag { Off, Normal, Full, Extra }; /// \brief Commit policy for a DbConnection enum class CommitPolicy { /// \brief Call begin_transaction() and commit_transaction() manually Manual = 0, /// \brief Automatically start new transactions every MaxRowsPerTransaction /// inserted rows Auto = 1, }; /// \brief SQLite connection class DbConnection { public: /// \brief Maximum number of rows per transaction, in CommitPolicy::Auto static const int MaxRowsPerTransaction = 8192; private: /// \brief Filename std::string _filename; /// \brief SQLite3 handle sqlite3* _handle = nullptr; /// \brief Commit policy CommitPolicy _commit_policy = CommitPolicy::Manual; /// \brief Number of inserted rows, in CommitPolicy::Auto std::size_t _inserted_rows = 0; public: /// \brief No default constructor DbConnection() = delete; /// \brief Open a database connection explicit DbConnection(std::string filename); /// \brief No copy constructor DbConnection(const DbConnection&) = delete; /// \brief No move constructor DbConnection(DbConnection&&) = delete; /// \brief No copy assignment operator DbConnection& operator=(const DbConnection&) = delete; /// \brief No move assignment operator DbConnection& operator=(DbConnection&&) = delete; /// \brief Destructor ~DbConnection(); /// \brief Return the database filename const std::string& filename() const { return this->_filename; } /// \brief Execute a SQL command void exec_command(const char* cmd); /// \brief Execute a SQL command void exec_command(const std::string& cmd); /// \brief Start a transaction void begin_transaction(); /// \brief Commit a transaction void commit_transaction(); /// \brief Rollback a transaction void rollback_transaction(); /// \brief Change the commit policy void set_commit_policy(CommitPolicy policy); /// \brief Return the current commit policy CommitPolicy commit_policy() const { return this->_commit_policy; } private: /// \brief Called upon a row insertion void row_inserted(); public: /// \brief Remove a table void drop_table(StringRef name); /// \brief Return the last inserted row ID DbInt64 last_insert_rowid() const; /// \brief Create a table with the given column names and types /// /// If a column is called "id", automatically mark it as a primary key. void create_table( StringRef name, llvm::ArrayRef< std::pair< StringRef, DbColumnType > > columns); /// \brief Create an index on the given column of the given table void create_index(StringRef index, StringRef table, StringRef column); /// \brief Set the journal mode void set_journal_mode(JournalMode mode); /// \brief Set the synchronous flag void set_synchronous_flag(SynchronousFlag flag); // friends friend class DbOstream; friend class DbIstream; }; // end class DbConnection /// \brief Stream-based interface for populating tables class DbOstream { private: /// \brief Database connection DbConnection& _db; /// \brief SQLite3 prepared statement sqlite3_stmt* _stmt = nullptr; /// \brief Number of columns int _columns; /// \brief Current number of column entered int _current_column = 1; public: /// \brief No default constructor DbOstream() = delete; /// \brief Constructor /// /// \param db The database connection /// \param table_name The table name /// \param columns Number of columns DbOstream(DbConnection& db, StringRef table_name, int columns); /// \brief No copy constructor DbOstream(const DbOstream&) = delete; /// \brief No move constructor DbOstream(DbOstream&&) = delete; /// \brief No copy assignment operator DbOstream& operator=(const DbOstream&) = delete; /// \brief No move assignment operator DbOstream& operator=(DbOstream&&) = delete; /// \brief Destructor ~DbOstream(); public: /// \brief Insert a string void add(StringRef s); /// \brief Insert NULL void add_null(); /// \brief Insert an integer void add(DbInt64 n); /// \brief Insert a double void add(DbDouble d); /// \brief Flush the row void flush(); // friends friend DbOstream& end_row(DbOstream&); }; // end class DbOstream /// \brief Insert a string inline DbOstream& operator<<(DbOstream& o, StringRef s) { o.add(s); return o; } /// \brief Mark the end of a row inline DbOstream& end_row(DbOstream& o) { o.flush(); return o; } /// \brief Insert NULL inline DbOstream& null(DbOstream& o) { o.add_null(); return o; } /// \brief Insert an integer inline DbOstream& operator<<(DbOstream& o, DbInt64 n) { o.add(n); return o; } /// \brief Insert an double inline DbOstream& operator<<(DbOstream& o, DbDouble d) { o.add(d); return o; } /// \brief Insert sqlite::end_row or sqlite::null inline DbOstream& operator<<(DbOstream& o, DbOstream& (*m)(DbOstream&)) { if (m == &end_row) { o.flush(); } else if (m == &null) { o.add_null(); } else { ikos_unreachable("invalid function pointer argument"); } return o; } /// \brief Stream-based interface for retrieving results of a SQL query class DbIstream { private: /// \brief Database connection DbConnection& _db; /// \brief SQLite3 prepared statement sqlite3_stmt* _stmt = nullptr; /// \brief SQL query std::string _query; /// \brief Are we done ready? bool _done = false; /// \brief Number of columns int _columns; /// \brief Current number of column retrieved int _current_column; public: /// \brief No default constructor DbIstream() = delete; /// \brief Constructor /// /// \param db The database connection /// \param query SQL query DbIstream(DbConnection& db, std::string query); /// \brief No copy constructor DbIstream(const DbIstream&) = delete; /// \brief No copy constructor DbIstream(DbIstream&&) = delete; /// \brief No copy assignment operator DbIstream& operator=(const DbIstream&) = delete; /// \brief No move assignment operator DbIstream& operator=(DbIstream&&) = delete; /// \brief Destructor ~DbIstream(); /// \brief Return the SQL query const std::string& query() const { return this->_query; } /// \brief Is the stream empty? bool empty() const { return _done; } private: /// \brief Retrieve the next row void step(); /// \brief Retrieve the next column void skip_column(); /// \brief Read a string friend DbIstream& operator>>(DbIstream&, std::string&); /// \brief Read an integer friend DbIstream& operator>>(DbIstream&, DbInt64&); /// \brief Read a double friend DbIstream& operator>>(DbIstream&, DbDouble&); }; // class DbIstream } // end namespace sqlite } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table.hpp000066400000000000000000000066271473507761200262370ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Base class for database tables * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Base class for database tables class DatabaseTable { protected: /// \brief Database connection sqlite::DbConnection& _db; /// \brief Table name std::string _name; public: /// \brief No default constructor DatabaseTable() = delete; /// \brief Constructor /// /// \param db The database connection /// \param name The table name /// \param cols The table columns /// \param indexes The table indexes DatabaseTable( sqlite::DbConnection& db, std::string name, llvm::ArrayRef< std::pair< StringRef, sqlite::DbColumnType > > cols, llvm::ArrayRef< StringRef > indexes); /// \brief No copy constructor DatabaseTable(const DatabaseTable&) = delete; /// \brief Move constructor DatabaseTable(DatabaseTable&&) = default; /// \brief No copy assignment operator DatabaseTable& operator=(const DatabaseTable&) = delete; /// \brief No move assignment operator DatabaseTable& operator=(DatabaseTable&&) = delete; /// \brief Destructor ~DatabaseTable() = default; /// \brief Name of the table const std::string& name() const { return this->_name; } }; // end class DatabaseTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/000077500000000000000000000000001473507761200255135ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/call_contexts.hpp000066400000000000000000000063471473507761200311000ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Call contexts database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Call contexts table class CallContextsTable : public DatabaseTable { private: /// \brief Functions table FunctionsTable& _functions; /// \brief Statements table StatementsTable& _statements; /// \brief Database output stream sqlite::DbOstream _row; /// \brief Map from CallContext* to id llvm::DenseMap< CallContext*, sqlite::DbInt64 > _map; /// \brief Last inserted id sqlite::DbInt64 _last_insert_id = 0; public: /// \brief Constructor explicit CallContextsTable(sqlite::DbConnection& db, FunctionsTable& functions, StatementsTable& statements); /// \brief Insert the given call context in the database and return the id sqlite::DbInt64 insert(CallContext* call_context); }; // end class CallContextsTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/checks.hpp000066400000000000000000000070321473507761200274660ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Checks database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Checks table class ChecksTable : public DatabaseTable { private: /// \brief Statements table StatementsTable& _statements; /// \brief Operands table OperandsTable& _operands; /// \brief Call contexts table CallContextsTable& _call_contexts; /// \brief Database output stream sqlite::DbOstream _row; /// \brief Last inserted id sqlite::DbInt64 _last_insert_id = 0; public: /// \brief Constructor explicit ChecksTable(sqlite::DbConnection& db, StatementsTable& statements, OperandsTable& operands, CallContextsTable& call_contexts); /// \brief Insert a check in the database void insert(CheckKind kind, CheckerName checker, Result status, ar::Statement* stmt, CallContext* call_context, llvm::ArrayRef< ar::Value* > operands = {}, const JsonDict& info = {}); }; // end class ChecksTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/files.hpp000066400000000000000000000057161473507761200273370ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Files database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace analyzer { /// \brief Files table class FilesTable : public DatabaseTable { private: /// \brief Database output stream sqlite::DbOstream _row; /// \brief Map from llvm::DIFile* to id llvm::DenseMap< llvm::DIFile*, sqlite::DbInt64 > _di_file_map; /// \brief Map from full path to id llvm::StringMap< sqlite::DbInt64 > _path_map; /// \brief Last inserted id sqlite::DbInt64 _last_insert_id = 0; public: /// \brief Constructor explicit FilesTable(sqlite::DbConnection& db); /// \brief Insert the given file in the database and return the id sqlite::DbInt64 insert(llvm::DIFile* file); }; // end class FilesTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/functions.hpp000066400000000000000000000065651473507761200302500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Functions database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Functions table class FunctionsTable : public DatabaseTable { private: /// \brief Files table FilesTable& _files; /// \brief Database output stream sqlite::DbOstream _row; /// \brief Map from ar::Function* to id llvm::DenseMap< ar::Function*, sqlite::DbInt64 > _map; /// \brief Last inserted id sqlite::DbInt64 _last_insert_id = 0; public: /// \brief Constructor FunctionsTable(sqlite::DbConnection& db, FilesTable& files); /// \brief Insert the given function in the database and return the id sqlite::DbInt64 insert(ar::Function* fun); /// \brief Return the name of the ar::Function used in the database /// /// The returned function name might be mangled static StringRef name(ar::Function*); /// \brief Return the name of the llvm::Function used in the database /// /// The returned function name might be mangled static StringRef name(llvm::Function*); }; // end class FunctionsTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/memory_locations.hpp000066400000000000000000000071331473507761200316130ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Memory locations database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Memory locations table class MemoryLocationsTable : public DatabaseTable { private: /// \brief Functions table FunctionsTable& _functions; /// \brief Statements table StatementsTable& _statements; /// \brief Call contexts table CallContextsTable& _call_contexts; /// \brief Database output stream sqlite::DbOstream _row; /// \brief Map from MemoryLocation* to id llvm::DenseMap< MemoryLocation*, sqlite::DbInt64 > _map; /// \brief Last inserted id sqlite::DbInt64 _last_insert_id = 0; public: /// \brief Constructor explicit MemoryLocationsTable(sqlite::DbConnection& db, FunctionsTable& functions, StatementsTable& statements, CallContextsTable& call_contexts); /// \brief Insert the given memory location in the database and return the id sqlite::DbInt64 insert(MemoryLocation* mem_loc); /// \brief Return the json info for the given memory location JsonDict info(MemoryLocation* mem_loc); }; // end class MemoryLocationsTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/operands.hpp000066400000000000000000000065421473507761200300460ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Operands database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Operands table class OperandsTable : public DatabaseTable { private: /// \brief Database output stream sqlite::DbOstream _row; /// \brief Map from ar::Value* to id llvm::DenseMap< ar::Value*, sqlite::DbInt64 > _map; /// \brief Last inserted id sqlite::DbInt64 _last_insert_id = 0; public: /// \brief Constructor explicit OperandsTable(sqlite::DbConnection& db); /// \brief Insert the given operand in the database and return the id sqlite::DbInt64 insert(ar::Value* value); /// \brief Return a textual representation of a llvm::Type static std::string repr(llvm::Type* type); /// \brief Return a textual representation of a llvm::Constant static std::string repr(llvm::Constant* cst); /// \brief Return a textual representation of a llvm::Value static std::string repr(llvm::Value* value); /// \brief Return a textual representation of an ar::Value static std::string repr(ar::Value* value); }; // end class OperandsTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/settings.hpp000066400000000000000000000055531473507761200300740ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Settings database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Settings table class SettingsTable : public DatabaseTable { private: sqlite::DbOstream _row; public: /// \brief Constructor explicit SettingsTable(sqlite::DbConnection& db); /// \brief Insert a row /// /// This is required because of insert(StringRef, bool) void insert(StringRef name, const char* value); /// \brief Insert a row void insert(StringRef name, StringRef value); /// \brief Insert a row void insert(StringRef name, const JsonNode& value); /// \brief Insert a row void insert(StringRef name, bool value); }; // end class SettingsTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/statements.hpp000066400000000000000000000062211473507761200304140ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Statements database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Statements table class StatementsTable : public DatabaseTable { private: /// \brief Files table FilesTable& _files; /// \brief Functions table FunctionsTable& _functions; /// \brief Database output stream sqlite::DbOstream _row; /// \brief Map from ar::Statement* to id llvm::DenseMap< ar::Statement*, sqlite::DbInt64 > _map; /// \brief Last inserted id sqlite::DbInt64 _last_insert_id = 0; public: /// \brief Constructor StatementsTable(sqlite::DbConnection& db, FilesTable& files, FunctionsTable& functions); /// \brief Insert the given statement in the database and return the id sqlite::DbInt64 insert(ar::Statement* stmt); }; // end class StatementsTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/database/table/times.hpp000066400000000000000000000050271473507761200273510ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Times database table * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Times table class TimesTable : public DatabaseTable { private: sqlite::DbOstream _row; public: /// \brief Constructor explicit TimesTable(sqlite::DbConnection& db); /// \brief Insert a row void insert(StringRef name, sqlite::DbDouble time); }; // end class TimesTable } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/exception.hpp000066400000000000000000000150551473507761200253750ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Exception definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Base class for analyzer exceptions class Exception : public core::Exception { public: /// \brief Create a new exception /// /// Note that a call to what() will return an empty string. Exception() noexcept = default; /// \brief Copy constructor Exception(const Exception&) noexcept = default; /// \brief Move constructor Exception(Exception&&) noexcept = default; /// \brief Copy assignment operator Exception& operator=(const Exception&) noexcept = default; /// \brief Move assignment operator Exception& operator=(Exception&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override; /// \brief Destructor ~Exception() override; }; // end class Exception /// \brief Exception for logical errors class LogicError : public Exception { private: /// \brief Explanatory message /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _msg; public: /// \brief Constructor /// /// \param msg Explanatory message explicit LogicError(const std::string& msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief Constructor /// /// \param msg Explanatory message explicit LogicError(const char* msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief No default constructor LogicError() = delete; /// \brief Copy constructor LogicError(const LogicError&) noexcept = default; /// \brief Move constructor LogicError(LogicError&&) noexcept = default; /// \brief Copy assignment operator LogicError& operator=(const LogicError&) noexcept = default; /// \brief Move assignment operator LogicError& operator=(LogicError&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override; /// \brief Destructor ~LogicError() override; }; // end class LogicError /// \brief Exception for errors in command line arguments class ArgumentError : public Exception { private: /// \brief Explanatory message /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _msg; public: /// \brief Constructor /// /// \param msg Explanatory message explicit ArgumentError(const std::string& msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief Constructor /// /// \param msg Explanatory message explicit ArgumentError(const char* msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief No default constructor ArgumentError() = delete; /// \brief Copy constructor ArgumentError(const ArgumentError&) noexcept = default; /// \brief Move constructor ArgumentError(ArgumentError&&) noexcept = default; /// \brief Copy assignment operator ArgumentError& operator=(const ArgumentError&) noexcept = default; /// \brief Move assignment operator ArgumentError& operator=(ArgumentError&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override; /// \brief Destructor ~ArgumentError() override; }; // end class ArgumentError /// \brief Exception for frontend errors class FrontendError : public Exception { private: /// \brief Explanatory message /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _msg; public: /// \brief Constructor /// /// \param msg Explanatory message explicit FrontendError(const std::string& msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief Constructor /// /// \param msg Explanatory message explicit FrontendError(const char* msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief No default constructor FrontendError() = delete; /// \brief Copy constructor FrontendError(const FrontendError&) noexcept = default; /// \brief Move constructor FrontendError(FrontendError&&) noexcept = default; /// \brief Copy assignment operator FrontendError& operator=(const FrontendError&) noexcept = default; /// \brief Move assignment operator FrontendError& operator=(FrontendError&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override; /// \brief Destructor ~FrontendError() override; }; // end class FrontendError } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/intrinsic.h000066400000000000000000000141771473507761200250450ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief ikos intrinsics definitions * * Include this header in an analyzed code to define ikos intrinsics, such as * __ikos_assert(), __ikos_assume(), etc. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #if defined(__IKOS__) #include #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus #define IKOS_NOEXCEPT noexcept #else #define IKOS_NOEXCEPT #endif /// \brief Test the given condition /// /// The assertion prover (ikos -a prover) will try to prove that the condition /// always holds. extern void __ikos_assert(int condition) IKOS_NOEXCEPT; // clang-format off /// \macro __ikos_assume /// /// Assume that the given condition always holds. #define __ikos_assume(condition) if (!(condition)) { __builtin_unreachable(); } // clang-format on /// \brief Return a non-deterministic signed integer extern int __ikos_nondet_int(void) IKOS_NOEXCEPT; /// \brief Return a non-deterministic unsigned integer extern unsigned __ikos_nondet_uint(void) IKOS_NOEXCEPT; /// \brief Check if a memory access is valid /// /// The buffer overflow analysis (ikos -a boa) will check if the memory at /// `[ptr, ptr + size - 1]` is accessible. /// /// The null pointer dereference analysis (ikos -a nullity) will check if the /// pointer is null. extern void __ikos_check_mem_access(const void* ptr, size_t size) IKOS_NOEXCEPT; /// \brief Check if a null-terminated string access is valid /// /// The buffer overflow analysis (ikos -a boa) will check if the given string /// access leads to a buffer overflow. /// /// The null pointer dereference analysis (ikos -a nullity) will check if the /// pointer is null. extern void __ikos_check_string_access(const char* str) IKOS_NOEXCEPT; /// \brief Assume that the memory pointed by `ptr` has the given size, in bytes extern void __ikos_assume_mem_size(const void* ptr, size_t size) IKOS_NOEXCEPT; /// \brief Forget the memory contents at `[ptr, ptr + size - 1]` /// /// Assume the memory now contains random bytes. /// /// This is undefined behavior if the pointer is null. extern void __ikos_forget_mem(void* ptr, size_t size) IKOS_NOEXCEPT; /// \brief Abstract the memory contents at `[ptr, ptr + size - 1]` /// /// Assume the memory now contains random bytes, but no valid pointers. /// /// This is undefined behavior if the pointer is null. extern void __ikos_abstract_mem(void* ptr, size_t size) IKOS_NOEXCEPT; /// \brief Watch the memory writes at `[ptr, ptr + size - 1]` /// /// The memory watcher (ikos -a watch) will print the location of statements /// that write at the given memory location. extern void __ikos_watch_mem(const void* ptr, size_t size) IKOS_NOEXCEPT; /// \brief Print the invariant at the function call /// /// The debugger (ikos -a dbg) will print the current invariant. extern void __ikos_print_invariant(void) IKOS_NOEXCEPT; /// \brief Partition the invariant according to the given integer variable extern void __ikos_partitioning_var_int(int) IKOS_NOEXCEPT; /// \brief Join the current partitions extern void __ikos_partitioning_join(void) IKOS_NOEXCEPT; /// \brief Disable the current partitioning extern void __ikos_partitioning_disable(void) IKOS_NOEXCEPT; /// \brief Print the information on the given values at the function call /// /// The debugger (ikos -a dbg) will print the information on the /// given values at the function call location. /// /// \param desc Description, for debugging purpose /// /// \code{.c} /// __ikos_print_values("x", x); /// \endcode extern void __ikos_print_values(const char* desc, ...) IKOS_NOEXCEPT; #undef IKOS_NOEXCEPT #ifdef __cplusplus } #endif #else // __IKOS__ #define __ikos_assert(condition) #define __ikos_assume(condition) #define __ikos_nondet_int() ((int)0) #define __ikos_nondet_uint() ((unsigned)0) #define __ikos_check_mem_access(ptr, size) #define __ikos_check_string_access(str) #define __ikos_assume_mem_size(ptr, size) #define __ikos_forget_mem(ptr, size) #define __ikos_abstract_mem(ptr, size) #define __ikos_watch_mem(ptr, size) #define __ikos_partitioning_var_int(x) #define __ikos_partitioning_join() #define __ikos_partitioning_disable() #define __ikos_print_invariant() #define __ikos_print_values(...) #endif NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/json/000077500000000000000000000000001473507761200236315ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/json/helper.hpp000066400000000000000000000063261473507761200256300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Helpers to convert analyzer objects into JSON. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2016-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace analyzer { /// \brief Convert a machine integer interval to a JSON dictionary inline JsonDict to_json(const core::machine_int::Interval& interval) { ikos_assert(!interval.is_bottom()); JsonDict dict; std::string type; type += (interval.sign() == Signed) ? 's' : 'u'; type += std::to_string(interval.bit_width()); dict.put("type", type); dict.put("lb", interval.lb()); dict.put("ub", interval.ub()); return dict; } /// \brief Convert a machine integer congruence to a JSON dictionary inline JsonDict to_json(const core::machine_int::Congruence& congruence) { ikos_assert(!congruence.is_bottom()); JsonDict dict; std::string type; type += (congruence.sign() == Signed) ? 's' : 'u'; type += std::to_string(congruence.bit_width()); dict.put("type", type); dict.put("a", congruence.modulus()); dict.put("b", congruence.residue()); return dict; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/json/json.hpp000066400000000000000000000224371473507761200253230ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Data structures for the manipulation of JSON objects * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2016-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Base class for JSON objects class JsonNode { public: /// \brief Constructor JsonNode() = default; /// \brief Copy constructor JsonNode(const JsonNode&) noexcept = default; /// \brief Move constructor JsonNode(JsonNode&&) noexcept = default; /// \brief Copy assignment operator JsonNode& operator=(const JsonNode&) noexcept = default; /// \brief Move assignment operator JsonNode& operator=(JsonNode&&) noexcept = default; /// \brief Return the string representation virtual std::string str() const = 0; /// \brief Destructor virtual ~JsonNode(); }; // end class JsonNode /// \brief Convert basic types to JsonNode inline const JsonNode& to_json(const JsonNode& n) { return n; } /// \brief A JSON integer class JsonInteger final : public JsonNode { private: ZNumber _n; public: /// \brief Constructor explicit JsonInteger(ZNumber n) : _n(std::move(n)) {} /// \brief Return the string representation std::string str() const override; }; // end class JsonInteger /// \brief Convert integers to JsonInteger template < typename T, class = std::enable_if_t< core::IsSupportedIntegral< T >::value > > inline JsonInteger to_json(T n) { return JsonInteger(ZNumber(n)); } /// \brief Convert integers to JsonInteger inline JsonInteger to_json(ZNumber n) { return JsonInteger(std::move(n)); } /// \brief Convert integers to JsonInteger inline JsonInteger to_json(const MachineInt& n) { return JsonInteger(n.to_z_number()); } /// \brief A JSON floating point class JsonFloat final : public JsonNode { private: double _d; public: /// \brief Constructor explicit JsonFloat(double d) : _d(d) {} /// \brief Return the string representation std::string str() const override; }; // end class JsonFloat /// \brief Convert floating points to JsonFloat inline JsonFloat to_json(float f) { return JsonFloat(static_cast< double >(f)); } /// \brief Convert floating points to JsonFloat inline JsonFloat to_json(double d) { return JsonFloat(d); } /// \brief A JSON boolean class JsonBool final : public JsonNode { private: bool _b; public: /// \brief Constructor explicit JsonBool(bool b) : _b(b) {} /// \brief Return the string representation std::string str() const override; }; // end class JsonBool /// \brief Convert booleans to JsonBool inline JsonBool to_json(bool b) { return JsonBool(b); } /// \brief A JSON string class JsonString final : public JsonNode { private: std::string _s; public: /// \brief Constructor explicit JsonString(std::string s) : _s(std::move(s)) {} /// \brief Return the string representation std::string str() const override; }; // end class JsonString /// \brief Convert strings to JsonString inline JsonString to_json(std::string s) { return JsonString(std::move(s)); } /// \brief Convert strings to JsonString inline JsonString to_json(const char* s) { return JsonString(s); } /// \brief A JSON list class JsonList final : public JsonNode { private: // No need to keep all elements of the list to implement str() /// \brief String representation std::string _buf; public: /// \brief Create an empty list JsonList() = default; /// \brief Copy constructor JsonList(const JsonList&) = default; /// \brief Create a list with the given parameters template < typename... Args > explicit JsonList(const Args&... args) { recursive_add(args...); } /// \brief Move constructor JsonList(JsonList&&) = default; /// \brief Copy assignment operator JsonList& operator=(const JsonList&) = default; /// \brief Move assignment operator JsonList& operator=(JsonList&&) = default; /// \brief Destructor ~JsonList() override = default; /// \brief Clear the list void clear() { this->_buf.clear(); } /// \brief Return true if the list is empty bool empty() const { return this->_buf.empty(); } /// \brief Add an element to the list template < typename T > void add(const T& v) { if (!this->_buf.empty()) { this->_buf.push_back(','); } this->_buf.append(to_json(v).str()); } /// \brief Return the string representation std::string str() const override; private: // Implementation details for JsonList(const Args&... args) void recursive_add() {} template < typename T, typename... Args > void recursive_add(const T& v, const Args&... args) { add(v); recursive_add(args...); } }; // end class JsonList /// \brief Create a JsonList with the given range template < typename Iterator > inline JsonList to_json(Iterator begin, Iterator end) { JsonList l; for (auto it = begin; it != end; ++it) { l.add(*it); } return l; } /// \brief A JSON dictionary class JsonDict final : public JsonNode { private: // No need to keep all elements of the dict to implement str() /// \brief String representation std::string _buf; private: // Helper for JsonDict(std::initializer_list< Binding >) class Binding { private: std::string _buf; public: /// \brief Constructor template < typename T > Binding(std::string key, const T& value) { this->_buf.append(JsonString(std::move(key)).str()); this->_buf.push_back(':'); this->_buf.append(to_json(value).str()); } /// \brief Copy constructor Binding(const Binding&) = default; /// \brief No move constructor Binding(Binding&&) = delete; /// \brief No copy assignment operator Binding& operator=(const Binding&) = delete; /// \brief No move assignment operator Binding& operator=(Binding&&) = delete; /// \brief Destructor ~Binding() = default; const std::string& str() const { return this->_buf; } }; public: /// \brief Create an empty dictionary JsonDict() = default; /// \brief Copy constructor JsonDict(const JsonDict&) = default; /// \brief Create a dictionary with the given pairs JsonDict(std::initializer_list< Binding > l) { for (const auto& binding : l) { if (!this->_buf.empty()) { this->_buf.push_back(','); } this->_buf.append(binding.str()); } } /// \brief Move constructor JsonDict(JsonDict&&) = default; /// \brief Copy assignment operator JsonDict& operator=(const JsonDict&) = default; /// \brief Move assignment operator JsonDict& operator=(JsonDict&&) = default; /// \brief Destructor ~JsonDict() override = default; /// \brief Clear the dictionary void clear() { this->_buf.clear(); } /// \brief Return true if the dictionary is empty bool empty() const { return this->_buf.empty(); } /// \brief Add a (key, value) pair in the dictionary template < typename T > void put(std::string key, const T& value) { if (!this->_buf.empty()) { this->_buf.push_back(','); } this->_buf.append(JsonString(std::move(key)).str()); this->_buf.push_back(':'); this->_buf.append(to_json(value).str()); } /// \brief Return the string representation std::string str() const override; }; // end class JsonDict /// \brief Write a JSON node on a stream inline std::ostream& operator<<(std::ostream& o, const JsonNode& n) { o << n.str(); return o; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/support/000077500000000000000000000000001473507761200243745ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/support/assert.hpp000066400000000000000000000042051473507761200264070ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Assertion definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/support/cast.hpp000066400000000000000000000067711473507761200260520ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Casting definitions (isa, cast, dyn_cast) * * This header includes: * * ikos/core/support/cast.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Check if the parameter is an instance of the template type argument /// /// Used like this: /// /// \code{.cpp} /// if (isa< GlobalVariable >(v)) { ... } /// \endcode using core::isa; /// \brief Return the argument parameter cast to the specified type /// /// This casting operator asserts that the type is correct. It does not allow /// a null argument. /// /// Used like this: /// /// \code{.cpp} /// Instruction* inst = cast< Instruction >(val) /// \endcode using core::cast; /// \brief Return the argument parameter cast to the specified type /// /// This is equivalent to cast< X >, except that a null value is allowed. using core::cast_or_null; /// \brief Return the argument parameter cast to the specified type /// /// This casting operator returns null if the argument is of the wrong type, so /// it can used to test for a type as well as cast if successful. /// /// Used like this: /// /// \code{.cpp} /// if (Instruction* inst = dyn_cast< Instruction >(val)) { ... } /// \endcode using core::dyn_cast; /// \brief Return the argument parameter cast to the specified type /// /// This is equivalent to dyn_cast< X >, except that a null value is allowed. using core::dyn_cast_or_null; } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/support/flags.hpp000066400000000000000000000046461473507761200262130ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Flags class definitions * * This header includes: * * ikos/ar/support/flags.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace analyzer { /// \brief Type-safe way of storing OR-combinations of enum values template < typename Enum > using Flags = ar::Flags< Enum >; } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/support/number.hpp000066400000000000000000000060661473507761200264050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Number definitions * * This header includes: * * ikos/core/number/supported_integral.hpp * * ikos/core/number/signedness.hpp * * ikos/core/number/dummy_number.hpp * * ikos/core/number/z_number.hpp * * ikos/core/number/machine_int.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Signedness (signed or unsigned) using Signedness = ikos::core::Signedness; using ikos::core::Signed; using ikos::core::Unsigned; /// \brief Empty class that represents a number using DummyNumber = ikos::core::DummyNumber; /// \brief Class for unlimited precision integers using ZNumber = ikos::core::ZNumber; /// \brief Class for arbitrary precision machine integers using MachineInt = ikos::core::MachineInt; } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/support/string_ref.hpp000066400000000000000000000052331473507761200272520ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Reference to a constant string * * This header includes ikos/core/adt/string_ref.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace analyzer { /// \brief Represents a reference to a constant string using StringRef = ikos::core::StringRef; /// \brief Append a StringRef to the end of a std::string using ikos::core::operator+=; /// \brief Convert a llvm::StringRef to a core::StringRef inline StringRef to_string_ref(llvm::StringRef s) { return {s.data(), s.size()}; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/util/000077500000000000000000000000001473507761200236355ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/util/color.hpp000066400000000000000000000106751473507761200254750ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Color utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once namespace ikos { namespace analyzer { /// \brief Terminal colors enum class TermColor { Grey = 0, Red = 1, Green = 2, Yellow = 3, Blue = 4, Magenta = 5, Cyan = 6, White = 7, }; /// \brief Terminal attributes enum class TermAttribute { Bold = 1, Dark = 2, Underline = 4, Blink = 5, Reverse = 7, Concealed = 8, }; namespace color { /// \brief Is color enabled? extern bool Enable; /// \brief Return a control escape sequence, or empty string if colors are /// disabled inline const char* if_enabled(const char* s) { return Enable ? s : ""; } inline const char* off() { return if_enabled("\x1B[0m"); } inline const char* bold() { return if_enabled("\x1B[1m"); } inline const char* grey() { return if_enabled("\x1B[30m"); } inline const char* red() { return if_enabled("\x1B[31m"); } inline const char* green() { return if_enabled("\x1B[32m"); } inline const char* yellow() { return if_enabled("\x1B[33m"); } inline const char* blue() { return if_enabled("\x1B[34m"); } inline const char* magenta() { return if_enabled("\x1B[35m"); } inline const char* cyan() { return if_enabled("\x1B[36m"); } inline const char* white() { return if_enabled("\x1B[37m"); } inline const char* bold_grey() { return if_enabled("\x1B[1;30m"); } inline const char* bold_red() { return if_enabled("\x1B[1;31m"); } inline const char* bold_green() { return if_enabled("\x1B[1;32m"); } inline const char* bold_yellow() { return if_enabled("\x1B[1;33m"); } inline const char* bold_blue() { return if_enabled("\x1B[1;34m"); } inline const char* bold_magenta() { return if_enabled("\x1B[1;35m"); } inline const char* bold_cyan() { return if_enabled("\x1B[1;36m"); } inline const char* bold_white() { return if_enabled("\x1B[1;37m"); } inline const char* on_grey() { return if_enabled("\x1B[40m"); } inline const char* on_red() { return if_enabled("\x1B[41m"); } inline const char* on_green() { return if_enabled("\x1B[42m"); } inline const char* on_yellow() { return if_enabled("\x1B[43m"); } inline const char* on_blue() { return if_enabled("\x1B[44m"); } inline const char* on_magenta() { return if_enabled("\x1B[45m"); } inline const char* on_cyan() { return if_enabled("\x1B[46m"); } inline const char* on_white() { return if_enabled("\x1B[47m"); } } // end namespace color } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/util/demangle.hpp000066400000000000000000000075051473507761200261310ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Utility functions to demangle C++ symbols. * * Authors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #if BOOST_VERSION <= 105500 #include #else #include #endif #include namespace ikos { namespace analyzer { /// \brief Return true if the given symbol name is mangled inline bool is_mangled(const char* name) { // No need to check the size because name is null-terminated // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return name[0] == '_' && name[1] >= 'A' && name[1] <= 'Z'; } /// \brief Return true if the given symbol name is mangled inline bool is_mangled(StringRef name) { // Check the size, name is not null-terminated return name.size() >= 2 && is_mangled(name.data()); } /// \brief Return the demangled symbol name, or name if it is not mangled inline std::string demangle(const char* name) { if (is_mangled(name)) { #if BOOST_VERSION <= 105500 return boost::units::detail::demangle(name); #else return boost::core::demangle(name); #endif } else { return name; } } /// \brief Return the demangled symbol name, or name if it is not mangled inline std::string demangle(const std::string& name) { return demangle(name.c_str()); } /// \brief Return the demangled symbol name, or name if it is not mangled inline std::string demangle(StringRef name) { // boost::core::demangle requires a null-terminated string return demangle(name.to_string()); } /// \brief Return the demangled symbol name, or name if it is not mangled inline std::string demangle(llvm::StringRef name) { // boost::core::demangle requires a null-terminated string return demangle(name.str()); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/util/log.hpp000066400000000000000000000174231473507761200251360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Logging utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Log level, from least to most verbose enum class LogLevel { None = 60, Critical = 50, Error = 40, Warning = 30, Info = 20, Debug = 10, All = 0 }; // forward declaration class Logger; /// \brief Represents a log message class LogMessage { private: friend class Logger; private: /// \brief Logger Logger* _logger; /// \brief Output stream std::ostream* _out; private: /// \brief Constructor LogMessage(Logger& logger, std::ostream& out) : _logger(&logger), _out(&out) { this->start(); } public: /// \brief No copy constructor LogMessage(const LogMessage&) = delete; /// \brief Move constructor LogMessage(LogMessage&& o) noexcept : _logger(o._logger), _out(o._out) { o._logger = nullptr; o._out = nullptr; } /// \brief No copy assignment operator LogMessage& operator=(const LogMessage&) = delete; /// \brief No move assignment operator LogMessage& operator=(LogMessage&&) = delete; /// \brief Return the output stream of the message std::ostream& stream() const { ikos_assert(this->_out != nullptr); return *this->_out; } /// \brief Destructor ~LogMessage() { if (this->_logger != nullptr) { this->end(); } } private: /// \brief Notify the logger of a new log message void start(); /// \brief Notify the logger of the end of a log message void end(); }; // end class LoggerOutputStream /// \brief Write a log message template < typename T > inline const LogMessage& operator<<(const LogMessage& msg, T&& v) { msg.stream() << std::forward< T >(v); return msg; } /// \brief Base class for loggers class Logger { private: friend class LogMessage; protected: /// \brief Output stream std::ostream& _out; public: /// \brief constructor explicit Logger(std::ostream& out) noexcept : _out(out) {} /// \brief No copy constructor Logger(const Logger&) = delete; /// \brief No move constructor Logger(Logger&&) = delete; /// \brief No copy assignment operator Logger& operator=(const Logger&) = delete; /// \brief No move assignment operator Logger& operator=(Logger&&) = delete; /// \brief Destructor virtual ~Logger() = default; /// \brief Return a new log message LogMessage create_message() { return {*this, this->_out}; } /// \brief This is called once when the logger becomes active virtual void start_logger() = 0; /// \brief This is called once when the logger becomes inactive virtual void end_logger() = 0; /// \brief This is called once before writing a log message virtual void start_message() = 0; /// \brief This is called once after writing a log message virtual void end_message() = 0; }; // end class Logger /// \brief Logger on the terminal class TerminalLogger final : public Logger { public: /// \brief Constructor explicit TerminalLogger(std::ostream& out) noexcept; /// \brief This is called once when the logger becomes active void start_logger() override; /// \brief This is called once when the logger becomes inactive void end_logger() override; /// \brief This is called once before writing a log message void start_message() override; /// \brief This is called once after writing a log message void end_message() override; }; // end class TerminalLogger /// \brief Setup a logger for a given scope class ScopeLogger { private: /// \brief Previous logger Logger& _previous_logger; public: /// \brief Constructor explicit ScopeLogger(Logger& logger); /// \brief No copy constructor ScopeLogger(const ScopeLogger&) = delete; /// \brief No move constructor ScopeLogger(ScopeLogger&&) = delete; /// \brief No copy assignment operator ScopeLogger& operator=(const ScopeLogger&) = delete; /// \brief No move assignment operator ScopeLogger& operator=(ScopeLogger&&) = delete; /// \brief Destructor ~ScopeLogger(); }; // end class ScopeLogger namespace log { /// \brief Global logging level extern LogLevel Level; /// \brief Set the logger void set_logger(Logger&); /// \brief Get the logger Logger& get_logger(); /// \brief Logging output stream inline LogMessage msg() { return get_logger().create_message(); } /// \brief Return true if a message of severity `level` would be displayed inline bool is_enabled_for(LogLevel user_level) { return Level <= user_level; } /// \brief Log a critical message inline void critical(StringRef message) { if (is_enabled_for(LogLevel::Critical)) { msg() << "[" << color::on_red() << "CRITICAL" << color::off() << "] " << message << "\n"; } } /// \brief Log an error message inline void error(StringRef message) { if (is_enabled_for(LogLevel::Error)) { msg() << "[" << color::on_red() << "ERROR" << color::off() << "] " << message << "\n"; } } /// \brief Log a warning message inline void warning(StringRef message) { if (is_enabled_for(LogLevel::Warning)) { msg() << "[" << color::bold_yellow() << "!" << color::off() << "] " << message << "\n"; } } /// \brief Log an informative message inline void info(StringRef message) { if (ikos_unlikely(is_enabled_for(LogLevel::Info))) { msg() << "[" << color::bold_blue() << "*" << color::off() << "] " << message << "\n"; } } /// \brief Log a debug message inline void debug(StringRef message) { if (ikos_unlikely(is_enabled_for(LogLevel::Debug))) { msg() << "[" << color::magenta() << "." << color::off() << "] " << message << "\n"; } } } // end namespace log } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/util/progress.hpp000066400000000000000000000145721473507761200262230ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Progress logging utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace analyzer { /// \brief Base class for loggers with progress report class ProgressLogger : public Logger { public: /// \brief Constructor explicit ProgressLogger(std::ostream& out); /// \brief Notify the beginning of a task with the given status message virtual void start_task(StringRef status) = 0; }; // end class ProgressLogger /// \brief Interactive progress logger class InteractiveProgressLogger final : public ProgressLogger { private: /// \brief Current task std::size_t _current_task; /// \brief Number of tasks std::size_t _num_tasks; /// \brief Current status std::string _status; /// \brief Number of columns in the output stream std::size_t _out_columns; public: /// \brief Constructor /// /// \param out Output stream /// \param num_tasks Number of tasks /// \param out_columns Number of columns in the output stream InteractiveProgressLogger(std::ostream& out, std::size_t num_tasks, std::size_t out_columns); /// \brief Notify the beginning of a task with the given status message void start_task(StringRef status) override; /// \brief This is called once when the logger becomes active void start_logger() override; /// \brief This is called once when the logger becomes inactive void end_logger() override; /// \brief This is called once before writing a log message void start_message() override; /// \brief This is called once after writing a log message void end_message() override; private: /// \brief Erase the current line void erase_line(); /// \brief Print the current status void print_status(); }; // end class InteractiveProgressLogger /// \brief Linear progress logger class LinearProgressLogger final : public ProgressLogger { private: /// \brief Current task std::size_t _current_task; /// \brief Number of tasks std::size_t _num_tasks; public: /// \brief Constructor /// /// \param out Output stream /// \param num_tasks Number of tasks LinearProgressLogger(std::ostream& out, std::size_t num_tasks); /// \brief Notify the beginning of a task with the given status message void start_task(StringRef status) override; /// \brief This is called once when the logger becomes active void start_logger() override; /// \brief This is called once when the logger becomes inactive void end_logger() override; /// \brief This is called once before writing a log message void start_message() override; /// \brief This is called once after writing a log message void end_message() override; }; // end class LinearProgressLogger /// \brief Progress logger that discards status updates class NoProgressLogger final : public ProgressLogger { public: /// \brief Constructor explicit NoProgressLogger(std::ostream& out); /// \brief Notify the beginning of a task with the given status message void start_task(StringRef status) override; /// \brief This is called once when the logger becomes active void start_logger() override; /// \brief This is called once when the logger becomes inactive void end_logger() override; /// \brief This is called once before writing a log message void start_message() override; /// \brief This is called once after writing a log message void end_message() override; }; // end class NoProgressLogger /// \brief Create a progress logger /// /// \param opt Progress option /// \param level Log level /// \param num_tasks Number of tasks std::unique_ptr< ProgressLogger > make_progress_logger(ProgressOption opt, LogLevel level, std::size_t num_tasks); /// \brief Create a progress logger /// /// \param opt Progress option /// \param level Log level /// \param num_tasks Number of tasks inline std::unique_ptr< ProgressLogger > make_progress_logger( ProgressOption opt, LogLevel level, std::ptrdiff_t num_tasks) { ikos_assert(num_tasks >= 0); return make_progress_logger(opt, level, static_cast< std::size_t >(num_tasks)); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/util/source_location.hpp000066400000000000000000000063311473507761200275410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Utilities for source code locations * * Authors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace analyzer { /// \brief Represents a source code location using frontend::import::SourceLocation; /// \brief Return the absolute path of the given source file using frontend::import::source_path; /// \brief Return the source location of the given statement using frontend::import::source_location; /// \brief Return the given source location as a string /// /// \param loc Source location /// \param wd Current working directory std::string source_location_string(SourceLocation loc, const boost::filesystem::path& wd); /// \brief Return the source location of the given statement as a string /// /// \param stmt Statement /// \param wd Current working directory inline std::string source_location_string(ar::Statement* stmt, const boost::filesystem::path& wd) { return source_location_string(source_location(stmt), wd); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/include/ikos/analyzer/util/timer.hpp000066400000000000000000000121471473507761200254730ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Timer utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace analyzer { /// \brief Timer class class Timer { public: using Clock = std::chrono::steady_clock; using TimePoint = std::chrono::time_point< Clock >; using Duration = std::chrono::duration< double >; private: TimePoint _start; TimePoint _end; public: /// \brief Constructor Timer() = default; /// \brief Copy constructor Timer(const Timer&) = default; /// \brief No move constructor Timer(Timer&&) = delete; /// \brief Copy assignment operator Timer& operator=(const Timer&) = default; /// \brief No move assignment operator Timer& operator=(Timer&&) = delete; /// \brief Destructor ~Timer() = default; /// \brief Start the timer void start() { this->_start = Clock::now(); } /// \brief Stop the timer void stop() { this->_end = Clock::now(); } /// \brief Return the elapsed time Duration elapsed() const { return std::chrono::duration_cast< Duration >(this->_end - this->_start); } }; // end class Timer /// \brief Timer on a scope class ScopeTimer { private: /// \brief Actual timer Timer _timer; /// \brief Function to run at the end of the scope std::function< void(Timer::Duration) > _callback; public: /// \brief Constructor /// /// \param callback Called at the end of the scope, with the elapsed time template < typename Fn > explicit ScopeTimer(Fn&& callback) : _callback(std::forward< Fn >(callback)) { this->_timer.start(); } /// \brief No copy constructor ScopeTimer(const ScopeTimer&) = delete; /// \brief No move constructor ScopeTimer(ScopeTimer&&) = delete; /// \brief No copy assignment operator ScopeTimer& operator=(const ScopeTimer&) = delete; /// \brief No move assignment operator ScopeTimer& operator=(ScopeTimer&&) = delete; /// \brief Destructor ~ScopeTimer() { this->_timer.stop(); try { this->_callback(this->_timer.elapsed()); } catch (...) { std::terminate(); } } }; // end class ScopeTimer // forward declaration class TimesTable; /// \brief Timer that saves the elapsed time at the end of the scope in a /// database class ScopeTimerDatabase { private: /// \brief Actual timer Timer _timer; /// \brief Times table TimesTable& _table; /// \brief Timer name std::string _name; public: /// \brief Constructor /// /// \param table The times table /// \param name Timer name ScopeTimerDatabase(TimesTable& table, std::string name); /// \brief No copy constructor ScopeTimerDatabase(const ScopeTimerDatabase&) = delete; /// \brief No move constructor ScopeTimerDatabase(ScopeTimerDatabase&&) = delete; /// \brief No copy assignment operator ScopeTimerDatabase& operator=(const ScopeTimerDatabase&) = delete; /// \brief No move assignment operator ScopeTimerDatabase& operator=(ScopeTimerDatabase&&) = delete; /// \brief Destructor ~ScopeTimerDatabase(); }; // end class ScopeTimerDatabase } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/python/000077500000000000000000000000001473507761200177645ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/000077500000000000000000000000001473507761200207315ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/__init__.py000066400000000000000000000000001473507761200230300ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/abs_int.py000066400000000000000000000205011473507761200227200ustar00rootroot00000000000000############################################################################### # # Abstract interpretation utilities for python # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### class Signedness: SIGNED = 0 UNSIGNED = 1 def assert_compatible(a, b): ''' Check that the given parameters have the same bit-width and sign ''' assert a.bit_width == b.bit_width and a.sign == b.sign class MachineInt: ''' Represents a machine integer ''' __slots__ = ('n', 'bit_width', 'sign') def __init__(self, n, bit_width, sign): self.n = n self.bit_width = bit_width self.sign = sign self._normalize() def _normalize(self): if self.is_signed(): # n needs to be within [-2**(n-1), 2**(n-1)-1] self.n = self.n + 2**(self.bit_width - 1) self.n = self.n % 2**self.bit_width self.n = self.n - 2**(self.bit_width - 1) else: # n needs to be within [0, 2**n-1] self.n = self.n % 2**self.bit_width def is_signed(self): return self.sign == Signedness.SIGNED def is_unsigned(self): return self.sign == Signedness.UNSIGNED @staticmethod def min(bit_width, sign): if sign == Signedness.SIGNED: return MachineInt(-2**(bit_width - 1), bit_width, sign) else: return MachineInt(0, bit_width, sign) def is_min(self): if self.is_signed(): return self.n == -2**(self.bit_width - 1) else: return self.n == 0 @staticmethod def max(bit_width, sign): if sign == Signedness.SIGNED: return MachineInt(2**(bit_width - 1) - 1, bit_width, sign) else: return MachineInt(2**bit_width - 1, bit_width, sign) def is_max(self): if self.is_signed(): return self.n == 2**(self.bit_width - 1) - 1 else: return self.n == 2**self.bit_width - 1 def high_bit(self): if self.is_signed(): return self.n < 0 else: return self.n >= 2**(self.bit_width - 1) def sign_cast(self, sign): return MachineInt(self.n, self.bit_width, sign) def __eq__(self, other): assert_compatible(self, other) return self.n == other.n def __lt__(self, other): assert_compatible(self, other) return self.n < other.n def __le__(self, other): assert_compatible(self, other) return self.n <= other.n def __gt__(self, other): assert_compatible(self, other) return self.n > other.n def __ge__(self, other): assert_compatible(self, other) return self.n >= other.n def __str__(self): return str(self.n) class Interval: ''' Represents an interval [a, b], or bottom ''' __slots__ = ('lb', 'ub') def __init__(self, lb, ub): assert_compatible(lb, ub) self.lb = lb self.ub = ub @staticmethod def top(bit_width, sign): return Interval(MachineInt.min(bit_width, sign), MachineInt.max(bit_width, sign)) @staticmethod def bottom(bit_width, sign): return Interval(MachineInt.max(bit_width, sign), MachineInt.min(bit_width, sign)) @staticmethod def from_dict(info): ''' Create an interval from a dictionary ''' t = info['type'] sign = Signedness.SIGNED if t[0] == 's' else Signedness.UNSIGNED bit_width = int(t[1:]) return Interval(MachineInt(info['lb'], bit_width, sign), MachineInt(info['ub'], bit_width, sign)) @property def bit_width(self): return self.lb.bit_width @property def sign(self): return self.lb.sign def is_bottom(self): return self.lb > self.ub def is_top(self): return self.lb.is_min() and self.ub.is_max() def is_constant(self): return self.lb == self.ub def to_constraints(self, var): assert not self.is_bottom() if self.is_top(): return 'could not bound %s' % var elif self.lb == self.ub: return '%s = %s' % (var, self.lb) elif self.lb.is_min(): return '%s <= %s' % (var, self.ub) elif self.ub.is_max(): return '%s >= %s' % (var, self.lb) else: return '%s <= %s <= %s' % (self.lb, var, self.ub) def sign_cast(self, sign): if self.sign == sign: return self elif self.is_bottom(): return Interval.bottom(self.bit_width, sign) else: if self.lb.high_bit() == self.ub.high_bit(): lb = self.lb.sign_cast(sign) ub = self.ub.sign_cast(sign) if lb <= ub: return Interval(lb, ub) else: return Interval(ub, lb) else: return Interval.top(self.bit_width, sign) def __str__(self): if self.is_bottom(): return '⊥' elif self.is_top(): return 'T' else: return '[%s, %s]' % (self.lb, self.ub) class Congruence: ''' Represents a congruence aZ + b, or bottom ''' __slots__ = ('a', 'b', 'bit_width', 'sign', 'bottom') def __init__(self, a, b, bit_width, sign, bottom): self.a = a self.b = b self.bit_width = bit_width self.sign = sign self.bottom = bottom self._normalize() def _normalize(self): if self.bottom: self.a = self.b = None return assert self.a >= 0 if self.a != 0: self.b = self.b % self.a @staticmethod def from_dict(info): ''' Create a congruence from a dictionary ''' t = info['type'] sign = Signedness.SIGNED if t[0] == 's' else Signedness.UNSIGNED bit_width = int(t[1:]) return Congruence(a=info['a'], b=info['b'], bit_width=bit_width, sign=sign, bottom=False) def is_bottom(self): return self.bottom def is_top(self): return not self.bottom and self.a == 1 def is_constant(self): return not self.bottom and self.a == 0 def __str__(self): if self.is_bottom(): return '⊥' if self.a == 0: return str(self.b) if self.b == 0: return '%dZ' % self.a return '%dZ+%d' % (self.a, self.b) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/analyzer.py000066400000000000000000001230461473507761200231360ustar00rootroot00000000000000############################################################################### # # Handle ikos toolchain: running clang, ikos-pp and ikos-analyzer. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import atexit import datetime import json import os import os.path import shlex import shutil import signal import subprocess import sys import tempfile import threading from ikos import args from ikos import colors from ikos import log from ikos import report from ikos import settings from ikos import stats from ikos.log import printf from ikos.output_db import OutputDatabase def parse_arguments(argv): usage = '%(prog)s [options] file[.c|.cpp|.bc|.ll]' description = 'ikos static analyzer' formatter_class = argparse.RawTextHelpFormatter parser = argparse.ArgumentParser(usage=usage, description=description, formatter_class=formatter_class) # Positional arguments parser.add_argument('file', metavar='file[.c|.cpp|.bc|.ll]', help='File to analyze') # Optional arguments parser.add_argument('-o', '--output-db', dest='output_db', metavar='', help='Output database file (default: output.db)', default='output.db') parser.add_argument('-v', dest='verbosity', help='Increase verbosity', action='count', default=1) parser.add_argument('-q', dest='verbosity', help='Be quiet', action='store_const', const=0) parser.add_argument('--version', action=args.VersionAction, nargs=0, help='Show ikos version') # Analysis options analysis = parser.add_argument_group('Analysis Options') analysis.add_argument('-a', '--analyses', dest='analyses', metavar='', help=args.help('Available analyses:', args.analyses, args.default_analyses), action='append') analysis.add_argument('-d', '--domain', dest='domain', metavar='', help=args.help('Available abstract domains:', args.domains, args.default_domain), choices=args.choices(args.domains), default=args.default_domain) analysis.add_argument('-e', '--entry-points', dest='entry_points', metavar='', help='List of program entry points (default: main)', action='append') analysis.add_argument('--globals-init', dest='globals_init', metavar='', help=args.help( 'Policy of initialization for global variables:', args.globals_init_policies, args.default_globals_init_policy), choices=args.choices(args.globals_init_policies), default=args.default_globals_init_policy) analysis.add_argument('--no-init-globals', dest='no_init_globals', metavar='', help='Do not initialize global variables for the ' 'given entry points', action='append') analysis.add_argument('--no-liveness', dest='no_liveness', help='Disable the liveness analysis', action='store_true', default=False) analysis.add_argument('--no-pointer', dest='no_pointer', help='Disable the pointer analysis', action='store_true', default=False) analysis.add_argument('--no-widening-hints', dest='no_widening_hints', help='Disable the widening hint analysis', action='store_true', default=False) analysis.add_argument('--no-fixpoint-cache', dest='no_fixpoint_cache', help='Disable the cache of fixpoints', action='store_true', default=False) analysis.add_argument('--no-checks', dest='no_checks', help='Disable all the checks', action='store_true', default=False) analysis.add_argument('--proc', dest='procedural', metavar='', help=args.help('Procedural:', args.proceduralities, args.default_procedurality), choices=args.choices(args.proceduralities), default=args.default_procedurality) analysis.add_argument('-j', '--jobs', dest='jobs', metavar='', nargs='?', help='Number of threads', type=int, const=0, default=1) analysis.add_argument('--widening-strategy', dest='widening_strategy', metavar='', help=args.help('Strategy for increasing iterations:', args.widening_strategies, args.default_widening_strategy), choices=args.choices(args.widening_strategies), default=args.default_widening_strategy) analysis.add_argument('--narrowing-strategy', dest='narrowing_strategy', metavar='', help=args.help('Strategy for decreasing iterations:', args.narrowing_strategies, args.default_narrowing_strategy), choices=args.choices(args.narrowing_strategies), default=args.default_narrowing_strategy) analysis.add_argument('--widening-delay', dest='widening_delay', metavar='', help='Number of loop iterations before using the' ' widening strategy (default: %d)' % args.default_widening_delay, default=args.default_widening_delay, type=args.Integer(min=0)) analysis.add_argument('--widening-delay-functions', dest='widening_delay_functions', metavar='', help='Widening delay for specific functions', action='append') analysis.add_argument('--widening-period', dest='widening_period', metavar='', help='Number of loop iterations between each' ' widening (default: %d)' % args.default_widening_period, default=args.default_widening_period, type=args.Integer(min=1)) analysis.add_argument('--narrowing-iterations', dest='narrowing_iterations', metavar='', help='Perform a fixed number of narrowing' ' iterations', type=args.Integer(min=0)) analysis.add_argument('--partitioning', dest='partitioning', metavar='', help=args.help('Partitioning strategy:', args.partitioning_strategies, args.default_partitioning_strategy), choices=args.choices(args.partitioning_strategies), default=args.default_partitioning_strategy) analysis.add_argument('--hardware-addresses', dest='hardware_addresses', metavar='', action='append', help='Specify ranges (x-y) of hardware addresses' ', separated by a comma') analysis.add_argument('--hardware-addresses-file', dest='hardware_addresses_file', metavar='', help='Specify ranges (x-y) of hardware addresses' ' from a file (one range per line)') analysis.add_argument('--argc', dest='argc', metavar='', help='Specify a value for argc', type=args.Integer(min=0)) # Compile options compiler = parser.add_argument_group('Compile Options') compiler.add_argument('-I', dest='compiler_include_flags', metavar='', help='Add the specified directory to the search ' 'path for include files', action='append') compiler.add_argument('-D', dest='compiler_define_flags', metavar='', help='Add an implicit #define into the source file', action='append') compiler.add_argument('-W', dest='compiler_warning_flags', metavar='', help='Use the specified warning options', action='append') compiler.add_argument('-w', dest='compiler_disable_warnings', help='Suppress all compiler warnings', action='store_true', default=False) compiler.add_argument('-m', dest='compiler_machine_flags', metavar='', help='Use the specified machine options', action='append') # Preprocessing options preprocess = parser.add_argument_group('Preprocessing Options') preprocess.add_argument('--opt', dest='opt_level', metavar='', help=args.help('Optimization level:', args.opt_levels, args.default_opt_level), choices=args.choices(args.opt_levels), default=args.default_opt_level) preprocess.add_argument('--inline-all', dest='inline_all', help='Front-end inline all functions', action='store_true', default=False) preprocess.add_argument('--no-bc-verify', dest='no_bc_verify', help='Do not run the LLVM bitcode verifier', action='store_true', default=False) # Import options imports = parser.add_argument_group('Import Options') imports.add_argument('--no-libc', dest='no_libc', help='Do not use libc intrinsics ' '(malloc, free, etc.)', action='store_true', default=False) imports.add_argument('--no-libcpp', dest='no_libcpp', help='Do not use libcpp intrinsics ' '(__cxa_throw, etc.)', action='store_true', default=False) imports.add_argument('--no-libikos', dest='no_libikos', help='Do not use ikos intrinsics ' '(__ikos_assert, etc.)', action='store_true', default=False) # AR passes options passes = parser.add_argument_group('AR Passes Options') passes.add_argument('--no-type-check', dest='no_type_check', help='Do not run the AR type checker', action='store_true', default=False) passes.add_argument('--no-simplify-cfg', dest='no_simplify_cfg', help='Do not run the simplify-cfg pass', action='store_true', default=False) passes.add_argument('--no-simplify-upcast-comparison', dest='no_simplify_upcast_comparison', help='Do not run the simplify-upcast-comparison pass', action='store_true', default=False) # Debug options debug = parser.add_argument_group('Debug Options') debug.add_argument('--display-llvm', dest='display_llvm', help='Display the LLVM bitcode as text', action='store_true', default=False) debug.add_argument('--display-ar', dest='display_ar', help='Display the Abstract Representation as text', action='store_true', default=False) debug.add_argument('--trace-ar-stmts', dest='trace_ar_stmts', help='Trace analysis of ar statements', action='store_true', default=False) debug.add_argument('--display-liveness', dest='display_liveness', help='Display liveness analysis results', action='store_true', default=False) debug.add_argument('--display-function-pointer', dest='display_function_pointer', help='Display function pointer analysis results', action='store_true', default=False) debug.add_argument('--display-pointer', dest='display_pointer', help='Display pointer analysis results', action='store_true', default=False) debug.add_argument('--display-fixpoint-parameters', dest='display_fixpoint_parameters', help='Display fixpoint parameters', action='store_true', default=False) debug.add_argument('--display-checks', dest='display_checks', metavar='', help=args.help('Display checks:', args.display_checks_choices, 'no'), choices=args.choices(args.display_checks_choices), default='no') debug.add_argument('--display-inv', dest='display_inv', metavar='', help=args.help('Display computed invariants:', args.display_inv_choices, 'no'), choices=args.choices(args.display_inv_choices), default='no') debug.add_argument('--display-raw-checks', dest='display_raw_checks', help='Display analysis raw checks', action='store_true', default=False) debug.add_argument('--generate-dot', dest='generate_dot', help='Generate a .dot file for each function', action='store_true', default=False) debug.add_argument('--generate-dot-dir', dest='generate_dot_dir', metavar='', help='Output directory for .dot files', default=None) debug.add_argument('--save-temps', dest='save_temps', help='Do not delete temporary files', action='store_true', default=False) debug.add_argument('--temp-dir', dest='temp_dir', metavar='', help='Temporary directory', default=None) # Misc. misc = parser.add_argument_group('Miscellaneous') misc.add_argument('--rm-db', dest='remove_db', help='Remove the output database file after use', action='store_true', default=False) misc.add_argument('--color', dest='color', metavar='', help=args.help('Enable terminal colors:', args.color_choices, args.default_color), choices=args.choices(args.color_choices), default=args.default_color) misc.add_argument('--log', dest='log_level', metavar='', help=args.help('Log level:', args.log_levels, args.default_log_level), choices=args.choices(args.log_levels), default=None) misc.add_argument('--progress', dest='progress', metavar='', help=args.help('Progress report:', args.progress_choices, args.default_progress), choices=args.choices(args.progress_choices), default=args.default_progress) # Report options report = parser.add_argument_group('Report Options') report.add_argument('--display-times', dest='display_times', metavar='', help=args.help('Display timing results', args.display_times_choices, 'short'), choices=args.choices(args.display_times_choices), default='short') report.add_argument('--display-summary', dest='display_summary', metavar='', help=args.help('Display the analysis summary', args.display_summary_choices, 'full'), choices=args.choices(args.display_summary_choices), default='full') report.add_argument('-f', '--format', dest='format', metavar='', help=args.help('Available report formats:', args.report_formats, 'auto'), choices=args.choices(args.report_formats), default='auto') report.add_argument('--report-file', dest='report_file', metavar='', help='Write the report into a file (default: stdout)', default=sys.stdout, type=argparse.FileType('w')) report.add_argument('--status-filter', dest='status_filter', metavar='', help=args.help('Available status filters:', args.status_filters, args.default_status_filter), action='append') report.add_argument('--report-verbosity', dest='report_verbosity', metavar='[1-4]', help='Report verbosity (default: 1)', type=args.Integer(min=1, max=4)) # Resource options resource = parser.add_argument_group('Resources Options') resource.add_argument('--cpu', dest='cpu', help='CPU time limit (seconds)', type=args.Integer(min=1)) resource.add_argument('--mem', dest='mem', help='MEM limit (MB)', type=args.Integer(min=1)) opt = parser.parse_args(argv) # parse --analyses opt.analyses = args.parse_argument(parser, 'analyses', choices=args.analyses, groups=None, default=args.default_analyses, value=opt.analyses) # by default, the entry point is main if not opt.entry_points: opt.entry_points = ('main',) # verbosity changes the log level, if --log is not specified if opt.log_level is None: if opt.verbosity <= 0: opt.log_level = 'error' elif opt.verbosity == 1: opt.log_level = 'info' elif opt.verbosity == 2: opt.log_level = 'debug' else: opt.log_level = 'all' # quiet mode does not display the timing results and the analysis summary if opt.verbosity <= 0: opt.display_times = 'no' opt.display_summary = 'no' # default value for generate-dot-dir if opt.generate_dot and not opt.generate_dot_dir: if opt.temp_dir and opt.save_temps: opt.generate_dot_dir = opt.temp_dir else: opt.generate_dot_dir = '.' # parse --status-filter opt.status_filter = args.parse_argument(parser, 'status-filter', choices=args.status_filters, groups=None, default=args.default_status_filter, value=opt.status_filter) # verbosity changes the report verbosity level, # if --report-verbosity is not specified if opt.report_verbosity is None: opt.report_verbosity = max(opt.verbosity, 1) return opt sh_quote = shlex.quote def command_string(cmd): return ' '.join(map(sh_quote, cmd)) def path_ext(path): ''' Return the filename extension. >>> path_ext('test.c') '.c' >>> path_ext('/tmp/file.my.ext') '.ext' ''' return os.path.splitext(path)[1] c_extensions = ('.c', '.h', '.i') cpp_extensions = ('.cpp', '.cc', '.cxx', '.cppm', '.c++', '.cp', '.C', '.CPP', '.hpp', '.hh', '.hxx', '.ii', '.iim') llvm_extensions = ('.bc', '.ll') def create_working_directory(wd=None, save=False): ''' Create a temporary working directory ''' if not wd: wd = tempfile.mkdtemp(prefix='ikos-') if not os.path.exists(wd): try: os.makedirs(wd) except OSError as e: printf('error: %s: %s\n', wd, e.strerror, file=sys.stderr) sys.exit(1) if not os.path.isdir(wd): printf('error: %s: Not a directory\n', wd, file=sys.stderr) sys.exit(1) if not save: atexit.register(shutil.rmtree, path=wd) else: log.info('Temporary files will be kept in directory: %s' % wd) return wd def namer(path, ext, wd): ''' Return the path to a file with the given extension, in the given working directory. >>> namer('/home/me/test.c', '.bc', '/tmp/ikos-xxx') '/tmp/ikos-xxx/test.bc' ''' base = os.path.basename(path) return os.path.join(wd, os.path.splitext(base)[0] + ext) def signal_name(signum): ''' Return the signal name given the signal number ''' for name, value in signal.__dict__.items(): if (name.startswith('SIG') and not name.startswith('SIG_') and value == signum): return name return str(signum) def is_apron_domain(domain): ''' Return True if the given domain is an APRON numerical domain ''' return 'apron-' in domain domains_without_narrowing = ( 'apron-polka-polyhedra', 'apron-polka-linear-equalities', 'apron-ppl-polyhedra', 'apron-ppl-linear-congruences', 'apron-pkgrid-polyhedra-lin-cong', 'var-pack-apron-polka-polyhedra', 'var-pack-apron-polka-linear-equalities', 'var-pack-apron-ppl-polyhedra', 'var-pack-apron-ppl-linear-congruences', 'var-pack-apron-pkgrid-polyhedra-lin-cong', ) def clang_emit_llvm_flags(): ''' Clang flags to emit llvm bitcode ''' return ['-c', '-emit-llvm'] def clang_ikos_flags(): ''' Clang flags for ikos ''' return [ # enable clang warnings '-Wall', # disable source code fortification '-U_FORTIFY_SOURCE', '-D_FORTIFY_SOURCE=0', # flag for intrinsic.h '-D__IKOS__', # compile in debug mode '-g', # disable optimizations '-O0', # disable the 'optnone' attribute # see https://bugs.llvm.org/show_bug.cgi?id=35950#c10 '-Xclang', '-disable-O0-optnone', ] ################## # ikos toolchain # ################## def clang( bc_path, cpp_path, include_flags=None, define_flags=None, warning_flags=None, disable_warnings=False, machine_flags=None, colors=True, ): cmd = [settings.clang()] cmd += clang_emit_llvm_flags() cmd += clang_ikos_flags() cmd += [cpp_path, '-o', bc_path] # For #include cmd += ['-isystem', settings.INCLUDE_DIR] if include_flags: cmd += ['-I%s' % i for i in include_flags] if define_flags: cmd += ['-D%s' % d for d in define_flags] if warning_flags: cmd += ['-W%s' % w for w in warning_flags] if disable_warnings: cmd.append('-w') if machine_flags: cmd += ['-m%s' % m for m in machine_flags] if colors: cmd.append('-fcolor-diagnostics') else: cmd.append('-fno-color-diagnostics') if path_ext(cpp_path) in cpp_extensions: cmd.append('-std=c++17') # available because clang >= 7.0 log.info('Compiling %s' % cpp_path) log.debug('Running %s' % command_string(cmd)) subprocess.check_call(cmd) def ikos_pp(pp_path, bc_path, entry_points, opt_level, inline_all, verify): if opt_level == 'aggressive': log.warning('Using aggressive optimizations is not recommended') log.warning('The translation from LLVM bitcode to AR might fail') cmd = [settings.ikos_pp(), '-opt=%s' % opt_level, '-entry-points=%s' % ','.join(entry_points)] if inline_all: cmd.append('-inline-all') if not verify: cmd.append('-no-verify') cmd += [bc_path, '-o', pp_path] log.info('Running ikos preprocessor') log.debug('Running %s' % command_string(cmd)) subprocess.check_call(cmd) def display_llvm(pp_path): log.info('Printing LLVM') cmd = [settings.opt(), '-S', pp_path] subprocess.check_call(cmd) class AnalyzerError(Exception): def __init__(self, message, cmd, returncode): super(AnalyzerError, self).__init__(message) self.cmd = cmd self.returncode = returncode def ikos_analyzer(db_path, pp_path, opt): if settings.BUILD_MODE == 'Debug': log.warning('ikos was built in debug mode, the analysis might be slow') if is_apron_domain(opt.domain) and opt.jobs != 1: log.warning('apron abstract domains are not thread-safe, ' 'the analysis might crash') # Fix huge slow down when ikos-analyzer uses DROP TABLE on an existing db if os.path.isfile(db_path): os.remove(db_path) cmd = [settings.ikos_analyzer()] # analysis options cmd += ['-a=%s' % ','.join(opt.analyses), '-d=%s' % opt.domain, '-entry-points=%s' % ','.join(opt.entry_points), '-globals-init=%s' % opt.globals_init, '-proc=%s' % opt.procedural, '-j=%d' % opt.jobs, '-widening-strategy=%s' % opt.widening_strategy, '-widening-delay=%d' % opt.widening_delay, '-widening-period=%d' % opt.widening_period] if opt.narrowing_strategy == 'auto': if opt.domain in domains_without_narrowing: cmd.append('-narrowing-strategy=meet') else: cmd.append('-narrowing-strategy=narrow') else: cmd.append('-narrowing-strategy=%s' % opt.narrowing_strategy) if opt.narrowing_iterations is not None: cmd.append('-narrowing-iterations=%d' % opt.narrowing_iterations) elif (opt.narrowing_strategy == 'auto' and opt.domain in domains_without_narrowing): cmd.append('-narrowing-iterations=%d' % args.meet_iterations_if_no_narrowing) if opt.widening_delay_functions: cmd.append('-widening-delay-functions=%s' % ','.join(opt.widening_delay_functions)) if opt.no_init_globals: cmd.append('-no-init-globals=%s' % ','.join(opt.no_init_globals)) if opt.no_liveness: cmd.append('-no-liveness') if opt.no_pointer: cmd.append('-no-pointer') if opt.no_widening_hints: cmd.append('-no-widening-hints') if opt.partitioning != 'no': cmd.append('-enable-partitioning-domain') if opt.no_fixpoint_cache: cmd.append('-no-fixpoint-cache') if opt.no_checks: cmd.append('-no-checks') if opt.hardware_addresses: cmd.append('-hardware-addresses=%s' % ','.join(opt.hardware_addresses)) if opt.hardware_addresses_file: cmd.append('-hardware-addresses-file=%s' % opt.hardware_addresses_file) if opt.argc is not None: cmd.append('-argc=%d' % opt.argc) # import options cmd.append('-allow-dbg-mismatch') if opt.no_bc_verify: cmd.append('-no-verify') if opt.no_libc: cmd.append('-no-libc') if opt.no_libcpp: cmd.append('-no-libcpp') if opt.no_libikos: cmd.append('-no-libikos') # AR passes options if opt.no_type_check: cmd.append('-no-type-check') if opt.no_simplify_cfg: cmd.append('-no-simplify-cfg') if opt.no_simplify_upcast_comparison: cmd.append('-no-simplify-upcast-comparison') if 'gauge' in opt.domain: cmd.append('-add-loop-counters') if opt.partitioning == 'return': cmd.append('-add-partitioning-variables') # debug options cmd += ['-display-checks=%s' % opt.display_checks, '-display-inv=%s' % opt.display_inv] if opt.display_ar: cmd.append('-display-ar') if opt.trace_ar_stmts: cmd.append('-trace-ar-stmts') if opt.display_liveness: cmd.append('-display-liveness') if opt.display_function_pointer: cmd.append('-display-function-pointer') if opt.display_pointer: cmd.append('-display-pointer') if opt.display_fixpoint_parameters: cmd.append('-display-fixpoint-parameters') if opt.generate_dot: cmd += ['-generate-dot', '-generate-dot-dir', opt.generate_dot_dir] # add -name-values if necessary if (opt.display_checks in ('all', 'fail') or opt.display_inv in ('all', 'fail') or opt.display_liveness or opt.display_fixpoint_parameters or opt.display_function_pointer or opt.display_pointer or opt.display_raw_checks): cmd.append('-name-values') # misc. options if opt.color == 'yes': cmd.append('-color=1') elif opt.color == 'no': cmd.append('-color=0') cmd.append('-log=%s' % opt.log_level) cmd.append('-progress=%s' % opt.progress) # input/output cmd += [pp_path, '-o', db_path] # set resource limit, if requested if opt.mem: import resource # fails on Windows def set_limits(): mem_bytes = opt.mem * 1024 * 1024 resource.setrlimit(resource.RLIMIT_AS, [mem_bytes, mem_bytes]) else: set_limits = None # called after timeout def kill(p): try: log.error('Timeout') p.send_signal(signal.SIGALRM) except OSError: pass log.info('Running ikos analyzer') log.debug('Running %s' % command_string(cmd)) p = subprocess.Popen(cmd, preexec_fn=set_limits) timer = threading.Timer(opt.cpu, kill, [p]) if opt.cpu: timer.start() try: if sys.platform.startswith('win'): return_status = p.wait() else: _, return_status = os.waitpid(p.pid, 0) finally: # kill the timer if the process has terminated already if timer.is_alive(): timer.cancel() # special case for Windows, since it does not define WIFEXITED & co. if sys.platform.startswith('win'): if return_status != 0: raise AnalyzerError('a run-time error occurred', cmd, return_status) else: return # if it did not terminate properly, propagate this error code if os.WIFEXITED(return_status) and os.WEXITSTATUS(return_status) != 0: exit_status = os.WEXITSTATUS(return_status) raise AnalyzerError('a run-time error occurred', cmd, exit_status) if os.WIFSIGNALED(return_status): signum = os.WTERMSIG(return_status) raise AnalyzerError('exited with signal %s' % signal_name(signum), cmd, signum) if os.WIFSTOPPED(return_status): signum = os.WSTOPSIG(return_status) raise AnalyzerError('exited with signal %d' % signal_name(signum), cmd, signum) def ikos_view(opt, db): from ikos import view v = view.View(db) v.serve() ################# # main for ikos # ################# def main(argv): progname = os.path.basename(argv[0]) start_date = datetime.datetime.now() # parse arguments opt = parse_arguments(argv[1:]) # setup colors and logging colors.setup(opt.color, file=log.out) log.setup(opt.log_level) if is_apron_domain(opt.domain) and not settings.HAS_APRON: printf('%s: error: cannot use apron abstract domains.\n' 'ikos was compiled without apron support, ' 'see analyzer/README.md\n', progname, file=sys.stderr) sys.exit(1) # create working directory wd = create_working_directory(opt.temp_dir, opt.save_temps) input_path = opt.file # compile c/c++ code if path_ext(input_path) in c_extensions + cpp_extensions: bc_path = namer(opt.file, '.bc', wd) try: with stats.timer('clang'): clang(bc_path, input_path, opt.compiler_include_flags, opt.compiler_define_flags, opt.compiler_warning_flags, opt.compiler_disable_warnings, opt.compiler_machine_flags, colors.ENABLE) except subprocess.CalledProcessError as e: printf('%s: error while compiling %s, abort.\n', progname, input_path, file=sys.stderr) sys.exit(e.returncode) input_path = bc_path if path_ext(input_path) not in llvm_extensions: printf('%s: error: unexpected file extension.\n', progname, file=sys.stderr) sys.exit(1) # ikos-pp: preprocess llvm bitcode pp_path = namer(opt.file, '.pp.bc', wd) try: with stats.timer('ikos-pp'): ikos_pp(pp_path, input_path, opt.entry_points, opt.opt_level, opt.inline_all, not opt.no_bc_verify) except subprocess.CalledProcessError as e: printf('%s: error while preprocessing llvm bitcode, abort.\n', progname, file=sys.stderr) sys.exit(e.returncode) # display the llvm bitcode, if requested if opt.display_llvm: display_llvm(pp_path) # ikos-analyzer: analyze llvm bitcode try: with stats.timer('ikos-analyzer'): ikos_analyzer(opt.output_db, pp_path, opt) except AnalyzerError as e: printf('%s: error: %s\n', progname, e, file=sys.stderr) sys.exit(e.returncode) # open output database db = OutputDatabase(path=opt.output_db) # insert timing results in the database db.insert_timing_results(stats.rows()) # insert settings in the database settings_rows = [ ('version', settings.VERSION), ('start-date', start_date.isoformat(' ')), ('end-date', datetime.datetime.now().isoformat(' ')), ('working-directory', wd), ('input', opt.file), ('bc-file', input_path), ('pp-bc-file', pp_path), ('clang', settings.clang()), ('ikos-pp', settings.ikos_pp()), ('opt-level', opt.opt_level), ('inline-all', json.dumps(opt.inline_all)), ('use-libc-intrinsics', json.dumps(not opt.no_libc)), ('use-libcpp-intrinsics', json.dumps(not opt.no_libcpp)), ('use-libikos-intrinsics', json.dumps(not opt.no_libikos)), ('use-simplify-cfg', json.dumps(not opt.no_simplify_cfg)), ('use-simplify-upcast-comparison', json.dumps(not opt.no_simplify_upcast_comparison)), ] if opt.cpu: settings_rows.append(('cpu-limit', opt.cpu)) if opt.mem: settings_rows.append(('mem-limit', opt.mem)) db.insert_settings(settings_rows) first = (log.LEVEL >= log.ERROR) # display timing results if opt.display_times != 'no': if not first: printf('\n') report.print_timing_results(db, opt.display_times == 'full') first = False # display summary if opt.display_summary != 'no': if not first: printf('\n') report.print_summary(db, opt.display_summary == 'full') first = False # display raw checks if opt.display_raw_checks: if not first: printf('\n') report.print_raw_checks(db, opt.procedural == 'inter') first = False # start ikos-view if opt.format == 'web': ikos_view(opt, db) return # report if opt.format != 'no': if not first and opt.report_file is sys.stdout: printf('\n' + colors.bold('# Results') + '\n') first = False # setup colors again (in case opt.color = 'auto') colors.setup(opt.color, file=opt.report_file) # generate report rep = report.generate_report(db, status_filter=opt.status_filter, analyses_filter=None) # format report formatter_class = report.formats[opt.format] formatter = formatter_class(opt.report_file, opt.report_verbosity) formatter.format(rep) # close database db.close() if opt.remove_db: os.remove(opt.output_db) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/args.py000066400000000000000000000260071473507761200222440ustar00rootroot00000000000000############################################################################### # # Helpers for arguments # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse from ikos import settings def help(title, choices, default=None): ''' Build a help message for an argument ''' maxlen = max(len(opt) for opt, _ in choices) s = title for opt, description in choices: s += '\n %s - %s' % (opt.ljust(maxlen), description) if opt == default: s += ' (default)' if isinstance(default, (list, tuple)): s += '\n(default: %s)' % ', '.join(default) return s def choices(choices): ''' Build the tuple of choices ''' return list(opt for opt, _ in choices) def parse_argument(parser, name, choices, groups, default, value): ''' Parse an argument with commas >>> choices = (('a', 'desc'), ('b','desc'), ('c', 'desc'), ('d', 'desc')) >>> default = ('a', 'b', 'c') >>> parse_argument(p, 'name', choices, None, default, None) set(['a', 'b', 'c']) >>> parse_argument(p, 'name', choices, None, default, 'a,b') set(['a', 'b']) >>> parse_argument(p, 'name', choices, None, default, '*,-a,-c') set(['b', 'd']) ''' if not value: value = default if isinstance(value, (list, tuple)): value = ','.join(value) choices = set(choice[0] for choice in choices) choices.discard('*') # prevent a bug result = set() for param in value.split(','): param = param.strip() if not param: pass # Parse +/- qualifier = '+' if param[0] == '+': param = param[1:] elif param[0] == '-': qualifier = '-' param = param[1:] param = param.strip() if not param: pass param_set = set() if param == '*': param_set = choices elif param in choices: param_set = {param} elif groups and param in groups: param_set = set(groups[param]) else: parser.error("argument --%s: invalid choice: '%s'" % (name, param)) if qualifier == '+': result.update(param_set) elif qualifier == '-': result.difference_update(param_set) return result class VersionAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): print('ikos %s' % settings.VERSION) print('Copyright (c) 2011-2023 United States Government as represented' ' by the') print('Administrator of the National Aeronautics and Space ' 'Administration.') print('All Rights Reserved.') parser.exit() def Integer(min=None, max=None): def parser(string): try: value = int(string) except ValueError: raise argparse.ArgumentTypeError( "invalid integer value: '%s'" % string ) if min is not None and value < min: raise argparse.ArgumentTypeError( "invalid integer value: %d < %d" % (value, min) ) if max is not None and value > max: raise argparse.ArgumentTypeError( "invalid integer value: %d > %d" % (value, max) ) return value return parser # Analysis options choices analyses = ( ('boa', 'Buffer Overflow Analysis'), ('dbz', 'Division by Zero Analysis'), ('nullity', 'Null Pointer Dereference Analysis'), ('prover', 'Assertion Prover'), ('upa', 'Unaligned Pointer Analysis'), ('uva', 'Uninitialized Variables Analysis'), ('sio', 'Signed Integer Overflow Analysis'), ('uio', 'Unsigned Integer Overflow Analysis'), ('shc', 'Shift Count Analysis'), ('poa', 'Pointer Overflow Analysis'), ('pcmp', 'Pointer Comparison Analysis'), ('sound', 'Soundness Analysis'), ('fca', 'Function Call Analysis'), ('dca', 'Dead Code Analysis'), ('dfa', 'Double Free Analysis'), ('dbg', 'Debugger'), ('watch', 'Memory Watcher'), ) default_analyses = ( 'boa', 'dbz', 'nullity', 'prover', 'uva', 'sio', 'shc', 'pcmp', 'sound', 'fca', 'dca', 'dfa', 'dbg', ) domains = ( ('interval', 'Interval domain'), ('congruence', 'Congruence domain'), ('interval-congruence', 'Reduced product of Interval and Congruence'), ('dbm', 'Difference-Bound Matrices domain'), ('var-pack-dbm', 'Difference-Bound Matrices domain with variable packing'), ('var-pack-dbm-congruence', 'Reduced product of DBM with variable packing and Congruence'), ('gauge', 'Gauge domain'), ('gauge-interval-congruence', 'Reduced product of Gauge, Interval and Congruence'), ('apron-interval', 'APRON Interval domain'), ('apron-octagon', 'APRON Octagon domain'), ('apron-polka-polyhedra', 'APRON Polka Polyhedra domain'), ('apron-polka-linear-equalities', 'APRON Polka Linear Equalities domain'), ('apron-ppl-polyhedra', 'APRON PPL Polyhedra domain'), ('apron-ppl-linear-congruences', 'APRON PPL Linear Congruences domain'), ('apron-pkgrid-polyhedra-lin-cong', 'APRON Pkgrid Polyhedra and Linear Congruences domain'), ('var-pack-apron-octagon', 'APRON Octagon domain with variable packing'), ('var-pack-apron-polka-polyhedra', 'APRON Polka Polyhedra domain with variable packing'), ('var-pack-apron-polka-linear-equalities', 'APRON Polka Linear Equalities domain with variable packing'), ('var-pack-apron-ppl-polyhedra', 'APRON PPL Polyhedra domain with variable packing'), ('var-pack-apron-ppl-linear-congruences', 'APRON PPL Linear Congruences domain with variable packing'), ('var-pack-apron-pkgrid-polyhedra-lin-cong', 'APRON Pkgrid Polyhedra and Linear Congruences domain' ' with variable packing'), ) default_domain = 'interval' globals_init_policies = ( ('all', 'Initialize all global variables'), ('skip-big-arrays', 'Initialize all global variables except big arrays'), ('skip-strings', 'Initialize all global variables except strings'), ('none', 'Do not initialize any global variable'), ) default_globals_init_policy = 'skip-big-arrays' proceduralities = ( ('inter', 'Interprocedural analysis'), ('intra', 'Intraprocedural analysis'), ) default_procedurality = 'inter' widening_strategies = ( ('widen', 'Widening operator'), ('join', 'Join operator'), ) default_widening_strategy = 'widen' narrowing_strategies = ( ('narrow', 'Narrowing operator'), ('meet', 'Meet operator'), ('auto', 'Narrowing if available, otherwise meet'), ) default_narrowing_strategy = 'auto' default_widening_delay = 1 default_widening_period = 1 meet_iterations_if_no_narrowing = 2 partitioning_strategies = ( ('return', 'Partition the states on function return values'), ('manual', 'Partition the states manually'), ('no', 'Disable partitioning'), ) default_partitioning_strategy = 'no' # Preprocessing options choices opt_levels = ( ('none', 'Disable all optimizations'), ('basic', 'Basic set of optimizations'), ('aggressive', 'Aggressive optimizations (not recommended)'), ) default_opt_level = 'basic' # Debug options choices display_checks_choices = ( ('all', 'Display all checks'), ('fail', 'Display only failed checks'), ('no', 'Do not display checks'), ) display_inv_choices = ( ('all', 'Display all invariants'), ('fail', 'Display invariants for failed checks'), ('no', 'Do not display invariants'), ) # Misc. options choices color_choices = ( ('yes', 'Enable colors'), ('auto', 'Enable colors if the output is a terminal'), ('no', 'Disable colors'), ) default_color = 'auto' log_levels = ( ('none', 'Disable logging'), ('critical', 'Critical level'), ('error', 'Error level'), ('warning', 'Warning level'), ('info', 'Informative level'), ('debug', 'Debug level'), ('all', 'Show all messages'), ) default_log_level = 'info' progress_choices = ( ('auto', 'Interactive if the output is a terminal'), ('interactive', 'Interactive'), ('linear', 'Linear'), ('no', 'Disable progress report'), ) default_progress = 'auto' # Report options choices display_times_choices = ( ('full', 'Display all timing results'), ('short', 'Display most meaningful timing results'), ('no', 'Do not display any timing results'), ) display_summary_choices = ( ('full', 'Display the complete analysis summary'), ('short', 'Display a shorter analysis summary'), ('no', 'Do not display the analysis summary'), ) report_formats = ( ('auto', 'Generate a text report, if less than 15 entries'), ('text', 'Generate a text report'), ('json', 'Generate a json report'), ('sarif', 'Generate a sarif report'), ('junit', 'Generate a JUnit.xml report'), ('csv', 'Generate a csv report'), ('web', 'Generate a web report (ikos-view)'), ('no', 'Do not generate a report'), ) status_filters = ( ('*', 'All'), ('error', 'Error'), ('warning', 'Warning'), ('safe', 'Safe'), ('unreachable', 'Unreachable'), ) default_status_filter = ('error', 'warning', 'unreachable') NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/colors.py000066400000000000000000000072601473507761200226110ustar00rootroot00000000000000############################################################################### # # Color utilities # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os import sys # are colors enable? ENABLE = True # available colors COLORS = { 'grey': 0, 'red': 1, 'green': 2, 'yellow': 3, 'blue': 4, 'magenta': 5, 'cyan': 6, 'white': 7, } # available attributes ATTRIBUTES = { 'bold': 1, 'dark': 2, 'underline': 4, 'blink': 5, 'reverse': 7, 'concealed': 8 } def setup(color, file=sys.stdout): global ENABLE if color in ('yes', 'on', 'always'): ENABLE = True elif color in ('no', 'off', 'never'): ENABLE = False elif color == 'auto': ENABLE = os.isatty(file.fileno()) def colorize(text, color=None, on_color=None, attrs=None): ''' Colorize text. >>> colorize('Hello, World!', 'red', 'grey', ['bold', 'blink']) '\x1b[5m\x1b[1m\x1b[40m\x1b[31mHello, World!\x1b[0m' >>> colorize('Hello, World!', 'green') '\x1b[32mHello, World!\x1b[0m' ''' if ENABLE: if color: text = '\033[%dm%s' % (30 + COLORS[color], text) if on_color: text = '\033[%dm%s' % (40 + COLORS[on_color], text) if attrs: for attr in attrs: text = '\033[%dm%s' % (ATTRIBUTES[attr], text) text += '\033[0m' return text ########### # helpers # ########### def bold(s): return colorize(s, attrs=['bold']) for color in COLORS: globals()[color] = (lambda s, color=color: colorize(s, color)) globals()['bold_%s' % color] = (lambda s, color=color: colorize(s, color, attrs=['bold'])) globals()['on_%s' % color] = (lambda s, color=color: colorize(s, on_color=color)) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/enums.py000066400000000000000000000237321473507761200224410ustar00rootroot00000000000000############################################################################### # # IKOS enums # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### def auto(reset=None): ''' Helper for enumerations ''' if reset is not None: auto.counter = reset value = auto.counter auto.counter += 1 return value class Result: OK = 0 WARNING = 1 ERROR = 2 UNREACHABLE = 3 STRING_LIST = ['ok', 'warning', 'error', 'unreachable'] STRING_MAP = { 'ok': OK, 'safe': OK, 'warning': WARNING, 'error': ERROR, 'unreachable': UNREACHABLE, } @classmethod def str(cls, v): return cls.STRING_LIST[v] @classmethod def from_str(cls, v): return cls.STRING_MAP[v] class CheckKind: UNREACHABLE = auto(reset=0) UNEXPECTED_OPERAND = auto() UNINITIALIZED_VARIABLE = auto() ASSERT = auto() DIVISION_BY_ZERO = auto() SHIFT_COUNT = auto() _BEGIN_INT_OVERFLOW = auto() SIGNED_INT_UNDERFLOW = auto() SIGNED_INT_OVERFLOW = auto() UNSIGNED_INT_UNDERFLOW = auto() UNSIGNED_INT_OVERFLOW = auto() _END_INT_OVERFLOW = auto() NULL_POINTER_DEREF = auto() NULL_POINTER_COMPARISON = auto() INVALID_POINTER_COMPARISON = auto() POINTER_COMPARISON = auto() POINTER_OVERFLOW = auto() INVALID_POINTER_DEREF = auto() UNKNOWN_MEMORY_ACCESS = auto() UNALIGNED_POINTER = auto() _BEGIN_BUFFER_OVERFLOW = auto() BUFFER_OVERFLOW_GETS = auto() BUFFER_OVERFLOW = auto() _END_BUFFER_OVERFLOW = auto() _BEGIN_SOUNDNESS = auto() IGNORED_STORE = auto() IGNORED_MEMORY_COPY = auto() IGNORED_MEMORY_MOVE = auto() IGNORED_MEMORY_SET = auto() IGNORED_FREE = auto() IGNORED_CALL_SIDE_EFFECT_ON_POINTER_PARAM = auto() IGNORED_CALL_SIDE_EFFECT = auto() RECURSIVE_FUNCTION_CALL = auto() _END_SOUNDNESS = auto() _BEGIN_FUNCTION_CALL = auto() FUNCTION_CALL_INLINE_ASSEMBLY = auto() UNKNOWN_FUNCTION_CALL_POINTER = auto() FUNCTION_CALL = auto() _END_FUNCTION_CALL = auto() FREE = auto() SHORT_NAME_LIST = [ 'unreachable', 'unexpected-operand', 'uninitialized-variable', 'assert', 'division-by-zero', 'shift-count', 'begin-int-overflow', 'signed-int-underflow', 'signed-int-overflow', 'unsigned-int-underflow', 'unsigned-int-overflow', 'end-int-overflow', 'null-pointer-deref', 'null-pointer-comparison', 'invalid-pointer-comparison', 'pointer-comparison', 'pointer-overflow', 'invalid-pointer-deref', 'unknown-memory-access', 'unaligned-pointer', 'begin-buffer-overflow', 'buffer-overflow-gets', 'buffer-overflow', 'end-buffer-overflow', 'begin-soundness', 'ignored-store', 'ignored-memory-copy', 'ignored-memory-move', 'ignored-memory-set', 'ignored-free', 'ignored-call-side-effect-pointer-param', 'ignored-call-side-effect', 'recursive-function-call', 'end-soundness', 'begin-function-call', 'function-call-inline-asm', 'unknown-function-call-pointer', 'function-call', 'end-function-call', 'free', ] @classmethod def short_name(cls, v): return cls.SHORT_NAME_LIST[v] LONG_NAME_LIST = [ 'dead code', 'unexpected operand', 'uninitialized variable', 'assert', 'division by zero', 'shift count', 'begin integer overflow', 'signed integer underflow', 'signed integer overflow', 'unsigned integer underflow', 'unsigned integer overflow', 'end integer overflow', 'null pointer dereference', 'null pointer comparison', 'invalid pointer comparison', 'pointer comparison', 'pointer overflow', 'invalid pointer dereference', 'unknown memory access', 'unaligned pointer', 'begin buffer overflow', 'buffer overflow gets', 'buffer overflow', 'end buffer overflow', 'begin soundness', 'ignored store', 'ignored memory copy', 'ignored memory move', 'ignored memory set', 'ignored free', 'ignored call side effect on pointer parameter', 'ignored call side effect', 'recursive function call', 'end soundness', 'begin function call', 'function call inline assembly', 'unknown function call pointer', 'function call', 'end function call', 'free', ] @classmethod def long_name(cls, v): return cls.LONG_NAME_LIST[v] class CheckerName: BUFFER_OVERFLOW = auto(reset=0) DIVISION_BY_ZERO = auto() NULL_POINTER_DEREF = auto() ASSERT_PROVER = auto() UNALIGNED_POINTER = auto() UNINITIALIZED_VARIABLE = auto() SIGNED_INT_OVERFLOW = auto() UNSIGNED_INT_OVERFLOW = auto() SHIFT_COUNT = auto() POINTER_OVERFLOW = auto() POINTER_COMPARE = auto() SOUNDNESS = auto() FUNCTION_CALL = auto() DEAD_CODE = auto() DOUBLE_FREE = auto() DEBUG = auto() MEMORY_WATCH = auto() SHORT_NAME_LIST = [ 'boa', 'dbz', 'nullity', 'prover', 'upa', 'uva', 'sio', 'uio', 'shc', 'poa', 'pcmp', 'sound', 'fca', 'dca', 'dfa', 'dbg', 'watch', ] SHORT_NAME_MAP = {v: k for k, v in enumerate(SHORT_NAME_LIST)} @classmethod def short_name(cls, v): return cls.SHORT_NAME_LIST[v] @classmethod def from_short_name(cls, v): return cls.SHORT_NAME_MAP[v] class ValueKind: BEGIN_CONSTANT = auto(reset=0) UNDEFINED_CONSTANT = auto() INTEGER_CONSTANT = auto() FLOAT_CONSTANT = auto() NULL_CONSTANT = auto() STRUCT_CONSTANT = auto() BEGIN_SEQUENTIAL_CONSTANT = auto() ARRAY_CONSTANT = auto() VECTOR_CONSTANT = auto() END_SEQUENTIAL_CONSTANT = auto() AGGREGATE_ZERO_CONSTANT = auto() FUNCTION_POINTER_CONSTANT = auto() INLINE_ASSEMBLY_CONSTANT = auto() END_CONSTANT = auto() BEGIN_VARIABLE = auto() GLOBAL_VARIABLE = auto() LOCAL_VARIABLE = auto() INTERNAL_VARIABLE = auto() END_VARIABLE = auto() class StatementKind: ASSIGNMENT = auto(reset=0) UNARY_OPERATION = auto() BINARY_OPERATION = auto() COMPARISON = auto() RETURN = auto() UNREACHABLE = auto() ALLOCATE = auto() POINTER_SHIFT = auto() LOAD = auto() STORE = auto() EXTRACT_ELEMENT = auto() INSERT_ELEMENT = auto() BEGIN_CALL_BASE = auto() CALL = auto() INVOKE = auto() END_CALL_BASE = auto() LANDING_PAD = auto() RESUME = auto() class MemoryLocationKind: LOCAL = auto(reset=0) GLOBAL = auto() FUNCTION = auto() AGGREGATE = auto() ABSOLUTE_ZERO = auto() ARGV = auto() LIBC_ERRNO = auto() DYN_ALLOC = auto() class FunctionCallCheckKind: NOT_FUNCTION = auto(reset=0) WRONG_SIGNATURE = auto() OK = auto() class BufferOverflowCheckKind: FUNCTION = auto(reset=0) USE_AFTER_FREE = auto() USE_AFTER_RETURN = auto() HARDWARE_ADDRESSES = auto() OUT_OF_BOUND = auto() class FilesTable: ID = auto(reset=0) PATH = auto() class FunctionsTable: ID = auto(reset=0) NAME = auto() DEMANGLED = auto() DEFINITION = auto() FILE_ID = auto() LINE = auto() class StatementsTable: ID = auto(reset=0) KIND = auto() FUNCTION_ID = auto() FILE_ID = auto() LINE = auto() COLUMN = auto() class OperandsTable: ID = auto(reset=0) KIND = auto() REPR = auto() class CallContextsTable: ID = auto(reset=0) CALL_ID = auto() FUNCTION_ID = auto() PARENT_ID = auto() class MemoryLocationsTable: ID = auto(reset=0) KIND = auto() INFO = auto() class ChecksTable: ID = auto(reset=0) KIND = auto() CHECKER = auto() STATUS = auto() STATEMENT_ID = auto() OPERANDS = auto() CALL_CONTEXT_ID = auto() INFO = auto() NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/filetype.py000066400000000000000000000047661473507761200231410ustar00rootroot00000000000000############################################################################### # # File type detection utility # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import subprocess import sys from ikos.log import printf def filetype(path): ''' Return the file type as returned by the 'file' command ''' try: output = subprocess.check_output(['file', '--brief', path]) except OSError as e: printf('error: file: %s', e.strerror, file=sys.stderr) sys.exit(e.errno) if output.startswith(b'cannot open '): open(path) # raise IOError return output.decode('utf-8').strip() NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/highlight.py000066400000000000000000000060031473507761200232510ustar00rootroot00000000000000############################################################################### # # Highlight utility for ikos-view # # Author: Thomas Bailleux # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import html from ikos import log class DummyLexer(object): def __init__(self, *args, **kwargs): pass class DummyHtmlFormatter(object): def __init__(self): pass def get_style_defs(self, cl): return '' def wrap(self, src): pass def dummy_highlight(data, lexer, formatter): lines = ((1, html.escape(line)) for line in data.split('\n')) code = '' for _, line in formatter.wrap(lines): code += line return code try: from pygments.lexers import CLexer, CppLexer from pygments.formatters import HtmlFormatter from pygments import highlight except ImportError: log.warning("Syntax highlighting is not available:" " module `pygments` is not installed.") log.warning("Note: use `pip install --user pygments`" " to install `pygments`") CLexer = DummyLexer CppLexer = DummyLexer HtmlFormatter = DummyHtmlFormatter highlight = dummy_highlight NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/http.py000066400000000000000000000066571473507761200223000ustar00rootroot00000000000000############################################################################### # # Wrapper for python standard library HTTP server # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os from errno import EAFNOSUPPORT from http.server import HTTPServer, BaseHTTPRequestHandler from socket import AF_INET, AF_INET6 from urllib.parse import parse_qs, urlencode from urllib.request import urlopen class HTTPServerIPv6(HTTPServer): ''' HTTP server that listens on IPv6 when available. In systems with dual stack, this also listens on IPv4. This class tries to listen on IPv6 first (and IPv4 if available). If that is not supported, then it tries IPv4 only. ''' address_family = AF_INET6 def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): try: # Initially try to open the server with IPv6. This will also select # IPv4 on systems with dual stack. super().__init__(server_address, RequestHandlerClass, bind_and_activate) except OSError as e: if e.errno == EAFNOSUPPORT: # If the exception is due to IPv6 not being supported, we # select IPv4 only and try to re-open the server again. self.address_family = AF_INET super().__init__(server_address, RequestHandlerClass, bind_and_activate) else: # If the exception is for any other reason other than IPv6 not # being supported, then we cannot do anything about it. raise e NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/log.py000066400000000000000000000064751473507761200221000ustar00rootroot00000000000000############################################################################### # # Logging utilities # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import sys from ikos import colors # Logging levels NONE = 60 CRITICAL = 50 ERROR = 40 WARNING = 30 INFO = 20 DEBUG = 10 ALL = 0 LEVELS = { 'none': NONE, 'critical': CRITICAL, 'error': ERROR, 'warning': WARNING, 'info': INFO, 'debug': DEBUG, 'all': ALL, } # Current log level LEVEL = WARNING # output file out = sys.stdout def setup(level): global LEVEL if level in LEVELS: LEVEL = LEVELS[level] else: LEVEL = WARNING def printf(fmt, *args, **kwargs): file = kwargs.pop('file', sys.stdout) file.write(fmt % args if args else fmt) file.flush() def is_enabled_for(user_level): return LEVEL <= user_level def critical(message): if is_enabled_for(CRITICAL): printf('[%s] %s\n', colors.on_red('CRITICAL'), message, file=out) def error(message): if is_enabled_for(ERROR): printf('[%s] %s\n', colors.on_red('ERROR'), message, file=out) def warning(message): if is_enabled_for(WARNING): printf('[%s] %s\n', colors.bold_yellow('!'), message, file=out) def info(message): if is_enabled_for(INFO): printf('[%s] %s\n', colors.bold_blue('*'), message, file=out) def debug(message): if is_enabled_for(DEBUG): printf('[%s] %s\n', colors.magenta('.'), message, file=out) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/output_db.py000066400000000000000000000267751473507761200233310ustar00rootroot00000000000000############################################################################### # # Extract information from a result database # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import collections import json import sqlite3 from ikos.enums import FilesTable, FunctionsTable, StatementsTable, \ CallContextsTable, OperandsTable, MemoryLocationsTable, ChecksTable class CachedProperty(object): ''' A property attribute that only calls its getter the first access. ''' def __init__(self, factory): self._attr_name = factory.__name__ self._factory = factory def __get__(self, instance, owner): value = self._factory(instance) setattr(instance, self._attr_name, value) return value class OutputDatabase(object): ''' Represents an output database ''' def __init__(self, path): self.path = path self.con = sqlite3.connect(path) # Use 'str' as text factory since it's the type of string literals # This is unicode self.con.text_factory = str def close(self): self.con.close() def load_settings(self): ''' Load the analysis settings from the database ''' c = self.con.cursor() c.execute('SELECT name, value FROM settings') settings = {} for key, value in c: try: settings[key] = json.loads(value) except ValueError: settings[key] = value return settings def insert_settings(self, rows): ''' Insert the analysis settings into the database ''' c = self.con.cursor() c.executemany('INSERT INTO settings VALUES (?, ?)', rows) self.con.commit() def load_timing_results(self, full=True, sort=True): ''' Load the timing results from the database, as a list of tuples (pass, elapsed) ''' c = self.con.cursor() where = "WHERE pass NOT LIKE '%ikos-analyzer.%'" if not full else '' order_by = 'ORDER BY pass' if sort else '' c.execute('SELECT pass, time FROM times %s %s' % (where, order_by)) return c.fetchall() def insert_timing_results(self, rows): ''' Insert the timing results into the database ''' c = self.con.cursor() c.executemany('INSERT INTO times VALUES (?, ?)', rows) self.con.commit() @CachedProperty def files(self): return self._fetch_table('files', File) @CachedProperty def functions(self): return self._fetch_table('functions', Function) @CachedProperty def statements(self): return self._fetch_table('statements', Statement) @CachedProperty def operands(self): return self._fetch_table('operands', Operand) @CachedProperty def call_contexts(self): return self._fetch_table('call_contexts', CallContext) @CachedProperty def memory_locations(self): return self._fetch_table('memory_locations', MemoryLocation) def _fetch_table(self, table, klass): c = self.con.cursor() c.execute('SELECT * FROM %s ORDER BY id' % table) return [klass(row, self) for row in c] class File(object): ''' Represents a source file ''' __slots__ = ('id', 'path') def __init__(self, row, db): self.id = row[FilesTable.ID] self.path = row[FilesTable.PATH] class Function(object): ''' Represents a function ''' __slots__ = ( 'id', 'name', 'demangled', 'definition', 'file_id', 'line', 'db' ) def __init__(self, row, db): self.id = row[FunctionsTable.ID] self.name = row[FunctionsTable.NAME] self.demangled = row[FunctionsTable.DEMANGLED] # or None self.definition = (row[FunctionsTable.DEFINITION] == 1) self.file_id = row[FunctionsTable.FILE_ID] # or None self.line = row[FunctionsTable.LINE] # or None self.db = db def pretty_name(self): ''' Return a pretty name ''' if self.demangled: return self.demangled else: return self.name def file(self): ''' Return the source file, or None ''' if self.file_id is None: return None return self.db.files[self.file_id] def file_path(self): ''' Return the source file path, or None ''' if self.file_id is None: return None return self.db.files[self.file_id].path class Statement(object): ''' Represents a statement ''' __slots__ = ( 'id', 'kind', 'function_id', 'file_id', 'line', 'column', 'db' ) def __init__(self, row, db): self.id = row[StatementsTable.ID] self.kind = row[StatementsTable.KIND] self.function_id = row[StatementsTable.FUNCTION_ID] self.file_id = row[StatementsTable.FILE_ID] # or None self.line = row[StatementsTable.LINE] # or None self.column = row[StatementsTable.COLUMN] # or None self.db = db def function(self): ''' Return the function ''' return self.db.functions[self.function_id] def file(self): ''' Return the source file, or None ''' if self.file_id is None: return None return self.db.files[self.file_id] def file_path(self): ''' Return the source file path, or None ''' if self.file_id is None: return None return self.db.files[self.file_id].path def file_id_or(self, default): ''' Return the file id, or default ''' if self.file_id is None: return default return self.file_id def line_or(self, default): ''' Return the line number, or default ''' if self.line is None: return default return self.line def column_or(self, default): ''' Return the column number, or None ''' if self.column is None: return default return self.column class Operand(object): ''' Represents an operand ''' __slots__ = ('id', 'kind', 'repr') def __init__(self, row, db): self.id = row[OperandsTable.ID] self.kind = row[OperandsTable.KIND] self.repr = row[OperandsTable.REPR] # Represents a pair (operand number, operand) NumOperandPair = collections.namedtuple('NumOperandPair', ('num', 'operand')) class CallContext(object): ''' Represents a calling context ''' __slots__ = ('id', 'call_id', 'function_id', 'parent_id', 'db') def __init__(self, row, db): self.id = row[CallContextsTable.ID] self.call_id = row[CallContextsTable.CALL_ID] # or None self.function_id = row[CallContextsTable.FUNCTION_ID] # or None self.parent_id = row[CallContextsTable.PARENT_ID] # or None self.db = db def empty(self): return self.call_id is None def call(self): ''' Return the call statement ''' assert self.call_id is not None return self.db.statements[self.call_id] def function(self): ''' Return the function ''' assert self.function_id is not None return self.db.functions[self.function_id] def parent(self): ''' Return the parent calling context ''' assert self.parent_id is not None return self.db.call_contexts[self.parent_id] def str(self): ''' Format a calling context ''' call_context = self ctx = [] while not call_context.empty(): function = call_context.function() call = call_context.call() ctx.append('%s@%s:%s:%d' % (function.pretty_name(), call.line_or('?'), call.column_or('?'), call_context.call_id)) call_context = call_context.parent() ctx.append('.') ctx.reverse() return '/'.join(ctx) def __str__(self): ''' Format a calling context ''' return self.str() class MemoryLocation(object): ''' Represents a memory location ''' __slots__ = ('id', 'kind', 'info', 'db') def __init__(self, row, db): self.id = row[MemoryLocationsTable.ID] self.kind = row[MemoryLocationsTable.KIND] self.info = row[MemoryLocationsTable.INFO] # or None self.db = db def load_info(self): ''' Return the info, or None ''' if not self.info: return None return json.loads(self.info) class Check(object): ''' Represents a check ''' __slots__ = ( 'id', 'kind', 'checker', 'status', 'statement_id', 'call_context_id', 'operands', 'info', 'db' ) def __init__(self, row, db): self.id = row[ChecksTable.ID] self.kind = row[ChecksTable.KIND] self.checker = row[ChecksTable.CHECKER] self.status = row[ChecksTable.STATUS] self.statement_id = row[ChecksTable.STATEMENT_ID] self.call_context_id = row[ChecksTable.CALL_CONTEXT_ID] self.operands = row[ChecksTable.OPERANDS] # or None self.info = row[ChecksTable.INFO] # or None self.db = db def statement(self): ''' Return the statement ''' return self.db.statements[self.statement_id] def call_context(self): ''' Return the call context ''' return self.db.call_contexts[self.call_context_id] def load_operands(self): ''' Return the operands, or None ''' if not self.operands: return None operands = json.loads(self.operands) return [NumOperandPair(num, self.db.operands[id]) for num, id in operands] NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/report.py000066400000000000000000002334001473507761200226200ustar00rootroot00000000000000############################################################################## # # Generate an analysis report from a result database # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import collections import csv import functools import io import itertools import json import operator import os import os.path import sqlite3 import sys from xml.etree import ElementTree from xml.sax.saxutils import escape from xml.sax.saxutils import quoteattr from ikos import args from ikos import colors from ikos import settings from ikos.abs_int import Signedness, MachineInt, Interval, Congruence from ikos.colors import bold, bold_blue, bold_green, bold_magenta, bold_red, \ bold_yellow from ikos.enums import Result, CheckKind, CheckerName, ValueKind, \ StatementKind, MemoryLocationKind, FunctionCallCheckKind, \ BufferOverflowCheckKind, ChecksTable from ikos.log import printf from ikos.output_db import OutputDatabase, File, Function, Statement, \ CallContext, Operand, NumOperandPair, MemoryLocation, Check ################## # timing results # ################## def format_time(elapsed): ''' Format an elapsed time. >>> format_time(3.1415) '3.142 sec' >>> format_time(2 * 3600 * 24 + 23 * 3600 + 42 * 60 + 3.20498) '2 day 23 hour 42 min 3.205 sec' ''' s = [] if elapsed >= 3600 * 24: s.append('%d day' % int(elapsed // (3600 * 24))) elapsed %= 3600 * 24 if elapsed >= 3600: s.append('%d hour' % int(elapsed // 3600)) elapsed %= 3600 if elapsed >= 60: s.append('%d min' % int(elapsed // 60)) elapsed %= 60 s.append('%.3f sec' % elapsed) return ' '.join(s) def print_timing_results(db, full=True, sort=True): ''' Print the timing results from the database ''' results = db.load_timing_results(full, sort) printf(bold('# Time stats:') + '\n') name_width = max(len(name) for name, _ in results) for name, elapsed in results: printf('%s: %s\n', name.ljust(name_width), format_time(elapsed)) ########### # summary # ########### # Represents a check, as a hashable type CheckTuple = collections.namedtuple('CheckTuple', ('kind', 'operands', 'info')) def generate_statement_result(checks, keep_oks=True, keep_checkers=True): ''' Generate a result for a list of checks on a specific statement and call context ''' result = Result.OK errors = set() warnings = set() oks = set() if keep_oks else None checkers = set() if keep_checkers else None for check in checks: if keep_checkers: checkers.add(check[ChecksTable.CHECKER]) status = check[ChecksTable.STATUS] if status == Result.UNREACHABLE: result = Result.UNREACHABLE if keep_checkers: continue # keep iterating else: break # exit early check = CheckTuple(check[ChecksTable.KIND], check[ChecksTable.OPERANDS], check[ChecksTable.INFO]) if status == Result.ERROR: result = Result.ERROR errors.add(check) elif status == Result.WARNING: if result == Result.OK: result = Result.WARNING warnings.add(check) elif status == Result.OK: if keep_oks: oks.add(check) else: assert False, 'unexpected status' return result, errors, warnings, oks, checkers class Summary: ''' Represents a summary ''' def __init__(self, ok, error, warning, unreachable): self.ok = ok self.error = error self.warning = warning self.unreachable = unreachable @property def total(self): return self.ok + self.error + self.warning + self.unreachable def generate_summary(db): ''' Return the analysis summary: number of errors, warnings, ok and unreachable per checked statements. ''' summary = Summary(ok=0, error=0, warning=0, unreachable=0) c = db.con.cursor() order_by = 'statement_id, call_context_id' c.execute('SELECT * FROM checks ORDER BY %s' % order_by) stmt_id_key = operator.itemgetter(ChecksTable.STATEMENT_ID) context_id_key = operator.itemgetter(ChecksTable.CALL_CONTEXT_ID) for statement_id, statement_checks in itertools.groupby(c, key=stmt_id_key): # Iterate over the checks for statement = statement_id statement_results = set() statement_checkers = set() statement_errors = set() statement_warnings = set() for context_id, checks in itertools.groupby(statement_checks, key=context_id_key): # Iterate over the checks for statement = statement_id # and context = context_id result, errors, warnings, _, checkers = \ generate_statement_result(checks, keep_oks=False, keep_checkers=True) statement_results.add(result) statement_checkers.update(checkers) statement_errors.update(errors) statement_warnings.update(warnings) if statement_results == {Result.UNREACHABLE}: # Statement is unreachable for all the calling contexts, # check that it comes from dca if CheckerName.DEAD_CODE in statement_checkers: # Statement is never reachable summary.unreachable += 1 else: if Result.OK in statement_results: # Some paths are safe summary.ok += 1 summary.error += len(statement_errors) summary.warning += len(statement_warnings) c.close() return summary def print_summary(db, full=True): ''' Print the analysis summary from the database ''' summary = generate_summary(db) printf(bold('# Summary:') + '\n') if full: printf('Total number of checks : %s\n', bold(summary.total)) printf('Total number of unreachable checks : %s\n', bold_magenta(summary.unreachable) if summary.unreachable else '0') printf('Total number of safe checks : %s\n', bold_green(summary.ok) if summary.ok else '0') printf('Total number of definite unsafe checks: %s\n', bold_red(summary.error) if summary.error else '0') printf('Total number of warnings : %s\n', bold_yellow(summary.warning) if summary.warning else '0') printf('\n') if summary.error == 0 and summary.warning == 0: printf(bold_green('The program is SAFE') + '\n') else: if summary.error != 0: printf(bold_red('The program is definitely UNSAFE') + '\n') else: printf(bold_yellow('The program is potentially UNSAFE') + '\n') ###################### # display raw checks # ###################### def memoize(f): ''' Decorator to wrap a function with memoizing ''' cache = {} def helper(*args): if args not in cache: cache[args] = f(*args) return cache[args] return helper @memoize def format_path(path): ''' Format a path. Return the shortest between the absolute path or the relative path. ''' if not path: return None abs_path = os.path.realpath(path) # Check the drives to make sure a relpath can be obtained path_drive_split = os.path.splitdrive(abs_path) cur_drive_split = os.path.splitdrive(os.getcwd()) if path_drive_split and (path_drive_split[0] != cur_drive_split[0]): return abs_path else: rel_path = os.path.relpath(os.path.realpath(path), os.getcwd()) return min(abs_path, rel_path, key=len) def format_status(status): ''' Add colors to a status ''' if status == 'ok': return bold_green(status) elif status == 'error': return bold_red(status) elif status == 'warning': return bold_yellow(status) elif status == 'unreachable': return bold_magenta(status) else: assert False, 'unexpected status' def format_operands(operands): if not operands: return None operands = ('%d: %s' % (p.num, p.operand.repr) for p in operands) return ', '.join(operands) def print_raw_checks(db, interprocedural): ''' Print all checks in the database, with very little processing ''' header = [ 'context', 'function', 'file', 'line', 'col', 'stmt', 'check', 'checker', 'result', 'operands', 'info' ] order_by = 'call_context_id, statement_id, kind' if not interprocedural: header.pop(0) # no context column if intraprocedural c = db.con.cursor() c.execute('SELECT * FROM checks ORDER BY %s' % order_by) rows = c.fetchall() # Format all rows for i, row in enumerate(rows): check = Check(row, db) statement = check.statement() function = statement.function() call_context = check.call_context() rows[i] = [call_context.str(), function.pretty_name(), format_path(statement.file_path()) or ' ', str(statement.line_or(' ')), str(statement.column_or(' ')), str(statement.id), CheckKind.short_name(check.kind), CheckerName.short_name(check.checker), Result.str(check.status), format_operands(check.load_operands()) or ' ', check.info or ' '] if not interprocedural: rows[i].pop(0) # no context column if intraprocedural # Reorganize data by columns cols = zip(*([header] + rows)) # Compute column widths by taking maximum length of values per column col_widths = [max(len(value) for value in col) for col in cols] # Print table printf(bold('# Checks') + '\n') printf('|' + '|'.join(' %s ' % head.ljust(width) for head, width in zip(header, col_widths)) + '|\n') printf('+' + '+'.join('-' * (width + 2) for width in col_widths) + '+\n') for row in rows: fmt = ('|' + '|'.join(' %s ' + ' ' * (width - len(e)) for e, width in zip(row, col_widths)) + '|\n') row[-3] = format_status(row[-3]) # add colors for result column printf(fmt, *row) c.close() ########## # report # ########## class Report: ''' Represents an analysis report ''' def __init__(self, db): self.db = db self.statement_reports = [] def append(self, statement_report): self.statement_reports.append(statement_report) def __repr__(self): if not self.statement_reports: return 'Report([])' lines = ',\n'.join(map(repr, self.statement_reports)) return 'Report([\n%s\n])' % lines class StatementReport: ''' Represents a report on a statement ''' def __init__(self, db, kind, status, statement_id, call_context_ids, operands=None, info=None): self.db = db self.kind = kind self.status = status self.statement_id = statement_id self.call_context_ids = call_context_ids self.operands = operands self.info = info def statement(self): return self.db.statements[self.statement_id] def call_contexts(self): return (self.db.call_contexts[id] for id in self.call_context_ids) def load_operands(self): ''' Return the operands, or None ''' if not self.operands: return None operands = json.loads(self.operands) return [NumOperandPair(no, self.db.operands[id]) for no, id in operands] def load_info(self): ''' Return the info, or None ''' if not self.info: return None return json.loads(self.info) def __repr__(self): s = ('StatementReport(' 'kind=%s, ' 'status=%s, ' 'statement_id=%d, ' 'context_ids=%r, ' 'operands=%s, ' 'info=%s)') return s % (CheckKind.short_name(self.kind), Result.str(self.status), self.statement_id, self.call_context_ids, self.operands, self.info) def generate_report(db, status_filter=None, analyses_filter=None): ''' Generate an analysis report. Arguments: status_filter(list): List of status, or None analyses_filter(list): List of checkers, or None ''' report = Report(db) # Parse filters if status_filter is not None: status_filter = tuple(map(Result.from_str, status_filter)) if analyses_filter is not None: analyses_filter = tuple(map(CheckerName.from_short_name, analyses_filter)) display_oks = (status_filter is None or Result.OK in status_filter) display_unreachables = ((status_filter is None or Result.UNREACHABLE in status_filter) and (analyses_filter is None or CheckerName.DEAD_CODE in analyses_filter)) # Generate where clause where = [] if status_filter is not None: if not status_filter: where = ['0=1'] # status_filter=[], filter everything else: where.append(' OR '.join('(status=%d)' % status for status in status_filter)) if analyses_filter is not None: if not analyses_filter: where = ['0=1'] # analyses_filter=[], filter everything elif len(analyses_filter) == len(args.analyses): pass # nothing to filter else: where.append(' OR '.join('(checker=%d)' % checker for checker in analyses_filter)) where = ' AND '.join('(%s)' % clause for clause in where) if display_unreachables and not display_oks: # Only show unreachable statements if the statement is unreachable for # all calling contexts. To detect this, we need to make sure to get all # checks from the DeadCodeChecker, especially 'ok' checks. where = '(%s) OR (checker=%d)' % (where, CheckerName.DEAD_CODE) if where: where = 'WHERE %s' % where order_by = 'ORDER BY statement_id, call_context_id' # Execute query c = db.con.cursor() c.execute('SELECT * FROM checks %s %s' % (where, order_by)) stmt_id_key = operator.itemgetter(ChecksTable.STATEMENT_ID) context_id_key = operator.itemgetter(ChecksTable.CALL_CONTEXT_ID) for statement_id, statement_checks in itertools.groupby(c, key=stmt_id_key): # Iterate over the checks for statement = statement_id statement_results = set() statement_context_ids = list() statement_checkers = set() statement_errors = collections.defaultdict(list) statement_warnings = collections.defaultdict(list) statement_oks = collections.defaultdict(list) for context_id, checks in itertools.groupby(statement_checks, key=context_id_key): # Iterate over the checks for statement = statement_id # and context = context_id result, errors, warnings, oks, checkers = \ generate_statement_result(checks, keep_oks=display_oks, keep_checkers=display_unreachables) statement_results.add(result) statement_context_ids.append(context_id) if display_unreachables: statement_checkers.union(checkers) for error in errors: statement_errors[error].append(context_id) for warning in warnings: statement_warnings[warning].append(context_id) if display_oks: for ok in oks: statement_oks[ok].append(context_id) if statement_results == {Result.UNREACHABLE}: # Statement is unreachable for all the calling contexts, # check that we want unreachable checks and that it comes from dca if display_unreachables and CheckerName.DEAD_CODE in checkers: report.append(StatementReport( db=db, kind=CheckKind.UNREACHABLE, status=Result.UNREACHABLE, statement_id=statement_id, call_context_ids=statement_context_ids )) else: for check, context_ids in statement_errors.items(): report.append(StatementReport(db=db, kind=check.kind, status=Result.ERROR, statement_id=statement_id, call_context_ids=context_ids, operands=check.operands, info=check.info)) for check, context_ids in statement_warnings.items(): report.append(StatementReport(db=db, kind=check.kind, status=Result.WARNING, statement_id=statement_id, call_context_ids=context_ids, operands=check.operands, info=check.info)) for check, context_ids in statement_oks.items(): report.append(StatementReport(db=db, kind=check.kind, status=Result.OK, statement_id=statement_id, call_context_ids=context_ids, operands=check.operands, info=check.info)) c.close() return report ################## # report formats # ################## class Formatter(object): ''' Base class for formatters ''' def __init__(self, output, verbosity): ''' Arguments: output(file): output file verbosity(int): verbosity level ''' self.output = output self.verbosity = verbosity def format(self, report): raise NotImplementedError class TextFormatter(Formatter): ''' Text output formatter (similar to clang compilation warnings) ''' def __init__(self, output, verbosity): super(TextFormatter, self).__init__(output, verbosity) self.sources = {} # error, warning, unreachable, ok RESULT_ORDER = [3, 1, 0, 2] @classmethod def sorting_key(cls, report): statement = report.statement() return (cls.RESULT_ORDER[report.status], statement.file_id_or(-1), statement.line_or(-1), statement.column_or(-1), report.kind) def write_path(self, file): printf(bold('%s: '), format_path(file.path) if file else '?', file=self.output) def write_in_function(self, function): printf("In function '%s':", function.pretty_name(), file=self.output) def write_newline(self): printf('\n', file=self.output) def write_source_location(self, statement): printf(bold('%s:%s:%s: '), format_path(statement.file_path()) or '?', statement.line_or('?'), statement.column_or('?'), file=self.output) RESULT_STR = ['safe', 'warning', 'error', 'unreachable'] RESULT_FORMATTER = [bold_green, bold_yellow, bold_red, bold_magenta] def write_status(self, result): formatter = TextFormatter.RESULT_FORMATTER[result] printf('%s: ' % formatter(TextFormatter.RESULT_STR[result]), file=self.output) def write_note(self): printf('%s: ' % bold_blue('note'), file=self.output) def source_location_indent(self, statement): return len('%s:%s:%s: ' % (format_path(statement.file_path()) or '?', statement.line_or('?'), statement.column_or('?'))) def status_indent(self, result): return len('%s: ' % TextFormatter.RESULT_STR[result]) def write_message(self, statement, result, message): if '\n' in message: # Assume write_source_location and write_status have been called n = self.source_location_indent(statement) n += self.status_indent(result) message = message.replace('\n', '\n' + ' ' * n) printf('%s\n', message, file=self.output) def load_source_code(self, path): if path not in self.sources: try: with io.open(path, 'r', encoding='utf-8', errors='ignore') as f: self.sources[path] = tuple(f.readlines()) except IOError: printf('warning: could not open file %s\n', path, file=sys.stderr) self.sources[path] = [] return self.sources[path] def write_source_code(self, statement, pointer_color=bold_green): if statement.file_id is not None and statement.line is not None: source_code = self.load_source_code(statement.file_path()) if statement.line <= len(source_code): line = source_code[statement.line - 1].rstrip() printf(line + '\n', file=self.output) if statement.column is not None: footer = ''.join('\t' if c == '\t' else ' ' for c in line[:statement.column - 1]) footer += pointer_color('^') printf(footer + '\n', file=self.output) def write_call_context(self, statement, call_context, max_depth=3): self.write_source_location(statement) self.write_note() if call_context.empty(): function = statement.function() printf("called from entry point '%s'\n", function.pretty_name(), file=self.output) return printf('called from:\n', file=self.output) for _ in range(max_depth): if call_context.empty(): return call_statement = call_context.call() function = call_context.function() self.write_source_location(call_statement) printf("function '%s'\n", function.pretty_name(), file=self.output) self.write_source_code(call_statement) call_context = call_context.parent() def format(self, report): statement_reports = report.statement_reports # Sort reports statement_reports.sort(key=self.sorting_key) for statement_report in statement_reports: statement = statement_report.statement() function = statement.function() message = generate_message(statement_report, self.verbosity) self.write_path(function.file()) self.write_in_function(function) self.write_newline() self.write_source_location(statement) self.write_status(statement_report.status) self.write_message(statement, statement_report.status, message) self.write_source_code(statement) if self.verbosity >= 3: for call_context in statement_report.call_contexts(): self.write_call_context(statement, call_context) class JSONEncoder(json.JSONEncoder): ''' JSON encoder ''' def default(self, obj): if isinstance(obj, Report): return self.encode_report(obj) elif isinstance(obj, StatementReport): return self.encode_statement_report(obj) elif isinstance(obj, File): return self.encode_file(obj) elif isinstance(obj, Function): return self.encode_function(obj) elif isinstance(obj, Statement): return self.encode_statement(obj) elif isinstance(obj, Operand): return self.encode_operand(obj) elif isinstance(obj, CallContext): return self.encode_call_context(obj) elif isinstance(obj, MemoryLocation): return self.encode_memory_location(obj) return json.JSONEncoder.default(self, obj) @staticmethod def encode_report(report): return { 'files': report.db.files, 'functions': report.db.functions, 'statements': report.db.statements, 'operands': report.db.operands, 'call_contexts': report.db.call_contexts, 'memory_locations': report.db.memory_locations, 'reports': report.statement_reports, } @staticmethod def encode_statement_report(report): operands = None if report.operands is not None: operands = [(p.num, p.operand.id) for p in report.load_operands()] return { 'kind': report.kind, 'status': report.status, 'statement_id': report.statement_id, 'call_context_ids': report.call_context_ids, 'operands': operands, 'info': report.load_info(), } @staticmethod def encode_file(file): return { 'id': file.id, 'path': file.path, } @staticmethod def encode_function(function): return { 'id': function.id, 'name': function.name, 'demangled': function.demangled, 'definition': function.definition, 'file_id': function.file_id, 'line': function.line, } @staticmethod def encode_statement(statement): return { 'id': statement.id, 'kind': statement.kind, 'function_id': statement.function_id, 'file_id': statement.file_id, 'line': statement.line, 'column': statement.column, } @staticmethod def encode_operand(operand): return { 'id': operand.id, 'kind': operand.kind, 'repr': operand.repr, } @staticmethod def encode_call_context(call_context): return { 'id': call_context.id, 'call_id': call_context.call_id, 'function_id': call_context.function_id, 'parent_id': call_context.parent_id, } @staticmethod def encode_memory_location(memory_location): return { 'id': memory_location.id, 'kind': memory_location.kind, 'info': memory_location.load_info() } class JSONFormatter(Formatter): ''' JSON output formatter ''' def format(self, report): json.dump(report, self.output, cls=JSONEncoder) self.output.write('\n') class SARIFFormatter(Formatter): ''' SARIF output formatter ''' checks = [ ('buffer_overflow_analysis', 'checks for buffer overflows and out-of-bound array accesses.'), ('division_by_zero_analysis', 'checks for integer divisions by zero.'), ('null_pointer_analysis', 'checks for null pointer dereferences.'), ('assertion_prover', 'prove user-defined properties, using __ikos_assert(condition).'), ('unaligned_pointer_analysis', 'checks for unaligned pointer dereferences.'), ('uninitialized_variable_analysis', 'checks for read of uninitialized variables.'), ('signed_integer_overflow_analysis', 'checks for signed integer overflows.'), ('unsigned_integer_overflow_analysis', 'checks for unsigned integer overflows.'), ('shift_count_analysis', 'checks for invalid shifts, where the amount shifted is greater or equal to the bit-width of the left operand, or less than zero.'), ('pointer_overflow_analysis', 'checks for pointer arithmetic overflows.'), ('pointer_comparison_analysis', 'checks for pointer comparisons between pointers referring to different objects.'), ('soundness_analysis', 'checks for instructions that could make the analysis unsound, i.e miss bugs.'), ('function_call_analysis', 'checks for function calls through function pointers of the wrong type.'), ('dead_code_analysis', 'checks for unreachable statements.'), ('double_free_analysis', 'checks for double free, invalid free, use after free and use after return.'), ('debugger', 'prints debug information, using __ikos_print_values("desc", x) and __ikos_print_invariant().'), ('memory_watcher', 'prints memory writes at a given memory location, using __ikos_watch_mem(ptr, size)') ] rules = [ { 'id': name, 'shortDescription': {'text': text}, 'helpUri': 'https://github.com/NASA-SW-VnV/ikos/blob/master/analyzer/README.md#checks' } for (name, text) in checks ] tool = { 'driver': { 'name': 'IKOS', 'version': settings.VERSION, 'informationUri': 'https://github.com/NASA-SW-VnV/ikos', 'rules': rules, }, } def format_artifacts(self, report): files = set() for statement_report in report.statement_reports: statement = statement_report.statement() name = statement.file_path() if name: files.add(name) return [{'location': {'uri': format_path(file)}} for file in files] # the only levels in SARIF are error, warning, and note => change unreachable into note def format_level(self, level): if level == "unreachable": return "note" else: return level # some messages provided by IKOS are multi-line but it's not possible under the SARIF format: # change it into some single line message def single_line(self, text): # bundle multi-line messages into single-line messages if '\n\t*' in text: return text.replace('\n\t*', ' +--> ') else: return text def format_location(self, statement, message=None): path = format_path(statement.file_path()) artifact = {'uri': path} region = {'startLine': statement.line, 'startColumn': statement.column} physical = {'artifactLocation': artifact, 'region': region} location = {'physicalLocation': physical} if message: location['message'] = {'text': message} return location def format_stacks(self, statement_report): call_contexts = statement_report.call_contexts() stacks = [] for context in call_contexts: frames = [] while not context.empty(): call = context.call() func = call.function().pretty_name() location = self.format_location(call, message="Call from %s" % func) frames.append({'location': location}) context = context.parent() if frames: # The Sarif Viewer extension for VS Code ignores stacks without # a message for some reason message = {'text': str(context)} stack = {'message': message, 'frames': frames} stacks.append(stack) return stacks def format_results(self, report): results = [] for statement_report in report.statement_reports: statement = statement_report.statement() path = statement.file_path() # check if it's not a garbage result by checking if a filename path is provided # and if the line and column numbers are not zero if path and statement.line > 0 and statement.column > 0: result = { 'ruleId': CheckKind.short_name(statement_report.kind), 'level': self.format_level(Result.str(statement_report.status)), 'message': { 'text': quoteattr(self.single_line(generate_message(statement_report, self.verbosity))), }, 'locations': [self.format_location(statement)], } stacks = self.format_stacks(statement_report) if stacks: result['stacks'] = stacks results.append(result) return results # main method to format an IKOS report into a SARIF formatted report def format(self, report): run = { 'tool': self.tool, 'artifacts': self.format_artifacts(report), 'results': self.format_results(report), } log = { 'version': '2.1.0', '$schema': 'http://json.schemastore.org/sarif-2.1.0', 'runs': [run], } json.dump(log, self.output, indent = 3) self.output.write('\n') class CSVFormatter(Formatter): ''' CSV output formatter ''' def format(self, report): writer = csv.writer(self.output, quoting=csv.QUOTE_MINIMAL) writer.writerow([ 'file', 'function', 'line', 'column', 'statement_id', 'contexts', 'status', 'check', 'message' ]) for statement_report in report.statement_reports: statement = statement_report.statement() function = statement.function() writer.writerow([ statement.file_path(), function.pretty_name(), statement.line, statement.column, statement.id, ' | '.join(call_context.str() for call_context in statement_report.call_contexts()), Result.str(statement_report.status), CheckKind.short_name(statement_report.kind), generate_message(statement_report, self.verbosity), ]) class JUnitFormatter(Formatter): ''' JUnit.xml formatter ''' def get_timing_result(self, report): ''' get the timing results for the analysis from the database ''' db = report.db elapsed = 0.0 if db: results = db.load_timing_results(True, True) for result in results: if result[0] == 'ikos-analyzer': return result[1] return elapsed # some messages provided by IKOS are multi-line but # we want to change it into some single line message def single_line (self, text): # if '\n\t*' in text: return text.replace('\n\t*', ' +--> ') else: return text def format(self, report): testname = '.ikos-analysis-results' # get the time spent on analysis elapsed = self.get_timing_result (report) # get the summary report summary = generate_summary (report.db) test_count = summary.ok + summary.error + summary.warning + summary.unreachable error_count = summary.error + summary.warning # build the data structure to report the analysis summary data = { 'testname': testname, 'test_count': test_count, 'error_count': error_count, 'time': '%.3f' % round(elapsed, 3), 'skip': 0, } xml = """ """ % data for statement_report in report.statement_reports: statement = statement_report.statement() path = statement.file_path() # make sure that it's not one of those unreachable statements without any info if path and statement.line > 0 and statement.column > 0: # report each error/warning as a failing testcase data = { 'quoted_name': quoteattr( '%s: %s (%s:%d)' % ( Result.str(statement_report.status), CheckKind.short_name(statement_report.kind), path, statement.line)), 'testname': testname, 'quoted_message': quoteattr(self.single_line(generate_message(statement_report, self.verbosity))), } xml += """ """ % data xml += '' self.output.write(xml) class AutoFormatter(TextFormatter): ''' Automatic output formatter If the number of report is too big, it recommends to use ikos-report. Otherwise, it uses the TextFormatter. ''' MAX_NUM_REPORT = 15 def format(self, report): if len(report.statement_reports) == 0: printf('No entries.\n', file=self.output) elif len(report.statement_reports) > AutoFormatter.MAX_NUM_REPORT: printf('Report is too big (> %d entries)\n\n' 'Use `ikos-report %s` to examine the report' ' in your terminal.\n' 'Use `ikos-view %s` to examine the report' ' in a web interface.\n', AutoFormatter.MAX_NUM_REPORT, report.db.path, report.db.path, file=self.output) else: super(AutoFormatter, self).format(report) # available formats formats = { 'text': TextFormatter, 'json': JSONFormatter, 'sarif': SARIFFormatter, 'csv': CSVFormatter, 'auto': AutoFormatter, 'junit': JUnitFormatter } ################### # report messages # ################### def generate_message(report, verbosity): ''' Generate a message for the given statement report and verbosity ''' return GENERATE_MESSAGE_MAP[report.kind](report, verbosity) def is_variable_name(s): ''' Return true if the given string is a variable name ''' # First letter is alpha or underscore # Everything else is alphanumeric or underscore return (s and (s[0].isalpha() or s[0] == '_') and all(c.isalnum() or c == '_' for c in s)) def ordinal_str(num): assert num >= 1 if num == 1: return 'first' elif num == 2: return 'second' elif num == 3: return 'third' if num > 9: if str(num)[-2] == '1': return '%dth' % num last_digit = num % 10 if last_digit == 1: return '%dst' % num elif last_digit == 2: return '%dnd' % num elif last_digit == 3: return '%drd' % num else: return '%dth' % num def statement_operand_str(statement, num): ''' Return a string to represent the num-th operand of the given statement ''' if (statement.kind == StatementKind.ASSIGNMENT or statement.kind == StatementKind.UNARY_OPERATION): return 'right hand side' elif (statement.kind == StatementKind.BINARY_OPERATION or statement.kind == StatementKind.COMPARISON): if num == 0: return 'left operand' else: return 'right operand' elif statement.kind == StatementKind.RETURN: return 'returned value' elif statement.kind == StatementKind.ALLOCATE: return 'size operand' elif statement.kind == StatementKind.POINTER_SHIFT: if num == 0: return 'base operand' else: return '%s operand' % ordinal_str(num) elif statement.kind == StatementKind.LOAD: return 'pointer' elif statement.kind == StatementKind.STORE: if num == 0: return 'pointer' else: return 'stored value' elif (statement.kind == StatementKind.EXTRACT_ELEMENT or statement.kind == StatementKind.INSERT_ELEMENT): return '%s operand' % ordinal_str(num + 1) elif (statement.kind == StatementKind.CALL or statement.kind == StatementKind.INVOKE): if num == 0: return 'function pointer' else: return '%s argument' % ordinal_str(num) elif (statement.kind == StatementKind.LANDING_PAD or statement.kind == StatementKind.RESUME): return 'operand' else: assert False, 'unexpected kind' def memory_location_str(mem_loc): ''' Return a string to represent the given memory location ''' info = mem_loc.load_info() if mem_loc.kind == MemoryLocationKind.LOCAL: if info and 'name' in info: return "local variable '%s'" % info['name'] else: return 'unnamed local variable' elif mem_loc.kind == MemoryLocationKind.GLOBAL: if 'demangle' in info: return "global variable '%s'" % info['demangle'] elif 'name' in info: return "global variable '%s'" % info['name'] elif 'cst' in info: return "constant %s" % info['cst'] else: return 'unnamed global variable' elif mem_loc.kind == MemoryLocationKind.FUNCTION: function = mem_loc.db.functions[info['id']] return "function '%s'" % function.pretty_name() elif mem_loc.kind == MemoryLocationKind.AGGREGATE: return 'aggregate variable' elif mem_loc.kind == MemoryLocationKind.ABSOLUTE_ZERO: return 'zero' elif mem_loc.kind == MemoryLocationKind.ARGV: return "'argv'" elif mem_loc.kind == MemoryLocationKind.LIBC_ERRNO: return "'errno'" elif mem_loc.kind == MemoryLocationKind.DYN_ALLOC: call = mem_loc.db.statements[info['call_id']] function = call.function() if call.line is not None and call.column is not None: return "dynamic memory allocated at '%s:%d:%d'" % ( function.pretty_name(), call.line, call.column ) else: return "dynamic memory allocated in '%s'" % function.pretty_name() else: assert False, 'unexpected kind' def generate_unreachable_message(report, verbosity): if report.status == Result.OK: return 'statement is reachable' elif report.status == Result.UNREACHABLE: return 'code is dead' else: assert False, 'unexpected status' def generate_unexpected_operand_message(report, verbosity): assert report.status == Result.ERROR return 'unexpected operand' def generate_uninitialized_variable_message(report, verbosity): if report.status == Result.OK: return 'operand is well initialized' (num, operand), = report.load_operands() if ValueKind.BEGIN_CONSTANT <= operand.kind <= ValueKind.END_CONSTANT: s = statement_operand_str(report.statement(), num) elif ValueKind.BEGIN_VARIABLE <= operand.kind <= ValueKind.END_VARIABLE: if is_variable_name(operand.repr): s = "variable '%s'" % operand.repr else: s = "expression '%s'" % operand.repr else: assert False, 'unexpected operand' if report.status == Result.WARNING: s += ' might be uninitialized' elif report.status == Result.ERROR: s += ' is uninitialized' else: assert False, 'unexpected status' return s def generate_assert_message(report, verbosity): if report.status == Result.OK: return 'assertion holds' elif report.status == Result.WARNING: return 'assertion could not be proven' elif report.status == Result.ERROR: return 'assertion never holds' else: assert False, 'unexpected status' def generate_division_by_zero_message(report, verbosity): if report.status == Result.OK: return 'divisor is not zero' elif report.status == Result.ERROR: return 'division by zero' assert report.status == Result.WARNING (_, operand), = report.load_operands() interval = Interval.from_dict(report.load_info()) s = 'divisor might be zero' if verbosity >= 2 or not interval.is_top(): if is_variable_name(operand.repr): s += ' (%s)' % interval.to_constraints(operand.repr) else: s += ' (%s)' % interval.to_constraints('divisor') return s def generate_shift_count_message(report, verbosity): if report.status == Result.OK: return 'shift count is valid' if report.status == Result.ERROR: s = 'invalid shift count' elif report.status == Result.WARNING: s = 'shift count might be invalid' else: assert False, 'unexpected status' (_, operand), = report.load_operands() interval = Interval.from_dict(report.load_info()) if ((verbosity >= 2 or not interval.is_top()) and operand.kind != ValueKind.INTEGER_CONSTANT): if is_variable_name(operand.repr): s += ' (%s)' % interval.to_constraints(operand.repr) else: s += ' (%s)' % interval.to_constraints('count') if verbosity >= 2: n = interval.bit_width - 1 s += '\nshift count is required to be between 0 and %d' % n return s def generate_integer_overflow_message(report, verbosity, signedness, kind): if report.status == Result.OK: return 'safe from %s integer %s' % (signedness, kind) if report.status == Result.ERROR: s = '%s integer %s' % (signedness, kind) elif report.status == Result.WARNING: s = 'possible %s integer %s' % (signedness, kind) else: assert False, 'unexpected status' (_, left_operand), (_, right_operand) = report.load_operands() info = report.load_info() left_interval = Interval.from_dict(info['left']) right_interval = Interval.from_dict(info['right']) ops = [] if ((verbosity >= 2 or not left_interval.is_top()) and left_operand.kind != ValueKind.INTEGER_CONSTANT): if is_variable_name(left_operand.repr): ops.append(left_interval.to_constraints(left_operand.repr)) else: ops.append(left_interval.to_constraints('left')) if ((verbosity >= 2 or not right_interval.is_top()) and right_operand.kind != ValueKind.INTEGER_CONSTANT): if is_variable_name(right_operand.repr): ops.append(right_interval.to_constraints(right_operand.repr)) else: ops.append(right_interval.to_constraints('right')) if ops: s += ' (%s)' % ', '.join(ops) if verbosity >= 2: s += "\nbetween operands '%s' and '%s'" % ( left_operand.repr, right_operand.repr ) return s def generate_null_pointer_deref_message(report, verbosity): if report.status == Result.OK: return 'pointer is non-null' (num, operand), = report.load_operands() if ValueKind.BEGIN_CONSTANT <= operand.kind <= ValueKind.END_CONSTANT: s = statement_operand_str(report.statement(), num) elif ValueKind.BEGIN_VARIABLE <= operand.kind <= ValueKind.END_VARIABLE: s = "pointer '%s'" % operand.repr else: assert False, 'unexpected operand' if report.status == Result.WARNING: s += ' might be null' elif report.status == Result.ERROR: s += ' is null' else: assert False, 'unexpected status' return s def generate_null_pointer_cmp_message(report, verbosity): assert report.status == Result.ERROR (num, _), = report.load_operands() if num == 0: return 'invalid comparison with null as left operand' else: return 'invalid comparison with null as right operand' def generate_invalid_pointer_cmp_message(report, verbosity): assert report.status == Result.ERROR (_, operand), = report.load_operands() return "pointer '%s' is invalid" % operand.repr def generate_pointer_cmp_message(report, verbosity): if report.status == Result.OK: return 'safe pointer comparison' elif report.status == Result.ERROR: return 'comparison of pointers referring to different objects' elif report.status == Result.WARNING: return 'comparison of pointers that might refer to different objects' else: assert False, 'unexpected status' def generate_pointer_overflow_message(report, verbosity): if report.status == Result.OK: return 'safe pointer arithmetic' elif report.status == Result.WARNING: return 'pointer arithmetic might overflow' elif report.status == Result.ERROR: return 'pointer arithmetic overflow' else: assert False, 'unexpected status' def generate_invalid_pointer_deref_message(report, verbosity): assert report.status == Result.ERROR (_, operand), = report.load_operands() s = "pointer '%s' is invalid" % operand.repr return s def generate_unknown_memory_access_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() s = 'memory access might be invalid' s += ", could not infer information about pointer '%s'" % operand.repr return s def generate_unaligned_pointer_message(report, verbosity): if report.status == Result.OK: return 'memory access is well aligned' if report.status == Result.WARNING: s = 'memory access might be unaligned' elif report.status == Result.ERROR: s = 'memory access is unaligned' else: assert False, 'unexpected status' info = report.load_info() requirement = Congruence.from_dict(info['requirement']) s += ', access requires %d bytes alignment' % requirement.a if verbosity <= 1: return s offset = Congruence.from_dict(info['offset']) if offset.is_top(): s += '\npointer offset is unknown' elif offset.a == 0: s += '\npointer offset is %d bytes' % offset.b elif offset.b == 0: s += '\npointer offset is a multiple of %d bytes' % offset.a, else: s += '\npointer offset is equal to (%d modulo %d) bytes' % ( offset.b, offset.a ) points_to = [] for block_info in info['points_to']: mem_loc_id = block_info['id'] mem_loc = report.db.memory_locations[mem_loc_id] if mem_loc.kind == MemoryLocationKind.ABSOLUTE_ZERO: continue line = memory_location_str(mem_loc) if 'congruence' in block_info: congruence = Congruence.from_dict(block_info['congruence']) if not congruence.is_top(): line += ' with alignment of %d bytes' % congruence.a points_to.append(line) # make the output deterministic points_to.sort() if len(points_to) == 1: s += '\npointer points to ' + points_to[0] elif len(points_to) > 1: lines = ''.join('\n\t* %s' % p for p in points_to) s += '\npointer points to:' + lines return s def generate_buffer_overflow_gets_message(report, verbosity): assert report.status == Result.ERROR return "call to unsafe function 'gets'" def generate_buffer_overflow_message(report, verbosity): if report.status == Result.OK: return 'safe memory access' info = report.load_info() kinds = set(block_info['kind'] for block_info in info['points_to']) if len(kinds) > 1: # different kind of errors, use a generic message if report.status == Result.WARNING: s = 'memory access might be invalid' elif report.status == Result.ERROR: s = 'invalid memory access' else: assert False, 'unexpected status' elif kinds == {BufferOverflowCheckKind.FUNCTION}: assert report.status == Result.ERROR s = 'dereferencing a function pointer' elif kinds == {BufferOverflowCheckKind.USE_AFTER_FREE}: if report.status == Result.WARNING: s = 'possible use after free' elif report.status == Result.ERROR: s = 'use after free' else: assert False, 'unexpected status' elif kinds == {BufferOverflowCheckKind.USE_AFTER_RETURN}: if report.status == Result.WARNING: s = 'possible use after return' elif report.status == Result.ERROR: s = 'use after return' else: assert False, 'unexpected status' elif kinds == {BufferOverflowCheckKind.HARDWARE_ADDRESSES}: if report.status == Result.WARNING: s = 'memory access might be invalid' elif report.status == Result.ERROR: s = 'invalid memory access' else: assert False, 'unexpected status' access_size = Interval.from_dict(info['access_size']) offset = Interval.from_dict(info['offset']) if access_size.ub.is_max(): s += ', could not bound access size' return s if offset.ub.is_max(): s += ', could not bound offset' return s if access_size.is_constant(): s += ', accessing %d bytes' % access_size.ub.n elif not access_size.lb.is_min(): s += ', accessing between %d and %d bytes' % ( access_size.lb.n, access_size.ub.n ) else: s += ', accessing up to %d bytes' % access_size.ub.n if offset.is_constant(): s += ' at address 0x%x' % offset.ub.n else: s += ' at address between 0x%x and 0x%x' % ( offset.lb.n, offset.ub.n ) return s elif kinds == {BufferOverflowCheckKind.OUT_OF_BOUND}: if report.status == Result.WARNING: s = 'possible buffer overflow' elif report.status == Result.ERROR: s = 'buffer overflow' else: assert False, 'unexpected status' else: assert False, 'unexpected kind' # Size of an array element, or None if it's not an array access array_element_size = info.get('array_element_size', None) points_to = [] for block_info in info['points_to']: status = block_info['status'] kind = block_info['kind'] mem_loc_id = block_info['id'] mem_loc = report.db.memory_locations[mem_loc_id] line = memory_location_str(mem_loc) if kind == BufferOverflowCheckKind.OUT_OF_BOUND: size = Interval.from_dict(block_info['size']) if array_element_size: if size.is_constant(): n = size.ub.n // array_element_size line += ' of %d elements' % n elif not size.ub.is_max(): ub = size.ub.n // array_element_size line += ' of at most %d elements' % ub else: if size.is_constant(): line += ' of size %d bytes' % size.ub.n elif not size.ub.is_max(): line += ' of size at most %d bytes' % size.ub.n if len(info['points_to']) == 1: # no need for further explanation points_to.append(line) break if kind == BufferOverflowCheckKind.FUNCTION: assert status == Result.ERROR line += ', which is a function' elif kind == BufferOverflowCheckKind.USE_AFTER_FREE: if status == Result.WARNING: line += ', which might be released' elif status == Result.ERROR: line += ', which is released' else: assert False, 'unexpected status' elif kind == BufferOverflowCheckKind.USE_AFTER_RETURN: if status == Result.WARNING: line += ', which might be out of scope' elif status == Result.ERROR: line += ', which is out of scope' else: assert False, 'unexpected status' elif kind == BufferOverflowCheckKind.HARDWARE_ADDRESSES: if status == Result.WARNING: line += ', which might not be a valid hardware address' elif status == Result.ERROR: line += ', which is an invalid hardware address' else: assert False, 'unexpected status' elif kind == BufferOverflowCheckKind.OUT_OF_BOUND: if status == Result.OK: line += ', which is valid' elif status == Result.WARNING: line += ', which might be out of bounds' elif status == Result.ERROR: line += ', which is out of bounds' else: assert False, 'unexpected status' else: assert False, 'unexpected kind' points_to.append(line) # make the output deterministic points_to.sort() if kinds == {BufferOverflowCheckKind.OUT_OF_BOUND} and array_element_size: # Out of bound array access offset = Interval.from_dict(info['offset']) offset = offset.sign_cast(Signedness.SIGNED) if offset.is_constant(): n = offset.ub.n // array_element_size s += ', accessing index %d' % n elif not offset.ub.is_max(): ub = offset.ub.n // array_element_size if not offset.lb.is_min(): lb = offset.lb.n // array_element_size s += ', accessing index between %d and %d' % (lb, ub) else: s += ', accessing index up to %d' % ub else: s += ', could not bound index for access' if len(points_to) == 1: s += ' of %s' % points_to[0] else: s += ' of:%s' % ''.join('\n\t* %s' % p for p in points_to) return s (_, operand), _ = report.load_operands() s += ", pointer '%s'" % operand.repr points_to_prep = ' points to' if BufferOverflowCheckKind.OUT_OF_BOUND in kinds: offset_prep = ' at' points_to_prep = ' of' access_size = Interval.from_dict(info['access_size']) if access_size.is_constant(): s += ' accesses %d bytes' % access_size.ub.n elif not access_size.ub.is_max(): if not access_size.lb.is_min(): s += ' accesses between %d and %d bytes' % ( access_size.lb.n, access_size.ub.n ) else: s += ' accesses up to %d bytes' % access_size.ub.n else: offset_prep = ' with' points_to_prep = ' points to' offset = Interval.from_dict(info['offset']) offset = offset.sign_cast(Signedness.SIGNED) if offset.is_constant(): s += offset_prep + ' offset %d bytes' % offset.ub.n elif not offset.ub.is_max(): if not offset.lb.is_min(): s += offset_prep + ' offset between %d and %d bytes' % ( offset.lb.n, offset.ub.n ) else: s += offset_prep + ' offset up to %d bytes' % offset.ub.n s += points_to_prep if len(points_to) == 1: s += ' %s' % points_to[0] else: s += ':%s' % ''.join('\n\t* %s' % p for p in points_to) return s def generate_ignored_store_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() s = 'ignored memory write' s += ", could not infer information about pointer '%s'." % operand.repr s += ' Analysis might be unsound.' return s def generate_ignored_memcpy_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() s = 'ignored memcpy()' s += ", could not infer information about pointer '%s'." % operand.repr s += ' Analysis might be unsound.' return s def generate_ignored_memmove_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() s = 'ignored memmove()' s += ", could not infer information about pointer '%s'." % operand.repr s += ' Analysis might be unsound.' return s def generate_ignored_memset_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() s = 'ignored memset()' s += ", could not infer information about pointer '%s'." % operand.repr s += ' Analysis might be unsound.' return s def generate_ignored_free_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() s = 'ignored memory deallocation' s += ", could not infer information about pointer '%s'." % operand.repr s += ' Analysis might be unsound.' return s def generate_ignored_call_side_effect_on_pointer_param_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() info = report.load_info() function_id = info['fun_id'] function = report.db.functions[function_id] s = "ignored side effect of call to function '%s'" % function.pretty_name() s += ", could not infer information about pointer '%s'." % operand.repr s += ' Analysis might be unsound.' return s def generate_ignored_call_side_effect_message(report, verbosity): assert report.status == Result.WARNING info = report.load_info() function_id = info['fun_id'] function = report.db.functions[function_id] s = "ignored side effect of call to extern function '%s'." s = s % function.pretty_name() s += ' Analysis might be unsound.' return s def generate_recursive_function_call_message(report, verbosity): assert report.status == Result.WARNING info = report.load_info() function_id = info['fun_id'] function = report.db.functions[function_id] s = "function call to '%s' is recursive." s = s % function.pretty_name() s += ' Analysis might be unsound.' return s def generate_call_inline_asm_message(report, verbosity): assert report.status == Result.OK return 'safe call to inline assembly code' def generate_unknown_function_call_message(report, verbosity): assert report.status == Result.WARNING (_, operand), = report.load_operands() s = 'function call might be unsafe' s += ", could not infer information about pointer '%s'" % operand.repr return s def generate_function_call_message(report, verbosity): info = report.load_info() if report.status == Result.OK: s = 'safe function call' callees = [] for block_info in info['points_to']: function_id = block_info['fun_id'] function = report.db.functions[function_id] callees.append("'%s'" % function.pretty_name()) # make the output deterministic callees.sort() if len(callees) == 1: s += ' to %s' % callees[0] else: lines = ''.join('\n\t* %s' % c for c in callees) s += ', called functions are:' + lines return s if report.status == Result.WARNING: s = 'function call might be invalid' elif report.status == Result.ERROR: s = 'invalid function call' else: assert False, 'unexpected status' (_, operand), = report.load_operands() s += ", pointer '%s' points to" % operand.repr callees = [] for block_info in info['points_to']: status = block_info['kind'] mem_loc_id = block_info['id'] mem_loc = report.db.memory_locations[mem_loc_id] if status == FunctionCallCheckKind.NOT_FUNCTION: line = '%s, which is not a function' % memory_location_str(mem_loc) else: function_id = block_info['fun_id'] function = report.db.functions[function_id] line = "function '%s'" % function.pretty_name() if status == FunctionCallCheckKind.WRONG_SIGNATURE: line += ', which has a mismatching type' elif status == FunctionCallCheckKind.OK: line += ', which is valid' else: assert False, 'unexpected kind' callees.append(line) # make the output deterministic callees.sort() if len(callees) == 1: s += ' %s' % callees[0] else: s += ':%s' % ''.join('\n\t* %s' % c for c in callees) return s def generate_double_free_message(report, verbosity): if report.status == Result.OK: return 'safe memory deallocation' info = report.load_info() points_to = [] all_dyn_alloc = True for block_info in info['points_to']: mem_loc_id = block_info['id'] status = block_info['status'] mem_loc = report.db.memory_locations[mem_loc_id] line = memory_location_str(mem_loc) if mem_loc.kind != MemoryLocationKind.DYN_ALLOC: assert status == Result.ERROR all_dyn_alloc = False line += ', which is not dynamically allocated' elif status == Result.ERROR: line += ', which is already released' elif status == Result.WARNING: line += ', which might be already released' elif status == Result.OK: line += ', which is valid' else: assert False, 'unexpected status' points_to.append(line) # make the output deterministic points_to.sort() if all_dyn_alloc: if report.status == Result.WARNING: s = 'possible double free' elif report.status == Result.ERROR: s = 'double free' else: assert False, 'unexpected status' else: if report.status == Result.WARNING: s = 'memory deallocation might be invalid' elif report.status == Result.ERROR: s = 'invalid memory deallocation' else: assert False, 'unexpected status' (_, operand), = report.load_operands() s += ", pointer '%s' points to" % operand.repr if len(points_to) == 1: s += ' %s' % points_to[0] else: s += ':%s' % ''.join('\n\t* %s' % p for p in points_to) return s GENERATE_MESSAGE_MAP = { CheckKind.UNREACHABLE: generate_unreachable_message, CheckKind.UNEXPECTED_OPERAND: generate_unexpected_operand_message, CheckKind.UNINITIALIZED_VARIABLE: generate_uninitialized_variable_message, CheckKind.ASSERT: generate_assert_message, CheckKind.DIVISION_BY_ZERO: generate_division_by_zero_message, CheckKind.SHIFT_COUNT: generate_shift_count_message, CheckKind.SIGNED_INT_UNDERFLOW: functools.partial( generate_integer_overflow_message, signedness='signed', kind='underflow'), CheckKind.SIGNED_INT_OVERFLOW: functools.partial( generate_integer_overflow_message, signedness='signed', kind='overflow'), CheckKind.UNSIGNED_INT_UNDERFLOW: functools.partial( generate_integer_overflow_message, signedness='unsigned', kind='underflow'), CheckKind.UNSIGNED_INT_OVERFLOW: functools.partial( generate_integer_overflow_message, signedness='unsigned', kind='overflow'), CheckKind.NULL_POINTER_DEREF: generate_null_pointer_deref_message, CheckKind.NULL_POINTER_COMPARISON: generate_null_pointer_cmp_message, CheckKind.INVALID_POINTER_COMPARISON: generate_invalid_pointer_cmp_message, CheckKind.POINTER_COMPARISON: generate_pointer_cmp_message, CheckKind.POINTER_OVERFLOW: generate_pointer_overflow_message, CheckKind.INVALID_POINTER_DEREF: generate_invalid_pointer_deref_message, CheckKind.UNKNOWN_MEMORY_ACCESS: generate_unknown_memory_access_message, CheckKind.UNALIGNED_POINTER: generate_unaligned_pointer_message, CheckKind.BUFFER_OVERFLOW_GETS: generate_buffer_overflow_gets_message, CheckKind.BUFFER_OVERFLOW: generate_buffer_overflow_message, CheckKind.IGNORED_STORE: generate_ignored_store_message, CheckKind.IGNORED_MEMORY_COPY: generate_ignored_memcpy_message, CheckKind.IGNORED_MEMORY_MOVE: generate_ignored_memmove_message, CheckKind.IGNORED_MEMORY_SET: generate_ignored_memset_message, CheckKind.IGNORED_FREE: generate_ignored_free_message, CheckKind.IGNORED_CALL_SIDE_EFFECT_ON_POINTER_PARAM: generate_ignored_call_side_effect_on_pointer_param_message, CheckKind.IGNORED_CALL_SIDE_EFFECT: generate_ignored_call_side_effect_message, CheckKind.RECURSIVE_FUNCTION_CALL: generate_recursive_function_call_message, CheckKind.FUNCTION_CALL_INLINE_ASSEMBLY: generate_call_inline_asm_message, CheckKind.UNKNOWN_FUNCTION_CALL_POINTER: generate_unknown_function_call_message, CheckKind.FUNCTION_CALL: generate_function_call_message, CheckKind.FREE: generate_double_free_message, } ########################## # command line interface # ########################## def parse_arguments(argv): usage = '%(prog)s [options] file.db' description = 'Generate an analysis report from an output database' formatter_class = argparse.RawTextHelpFormatter parser = argparse.ArgumentParser(usage=usage, description=description, formatter_class=formatter_class) # Positional arguments parser.add_argument('file', metavar='file.db', help='Result database') # Optional arguments parser.add_argument('--version', action=args.VersionAction, nargs=0, help='Show ikos version') parser.add_argument('--color', dest='color', metavar='', help=args.help('Enable terminal colors:', args.color_choices, args.default_color), choices=args.choices(args.color_choices), default=args.default_color) parser.add_argument('-t', '--times', dest='display_times', metavar='', help=args.help('Display timing results', args.display_times_choices, 'no'), choices=args.choices(args.display_times_choices), default='no') parser.add_argument('-s', '--summary', dest='display_summary', metavar='', help=args.help('Display the analysis summary', args.display_summary_choices, 'no'), choices=args.choices(args.display_summary_choices), default='no') parser.add_argument('--display-raw-checks', dest='display_raw_checks', help='Display analysis raw checks', action='store_true', default=False) parser.add_argument('-f', '--format', dest='format', metavar='', help=args.help('Available report formats:', args.report_formats, 'text'), choices=args.choices(args.report_formats), default='text') parser.add_argument('-o', '--report-file', dest='report_file', metavar='', help='Write the report into a file (default: stdout)', default=sys.stdout, type=argparse.FileType('w')) parser.add_argument('--web-port', dest='web_port', metavar='', help='Listening port for ikos view', default=8080, type=int) parser.add_argument('--status-filter', dest='status_filter', metavar='', help=args.help('Available status filters:', args.status_filters, args.default_status_filter), action='append') parser.add_argument('--analyses-filter', dest='analyses_filter', metavar='', help=args.help('Available analyses filters:', args.analyses, '*'), action='append') parser.add_argument('-v', '--report-verbosity', dest='report_verbosity', metavar='[1-4]', help='Report verbosity (default: 1)', default=1, type=int) opt = parser.parse_args(argv) # parse --status-filter opt.status_filter = args.parse_argument(parser, 'status-filter', choices=args.status_filters, groups=None, default=args.default_status_filter, value=opt.status_filter) # parse --analyses-filter opt.analyses_filter = args.parse_argument(parser, 'analyses-filter', choices=args.analyses, groups=None, default='*', value=opt.analyses_filter) # check for consistency between --web-port and -f=web if opt.web_port != 8080 and opt.format != 'web': parser.error('cannot use --web-port without --format=web') return opt def ikos_view(opt, db): from ikos import view from ikos import log log.setup('info') v = view.View(db, port=opt.web_port) v.serve() ######################## # main for ikos-report # ######################## def main(argv): progname = os.path.basename(argv[0]) # parse arguments opt = parse_arguments(argv[1:]) # setup colors colors.setup(opt.color) if not os.path.isfile(opt.file): printf("%s: error: no such file: \'%s\'\n", progname, opt.file, file=sys.stderr) sys.exit(1) try: # open result database db = OutputDatabase(opt.file) first = True # load settings settings = db.load_settings() # display timing results if opt.display_times != 'no': if not first: printf('\n') print_timing_results(db, opt.display_times == 'full') first = False # display summary if opt.display_summary != 'no': if not first: printf('\n') print_summary(db, opt.display_summary == 'full') first = False # display raw checks if opt.display_raw_checks: if not first: printf('\n') print_raw_checks(db, settings['procedural'] == 'interprocedural') first = False # start ikos-view if opt.format == 'web': ikos_view(opt, db) return # report if opt.format != 'no': if not first and opt.report_file is sys.stdout: printf('\n') # setup colors again (in case opt.color = 'auto') colors.setup(opt.color, file=opt.report_file) # generate report rep = generate_report(db, status_filter=opt.status_filter, analyses_filter=opt.analyses_filter) # format report formatter_class = formats[opt.format] formatter = formatter_class(opt.report_file, opt.report_verbosity) formatter.format(rep) # close database db.close() except sqlite3.DatabaseError as e: printf('%s: error: %s\n', progname, e, file=sys.stderr) sys.exit(1) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/scan.py000066400000000000000000001051131473507761200222300ustar00rootroot00000000000000############################################################################### # # IKOS scan # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import codecs import collections import itertools import json import os import os.path import random import re import subprocess import sys import tempfile import threading from ikos import analyzer from ikos import args from ikos import colors from ikos import http from ikos import log from ikos import settings from ikos.analyzer import command_string from ikos.filetype import filetype from ikos.log import printf class ClangArgumentParser: ''' Parser for clang arguments ''' def __init__(self, cmd): # inputs and outputs self.source_files = [] self.object_files = [] self._output_file = None # compile and link arguments self.compile_args = [] self.link_args = [] # properties self.is_standard_in = False # - self.is_link = True # false if -c self.is_preprocess = False # -E self.is_assemble = False # -S self.is_assembly = False # .s or .S self.is_version = False # --version self.is_emit_llvm = False # -emit-llvm self.is_verbose = False # --verbose self.is_dependency = False # -M exact_arguments = { '-': (0, self._set_standard_in), '-o': (1, self._set_output_file), '-c': (0, self._set_compile_only), '-E': (0, self._set_preprocess_only), '-S': (0, self._set_assemble_only), '--version': (0, self._set_version_only), '-emit-llvm': (0, self._set_emit_llvm), '-v': (0, self._set_verbose), '--verbose': (0, self._set_verbose), # Warnings '-w': (0, self._add_compile_link_unary), '-W': (0, self._add_compile_link_unary), # Preprocessor assertions '-A': (1, self._add_compile_binary), '-D': (1, self._add_compile_binary), '-U': (1, self._add_compile_binary), # Dependency generator '-M': (0, self._add_dependency_unary), '-MM': (0, self._add_dependency_unary), '-MF': (1, self._add_dependency_binary), '-MG': (0, self._add_dependency_unary), '-MP': (0, self._add_dependency_unary), '-MT': (1, self._add_dependency_binary), '-MQ': (1, self._add_dependency_binary), '-MD': (0, self._add_dependency_unary), '-MMD': (0, self._add_dependency_unary), # Include '-I': (1, self._add_compile_binary), '-idirafter': (1, self._add_compile_binary), '-include': (1, self._add_compile_binary), '-imacros': (1, self._add_compile_binary), '-iprefix': (1, self._add_compile_binary), '-iwithprefix': (1, self._add_compile_binary), '-iwithprefixbefore': (1, self._add_compile_binary), '-isystem': (1, self._add_compile_binary), '-isysroot': (1, self._add_compile_binary), '-iquote': (1, self._add_compile_binary), '-imultilib': (1, self._add_compile_binary), # Linker '-l': (1, self._add_link_binary), '-L': (1, self._add_link_binary), '-T': (1, self._add_link_binary), '-u': (1, self._add_link_binary), # Language '-ansi': (0, self._add_compile_unary), '-pedantic': (0, self._add_compile_unary), '-x': (1, self._add_compile_binary), # Ignore debug flags '-g': (0, self._add_compile_unary), '-g0': (0, self._add_compile_unary), '-g1': (0, self._add_compile_unary), '-ggdb': (0, self._add_compile_unary), '-ggdb3': (0, self._add_compile_unary), '-gdwarf-2': (0, self._add_compile_unary), '-gdwarf-3': (0, self._add_compile_unary), '-gline-tables-only': (0, self._add_compile_unary), '-p': (0, self._add_compile_unary), '-pg': (0, self._add_compile_unary), # Ignore optimization flags '-O': (0, self._add_compile_unary), '-O0': (0, self._add_compile_unary), '-O1': (0, self._add_compile_unary), '-O2': (0, self._add_compile_unary), '-O3': (0, self._add_compile_unary), '-Os': (0, self._add_compile_unary), '-Ofast': (0, self._add_compile_unary), '-Og': (0, self._add_compile_unary), '-Oz': (0, self._add_compile_unary), # Ignore code coverage instrumentation '-fprofile-arcs': (0, self._add_compile_link_unary), '-coverage': (0, self._add_compile_link_unary), '--coverage': (0, self._add_compile_link_unary), # Component-specifiers '-Xclang': (1, self._add_compile_binary), '-Xpreprocessor': (1, self._ignore), '-Xassembler': (1, self._ignore), '-Xlinker': (1, self._ignore), # Link options '-e': (1, self._add_link_binary), '-rpath': (1, self._add_link_binary), '-shared': (0, self._add_link_unary), '-static': (0, self._add_link_unary), '-pie': (0, self._add_link_unary), '-nostdlib': (0, self._add_link_unary), '-nodefaultlibs': (0, self._add_link_unary), '-rdynamic': (0, self._add_link_unary), '-dynamiclib': (0, self._add_link_unary), '-current_version': (1, self._add_link_binary), '-compatibility_version': (1, self._add_link_binary), '-install_name': (1, self._add_link_binary), # Misc. '-arch': (1, self._add_compile_binary), '/dev/null': (0, self._add_source_file), '-pipe': (0, self._add_compile_unary), '-undef': (0, self._add_compile_unary), '-nostdinc': (0, self._add_compile_unary), '-nostdinc++': (0, self._add_compile_unary), '-nostdlibinc': (0, self._add_compile_unary), '-Qunused-arguments': (0, self._add_compile_unary), '-no-integrated-as': (0, self._add_compile_unary), '-integrated-as': (0, self._add_compile_unary), '-no-canonical-prefixes': (0, self._add_compile_link_unary), '-pthread': (0, self._add_compile_unary), '--param': (1, self._ignore), '-aux-info': (1, self._ignore), '-no-cpp-precomp': (0, self._add_compile_unary), '-mno-omit-leaf-frame-pointer': (0, self._add_compile_unary), '-maes': (0, self._add_compile_unary), '-mno-aes': (0, self._add_compile_unary), '-mavx': (0, self._add_compile_unary), '-mno-avx': (0, self._add_compile_unary), '-mcmodel=kernel': (0, self._add_compile_unary), '-mno-red-zone': (0, self._add_compile_unary), '-mmmx': (0, self._add_compile_unary), '-mno-mmx': (0, self._add_compile_unary), '-msse': (0, self._add_compile_unary), '-mno-sse': (0, self._add_compile_unary), '-msse2': (0, self._add_compile_unary), '-mno-sse2': (0, self._add_compile_unary), '-msse3': (0, self._add_compile_unary), '-mno-sse3': (0, self._add_compile_unary), '-mssse3': (0, self._add_compile_unary), '-mno-ssse3': (0, self._add_compile_unary), '-msse4': (0, self._add_compile_unary), '-mno-sse4': (0, self._add_compile_unary), '-msse4.1': (0, self._add_compile_unary), '-mno-sse4.1': (0, self._add_compile_unary), '-msse4.2': (0, self._add_compile_unary), '-mno-sse4.2': (0, self._add_compile_unary), '-msoft-float': (0, self._add_compile_unary), '-m3dnow': (0, self._add_compile_unary), '-mno-3dnow': (0, self._add_compile_unary), '-m16': (0, self._add_compile_unary), '-m32': (0, self._add_compile_unary), '-m64': (0, self._add_compile_unary), '-mx32': (0, self._add_compile_unary), '-miamcu': (0, self._add_compile_unary), '-mstackrealign': (0, self._add_compile_unary), '-mretpoline-external-thunk': (0, self._add_compile_unary), '-mno-fp-ret-in-387': (0, self._add_compile_unary), '-mskip-rax-setup': (0, self._add_compile_unary), '-mindirect-branch-register': (0, self._add_compile_unary), '-print-multi-directory': (0, self._add_compile_unary), '-print-multi-lib': (0, self._add_compile_unary), '-print-libgcc-file-name': (0, self._add_compile_unary), '-print-search-dirs': (0, self._add_compile_unary), '-mno-80387': (0, self._add_compile_unary), '-mno-global-merge': (0, self._add_compile_unary), '-Wl,-dead_strip': (0, self._warning_link_unary), '-dead_strip': (0, self._warning_link_unary), } pattern_arguments = { r'^.+\.(c|cc|cpp|C|cxx|i|s|S|bc)$': (0, self._add_source_file), r'^.+\.([fF](|[0-9]{2}|or|OR|pp|PP))$': (0, self._add_source_file), r'^.+\.(o|lo|So|so|po|a|dylib)$': (0, self._add_object_file), r'^.+\.dylib(\.\d)+$': (0, self._add_object_file), r'^.+\.(So|so)(\.\d)+$': (0, self._add_object_file), r'^-(l|L).+$': (0, self._add_link_unary), r'^-I.+$': (0, self._add_compile_unary), r'^-D.+$': (0, self._add_compile_unary), r'^-B.+$': (0, self._add_compile_link_unary), r'^-isystem.+$': (0, self._add_compile_link_unary), r'^-U.+$': (0, self._add_compile_unary), r'^-Wl,.+$': (0, self._add_link_unary), r'^-W[^l].+$': (0, self._add_compile_unary), r'^-Wl[^,].+$': (0, self._add_compile_unary), r'^-fsanitize=.+$': (0, self._add_compile_link_unary), r'^-f.+$': (0, self._add_compile_unary), r'^-rtlib=.+$': (0, self._add_link_unary), r'^-std=.+$': (0, self._add_compile_unary), r'^-stdlib=.+$': (0, self._add_compile_link_unary), r'^-mtune=.+$': (0, self._add_compile_unary), r'^-mstack-alignment=.+$': (0, self._add_compile_unary), r'^-mcmodel=.+$': (0, self._add_compile_unary), r'^-mpreferred-stack-boundary=.+$': (0, self._add_compile_unary), r'^-mindirect-branch=.+$': (0, self._add_compile_unary), r'^-mregparm=.+$': (0, self._add_compile_unary), r'^-march=.+$': (0, self._add_compile_unary), r'^--param=.+$': (0, self._add_compile_unary), r'-mmacosx-version-min=.+$': (0, self._add_compile_unary), r'^--sysroot=.+$': (0, self._add_compile_unary), r'^-print-prog-name=.*$': (0, self._add_compile_unary), r'^-print-file-name=.*$': (0, self._add_compile_unary), r'^-x.+$': (0, self._add_compile_unary), } self.args = collections.deque(cmd) while self.args: if (self.is_standard_in or self.is_preprocess or self.is_assemble or self.is_assembly or self.is_version or self.is_emit_llvm): break # no need to emit llvm bitcode # next argument arg = self.args.popleft() # check if it's an exact argument if arg in exact_arguments: (arity, handler) = exact_arguments[arg] params = self._shift(arity) handler(arg, *params) else: matched = False # check if it matches a known pattern for pattern, (arity, handler) in pattern_arguments.items(): if re.match(pattern, arg): params = self._shift(arity) handler(arg, *params) matched = True break if not matched: # unknown argument, just keep it self._add_compile_unary(arg) def _shift(self, nargs): if len(self.args) < nargs: printf('error: unexpected command line argument\n', file=sys.stderr) sys.exit(1) ret = [] for _ in range(nargs): ret.append(self.args.popleft()) return ret def _set_standard_in(self, flag): self.is_standard_in = True def _set_output_file(self, flag, path): self._output_file = path def _add_source_file(self, path): self.source_files.append(path) if re.search('\\.(s|S)$', path): self.is_assembly = True def _add_object_file(self, path): self.object_files.append(path) def _set_compile_only(self, flag): self.is_link = False def _set_preprocess_only(self, flag): self.is_preprocess = True def _set_assemble_only(self, flag): self.is_assemble = True def _set_version_only(self, flag): self.is_version = True def _set_emit_llvm(self, flag): self.is_emit_llvm = True def _set_verbose(self, flag): self.is_verbose = True def _ignore(self, flag, *params): pass def _add_compile_unary(self, flag): self.compile_args.append(flag) def _add_compile_binary(self, flag, param): self.compile_args.append(flag) self.compile_args.append(param) def _add_dependency_unary(self, flag): self.is_dependency = True self.compile_args.append(flag) def _add_dependency_binary(self, flag, param): self.is_dependency = True self.compile_args.append(flag) self.compile_args.append(param) def _add_link_unary(self, flag): self.link_args.append(flag) def _add_link_binary(self, flag, param): self.link_args.append(flag) self.link_args.append(param) def _add_compile_link_unary(self, flag): self.compile_args.append(flag) self.link_args.append(flag) def _warning_link_unary(self, flag): log.warning("Flag '%s' cannot be used with ikos-scan, ignored." % flag) @property def output_file(self): if self._output_file is not None: return self._output_file elif not self.is_link: # -c but no -o, guess the file name base = os.path.basename(self.source_files[0]) return os.path.splitext(base)[0] + '.o' else: return 'a.out' def skip_bitcode_gen(self): ''' Return True if it is unnecessary to generate llvm bitcode ''' if self.is_standard_in: return True if self.is_preprocess: return True if self.is_assemble or self.is_assembly: return True if self.is_version: return True if self.is_emit_llvm: return True if self.is_dependency and self.is_link: return True return False def run(cmd): ''' Run the given command and return the exit code ''' log.debug('Running %s' % command_string(cmd)) try: proc = subprocess.Popen(cmd) rc = proc.wait() except OSError as e: printf('error: %s: %s\n', cmd[0], e.strerror, file=sys.stderr) sys.exit(e.errno) if rc != 0: sys.exit(rc) return rc def check_output(cmd): ''' Run the given command and return the standard output, in bytes ''' log.debug('Running %s' % command_string(cmd)) try: return subprocess.check_output(cmd) except OSError as e: printf('error: %s: %s\n', cmd[0], e.strerror, file=sys.stderr) sys.exit(e.errno) def compiler(mode): ''' Return the full path to the compiler for the given mode ''' if mode == 'cc': return settings.clang() elif mode == 'c++': return settings.clangxx() else: assert False, 'unexpected mode' def build_bitcode(mode, parser, src_path, bc_path): ''' Compile the given source file to llvm bitcode ''' cmd = [compiler(mode)] cmd += analyzer.clang_emit_llvm_flags() cmd += parser.compile_args cmd += analyzer.clang_ikos_flags() cmd += [src_path, '-o', bc_path] run(cmd) def link_bitcodes(input_paths, output_path): ''' Link the given bitcode files to a single llvm bitcode ''' cmd = [settings.llvm_link()] cmd += input_paths cmd += ['-o', output_path] run(cmd) def build_object(mode, parser, src_path, obj_path): ''' Compile the given source file to an object file ''' cmd = [compiler(mode), '-c'] cmd += parser.compile_args cmd += [src_path, '-o', obj_path] run(cmd) def link_objects(mode, parser, input_paths, output_path): cmd = [compiler(mode)] cmd += input_paths cmd += parser.link_args cmd += ['-o', output_path] run(cmd) DARWIN_SEGMENT_NAME = '__WLLVM' DARWIN_SECTION_NAME = '__llvm_bc' ELF_SECTION_NAME = '.llvm_bc' PE_SECTION_NAME = '.llvm_bc' def attach_bitcode_path(obj_path, bc_path): ''' Attach the bitcode full path to the given object file ''' ext = os.path.splitext(obj_path)[1] if ext not in ('.o', '.lo', '.os', '.So', '.po'): return # unexpected file format if not os.path.exists(obj_path): log.warning( "Cannot attach bitcode path to missing file '%s'" % obj_path ) return abs_bc_path = os.path.abspath(bc_path) # write the absolute path to the bitcode file in a temporary file f = tempfile.NamedTemporaryFile(mode='w+b', suffix='.llvm_bc', delete=False) f.write(abs_bc_path.encode('utf-8')) f.write(b'\n') f.flush() os.fsync(f.fileno()) f.close() # add a section in the object file if sys.platform.startswith('darwin'): # TODO(marthaud): use llvm-objcopy when they start supporting Mach-O cmd = ['ld', '-r', '-keep_private_externs', obj_path, '-sectcreate', DARWIN_SEGMENT_NAME, DARWIN_SECTION_NAME, f.name, '-o', obj_path] run(cmd) elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'): cmd = [settings.llvm_objcopy(), '--add-section', '%s=%s' % (ELF_SECTION_NAME, f.name), obj_path] run(cmd) elif sys.platform.startswith('win'): # TODO(marthaud): use llvm-objcopy when they start supporting COFF/PE cmd = ['objcopy', '--add-section', '%s=%s' % (PE_SECTION_NAME, f.name), obj_path] run(cmd) else: assert False, 'unsupported platform' os.remove(f.name) def extract_bitcode(exe_path, bc_path): ''' Extract the llvm bitcode for the given executable file ''' # first, extract the llvm bitcode paths cmd = [settings.llvm_objdump(), '-s'] if sys.platform.startswith('darwin'): cmd.append('--section=%s' % DARWIN_SECTION_NAME) elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'): cmd.append('--section=%s' % ELF_SECTION_NAME) elif sys.platform.startswith('win'): cmd.append('--section=%s' % PE_SECTION_NAME) else: assert False, 'unsupported platform' cmd.append(exe_path) output = check_output(cmd) section_content = b'' # The output of llvm-objdump is prefixed by three lines: an empty one, one # that specifies the format, and one that describes what comes next (the # contents of the section requested). After that, lines have an address, # the hex representation (36 characters plus spaces), and the ASCII # representation, with some spaces in between sections or columns. The # following obtains only the hex code, ignoring the ASCII and the # addresses. for line in itertools.islice(output.splitlines(), 3, None): n = line.find(b' ', 1) line = line[n + 1:n + 36] for item in line.split(b' '): section_content += codecs.decode(item, 'hex') section_content = section_content.rstrip(b'\x00') bc_paths = [path.strip(b'\x00').decode('utf-8') for path in section_content.splitlines()] link_bitcodes(bc_paths, bc_path) def notify_binary_built(exe_path, bc_path): ''' Notify the scan server that a binary was built ''' abs_bc_path = os.path.abspath(bc_path) abs_exe_path = os.path.abspath(exe_path) if 'IKOS_SCAN_NOTIFIER_FILES' in os.environ: bc_base_path, _ = os.path.splitext(abs_bc_path) indicator_path = bc_base_path + '.ikosbin' with open(indicator_path, 'w') as indicator_file: indicator_file.write(json.dumps({ 'exe': abs_exe_path, 'bc': abs_bc_path, })) else: binary = { 'exe': abs_exe_path, 'bc': abs_bc_path, } data = http.urlencode(binary).encode('utf-8') http.urlopen(os.environ['IKOS_SCAN_SERVER'], data) class ScanServerRequestHandler(http.BaseHTTPRequestHandler): def do_POST(self): # parse request length = int(self.headers['content-length']) data = http.parse_qs(self.rfile.read(length).decode('utf-8')) binary = { 'exe_path': data['exe'][0], 'bc_path': data['bc'][0], } self.server.binaries.append(binary) log.debug('Received %r' % binary) # send response self.send_response(200) self.end_headers() self.wfile.write(b'OK\n') def log_message(self, fmt, *args): return # disable logging class ScanServer(threading.Thread): ''' HTTP server that logs the output files of the compiler Note that the server is single threaded. ''' def __init__(self): super(ScanServer, self).__init__() self.port = None while self.port is None: try: # try to start the http server on a random port self.port = random.randint(8000, 9000) self.httpd = http.HTTPServerIPv6(('', self.port), ScanServerRequestHandler) except (OSError, IOError): self.port = None # port already in use self.httpd.timeout = 0.1 self.httpd.binaries = [] # list of built binaries self.running = False def run(self): self.running = True while self.running: self.httpd.handle_request() def cancel(self): self.running = False @property def binaries(self): return self.httpd.binaries ########################################### # main for ikos-scan-cc and ikos-scan-c++ # ########################################### def compile_main(mode, argv): progname = os.path.basename(argv[0]) if not ('IKOS_SCAN_SERVER' in os.environ or 'IKOS_SCAN_NOTIFIER_FILES' in os.environ): printf('error: %s: missing environment variable IKOS_SCAN_SERVER or IKOS_SCAN_NOTIFIER_FILES.\n', progname, file=sys.stderr) sys.exit(1) # setup colors and logging colors.setup(os.environ.get('IKOS_SCAN_COLOR', args.default_color), file=log.out) log.setup(os.environ.get('IKOS_SCAN_LOG_LEVEL', args.default_log_level)) # first step, run the actual command run([compiler(mode)] + argv[1:]) # second step, parse the command line and compile to llvm bitcode parser = ClangArgumentParser(argv[1:]) if parser.skip_bitcode_gen(): return try: if (len(parser.source_files) == 1 and len(parser.object_files) == 0 and not parser.is_link): # in this case, just compile to llvm bitcode and attach the llvm # bitcode path to the output object file src_path = parser.source_files[0] obj_path = parser.output_file bc_path = '%s.bc' % obj_path build_bitcode(mode, parser, src_path, bc_path) attach_bitcode_path(obj_path, bc_path) return # compile the source files one by one and attach the llvm bitcode path new_object_files = [] for src_path in parser.source_files: # build the object file obj_path = '%s.o' % src_path build_object(mode, parser, src_path, obj_path) new_object_files.append(obj_path) # build the bitcode file if src_path.endswith('.bc'): bc_path = src_path else: bc_path = '%s.bc' % obj_path build_bitcode(mode, parser, src_path, bc_path) # attach the bitcode path to the object file, ready to be linked attach_bitcode_path(obj_path, bc_path) # re-link to merge the llvm bitcode paths section if new_object_files: if parser.is_link: link_objects(mode, parser, new_object_files + parser.object_files, parser.output_file) else: log.warning('New object files but nothing to link') if parser.is_link and u'executable' in filetype(parser.output_file): bc_path = '%s.bc' % parser.output_file extract_bitcode(parser.output_file, bc_path) notify_binary_built(parser.output_file, bc_path) except IOError as error: # ./configure sometimes removes the file while we are still running if error.filename == parser.output_file: pass else: raise error ############################## # main for ikos-scan-extract # ############################## def extract_parse_arguments(argv): usage = '%(prog)s [options] file' description = 'Extract the llvm bitcode generated for a given file' formatter_class = argparse.RawTextHelpFormatter parser = argparse.ArgumentParser(usage=usage, description=description, formatter_class=formatter_class) # Positional arguments parser.add_argument('input', metavar='file', help='Input file') # Optional arguments parser.add_argument('-o', dest='output', metavar='', help='Output file') parser.add_argument('-v', dest='verbosity', help='Increase verbosity', action='count', default=1) parser.add_argument('-q', dest='verbosity', help='Be quiet', action='store_const', const=0) parser.add_argument('--version', action=args.VersionAction, nargs=0, help='Show ikos version') parser.add_argument('--color', dest='color', metavar='', help=args.help('Enable terminal colors:', args.color_choices, args.default_color), choices=args.choices(args.color_choices), default=args.default_color) parser.add_argument('--log', dest='log_level', metavar='', help=args.help('Log level:', args.log_levels, args.default_log_level), choices=args.choices(args.log_levels), default=None) opt = parser.parse_args(argv) # verbosity changes the log level, if --log is not specified if opt.log_level is None: if opt.verbosity <= 0: opt.log_level = 'error' elif opt.verbosity == 1: opt.log_level = 'info' elif opt.verbosity == 2: opt.log_level = 'debug' else: opt.log_level = 'all' return opt def extract_main(argv): # parse arguments opt = extract_parse_arguments(argv[1:]) # setup colors and logging colors.setup(opt.color, file=log.out) log.setup(opt.log_level) input_path = opt.input output_path = opt.output if opt.output else '%s.bc' % input_path extract_bitcode(input_path, output_path) ###################### # main for ikos-scan # ###################### def scan_parse_arguments(argv): usage = '%(prog)s [options] command' description = 'python helper to analyze whole C/C++ projects' formatter_class = argparse.RawTextHelpFormatter parser = argparse.ArgumentParser(usage=usage, description=description, formatter_class=formatter_class) # Positional arguments parser.add_argument('args', nargs=argparse.REMAINDER, help=argparse.SUPPRESS) # Optional arguments parser.add_argument('-v', dest='verbosity', help='Increase verbosity', action='count', default=1) parser.add_argument('-q', dest='verbosity', help='Be quiet', action='store_const', const=0) parser.add_argument('--version', action=args.VersionAction, nargs=0, help='Show ikos version') parser.add_argument('--color', dest='color', metavar='', help=args.help('Enable terminal colors:', args.color_choices, args.default_color), choices=args.choices(args.color_choices), default=args.default_color) parser.add_argument('--log', dest='log_level', metavar='', help=args.help('Log level:', args.log_levels, args.default_log_level), choices=args.choices(args.log_levels), default=None) opt = parser.parse_args(argv) # remove leading '--' while opt.args and opt.args[0] == '--': opt.args.pop(0) if not opt.args: parser.error("too few arguments") # verbosity changes the log level, if --log is not specified if opt.log_level is None: if opt.verbosity <= 0: opt.log_level = 'error' elif opt.verbosity == 1: opt.log_level = 'info' elif opt.verbosity == 2: opt.log_level = 'debug' else: opt.log_level = 'all' return opt def scan_main(argv): # parse arguments opt = scan_parse_arguments(argv[1:]) # setup colors and logging colors.setup(opt.color, file=log.out) log.setup(opt.log_level) # scan server server = ScanServer() server.daemon = True server.start() # setup environment variables os.environ['IKOS_SCAN_COLOR'] = 'yes' if colors.ENABLE else 'no' os.environ['IKOS_SCAN_LOG_LEVEL'] = opt.log_level os.environ['IKOS_SCAN_SERVER'] = 'http://localhost:%d' % server.port os.environ['PATH'] += os.path.pathsep + settings.BIN_DIR os.environ['CC'] = 'ikos-scan-cc' os.environ['CXX'] = 'ikos-scan-c++' os.environ['LD'] = 'ikos-scan-cc' # add -e to make commands, to avoid makefiles overriding CC/CXX/LD if os.path.basename(opt.args[0]) in ('make', 'gmake'): opt.args.insert(1, '-e') # run the build command rc = run(opt.args) # stop the scan server server.cancel() server.join() # skip binaries that have been removed binaries = [binary for binary in server.binaries if os.path.exists(binary['exe_path'])] if not binaries: printf('Nothing to analyze.\n') # analyze each binary for binary in binaries: exe_path = os.path.relpath(binary['exe_path']) bc_path = os.path.relpath(binary['bc_path']) printf('Analyze %s? [Y/n] ', colors.bold(exe_path)) answer = sys.stdin.readline().strip().lower() if answer in ('', 'y', 'yes'): cmd = ['ikos', bc_path, '-o', '%s.db' % exe_path] log.info('Running %s' % colors.bold(command_string(cmd))) cmd = [sys.executable, settings.ikos(), bc_path, '-o', '%s.db' % exe_path, '--color=%s' % opt.color, '--log=%s' % opt.log_level] run(cmd) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/settings.py.in000066400000000000000000000172701473507761200235570ustar00rootroot00000000000000############################################################################### # # Configuration file for ikos # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2017-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import os import os.path import sys PACKAGE_VERSION = '@PACKAGE_VERSION@' GIT_COUNT_COMMITS = '@GIT_COUNT_COMMITS@' GIT_HEAD_HASH = '@GIT_HEAD_HASH@' GIT_HEAD_DIRTY = @GIT_HEAD_DIRTY@ APPEND_GIT_VERSION = (GIT_COUNT_COMMITS and GIT_HEAD_HASH) VERSION = PACKAGE_VERSION if APPEND_GIT_VERSION: VERSION += '.r%s' % GIT_COUNT_COMMITS VERSION += '.%s' % GIT_HEAD_HASH if GIT_HEAD_DIRTY: VERSION += '~dirty' BUILD_MODE = '@CMAKE_BUILD_TYPE@' PREFIX = '@CMAKE_INSTALL_PREFIX@' SRC_ROOT = '@SRC_DIR@' BIN_DIR = os.path.join(PREFIX, 'bin') INCLUDE_DIR = os.path.join(PREFIX, 'include') LIB_DIR = os.path.join(PREFIX, 'lib') LLVM_CONFIG = '@LLVM_CONFIG_EXECUTABLE@' LLVM_VERSION = '@LLVM_VERSION@' LLVM_PREFIX = '@LLVM_ROOT@' LLVM_BIN_DIR = '@LLVM_TOOLS_BINARY_DIR@' LLVM_INCLUDE_DIR = '@LLVM_INCLUDE_DIR@' LLVM_LIB_DIR = '@LLVM_LIBRARY_DIR@' CLANG = '@CLANG_EXECUTABLE@' CLANGXX = '@CLANGXX_EXECUTABLE@' CLANG_VERSION = '@CLANG_VERSION@' HAS_APRON = @HAS_APRON@ #################### # Helper functions # #################### def is_executable(path): return path and os.path.isfile(path) and os.access(path, os.X_OK) def clang(): path = CLANG assert os.path.isabs(path) assert is_executable(path), 'could not find clang executable' return path def clangxx(): path = CLANGXX assert os.path.isabs(path) assert is_executable(path), 'could not find clang++ executable' return path def opt(): path = os.path.join(LLVM_BIN_DIR, 'opt@CMAKE_EXECUTABLE_SUFFIX@') assert os.path.isabs(path) assert is_executable(path), 'could not find opt executable' return path def llvm_link(): path = os.path.join(LLVM_BIN_DIR, 'llvm-link@CMAKE_EXECUTABLE_SUFFIX@') assert os.path.isabs(path) assert is_executable(path), 'could not find llvm-link executable' return path def llvm_objdump(): path = os.path.join(LLVM_BIN_DIR, 'llvm-objdump@CMAKE_EXECUTABLE_SUFFIX@') assert os.path.isabs(path) assert is_executable(path), 'could not find llvm-objdump executable' return path def llvm_objcopy(): path = os.path.join(LLVM_BIN_DIR, 'llvm-objcopy@CMAKE_EXECUTABLE_SUFFIX@') assert os.path.isabs(path) assert is_executable(path), 'could not find llvm-objcopy executable' return path def ikos_pp(): path = os.path.join(BIN_DIR, 'ikos-pp@CMAKE_EXECUTABLE_SUFFIX@') assert os.path.isabs(path) assert is_executable(path), 'could not find ikos-pp executable' return path def ikos_analyzer(): path = os.path.join(BIN_DIR, 'ikos-analyzer@CMAKE_EXECUTABLE_SUFFIX@') assert os.path.isabs(path) assert is_executable(path), 'could not find ikos-analyzer executable' return path def ikos(): path = os.path.join(BIN_DIR, 'ikos') assert os.path.isabs(path) assert is_executable(path), 'could not find ikos python script' return path ######################## # main for ikos-config # ######################## def main(argv): usage = '%(prog)s [options]' description = 'Get configuration information about ikos' parser = argparse.ArgumentParser(usage=usage, description=description) def print_action(var): class action(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): print(str(var)) return action parser.add_argument('--version', action=print_action(VERSION), nargs=0, help='Print ikos version') parser.add_argument('--build-mode', action=print_action(BUILD_MODE), nargs=0, help='Print build mode of ikos (e.g, Debug or Release)') parser.add_argument('--prefix', action=print_action(PREFIX), nargs=0, help='Print the installation prefix') parser.add_argument('--src-root', action=print_action(SRC_ROOT), nargs=0, help='Print the source root ikos was built from') parser.add_argument('--bindir', action=print_action(BIN_DIR), nargs=0, help='Directory containing ikos executables') parser.add_argument('--includedir', action=print_action(INCLUDE_DIR), nargs=0, help='Directory containing ikos headers') parser.add_argument('--libdir', action=print_action(LIB_DIR), nargs=0, help='Directory containing ikos libraries') parser.add_argument('--has-apron', action=print_action(HAS_APRON), nargs=0, help='Check if ikos was built with apron') parser.add_argument('--llvm-config', action=print_action(LLVM_CONFIG), nargs=0, help='Print the path to llvm-config') parser.add_argument('--llvm-version', action=print_action(LLVM_VERSION), nargs=0, help='Print LLVM version') parser.add_argument('--llvm-prefix', action=print_action(LLVM_PREFIX), nargs=0, help='Print the LLVM installation prefix') parser.add_argument('--llvm-bindir', action=print_action(LLVM_BIN_DIR), nargs=0, help='Directory containing LLVM executables') parser.add_argument('--llvm-includedir', action=print_action(LLVM_INCLUDE_DIR), nargs=0, help='Directory containing LLVM headers') parser.add_argument('--llvm-libdir', action=print_action(LLVM_LIB_DIR), nargs=0, help='Directory containing LLVM libraries') parser.add_argument('--clang', action=print_action(CLANG), nargs=0, help='Print the path to clang') parser.add_argument('--clang-version', action=print_action(CLANG_VERSION), nargs=0, help='Print clang version') parser.parse_args(argv[1:]) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/stats.py000066400000000000000000000107611473507761200224460ustar00rootroot00000000000000############################################################################### # # Simple statistics module # # Author: Jorge A. Navas # # Contributors: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import time # use monotonic clock if available if hasattr(time, 'monotonic'): _current_time = time.monotonic else: _current_time = time.time class Stopwatch: ''' A stop watch ''' def __init__(self): self._started = 0 self._finished = -1 self._elapsed = 0 self.start() @property def elapsed(self): ''' Returns time (in seconds) since the stopwatch has been started ''' if self._finished < self._started: return self._elapsed + (_current_time() - self._started) else: return self._elapsed + (self._finished - self._started) def start(self): ''' Starts or resumes the stopwatch ''' # collect elapsed time so far if self._finished >= self._started: self._elapsed += (self._finished - self._started) self._started = _current_time() self._finished = -1 def stop(self): ''' Stops the stopwatch ''' if self._finished < self._started: self._finished = _current_time() def reset(self): ''' Resets the stopwatch by erasing all elapsed time ''' self._elapsed = 0 self._finished = -1 self.start() def __str__(self): ''' Reports time in seconds up to three decimal places ''' return '{0:.3f}'.format(self.elapsed) _statistics = dict() def get(key): ''' Gets a value from statistics table ''' return _statistics.get(key) def put(key, v): ''' Puts a value in statistics table ''' _statistics[key] = v def start(key): ''' Starts (or resumes) a named stopwatch ''' sw = get(key) if sw is None: sw = Stopwatch() put(key, sw) return sw else: sw.start() def stop(key): ''' Stops a named stopwatch ''' sw = get(key) if sw is not None: sw.stop() def rows(): ''' Return all statistics as rows ''' return [(name, sw.elapsed) for name, sw in _statistics.items()] def timer(key): ''' ContextManager to help measuring time. with timer('myname') as t: do_code_that_is_timed ''' class TimerContextManager(object): def __init__(self, key): self._key = key def __enter__(self): start(self._key) return None def __exit__(self, exc_type, exc_value, traceback): stop(self._key) return False return TimerContextManager(key) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view.py000066400000000000000000000507451473507761200222700ustar00rootroot00000000000000############################################################################### # # IKOS web view # # Author: Thomas Bailleux # # Contributor: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import collections import html import io import json import operator import os import os.path import re import sqlite3 import sys import threading import webbrowser from ikos import args from ikos import colors from ikos import log from ikos import report from ikos import settings from ikos.enums import Result, CheckKind from ikos.highlight import CppLexer, HtmlFormatter, highlight from ikos.http import HTTPServerIPv6, BaseHTTPRequestHandler from ikos.log import printf from ikos.output_db import OutputDatabase # Path to web resources SHARE_DIR = os.path.join(settings.PREFIX, 'share', 'ikos', 'view') class TemplateEngine: ''' Simple template engine for formatting HTML page ''' _singleton = None @classmethod def get(cls): ''' Get the singleton instance of the template engine ''' if cls._singleton is None: cls._singleton = TemplateEngine() return cls._singleton def __init__(self): self._cache = {} def _read(self, fullpath): ''' Read a template from a file or cache ''' if fullpath in self._cache and settings.BUILD_MODE == 'Release': log.debug("Using '%s' from cache" % fullpath) return self._cache[fullpath] else: with io.open(fullpath, 'r', encoding='utf-8', errors='ignore') as f: data = f.read() self._cache[fullpath] = data return data def process(self, path, values={}): ''' Format an HTML page with a given template and a dictionary of values ''' # read the template file fullpath = os.path.join(SHARE_DIR, 'template', path) data = self._read(fullpath) # decode bytes as utf-8 for key in values: if isinstance(values[key], bytes): values[key] = values[key].decode('utf-8') # substitute {xxx} placeholders try: data = data.format(**values) except KeyError: pass return data class RequestHandler(BaseHTTPRequestHandler): ''' Handler for an HTTP request ''' _static_cache = {} def do_GET(self): ''' Handle a GET request ''' urls = [ (r'^/$', self._serve_homepage), (r'^/static/(?P[a-zA-Z_-]+/[a-zA-Z0-9_-]+\.[a-zA-Z_-]+)$', self._serve_static), (r'^/settings$', self._serve_settings), (r'^/report/(?P[0-9]+)(\?k=(?P[A-Z0-9]+))?$', self._serve_report) ] for pattern, f in urls: m = re.match(pattern, self.path) if m: f(**m.groupdict()) return self._serve_not_found() # Static files def _serve_static(self, path): ''' Serve a static file ''' fullpath = os.path.join(SHARE_DIR, 'static', path) if os.path.isfile(fullpath): self._send_static_headers(path) self._write_file(fullpath) else: self._serve_not_found() # Homepage def _serve_homepage(self): ''' Serve the homepage ''' self._write_template('homepage.html', { 'check_kinds': json.dumps(self._check_kinds()), 'check_kinds_filter': json.dumps(self._check_kinds_filter()), 'files': json.dumps(self._files()), }) def _check_kinds(self): ''' Generate the Javascript variable check_kinds ''' view_report = View.get().report return [{'id': kind, 'name': CheckKind.long_name(kind)} for kind in view_report.kinds] def _check_kinds_filter(self, param=None): ''' Generate the Javascript variable check_kinds_filter ''' view_report = View.get().report filter = {kind: True for kind in view_report.kinds} if not param: return filter param = [int(param[i:i + 2], 16) for i in range(0, len(param), 2)] for kind in view_report.kinds: try: filter[kind] = (param[kind // 8] & (1 << (kind % 8))) != 0 except IndexError: pass return filter def _files(self): ''' Generate the Javascript variable files ''' view_report = View.get().report files = [] for file in view_report.files: files.append({ 'id': file.id, 'path': report.format_path(file.path), 'status_kinds': view_report.files_status_kinds[file.id] }) # Sort by path files.sort(key=operator.itemgetter('path')) return files # Settings def _serve_settings(self): ''' Serve the settings page ''' db = View.get().db settings = db.load_settings() s = [] for name, value in settings.items(): if isinstance(value, list): s.append('%s%s' % (html.escape(name), html.escape(json.dumps(value)))) else: s.append('%s%s' % (html.escape(name), html.escape(str(value)))) self._write_template('settings.html', {'settings': '\n\t'.join(s)}) # File report def _serve_report(self, id, kinds_filter): ''' Serve a specific report for a file ''' id = int(id) view_report = View.get().report try: file = view_report.files[id] except IndexError: self._serve_not_found() return try: with io.open(file.path, 'r', encoding='utf-8', errors='ignore') as f: code = f.read() except (OSError, IOError): self._serve_error("No such file: %s" % file.path) return fmt = Formatter(file) lexer = CppLexer(stripnl=False) code = highlight(code, lexer, fmt) check_kinds_filter = self._check_kinds_filter(param=kinds_filter) self._write_template('report.html', { 'filepath': html.escape(report.format_path(file.path)), 'check_kinds': json.dumps(self._check_kinds()), 'check_kinds_filter': json.dumps(check_kinds_filter), 'code': code, 'functions': json.dumps(fmt.functions), 'call_contexts': json.dumps(fmt.call_contexts), 'checks': json.dumps(fmt.checks), 'pygments_css': fmt.get_style_defs('.highlight') }) # Helpers def _send_static_headers(self, path): ''' Send header for a static file ''' self.send_response(200) mimetype = 'text/plain' if path.endswith('.css'): mimetype = 'text/css' elif path.endswith('.js'): mimetype = 'application/javascript' elif path.endswith('.jpg'): mimetype = 'image/jpg' elif path.endswith('.png'): mimetype = 'image/png' self.send_header('Content-Type', '%s; charset=UTF-8' % mimetype) self.end_headers() def _write_file(self, fullpath): ''' Write a static file to the response stream ''' if fullpath in RequestHandler._static_cache \ and settings.BUILD_MODE == 'Release': self.wfile.write(RequestHandler._static_cache[fullpath]) log.debug("Using '%s' from cache" % fullpath) else: with open(fullpath, 'rb') as f: data = f.read() self.wfile.write(data) RequestHandler._static_cache[fullpath] = data def _write_template(self, path, values={}, status=200): ''' Write a template to the response stream ''' engine = TemplateEngine.get() self.send_response(status) self.send_header('Content-Type', 'text/html; charset=UTF-8') self.end_headers() self.wfile.write(engine.process(path, values).encode('utf8')) def _serve_not_found(self): ''' Server a 404 Not Found page ''' self._write_template('not_found.html', {'path': html.escape(self.path)}, status=404) def _serve_error(self, message): ''' Server a 500 Internal Error page ''' self._write_template('error.html', {'message': html.escape(message)}, status=500) class View: ''' Class for IKOS view (ikos-view) ''' _singleton = None @classmethod def get(cls): ''' Get the singleton instance of view ''' assert cls._singleton is not None return cls._singleton def __init__(self, db, port=8080): View._singleton = self self.db = db self.port = port self.report = ViewReport(self.db) try: self.httpd = HTTPServerIPv6(('', self.port), RequestHandler) except (OSError, IOError) as e: log.error("Could not start the HTTP server: %s" % e) sys.exit(1) def serve(self): log.info("Pre-processing...") self.report.pre_process() log.info("Starting ikos-view at http://localhost:%d" % self.port) log.warning("Use Ctrl-C to exit") self.httpd.serve_forever() StatusKinds = collections.namedtuple('StatusKinds', ['ok', 'warning', 'error', 'unreachable']) class ViewReport: ''' IKOS view report ''' def __init__(self, db): self.db = db self._report = None self.kinds = None self.files = None # Map[file.id, Map[check.status, Map[check.kind, count]]] self.files_status_kinds = None # Map[file.id, Map[check.line, List[Check]]] self.files_lines_reports = None def pre_process(self): ''' Pre processing some values ''' # List of CheckKind c = self.db.con.cursor() rows = c.execute("SELECT DISTINCT kind FROM checks ORDER BY kind") self.kinds = [row[0] for row in rows] # Generate report self._report = report.generate_report(self.db) self.files = self.db.files self.files_status_kinds = {} self.files_lines_reports = {} for file in self.files: self.files_status_kinds[file.id] = StatusKinds(ok={}, warning={}, error={}, unreachable={}) self.files_lines_reports[file.id] = {} for statement_report in self._report.statement_reports: stmt = statement_report.statement() file = stmt.file() if file is None: continue # Ignore checks without a file kind = statement_report.kind status = statement_report.status # Update self.files_status_kinds kinds = self.files_status_kinds[file.id][status] if kind not in kinds: kinds[kind] = 0 kinds[kind] += 1 # Update self.files_lines_reports lines_reports = self.files_lines_reports[file.id] if stmt.line not in lines_reports: lines_reports[stmt.line] = [] lines_reports[stmt.line].append(statement_report) class Formatter(HtmlFormatter): ''' Source code HTML formatter ''' def __init__(self, file): super(Formatter, self).__init__() self.file = file self.functions = {} self.call_contexts = {} self.checks = {} def wrap(self, source): return self._wrap_code(source) def _wrap_code(self, source): view_report = View.get().report lines_reports = view_report.files_lines_reports[self.file.id] yield 0, '' def _line_status(self, statement_reports): ''' Return the status of a source line ''' if not statement_reports: return -1 status = [0, 0, 0, 0] for statement_report in statement_reports: status[statement_report.status] += 1 if status[Result.ERROR] > 0: return Result.ERROR elif status[Result.WARNING] > 0: return Result.WARNING elif status[Result.UNREACHABLE] > 0: return Result.UNREACHABLE else: return Result.OK def _build_checks(self, statement_reports): ''' Return the list of check for a source line ''' checks = [] for statement_report in statement_reports: statement = statement_report.statement() checks.append({ 'kind': statement_report.kind, 'status': statement_report.status, 'column': statement.column_or('?'), 'message': report.generate_message(statement_report, 4), 'function_id': statement.function_id, 'call_context_ids': statement_report.call_context_ids, }) self._build_function(statement.function()) self._build_call_contexts(statement_report.call_contexts()) # Sort by status (error > warning > ok) checks.sort(key=operator.itemgetter('status'), reverse=True) return checks def _build_function(self, function): if function.id in self.functions: return self.functions[function.id] = function.pretty_name() def _build_call_contexts(self, call_contexts): for call_context in call_contexts: self._build_call_context(call_context) def _build_call_context(self, call_context): call_context_id = call_context.id if call_context_id in self.call_contexts: return lines = [] while not call_context.empty(): call_statement = call_context.call() function = call_context.function() line = "%s:%s:%s: function '%s'" % ( report.format_path(call_statement.file_path()) or '?', call_statement.line_or('?'), call_statement.column_or('?'), function.pretty_name() ) lines.append(line) call_context = call_context.parent() self.call_contexts[call_context_id] = '\n'.join(lines) ########################## # command line interface # ########################## def parse_arguments(argv): usage = '%(prog)s [options] file.db' description = 'Launch ikos view on an output database' formatter_class = argparse.RawTextHelpFormatter parser = argparse.ArgumentParser(usage=usage, description=description, formatter_class=formatter_class) # Positional arguments parser.add_argument('file', metavar='file.db', help='Result database') # Optional arguments parser.add_argument('--version', action=args.VersionAction, nargs=0, help='Show ikos version') parser.add_argument('--color', dest='color', metavar='', help=args.help('Enable terminal colors:', args.color_choices, args.default_color), choices=args.choices(args.color_choices), default=args.default_color) parser.add_argument('--log', dest='log_level', metavar='', help=args.help('Log level:', args.log_levels, args.default_log_level), choices=args.choices(args.log_levels), default='info') parser.add_argument('--port', dest='port', metavar='', help='Listening port', default=8080, type=int) return parser.parse_args(argv) def open_browser(url): browser = webbrowser.get() if browser.name in ('links', 'elinks', 'lynx', 'w3m'): return log.debug('Launching browser') browser.open_new_tab(url) ###################### # main for ikos-view # ###################### def main(argv): progname = os.path.basename(argv[0]) # parse arguments opt = parse_arguments(argv[1:]) # setup colors and logging colors.setup(opt.color, file=log.out) log.setup(opt.log_level) if not os.path.isfile(opt.file): printf("%s: error: no such file: \'%s\'\n", progname, opt.file, file=sys.stderr) sys.exit(1) try: # open result database db = OutputDatabase(opt.file) v = View(db, port=opt.port) browser_timer = threading.Timer(0.1, open_browser, ['http://localhost:%d/' % opt.port]) browser_timer.start() v.serve() # close database db.close() except sqlite3.DatabaseError as e: printf('%s: error: %s\n', progname, e, file=sys.stderr) sys.exit(1) NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/000077500000000000000000000000001473507761200217035ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/static/000077500000000000000000000000001473507761200231725ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/static/css/000077500000000000000000000000001473507761200237625ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/static/css/ikos_theme.css000066400000000000000000000135251473507761200266310ustar00rootroot00000000000000/**************** * Global style * ****************/ html, body { background-color: #F7F7F7; display: flex; flex-direction: column; flex: 1; height: 100%; } body { max-height: 100%; margin: 0; padding: .8em; overflow: auto; } header { background-color: #FFF; border: 1px solid #E7E7E7; display: flex; flex-direction: row; align-items: center; } header > h3 { padding: 0 1em; } header > h3 > a { color: #8B8BFF; text-decoration: none; } header > nav { flex: 1; display: flex; flex-direction: row; align-items: center; justify-content: flex-end; padding: 1em; } header > nav > a { padding: 0 .5em; color: #8B8BFF; text-decoration: none; border-bottom: 3px solid transparent; } header > nav > a.active { border-bottom-color: #A7A7A7; } #page_container { display: flex; flex: 1; margin: 1em 0 0 0; overflow-y: auto; } #page_sidebar { margin-right: 1em; display: flex; flex-direction: column; } .sidebar_item { background: #FFF; border: 1px solid #E7E7E7; overflow-y: auto; margin: 0 0 0.2em 0; padding: .5em; } .sidebar_item h5 { text-align: center; margin: 0; } .sidebar_item ul { padding-left: 0; } .sidebar_item li { list-style-type: none; font-size: .8em; } .page_content { flex: 1; overflow-x: auto; } /***************** * Settings page * *****************/ #settings { background-color: #FFF; margin: auto; border-collapse: collapse; border: 1px solid #999; overflow-y: auto !important; max-height: 100%; } #settings tr { border-top: 1px solid #999; } #settings > thead > tr { background-color: #E7E7E7; border: 1px solid #999; } #settings td { padding: 0.1em 0.2em; } /************ * Homepage * ************/ #table_files { width: 100%; flex: 1; background-color: #FFF; border: 1px solid #E7E7E7; padding-top: 0.2em; } #table_files td { border-top: 1px solid #E7E7E7; padding: 0.5em 0.2em 0.2em 0.2em; } #table_files td:nth-of-type(1) { font-size: 1em; font-family: monospace; } .stats { display: flex; text-align: center; } .stats span { flex: 1; align-items: center; justify-content: center; text-align: center; } .text_ok { color: #00FF45; font-weight: bold; } .text_warning { color: #9AA21A; font-weight: bold; } .text_error { color: #FF2741; font-weight: bold; } .text_deadcode { color: #903989; font-weight: bold; } .file_link { text-decoration: none; padding-left: 1em; color: #5F5E5E; } .file_link:visited { color: #5F5E5E; } .file_link:hover { color: #000; } /********** * Report * **********/ #page_content_report { background: #FFF; border: 1px solid #E7E7E7; padding: 0.2em 0; } .highlight { background: #FFF !important; } .line_number { color: rgba(27, 31, 35, 0.3); padding: 0em 1em 0em .5em; text-align: right; width: 2em; display: flex; justify-content: flex-end; } .line_number a { color: rgba(27, 31, 35, 0.3); text-align: right; text-decoration: none; font-size: .7em; } .line_number a:hover { color: rgba(27, 31, 35, 0.6); } .line_wrap { display: flex; justify-content: center; align-items: flex-start; } .line_highlight { background-color: rgb(169, 215, 256) !important; } .line_code_wrap { display: flex; } .line_code { flex: 1; } .line_checks { display: flex; flex-direction: column; flex: 1; overflow-x: auto; } .line_content { display: flex; flex-direction: column; flex: 1; overflow-x: hidden; } .checks { border: 1px solid #E1E4E8; margin: 1em 1.3em; border-radius: 3px; padding: .7em; } .line_wrap.status_0 { background-color: #E6FFED; } .line_wrap.status_3 { background-color: #BF90BB; } .line_wrap.status_1 { background-color: #FAFFA8; } .line_wrap.status_2 { background-color: #FFEEF0; } .line_wrap.status_0 .checks { background-color: #BEFDCF; } .line_wrap.status_1 .checks { background-color: #F6FF68; } .line_wrap.status_2 .checks { background-color: #FB96A2; } .line_wrap.status_3 .checks { background-color: #903989; } .highlight pre { white-space: pre-wrap; /* Since CSS 2.1 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ margin: 0; } .hidden, .always_hidden, .kind_hidden, .status_hidden { display: none !important; } .check.status_0:before { content: "☑"; margin-right: .5em; } .check.status_1:before { content: "⚠"; margin-right: .5em; } .check.status_2:before { content: "⛔"; margin-right: .5em; } .check.status_3:before { content: "☢"; margin-right: .5em; } .checks_toggle a { color: rgba(27, 31, 35, 0.3); text-decoration: none; padding: 0em .3em; display: block; font-size: 12px; } .checks_toggle a:hover { color: rgba(27, 31, 35, 0.6); } .navigator-container h6 { margin: .5em .3em; padding: 0; } .navigator-container button { font-size: .7em; } .checks > span { display: flex; align-items: center; } .call_contexts { display: none; } .checks pre { flex: 1; } .call_contexts_toggle { color: #999; text-decoration: none; } .call_contexts_toggle:hover { color: #555; } #modal { position: fixed; top: 0; left: 0; margin: 0; display: flex; flex: 1; width: 100%; height: 100%; align-items: center; justify-content: center; background-color: rgba(0, 0, 0, .7); } #modal_body { background: #FFF; padding: 1em; border-radius: 3px; z-index: 5; min-width: 5em; } #modal_body h5 { margin: 0; flex: 1; } #modal_body pre { background-color: #E7E7E7; border: 1px solid #D7D7D7; border-radius: 3px; padding: .2em; } #modal_header { display: flex; align-items: center; } .modal_close { color: #222; text-decoration: none; } #modal_header .modal_close:nth-of-type(1) { font-size: 2em; margin-left: 3em; } NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/static/js/000077500000000000000000000000001473507761200236065ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/static/js/ikos_homepage.js000066400000000000000000000071441473507761200267640ustar00rootroot00000000000000/** Initialize the list of check kinds * * param e - event */ function init_check_kinds_list(e) { var list = document.getElementById('check_kinds_list'); for (var i = 0; i < window.check_kinds.length; i++) { var check_kind = window.check_kinds[i]; var button = document.createElement('input'); button.type = 'checkbox'; button.checked = window.check_kinds_filter[check_kind.id]; button.value = check_kind.id; button.addEventListener('change', function(e) { update_check_kinds_list_value(e); }); var label = document.createElement('label') label.appendChild(button); label.appendChild(document.createTextNode(check_kind.name)); var li = document.createElement('li'); li.appendChild(label); list.appendChild(li); } } /** Callback function called when the user clicks on a check kinds checkbox * * param e - event */ function update_check_kinds_list_value(e) { window.check_kinds_filter[e.target.value] = e.target.checked; init_files_list(); } /** Get the URL parameter for the check kinds filter */ function check_kinds_filter_parameter() { // Find the maximum kind var max_kind = Object.keys(window.check_kinds_filter).reduce(function(a, b) { return Math.max(a, b); }); // Build a byte array var array = new Uint8Array(Math.floor(max_kind / 8) + 1); for (var kind in window.check_kinds_filter) { if (window.check_kinds_filter[kind] === true) { array[Math.floor(kind / 8)] |= 1 << (kind % 8); } } // Convert to hexadecimal return Array.from(array, function(byte) { return ('0' + byte.toString(16)).slice(-2).toUpperCase(); }).join(''); } /** Initialize the list of files * * param e - event */ function init_files_list(e) { var check_kinds_filter_param = check_kinds_filter_parameter(); var table = document.getElementById('table_files_tbody'); table.innerHTML = ''; for (var i = 0; i < window.files.length; i++) { var file = window.files[i]; var a = document.createElement('a'); a.className = 'file_link'; a.href = '/report/' + file.id + '?k=' + check_kinds_filter_param; a.appendChild(document.createTextNode(file.path)); var td_name = document.createElement('td'); td_name.appendChild(a); var stats_span = document.createElement('span'); stats_span.className = 'stats'; var oks = this.count_checks(file.status_kinds[0]); var warnings = this.count_checks(file.status_kinds[1]); var errors = this.count_checks(file.status_kinds[2]); var unreachables = this.count_checks(file.status_kinds[3]); if (warnings === 0 && errors === 0 && unreachables == 0) { stats_span.innerHTML = 'Safe'; } else { stats_span.innerHTML = '' + oks + '' + '' + unreachables + '' + '' + warnings + '' + '' + errors + ''; } var td_stats = document.createElement('td'); td_stats.appendChild(stats_span); var tr = document.createElement('tr'); tr.appendChild(td_name); tr.appendChild(td_stats); table.appendChild(tr); } } /** Count the number of checks given the map from kind to count * * param kinds - the map from kind to count */ function count_checks(kinds) { var value = 0; for (var kind in kinds) { if (window.check_kinds_filter[kind] === true) { value += kinds[kind]; } } return value; } /** load event */ window.addEventListener('load', init_check_kinds_list); window.addEventListener('load', init_files_list); NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/static/js/ikos_report.js000066400000000000000000000274501473507761200265140ustar00rootroot00000000000000/** Init the list of checks * * param e - event */ function init_checks(e) { for (var line_num in window.checks) { var checks = window.checks[line_num]; var line_wrap = document.getElementById('L' + line_num); // Init checks box var checks_box = line_wrap.getElementsByClassName('checks')[0]; for (var i = 0; i < checks.length; i++) { var check_line = create_check_line(line_num, checks[i]); checks_box.appendChild(check_line); } checks_box.classList.remove('hidden') // Init toggle button var toggle = line_wrap.getElementsByClassName('toggle')[0]; toggle.addEventListener('click', toggle_checks); toggle.parentNode.classList.remove('hidden'); } } /** Create a check line * * param line_num - line number * param check - the check */ function create_check_line(line_num, check) { var check_line = window.template_check.cloneNode(true); // Attach check information check_line._line_num = line_num; check_line._check = check; // Update id and class check_line.id = ''; check_line.className = [ 'check', 'kind_' + check.kind, 'status_' + check.status ].join(' '); // Add message var message = check_line.getElementsByClassName('message')[0]; var header = line_num + ':' + check.column + ': '; var bold = document.createElement('b'); bold.appendChild(document.createTextNode(header)); message.appendChild(bold); var text = check.message; text = text.replace(/\n/g, "\n" + " ".repeat(header.length) + "\t"); text = text.replace(/\t/g, " "); message.appendChild(document.createTextNode(text)); var call_contexts_toggle = check_line.getElementsByClassName('call_contexts_toggle')[0]; call_contexts_toggle.addEventListener('click', toggle_call_contexts_modal); return check_line; } /** Initialize the list of check kinds * * param e - event */ function init_check_kinds_list(e) { var list = document.getElementById('check_kinds_list'); for (var i = 0; i < window.check_kinds.length; i++) { var check_kind = window.check_kinds[i]; var button = document.createElement('input'); button.type = 'checkbox'; button.checked = window.check_kinds_filter[check_kind.id] button.value = check_kind.id; button.addEventListener('change', function(e) { filter_by_check_kind(e); }); var label = document.createElement('label') label.appendChild(button); label.appendChild(document.createTextNode(check_kind.name)); var li = document.createElement('li'); li.appendChild(label); list.appendChild(li); if (!button.checked) { filter_by_check_kind({target: button}); // Initial filter } } } /** Initialize the status checkbox (Ok, Warning, Error, Dead Code) * * param e - event */ function init_status_checkbox(e) { var checkboxs = document.getElementsByClassName("checkbox_status"); for (var i = 0; i < checkboxs.length; i++) { var checkbox = checkboxs[i]; checkbox.addEventListener('change', filter_by_status); if (!checkbox.checked) { filter_by_status({target: checkbox}); // Initial filter } } } /** Callback function called when the user clicks on a check kinds checkbox * * param e - event */ function filter_by_check_kind(e) { var checked = e.target.checked; var kind = e.target.value; // Show/hide check lines var check_lines = document.getElementsByClassName("check kind_" + kind); var updated_lines = []; for (var i = 0; i < check_lines.length; i++) { var check_line = check_lines[i]; if (checked) { check_line.classList.remove('kind_hidden'); } else { check_line.classList.add('kind_hidden'); } updated_lines.push(check_line._line_num); } // Show/Hide checks boxes update_checks_boxes(updated_lines); // Update filter window.check_kinds_filter[kind] = checked; } /** Callback function called when the use clicks on a status checkbox * * param e - event */ function filter_by_status(e) { var checked = e.target.checked; var status = e.target.value; // Show/hide check lines var check_lines = document.getElementsByClassName('check status_' + status); var updated_lines = []; for (var i = 0; i < check_lines.length; i++) { var check_line = check_lines[i]; if (checked) { check_line.classList.remove('status_hidden'); } else { check_line.classList.add('status_hidden'); } updated_lines.push(check_line._line_num); } // Show/Hide checks boxes update_checks_boxes(updated_lines); } /** Update the 'checks' boxes: display or hide them if every checks inside are * hidden, or not. * * param line_numbers - list of line numbers to update */ function update_checks_boxes(line_numbers) { // Remove duplicates line_numbers = line_numbers.filter(function(item, index, array) { return array.indexOf(item) === index; }); for (var i = 0; i < line_numbers.length; i++) { var line_num = line_numbers[i]; var line_wrap = document.getElementById('L' + line_num); var checks_box = line_wrap.getElementsByClassName('checks')[0]; var hidden_checks = checks_box.getElementsByClassName('status_hidden').length + checks_box.getElementsByClassName('kind_hidden').length - checks_box.getElementsByClassName('status_hidden kind_hidden').length; if (hidden_checks === checks_box.childElementCount) { // No checks in the checks box, hide it checks_box.classList.add('hidden'); } else { // At least one check, show it checks_box.classList.remove('hidden'); } } } /** Callback function called when the user toggles the checks for a line * * param e - event */ function toggle_checks(e) { var checks_box = e.target.parentNode.parentNode.nextElementSibling; if (checks_box.classList.contains('hidden')) { // Show the checks box checks_box.classList.remove('hidden'); // Show all the check lines var check_lines = checks_box.getElementsByClassName("check"); for (var i = 0; i < check_lines.length; i++) { var check_line = check_lines[i]; check_line.classList.remove('kind_hidden'); check_line.classList.remove('status_hidden'); } } else { // Hide the checks box checks_box.classList.add('hidden'); } } var navigators = { error: { lines: [], current: -1 }, warning: { lines: [], current: -1 }, deadcode: { lines: [], current: -1 }, container: null } /** Initialize the navigator * * param e - event */ function init_navigators(e) { window.navigators.error.lines = document.getElementsByClassName('line_wrap status_2'); window.navigators.warning.lines = document.getElementsByClassName('line_wrap status_1'); window.navigators.deadcode.lines = document.getElementsByClassName('line_wrap status_3'); window.navigators.container = document.getElementById('page_content_report'); // errors document.getElementById('nav_error_prev') .addEventListener('click', function(e) { move_navigator(e, 'error', -1); }); document.getElementById('nav_error_next') .addEventListener('click', function(e) { move_navigator(e, 'error', 1); }); if (window.navigators.error.lines.length == 0) { document.getElementById('navigator-error').classList.add('hidden'); } // warnings document.getElementById('nav_warning_prev') .addEventListener('click', function(e) { move_navigator(e, 'warning', -1); }); document.getElementById('nav_warning_next') .addEventListener('click', function(e) { move_navigator(e, 'warning', 1); }); if (window.navigators.warning.lines.length == 0) { document.getElementById('navigator-warning').classList.add('hidden'); } // deadcodes document.getElementById('nav_deadcode_prev') .addEventListener('click', function(e) { move_navigator(e, 'deadcode', -1); }); document.getElementById('nav_deadcode_next') .addEventListener('click', function(e) { move_navigator(e, 'deadcode', 1); }); if (window.navigators.deadcode.lines.length == 0) { document.getElementById('navigator-deadcode').classList.add('hidden'); } // reset button document.getElementById('nav_reset') .addEventListener('click', reset_navigator); // update labels of buttons update_navigator_buttons('error'); update_navigator_buttons('warning'); update_navigator_buttons('deadcode'); } /** Update navigator buttons * * param status - error or warning */ function update_navigator_buttons(status) { var current = window.navigators[status].current; var lines = window.navigators[status].lines; var prev = document.getElementById('nav_' + status + '_prev'); if (current <= 0) { prev.disabled = true; prev.innerHTML = '←'; } else { prev.disabled = false; prev.innerHTML = '← (' + lines[current - 1].id + ')'; } var next = document.getElementById('nav_' + status + '_next'); if (current >= lines.length - 1) { next.disabled = true; next.innerHTML = '→'; } else { next.disabled = false; next.innerHTML = '→ (' + lines[current + 1].id + ')'; } } /** Callback function called when the user clicks on a navigator button * * param e - event * param status - kind of navigator (warning or error) * direction - 1 for next, -1 for previous */ function move_navigator(e, status, direction) { var navigator = window.navigators[status]; var container = window.navigators.container; navigator.current += direction; var line = navigator.lines[navigator.current]; // Move to the line position container.scrollTop = line.offsetTop - container.offsetTop; // Add a highlight effect line.classList.add('line_highlight'); setTimeout(function() { line.classList.remove('line_highlight'); }, 100); update_navigator_buttons(status); } /** Reset the navigator buttons * * param e - event */ function reset_navigator(e) { window.navigators.error.current = -1; window.navigators.warning.current = -1; window.navigators.deadcode.current = -1; update_navigator_buttons('error'); update_navigator_buttons('warning'); update_navigator_buttons('deadcode'); } /** Initialize the event for the call_contexts modal * * param e - event */ function init_call_contexts_modals(e) { var modal = document.getElementById('modal'); modal.addEventListener('click', close_modal); var close = modal.getElementsByClassName('modal_close'); for (var i = 0; i < close.length; i++) { close[i].addEventListener('click', close_modal); } } /** Callback function called when the user click on the call contexts toggle * * param e - event */ function toggle_call_contexts_modal(e) { var check = e.target.parentNode._check; var message = ''; var function_name = window.functions[check.function_id]; var call_context_ids = check.call_context_ids; for (var i = 0; i < call_context_ids.length; i++) { var call_context_id = call_context_ids[i]; var call_context = window.call_contexts[call_context_id]; if (i > 0) { message += '\n'; } if (call_context === '') { message += 'Called from entry point \'' + function_name + '\'\n'; } else { message += 'Called from:\n' + call_context + '\n'; } } display_modal(message); } /** Display the modal window * * param content - the content of the modal window */ function display_modal(content) { var modal = document.getElementById('modal'); var modal_content = document.getElementById('modal_call_context_content'); modal_content.textContent = content; modal.classList.remove('hidden'); } /** Close the modal */ function close_modal(e) { if (e.target.id !== 'modal' && e.target.className !== 'modal_close') { return; } var modal = document.getElementById('modal'); modal.classList.add('hidden'); } //** load events */ window.addEventListener('load', init_checks); window.addEventListener('load', init_check_kinds_list); window.addEventListener('load', init_status_checkbox); window.addEventListener('load', init_navigators); window.addEventListener('load', init_call_contexts_modals); NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/template/000077500000000000000000000000001473507761200235165ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/template/error.html000066400000000000000000000012021473507761200255300ustar00rootroot00000000000000 500 Internal Error

IKOS-VIEW

Internal Error - 500

{message}

NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/template/homepage.html000066400000000000000000000030341473507761200261710ustar00rootroot00000000000000 IKOS-VIEW

IKOS-VIEW

File path Ok Dead Codes Warnings Errors
NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/template/not_found.html000066400000000000000000000012611473507761200263770ustar00rootroot00000000000000 404 Not Found

IKOS-VIEW

File Not Found - 404

The requested URL {path} was not found on this server.

NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/template/report.html000066400000000000000000000071401473507761200257210ustar00rootroot00000000000000 IKOS-VIEW / {filepath}

IKOS-VIEW > {filepath}

{code}
NASA-SW-VnV-ikos-1d98c65/analyzer/python/ikos/view/template/settings.html000066400000000000000000000014761473507761200262540ustar00rootroot00000000000000 IKOS-VIEW / Settings

IKOS-VIEW > Settings

{settings}
Name Value
NASA-SW-VnV-ikos-1d98c65/analyzer/python/settings.cmake.in000066400000000000000000000076601473507761200232440ustar00rootroot00000000000000################################################################################ # # cmake script to generate settings/__init__.py # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2017-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR) set(SRC_DIR "@CMAKE_CURRENT_SOURCE_DIR@") set(BIN_DIR "@CMAKE_CURRENT_BINARY_DIR@") set(PACKAGE_VERSION "@PACKAGE_VERSION@") set(CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") set(CMAKE_BUILD_TYPE "@CMAKE_BUILD_TYPE@") set(CMAKE_EXECUTABLE_SUFFIX "@CMAKE_EXECUTABLE_SUFFIX@") set(LLVM_CONFIG_EXECUTABLE "@LLVM_CONFIG_EXECUTABLE@") set(LLVM_VERSION "@LLVM_VERSION@") set(LLVM_ROOT "@LLVM_ROOT@") set(LLVM_INCLUDE_DIR "@LLVM_INCLUDE_DIR@") set(LLVM_TOOLS_BINARY_DIR "@LLVM_TOOLS_BINARY_DIR@") set(LLVM_LIBRARY_DIR "@LLVM_LIBRARY_DIR@") set(CLANG_EXECUTABLE "@CLANG_EXECUTABLE@") set(CLANGXX_EXECUTABLE "@CLANGXX_EXECUTABLE@") set(CLANG_VERSION "@CLANG_VERSION@") if (@APRON_FOUND@) set(HAS_APRON "True") else() set(HAS_APRON "False") endif() if (@APPEND_GIT_VERSION@) # number of commits in the current branch execute_process( COMMAND git rev-list --count HEAD WORKING_DIRECTORY "${SRC_DIR}" OUTPUT_VARIABLE GIT_COUNT_COMMITS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) # hash of the latest commit execute_process( COMMAND git rev-parse --short HEAD WORKING_DIRECTORY "${SRC_DIR}" OUTPUT_VARIABLE GIT_HEAD_HASH ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) # git status execute_process( COMMAND git status --porcelain WORKING_DIRECTORY "${SRC_DIR}" OUTPUT_VARIABLE GIT_HEAD_STATUS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_HEAD_STATUS STREQUAL "") set(GIT_HEAD_DIRTY "False") else() set(GIT_HEAD_DIRTY "True") endif() else() set(GIT_COUNT_COMMITS "") set(GIT_HEAD_HASH "") set(GIT_HEAD_DIRTY "False") endif() # remove to force update file(REMOVE "${BIN_DIR}/python/ikos/settings/__init__.py") # run configure configure_file("${SRC_DIR}/python/ikos/settings.py.in" "${BIN_DIR}/python/ikos/settings/__init__.py" @ONLY) NASA-SW-VnV-ikos-1d98c65/analyzer/python/setup.py.in000066400000000000000000000050261473507761200221060ustar00rootroot00000000000000################################################################################ # # setup.py called automatically by cmake. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2017-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ from setuptools import setup setup(name='ikos', version='@PACKAGE_VERSION@', description='A static analyzer for C/C++ programs', author='NASA', author_email='ikos@lists.nasa.gov', url='https://github.com/NASA-SW-VnV/ikos', license='NOSA 1.3', package_dir={'ikos': '@CMAKE_CURRENT_SOURCE_DIR@/python/ikos', 'ikos.settings': '@CMAKE_CURRENT_BINARY_DIR@/python/ikos/settings'}, packages=['ikos', 'ikos.settings']) NASA-SW-VnV-ikos-1d98c65/analyzer/script/000077500000000000000000000000001473507761200177475ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos-config.py.in000077500000000000000000000046701473507761200231500ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos-config: get configuration information # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2017-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.settings except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.settings.main(sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos-report.py.in000077500000000000000000000047111473507761200232120ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos-report: generate an analysis report from a result database # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.report except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.report.main(sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos-scan-c++.py.in000077500000000000000000000047101473507761200231700ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos-scan-c++: wrapper around clang++ for ikos-scan # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.scan except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.scan.compile_main('c++', sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos-scan-cc.py.in000077500000000000000000000047041473507761200232100ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos-scan-cc: wrapper around clang for ikos-scan # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.scan except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.scan.compile_main('cc', sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos-scan-extract.py.in000077500000000000000000000047241473507761200242770ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos-scan-extract: extract the llvm bitcode generated for a given file # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2019-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.scan except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.scan.extract_main(sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos-scan.py.in000077500000000000000000000046651473507761200226330ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos-scan: tool to analyze a whole project # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.scan except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.scan.scan_main(sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos-view.py.in000077500000000000000000000046711473507761200226560ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos-view: web server to display an analysis report # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.view except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.view.main(sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/script/ikos.py.in000077500000000000000000000046661473507761200217120ustar00rootroot00000000000000#!@PYTHON_VENV_EXECUTABLE@ ############################################################################### # # ikos: static analyzer for C/C++ programs # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import os.path import sys if __name__ == '__main__': try: import ikos.analyzer except ImportError: sys.stderr.write('error: could not find ikos python module\n') sys.stderr.write('error: see TROUBLESHOOTING.md\n') sys.exit(1) try: ikos.analyzer.main(sys.argv) except KeyboardInterrupt: pass NASA-SW-VnV-ikos-1d98c65/analyzer/src/000077500000000000000000000000001473507761200172325ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/000077500000000000000000000000001473507761200210555ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/call_context.cpp000066400000000000000000000061241473507761200242430ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief CallContext and CallContextFactory implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { CallContextFactory::CallContextFactory() : _empty_call_context(new CallContext()) {} CallContextFactory::~CallContextFactory() = default; CallContext* CallContextFactory::get_context(CallContext* parent, ar::CallBase* call) { ikos_assert(parent != nullptr && call != nullptr); { boost::shared_lock< boost::shared_mutex > lock(this->_mutex); auto it = this->_map.find({parent, call}); if (it != this->_map.end()) { return it->second.get(); } } auto call_context = std::unique_ptr< CallContext >(new CallContext(parent, call)); { boost::unique_lock< boost::shared_mutex > lock(this->_mutex); auto res = this->_map.try_emplace({parent, call}, std::move(call_context)); return res.first->second.get(); } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/fixpoint_parameters.cpp000066400000000000000000000151231473507761200256460ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Fixpoint parameters implementation * * Author: Thomas Bailleux * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { // WideningHints boost::optional< const MachineInt& > WideningHints::get( ar::BasicBlock* head) const { auto it = this->_map.find(head); if (it != this->_map.end()) { return it->second; } else { return boost::none; } } void WideningHints::add(ar::BasicBlock* head, const MachineInt& hint) { this->_map.try_emplace(head, hint); } // CodeFixpointParameters CodeFixpointParameters::CodeFixpointParameters( WideningStrategy widening_strategy_, NarrowingStrategy narrowing_strategy_, unsigned widening_delay_, unsigned widening_period_, boost::optional< unsigned > narrowing_iterations_) : widening_strategy(widening_strategy_), narrowing_strategy(narrowing_strategy_), widening_delay(widening_delay_), widening_period(std::max(widening_period_, 1U)), narrowing_iterations(narrowing_iterations_) {} // FixpointParameters FixpointParameters::FixpointParameters(const AnalysisOptions& opts) : _default_params(opts.widening_strategy, opts.narrowing_strategy, opts.widening_delay, opts.widening_period, opts.narrowing_iterations) { // Store the parameters for functions with a given widening delay for (const auto& p : opts.widening_delay_functions) { ar::Function* fun = p.first; if (!fun->is_definition()) { continue; } auto fun_fixpoint_params = std::make_unique< CodeFixpointParameters >(this->_default_params); fun_fixpoint_params->widening_delay = p.second; this->_map.try_emplace(fun, std::move(fun_fixpoint_params)); } } FixpointParameters::~FixpointParameters() = default; CodeFixpointParameters& FixpointParameters::get(ar::Function* fun) { ikos_assert(fun->is_definition()); auto it = this->_map.find(fun); if (it != this->_map.end()) { return *it->second; } else { auto fun_fixpoint_params = std::make_unique< CodeFixpointParameters >(this->_default_params); auto res = this->_map.try_emplace(fun, std::move(fun_fixpoint_params)); ikos_assert(res.second); return *res.first->second; } } const CodeFixpointParameters& FixpointParameters::get(ar::Function* fun) const { ikos_assert(fun->is_definition()); auto it = this->_map.find(fun); ikos_assert(it != this->_map.end()); return *it->second; } void FixpointParameters::dump(std::ostream& o) const { // Print default parameters o << "default widening strategy: " << widening_strategy_str(this->_default_params.widening_strategy) << "\n"; o << "default narrowing strategy: " << narrowing_strategy_str(this->_default_params.narrowing_strategy) << "\n"; o << "default widening delay: " << this->_default_params.widening_delay << "\n"; o << "default widening period: " << this->_default_params.widening_period << "\n"; o << "default narrowing iterations: "; if (this->_default_params.narrowing_iterations) { o << *this->_default_params.narrowing_iterations << "\n"; } else { o << "none\n"; } // Print function parameters for (const auto& p : this->_map) { ar::Function* fun = p.first; CodeFixpointParameters& params = *p.second; if (params.widening_strategy != this->_default_params.widening_strategy) { o << fun->name() << " widening strategy: " << widening_strategy_str(params.widening_strategy) << "\n"; } if (params.narrowing_strategy != this->_default_params.narrowing_strategy) { o << fun->name() << " narrowing strategy: " << narrowing_strategy_str(params.narrowing_strategy) << "\n"; } if (params.widening_delay != this->_default_params.widening_delay) { o << fun->name() << " widening delay: " << params.widening_delay << "\n"; } if (params.widening_period != this->_default_params.widening_period) { o << fun->name() << " widening period: " << params.widening_period << "\n"; } if (params.narrowing_iterations != this->_default_params.narrowing_iterations) { o << fun->name() << " narrowing iterations: "; if (params.narrowing_iterations) { o << *params.narrowing_iterations << "\n"; } else { o << "none\n"; } } for (const auto& hint : params.widening_hints) { o << fun->name() << " hint for "; hint.first->dump(o); o << ": " << hint.second << "\n"; } } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/hardware_addresses.cpp000066400000000000000000000201221473507761200254100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of hardware addresses utility for the analyzer * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace { using Interval = core::machine_int::Interval; /// \brief Get the range regex const std::regex& range_regex() { static std::regex RangeRegex( R"(^[\s]*((?:0x)?[0-9a-f]+)[\s]*-[\s]*((?:0x)?[0-9a-f]+)[\s]*$)", std::regex_constants::icase); return RangeRegex; } Interval parse_range(StringRef buffer, uint64_t n_line, uint64_t ptr_bit_width) { uint64_t lbound; uint64_t ubound; std::cmatch rmatch; if (!std::regex_match(buffer.data(), rmatch, range_regex())) { throw HardwareAddressesException(buffer, HardwareAddressesException:: HardwareAddressesExceptionKind:: InvalidFormatKind, n_line); } std::string lbound_str = rmatch.str(0); std::string ubound_str = rmatch.str(2); try { lbound = std::stoull(lbound_str, nullptr, 0); ubound = std::stoull(ubound_str, nullptr, 0); } catch (const std::invalid_argument&) { throw HardwareAddressesException(buffer, HardwareAddressesException:: HardwareAddressesExceptionKind:: InvalidRangeKind, n_line); } catch (const std::out_of_range&) { throw HardwareAddressesException(buffer, HardwareAddressesException:: HardwareAddressesExceptionKind:: InvalidRangeKind, n_line); } if (lbound > ubound) { throw HardwareAddressesException(buffer, HardwareAddressesException:: HardwareAddressesExceptionKind:: InvalidRangeKind, n_line); } return Interval(core::MachineInt(lbound, ptr_bit_width, core::Unsigned), core::MachineInt(ubound, ptr_bit_width, core::Unsigned)); } } // end anonymous namespace HardwareAddresses::HardwareAddresses( ar::Bundle* bundle, const llvm::cl::list< std::string >& hardware_addresses, const llvm::cl::opt< std::string >& hardware_addresses_file) : _data_layout(bundle->data_layout()) { if (!hardware_addresses.empty()) { for (const auto& range : hardware_addresses) { this->add_range(range); } } if (!hardware_addresses_file.empty()) { this->add_range_from_file(hardware_addresses_file.getValue()); } } void HardwareAddresses::add_range(StringRef range_str) { this->add_range( parse_range(range_str, 0, this->_data_layout.pointers.bit_width)); } void HardwareAddresses::add_range_from_file(const std::string& filepath) { std::ifstream stream(filepath); if (!stream.is_open()) { throw HardwareAddressesException(StringRef(), HardwareAddressesException:: HardwareAddressesExceptionKind:: CannotOpenFileKind); } // parse each line std::string line; uint64_t n_line = 1; for (; std::getline(stream, line); n_line++) { if (line.empty()) { continue; } std::cmatch rmatch; if (std::regex_match(line.c_str(), rmatch, range_regex())) { this->add_range( parse_range(line, n_line, this->_data_layout.pointers.bit_width)); } else { throw HardwareAddressesException(line, HardwareAddressesException:: HardwareAddressesExceptionKind:: InvalidFormatKind, n_line); } } } void HardwareAddresses::add_range(Interval range) { this->_address_ranges.push_back(std::move(range)); } bool HardwareAddresses::geq(const Interval& other) const { for (const auto& it : this->ranges()) { if (other.leq(it)) { return true; } } return false; } bool HardwareAddresses::is_meet_bottom(const Interval& other) const { for (const auto& it : this->ranges()) { if (!it.meet(other).is_bottom()) { return false; } } return true; } void HardwareAddresses::dump(std::ostream& o) const { o << "HardwareAddresses:\n"; for (const auto& it : this->ranges()) { o << " - " << it << "\n"; } } HardwareAddressesException::HardwareAddressesException( StringRef pattern, HardwareAddressesException::HardwareAddressesExceptionKind kind) : _n_line(0), _kind(kind) { this->create_errstr(pattern); } HardwareAddressesException::HardwareAddressesException( StringRef pattern, HardwareAddressesException::HardwareAddressesExceptionKind kind, uint64_t n_line) : _n_line(n_line), _kind(kind) { this->create_errstr(pattern); } const char* HardwareAddressesException::what() const noexcept { return this->_errstr->c_str(); } HardwareAddressesException::~HardwareAddressesException() = default; void HardwareAddressesException::create_errstr(StringRef pattern) { std::stringstream ss; switch (this->_kind) { case InvalidFormatKind: { ss << "Invalid range format"; if (!pattern.empty()) { ss << ": " << pattern.data(); } } break; case InvalidRangeKind: { ss << "Invalid range"; if (!pattern.empty()) { ss << ": " << pattern.data(); } } break; case CannotOpenFileKind: { ss << "Cannot open hardware addresses file"; } break; } if (this->_n_line != 0) { ss << ", at line " << this->_n_line; } this->_errstr = std::make_shared< const std::string >(ss.str()); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/literal.cpp000066400000000000000000000254011473507761200232170ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of LiteralFactory * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { LiteralFactory::LiteralFactory(VariableFactory& vfac, const ar::DataLayout& data_layout) : _vfac(vfac), _data_layout(data_layout) {} LiteralFactory::~LiteralFactory() = default; const ScalarLit& LiteralFactory::get_scalar(ar::Value* value) { const Literal& lit = this->get(value); if (lit.is_scalar()) { return lit.scalar(); } else { throw AggregateLiteralError(lit.aggregate()); } } const AggregateLit& LiteralFactory::get_aggregate(ar::Value* value) { const Literal& lit = this->get(value); if (lit.is_aggregate()) { return lit.aggregate(); } else { throw ScalarLiteralError(lit.scalar()); } } const Literal& LiteralFactory::get(ar::Value* value) { { boost::shared_lock< boost::shared_mutex > lock(this->_mutex); auto it = this->_map.find(value); if (it != this->_map.end()) { return it->second; } } Literal literal = this->create_literal(value); { boost::unique_lock< boost::shared_mutex > lock(this->_mutex); std::pair< Map::iterator, bool > res = this->_map.emplace(value, std::move(literal)); return res.first->second; } } namespace { /// \brief Convert a std::size_t representing a size or an offset to a /// MachineInt MachineInt to_machine_int(std::size_t n, const ar::DataLayout& dl) { return MachineInt(n, dl.pointers.bit_width, Unsigned); } /// \brief Convert a ZNumber representing a size or an offset to a MachineInt MachineInt to_machine_int(const ZNumber& n, const ar::DataLayout& dl) { return MachineInt(n, dl.pointers.bit_width, Unsigned); } /// \brief Add a Literal to a AggregateLit::Fields list class AddAggregateField : public Literal::Visitor<> { private: /// \brief Output Field list AggregateLit::Fields& _fields; /// \brief Offset of the input aggregate MachineInt _offset; /// \brief Size of the input aggregate MachineInt _size; public: /// \brief Constructor AddAggregateField(AggregateLit::Fields& fields, MachineInt offset, MachineInt size) : _fields(fields), _offset(std::move(offset)), _size(std::move(size)) {} public: void operator()(const ScalarLit& scalar) { this->_fields.push_back( AggregateLit::Field{this->_offset, scalar, this->_size}); } void operator()(const AggregateLit& aggregate) { if (aggregate.is_cst()) { for (const auto& field : aggregate.fields()) { this->_fields.push_back( AggregateLit::Field{this->_offset + field.offset, field.value, field.size}); } } else if (aggregate.is_zero()) { this->_fields.push_back( AggregateLit::Field{this->_offset, ScalarLit::null(), this->_size}); } else if (aggregate.is_undefined()) { this->_fields.push_back(AggregateLit::Field{this->_offset, ScalarLit::undefined(), this->_size}); } else if (aggregate.is_var()) { throw LogicError( "literal factory: unexpected variable aggregate within a constant " "aggregate"); } else { ikos_unreachable("unreachable"); } } }; // end class AddAggregateField /// \brief Create a Literal from an ar::Value* class ValueVisitor { public: using ResultType = Literal; private: /// \brief Variable factory VariableFactory& _vfac; /// \brief Data layout const ar::DataLayout& _dl; public: /// \brief Constructor ValueVisitor(VariableFactory& vfac, const ar::DataLayout& data_layout) : _vfac(vfac), _dl(data_layout) {} public: Literal operator()(ar::UndefinedConstant* c) { if (c->type()->is_scalar()) { return Literal(ScalarLit::undefined()); } else if (c->type()->is_aggregate()) { return Literal(AggregateLit::undefined( to_machine_int(_dl.store_size_in_bytes(c->type()), _dl))); } else { throw LogicError("literal factory: unexpected variable type"); } } Literal operator()(ar::IntegerConstant* c) { return Literal(ScalarLit::machine_int(c->value())); } Literal operator()(ar::FloatConstant* /*f*/) { return Literal(ScalarLit::floating_point(DummyNumber{})); } Literal operator()(ar::NullConstant* /*n*/) { return Literal(ScalarLit::null()); } Literal operator()(ar::StructConstant* c) { AggregateLit::Fields fields; for (auto it = c->field_begin(), et = c->field_end(); it != et; ++it) { // Translate element Literal value = ar::apply_visitor(*this, it->value); // Add in fields AddAggregateField vis(fields, /*offset = */ to_machine_int(it->offset, _dl), /*size = */ to_machine_int(_dl.store_size_in_bytes( it->value->type()), _dl)); value.apply_visitor(vis); } return Literal( AggregateLit::cst(fields, to_machine_int(_dl.store_size_in_bytes(c->type()), _dl))); } Literal operator()(ar::ArrayConstant* c) { ar::Type* element_type = c->type()->element_type(); MachineInt alloc_size = to_machine_int(_dl.alloc_size_in_bytes(element_type), _dl); AggregateLit::Fields fields; std::size_t n = 0; for (auto it = c->element_begin(), et = c->element_end(); it != et; ++it, ++n) { // Translate element Literal value = ar::apply_visitor(*this, *it); // Add in fields AddAggregateField vis(fields, /*offset = */ alloc_size * to_machine_int(n, _dl), /*size = */ alloc_size); value.apply_visitor(vis); } return Literal( AggregateLit::cst(fields, to_machine_int(_dl.store_size_in_bytes(c->type()), _dl))); } Literal operator()(ar::VectorConstant* c) { ar::Type* element_type = c->type()->element_type(); MachineInt store_size = to_machine_int(_dl.store_size_in_bytes(element_type), _dl); AggregateLit::Fields fields; std::size_t n = 0; for (auto it = c->element_begin(), et = c->element_end(); it != et; ++it, ++n) { // Translate element Literal value = ar::apply_visitor(*this, *it); // Add in fields AddAggregateField vis(fields, /*offset = */ store_size * to_machine_int(n, _dl), /*size = */ store_size); value.apply_visitor(vis); } return Literal( AggregateLit::cst(fields, to_machine_int(_dl.store_size_in_bytes(c->type()), _dl))); } Literal operator()(ar::AggregateZeroConstant* c) { return Literal(AggregateLit::zero( to_machine_int(_dl.store_size_in_bytes(c->type()), _dl))); } Literal operator()(ar::FunctionPointerConstant* c) { return Literal(ScalarLit::pointer_var(this->_vfac.get_function_ptr(c))); } Literal operator()(ar::InlineAssemblyConstant* c) { return Literal(ScalarLit::pointer_var(this->_vfac.get_asm_ptr(c))); } Literal operator()(ar::GlobalVariable* gv) { return Literal(ScalarLit::pointer_var(this->_vfac.get_global(gv))); } Literal operator()(ar::LocalVariable* lv) { return Literal(ScalarLit::pointer_var(this->_vfac.get_local(lv))); } Literal operator()(ar::InternalVariable* iv) { ar::Type* type = iv->type(); Variable* var = this->_vfac.get_internal(iv); if (type->is_integer()) { return Literal(ScalarLit::machine_int_var(var)); } else if (type->is_float()) { return Literal(ScalarLit::floating_point_var(var)); } else if (type->is_pointer()) { return Literal(ScalarLit::pointer_var(var)); } else if (type->is_aggregate()) { return Literal( AggregateLit::var(var, to_machine_int(_dl.store_size_in_bytes(iv->type()), _dl))); } else if (type->is_void()) { throw LogicError("literal factory: unexpected variable of type void"); } else { throw LogicError("literal factory: unexpected variable type"); } } }; // end class ValueVisitor } // end anonymous namespace Literal LiteralFactory::create_literal(ar::Value* value) { ValueVisitor vis(this->_vfac, this->_data_layout); return ar::apply_visitor(vis, value); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/liveness.cpp000066400000000000000000000426421473507761200234210ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the liveness analysis * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace { /// \brief Lattice of liveness /// /// This is a small wrapper around core::DiscreteDomain, with a few changes: /// * The default constructor returns bottom /// * Has convenient operator+ and operator- template < typename VariableRef > class LivenessDomain final : public core::AbstractDomain< LivenessDomain< VariableRef > > { private: using DiscreteDomain = core::DiscreteDomain< VariableRef >; public: using Iterator = typename DiscreteDomain::Iterator; private: DiscreteDomain _inv; private: /// \brief Private constructor explicit LivenessDomain(DiscreteDomain inv) : _inv(std::move(inv)) {} public: /// \brief Create the top liveness domain static LivenessDomain top() { return LivenessDomain(DiscreteDomain::top()); } /// \brief Create the bottom liveness domain static LivenessDomain bottom() { return LivenessDomain(DiscreteDomain::bottom()); } /// \brief Create the empty liveness domain static LivenessDomain empty() { return LivenessDomain(DiscreteDomain::bottom()); } /// \brief Create the liveness domain with the given elements LivenessDomain(std::initializer_list< VariableRef > elements) : _inv(elements) {} /// \brief Copy constructor LivenessDomain(const LivenessDomain&) noexcept = default; /// \brief Move constructor LivenessDomain(LivenessDomain&&) noexcept = default; /// \brief Copy assignment operator LivenessDomain& operator=(const LivenessDomain&) noexcept = default; /// \brief Move assignment operator LivenessDomain& operator=(LivenessDomain&&) noexcept = default; /// \brief Destructor ~LivenessDomain() override = default; /// \brief Return the number of elements in the liveness domain std::size_t size() const { return this->_inv.size(); } /// \brief Begin iterator over the elements Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the elements Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const LivenessDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const LivenessDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const LivenessDomain& other) override { this->_inv.join_with(other._inv); } void widen_with(const LivenessDomain& other) override { this->_inv.widen_with(other._inv); } void meet_with(const LivenessDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const LivenessDomain& other) override { this->_inv.narrow_with(other._inv); } void operator-=(const LivenessDomain& other) { this->_inv.difference_with(other._inv); } void operator-=(VariableRef v) { this->_inv.remove(v); } void operator+=(const LivenessDomain& other) { this->_inv.join_with(other._inv); } void operator+=(VariableRef v) { this->_inv.add(v); } void dump(std::ostream& o) const override { this->_inv.dump(o); } static std::string name() { return "liveness domain"; } }; // end class LivenessDomain /// \brief Inverse an ar::Code* graph /// /// The entry node is the exit node, and successors and predecessors are swapped struct ReverseCodeGraphTrait { using NodeRef = ar::BasicBlock*; using SuccessorNodeIterator = ar::BasicBlock::BasicBlockIterator; using PredecessorNodeIterator = ar::BasicBlock::BasicBlockIterator; static ar::BasicBlock* entry(ar::Code* code) { ikos_assert_msg(code->has_exit_block(), "code graph cannot be inversed"); return code->exit_block(); } static SuccessorNodeIterator successor_begin(ar::BasicBlock* bb) { return bb->predecessor_begin(); } static SuccessorNodeIterator successor_end(ar::BasicBlock* bb) { return bb->predecessor_end(); } static PredecessorNodeIterator predecessor_begin(ar::BasicBlock* bb) { return bb->successor_begin(); } static PredecessorNodeIterator predecessor_end(ar::BasicBlock* bb) { return bb->successor_end(); } }; // end struct ReverseCodeGraphTrait /// \brief Liveness fixpoint iterator class LivenessFixpointIterator final : public core::InterleavedFwdFixpointIterator< ar::Code*, LivenessDomain< Variable* >, ReverseCodeGraphTrait > { private: /// \brief Parent class using FwdFixpointIterator = core::InterleavedFwdFixpointIterator< ar::Code*, LivenessDomain< Variable* >, ReverseCodeGraphTrait >; /// \brief Liveness abstract domain using LivenessDomainT = LivenessDomain< Variable* >; /// \brief A pair (kill, gen) struct KillGen { LivenessDomainT kill; LivenessDomainT gen; }; /// \brief Map from basic block to a (kill, gen) pair using KillGenMap = llvm::DenseMap< ar::BasicBlock*, KillGen >; /// \brief Map from basic block to liveness domain using LivenessMap = llvm::DenseMap< ar::BasicBlock*, LivenessDomainT >; public: /// \brief Iterator on a map from basic block to liveness domain using LivenessMapIterator = LivenessMap::const_iterator; private: /// \brief Variable factory VariableFactory& _vfac; /// \brief Store (kill, gen) sets for each basic block KillGenMap _kg_map; /// \brief Set of all variables (defined and used) for each basic blocks LivenessMap _all_vars_map; /// \brief Set of live variables at the **entry** of a basic block LivenessMap _live_at_entry_map; /// \brief Set of dead variables at the **end** of a basic block LivenessMap _dead_at_end_map; public: LivenessFixpointIterator(ar::Code* code, VariableFactory& vfac) : FwdFixpointIterator(code, LivenessDomainT::bottom()), _vfac(vfac) { this->init(); } LivenessMapIterator live_at_entry_begin() const { return this->_live_at_entry_map.begin(); } LivenessMapIterator live_at_entry_end() const { return this->_live_at_entry_map.end(); } LivenessMapIterator dead_at_end_begin() const { return this->_dead_at_end_map.begin(); } LivenessMapIterator dead_at_end_end() const { return this->_dead_at_end_map.end(); } /// \brief Compute the set of dead and live variables void run(LivenessDomainT inv) override { FwdFixpointIterator::run(std::move(inv)); } /// \brief Apply the kill-gen equation /// /// IN(B) = (OUT(B) \ kill (B)) U gen (B) LivenessDomainT analyze_node(ar::BasicBlock* bb, LivenessDomainT post) override { auto it = this->_kg_map.find(bb); ikos_assert(it != this->_kg_map.end()); LivenessDomainT pre(post); pre -= it->second.kill; // delete kill set pre += it->second.gen; // add gen set return pre; } LivenessDomainT analyze_edge(ar::BasicBlock*, ar::BasicBlock*, LivenessDomainT pre) override { return pre; } /// \brief Store the set of dead variables at the exit of `bb` /// /// Note: this is the post invariant, because we reversed the graph void process_pre(ar::BasicBlock* bb, const LivenessDomainT& post_live) override { ikos_assert(!post_live.is_top()); auto it = this->_all_vars_map.find(bb); ikos_assert(it != this->_all_vars_map.end()); LivenessDomainT all = it->second; // dead = all - live LivenessDomainT dead(all); dead -= post_live; this->_dead_at_end_map.try_emplace(bb, dead); } /// \brief Store the set of live variables at the entry of `bb` /// /// Note: this is the pre invariant, because we reversed the graph void process_post(ar::BasicBlock* bb, const LivenessDomainT& pre_live) override { ikos_assert(!pre_live.is_top()); this->_live_at_entry_map.try_emplace(bb, pre_live); } private: /// \brief Compute kill/gen sets for each basic blocks void init() { ar::Code* code = this->cfg(); for (auto it = code->begin(), et = code->end(); it != et; ++it) { this->init(*it); } } /// \brief Compute kill/gen sets for the given basic block void init(ar::BasicBlock* bb) { auto kill = LivenessDomainT::empty(); auto gen = LivenessDomainT::empty(); auto all = LivenessDomainT::empty(); for (auto it = bb->rbegin(), et = bb->rend(); it != et; ++it) { ar::Statement* stmt = *it; // Process defs if (stmt->has_result()) { Variable* var = this->variable_ref(stmt->result()); ikos_assert_msg(var != nullptr, "result is not a variable"); kill += var; gen -= var; all += var; } // Process uses for (auto op_it = stmt->op_begin(), op_et = stmt->op_end(); op_it != op_et; ++op_it) { Variable* var = this->variable_ref(*op_it); if (var != nullptr) { gen += var; all += var; } } } this->_kg_map.try_emplace(bb, KillGen{kill, gen}); this->_all_vars_map.try_emplace(bb, all); } /// \brief Get the Variable* of an ar::Value /// /// Returns nullptr if the value is not an internal or local variable Variable* variable_ref(ar::Value* value) { if (auto ptr = ar::dyn_cast< ar::FunctionPointerConstant >(value)) { return this->_vfac.get_function_ptr(ptr); } else if (auto gv = ar::dyn_cast< ar::GlobalVariable >(value)) { return this->_vfac.get_global(gv); } else if (auto lv = ar::dyn_cast< ar::LocalVariable >(value)) { return this->_vfac.get_local(lv); } else if (auto iv = ar::dyn_cast< ar::InternalVariable >(value)) { return this->_vfac.get_internal(iv); } else { return nullptr; } } }; // end class LivenessFixpointIterator } // end anonymous namespace LivenessAnalysis::LivenessAnalysis(Context& ctx) : _ctx(ctx) {} LivenessAnalysis::~LivenessAnalysis() = default; boost::optional< const LivenessAnalysis::VariableRefList& > LivenessAnalysis:: live_at_entry(ar::BasicBlock* bb) const { auto it = this->_live_at_entry_map.find(bb); if (it != this->_live_at_entry_map.end()) { return it->second; } else { return boost::none; } } boost::optional< const LivenessAnalysis::VariableRefList& > LivenessAnalysis:: dead_at_end(ar::BasicBlock* bb) const { auto it = this->_dead_at_end_map.find(bb); if (it != this->_dead_at_end_map.end()) { return it->second; } else { return boost::none; } } void LivenessAnalysis::run() { ar::Bundle* bundle = _ctx.bundle; // Setup a progress logger std::unique_ptr< ProgressLogger > progress = make_progress_logger(_ctx.opts.progress, LogLevel::Info, /* num_tasks = */ std::count_if(bundle->global_begin(), bundle->global_end(), [](ar::GlobalVariable* gv) { return gv->is_definition(); }) + std::count_if(bundle->function_begin(), bundle->function_end(), [](ar::Function* fun) { return fun->is_definition(); })); ScopeLogger scope(*progress); for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { ar::GlobalVariable* gv = *it; if (gv->is_definition()) { progress->start_task( "Running liveness analysis on initializer of global variable '" + demangle(gv->name()) + "'"); this->run(gv->initializer()); } } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* fun = *it; if (fun->is_definition()) { progress->start_task("Running liveness analysis on function '" + demangle(fun->name()) + "'"); this->run(fun->body()); } } } /// \brief Convert a LivenessDomain into a VariableRefList static LivenessAnalysis::VariableRefList to_variable_ref_list( const LivenessDomain< Variable* >& value) { LivenessAnalysis::VariableRefList list; if (!value.is_bottom()) { list.reserve(value.size()); std::copy(value.begin(), value.end(), std::back_inserter(list)); } return list; } void LivenessAnalysis::run(ar::Code* code) { // If the code has no exit block, do nothing if (!code->has_exit_block()) { return; } // Run the liveness fixpoint iterator LivenessFixpointIterator fixpoint(code, *_ctx.var_factory); fixpoint.run(LivenessDomain< Variable* >::bottom()); // Store the results for (auto it = fixpoint.live_at_entry_begin(), et = fixpoint.live_at_entry_end(); it != et; ++it) { this->_live_at_entry_map.try_emplace(it->first, to_variable_ref_list(it->second)); } for (auto it = fixpoint.dead_at_end_begin(), et = fixpoint.dead_at_end_end(); it != et; ++it) { this->_dead_at_end_map.try_emplace(it->first, to_variable_ref_list(it->second)); } } void LivenessAnalysis::dump(std::ostream& o) const { ar::Bundle* bundle = _ctx.bundle; for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { ar::GlobalVariable* gv = *it; if (gv->is_definition()) { o << "Liveness analysis results for initializer of global variable @" << gv->name() << ":\n"; this->dump(o, gv->initializer()); } } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* fun = *it; if (fun->is_definition()) { o << "Liveness analysis results for function @" << fun->name() << ":\n"; this->dump(o, fun->body()); } } } void LivenessAnalysis::dump(std::ostream& o, ar::Code* code) const { for (ar::BasicBlock* bb : *code) { // Live at entry o << "live_at_entry("; bb->dump(o); o << ") = "; auto it = this->_live_at_entry_map.find(bb); if (it != this->_live_at_entry_map.end()) { dump(o, it->second); } else { o << "none"; } o << "\n"; // Dead at end o << "dead_at_end("; bb->dump(o); o << ") = "; it = this->_dead_at_end_map.find(bb); if (it != this->_dead_at_end_map.end()) { dump(o, it->second); } else { o << "none"; } o << "\n"; } } void LivenessAnalysis::dump(std::ostream& o, const LivenessAnalysis::VariableRefList& vars) { o << "{"; for (auto it = vars.begin(), et = vars.end(); it != et;) { (*it)->dump(o); if (++it != et) { o << ", "; } } o << "}"; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/memory_location.cpp000066400000000000000000000212571473507761200247700ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of MemoryLocation * * Author: Clement Decoodt * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { // MemoryLocation MemoryLocation::MemoryLocation(MemoryLocationKind kind) : _kind(kind) {} MemoryLocation::~MemoryLocation() = default; // LocalMemoryLocation LocalMemoryLocation::LocalMemoryLocation(ar::LocalVariable* var) : MemoryLocation(LocalMemoryKind), _var(var) { ikos_assert(this->_var != nullptr); } void LocalMemoryLocation::dump(std::ostream& o) const { o << "LocalMemoryLocation{"; this->_var->dump(o); o << "}"; } // GlobalMemoryLocation GlobalMemoryLocation::GlobalMemoryLocation(ar::GlobalVariable* var) : MemoryLocation(GlobalMemoryKind), _var(var) { ikos_assert(this->_var != nullptr); } void GlobalMemoryLocation::dump(std::ostream& o) const { o << "GlobalMemoryLocation{"; this->_var->dump(o); o << "}"; } // FunctionMemoryLocation FunctionMemoryLocation::FunctionMemoryLocation(ar::Function* fun) : MemoryLocation(FunctionMemoryKind), _fun(fun) { ikos_assert(this->_fun != nullptr); } void FunctionMemoryLocation::dump(std::ostream& o) const { o << "@" << this->_fun->name(); } // AggregateMemoryLocation AggregateMemoryLocation::AggregateMemoryLocation(ar::InternalVariable* var) : MemoryLocation(AggregateMemoryKind), _var(var) { ikos_assert(this->_var != nullptr); } void AggregateMemoryLocation::dump(std::ostream& o) const { o << "AggregateMemoryLocation{"; this->_var->dump(o); o << "}"; } // AbsoluteZeroMemoryLocation AbsoluteZeroMemoryLocation::AbsoluteZeroMemoryLocation() : MemoryLocation(AbsoluteZeroMemoryKind) {} void AbsoluteZeroMemoryLocation::dump(std::ostream& o) const { o << "absolute_zero"; } // ArgvMemoryLocation ArgvMemoryLocation::ArgvMemoryLocation() : MemoryLocation(ArgvMemoryKind) {} void ArgvMemoryLocation::dump(std::ostream& o) const { o << "argv"; } // LibcErrnoMemoryLocation LibcErrnoMemoryLocation::LibcErrnoMemoryLocation() : MemoryLocation(LibcErrnoMemoryKind) {} void LibcErrnoMemoryLocation::dump(std::ostream& o) const { o << "libc.errno"; } // DynAllocMemoryLocation DynAllocMemoryLocation::DynAllocMemoryLocation(ar::CallBase* call, CallContext* context) : MemoryLocation(DynAllocMemoryKind), _call(call), _context(context) { ikos_assert(this->_call != nullptr && this->_context != nullptr); } void DynAllocMemoryLocation::dump(std::ostream& o) const { ikos_assert_msg(this->_call->code()->is_function_body(), "dynamic allocation in global variable initializer"); auto fun = this->_call->code()->function(); o << "dyn_alloc:" << fun->name() << ":"; SourceLocation loc = source_location(this->_call); if (loc) { o << loc.line() << ":" << loc.column(); } else { o << this->_call; } if (!this->_context->empty()) { o << ":" << this->_context; } } // MemoryFactory MemoryFactory::MemoryFactory() : _absolute_zero(std::make_unique< AbsoluteZeroMemoryLocation >()), _argv(std::make_unique< ArgvMemoryLocation >()), _libc_errno(std::make_unique< LibcErrnoMemoryLocation >()) {} MemoryFactory::~MemoryFactory() = default; LocalMemoryLocation* MemoryFactory::get_local(ar::LocalVariable* var) { { boost::shared_lock< boost::shared_mutex > lock(this->_local_memory_mutex); auto it = this->_local_memory_map.find(var); if (it != this->_local_memory_map.end()) { return it->second.get(); } } auto ml = std::make_unique< LocalMemoryLocation >(var); { boost::unique_lock< boost::shared_mutex > lock(this->_local_memory_mutex); auto res = this->_local_memory_map.try_emplace(var, std::move(ml)); return res.first->second.get(); } } GlobalMemoryLocation* MemoryFactory::get_global(ar::GlobalVariable* var) { { boost::shared_lock< boost::shared_mutex > lock(this->_global_memory_mutex); auto it = this->_global_memory_map.find(var); if (it != this->_global_memory_map.end()) { return it->second.get(); } } auto ml = std::make_unique< GlobalMemoryLocation >(var); { boost::unique_lock< boost::shared_mutex > lock(this->_global_memory_mutex); auto res = this->_global_memory_map.try_emplace(var, std::move(ml)); return res.first->second.get(); } } FunctionMemoryLocation* MemoryFactory::get_function(ar::Function* fun) { { boost::shared_lock< boost::shared_mutex > lock( this->_function_memory_mutex); auto it = this->_function_memory_map.find(fun); if (it != this->_function_memory_map.end()) { return it->second.get(); } } auto ml = std::make_unique< FunctionMemoryLocation >(fun); { boost::unique_lock< boost::shared_mutex > lock( this->_function_memory_mutex); auto res = this->_function_memory_map.try_emplace(fun, std::move(ml)); return res.first->second.get(); } } FunctionMemoryLocation* MemoryFactory::get_function( ar::FunctionPointerConstant* cst) { return this->get_function(cst->function()); } AggregateMemoryLocation* MemoryFactory::get_aggregate( ar::InternalVariable* var) { { boost::shared_lock< boost::shared_mutex > lock( this->_aggregate_memory_mutex); auto it = this->_aggregate_memory_map.find(var); if (it != this->_aggregate_memory_map.end()) { return it->second.get(); } } auto ml = std::make_unique< AggregateMemoryLocation >(var); { boost::unique_lock< boost::shared_mutex > lock( this->_aggregate_memory_mutex); auto res = this->_aggregate_memory_map.try_emplace(var, std::move(ml)); return res.first->second.get(); } } AbsoluteZeroMemoryLocation* MemoryFactory::get_absolute_zero() { return this->_absolute_zero.get(); } ArgvMemoryLocation* MemoryFactory::get_argv() { return this->_argv.get(); } LibcErrnoMemoryLocation* MemoryFactory::get_libc_errno() { return this->_libc_errno.get(); } DynAllocMemoryLocation* MemoryFactory::get_dyn_alloc(ar::CallBase* call, CallContext* context) { { boost::shared_lock< boost::shared_mutex > lock(this->_dyn_alloc_mutex); auto it = this->_dyn_alloc_map.find({call, context}); if (it != this->_dyn_alloc_map.end()) { return it->second.get(); } } auto ml = std::make_unique< DynAllocMemoryLocation >(call, context); { boost::unique_lock< boost::shared_mutex > lock(this->_dyn_alloc_mutex); auto res = this->_dyn_alloc_map.try_emplace({call, context}, std::move(ml)); return res.first->second.get(); } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/option.cpp000066400000000000000000000123761473507761200231020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation for Analyses options * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { void AnalysisOptions::save(SettingsTable& table) { auto function_name = [](ar::Function* fun) { return fun->name(); }; table.insert("analyses", to_json(boost::make_transform_iterator(this->analyses.begin(), checker_short_name), boost::make_transform_iterator(this->analyses.end(), checker_short_name))); table .insert("entry-points", to_json(boost::make_transform_iterator(this->entry_points.begin(), function_name), boost::make_transform_iterator(this->entry_points.end(), function_name))); table.insert("no-init-globals", to_json(boost::make_transform_iterator(this->no_init_globals .begin(), function_name), boost::make_transform_iterator(this->no_init_globals .end(), function_name))); table.insert("machine-int-domain", machine_int_domain_option_str(this->machine_int_domain)); table.insert("procedural", procedural_str(this->procedural)); table.insert("num-threads", this->num_threads); table.insert("widening-strategy", widening_strategy_str(this->widening_strategy)); table.insert("narrowing-strategy", narrowing_strategy_str(this->narrowing_strategy)); table.insert("widening-delay", std::to_string(this->widening_delay)); JsonDict widening_delay_dict; for (const auto& p : this->widening_delay_functions) { widening_delay_dict.put(p.first->name(), p.second); } table.insert("widening-delay-functions", widening_delay_dict); table.insert("widening-period", std::to_string(this->widening_period)); if (this->narrowing_iterations) { table.insert("narrowing-iterations", std::to_string(*this->narrowing_iterations)); } table.insert("use-liveness", this->use_liveness); table.insert("use-pointer-analysis", this->use_pointer); table.insert("use-widening-hints", this->use_widening_hints); table.insert("use-partitioning-domain", this->use_partitioning_domain); table.insert("use-fixpoint-cache", this->use_fixpoint_cache); table.insert("use-checks", this->use_checks); table.insert("trace-ar-statements", this->trace_ar_statements); table.insert("globals-init-policy", globals_init_policy_str(this->globals_init_policy)); table.insert("hardware-addresses", hardware_addresses_str(this->hardware_addresses)); if (this->argc) { table.insert("argc", std::to_string(*this->argc)); } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/pointer/000077500000000000000000000000001473507761200225355ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/pointer/constraint.cpp000066400000000000000000000057641473507761200254410ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Pointer constraints generation implementation * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { PointerConstraints::PointerConstraints(const ar::DataLayout& dl) : _system(dl.pointers.bit_width, Unsigned) {} PointerConstraints::~PointerConstraints() = default; void PointerConstraints::add(std::unique_ptr< PointerConstraint > cst) { this->_system.add(std::move(cst)); } void PointerConstraints::solve() { this->_system.solve(); } void PointerConstraints::results(PointerInfo& info) const { info.clear(); for (auto it = this->_system.pointer_begin(), et = this->_system.pointer_end(); it != et; ++it) { info.insert(it->first, it->second); } } void PointerConstraints::dump(std::ostream& o) const { this->_system.dump(o); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/pointer/function.cpp000066400000000000000000000152451473507761200250750ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Implementation of the function pointer analysis * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { FunctionPointerAnalysis::FunctionPointerAnalysis(Context& ctx) : _ctx(ctx), _info(ctx.bundle->data_layout()) {} FunctionPointerAnalysis::~FunctionPointerAnalysis() = default; namespace { /// \brief Dummy scalar abstract domain using ScalarAbstractDomain = core::scalar::DummyDomain< Variable*, MemoryLocation* >; /// \brief Dummy memory abstract domain using MemoryAbstractDomain = core::memory:: DummyDomain< Variable*, MemoryLocation*, ScalarAbstractDomain >; /// \brief Dummy abstract domain for the function pointer analysis /// /// This is either top or bottom. using AbstractDomain = core::exception::ExceptionDomain< MemoryAbstractDomain >; /// \brief Create the top abstract value AbstractDomain make_top_abstract_value() { auto top = MemoryAbstractDomain(ScalarAbstractDomain::top()); return AbstractDomain(/*normal = */ top, /*caught_exceptions = */ top, /*propagated_exceptions = */ top); } /// \brief An empty code invariants class EmptyCodeInvariants { public: using AbstractDomainT = AbstractDomain; public: /// \brief Get the invariant at the entry of the given basic block AbstractDomainT entry(ar::BasicBlock* /*bb*/) const { return make_top_abstract_value(); } /// \brief Analyze the given statement and update the invariant AbstractDomainT analyze_statement(ar::Statement* /*stmt*/, const AbstractDomainT& /*inv*/) const { return make_top_abstract_value(); } }; } // end anonymous namespace void FunctionPointerAnalysis::run() { ar::Bundle* bundle = _ctx.bundle; // Setup a progress logger std::unique_ptr< ProgressLogger > progress = make_progress_logger(_ctx.opts.progress, LogLevel::Info, /* num_tasks = */ std::count_if(bundle->global_begin(), bundle->global_end(), [](ar::GlobalVariable* gv) { return gv->is_definition(); }) + std::count_if(bundle->function_begin(), bundle->function_end(), [](ar::Function* fun) { return fun->is_definition(); }) + 1); ScopeLogger scope(*progress); log::debug("Generating pointer constraints"); PointerConstraints constraints(bundle->data_layout()); PointerConstraintsGenerator< EmptyCodeInvariants > visitor(_ctx, constraints, nullptr); for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { ar::GlobalVariable* gv = *it; if (gv->is_definition()) { progress->start_task( "Generating pointer constraints for initializer of global variable " "'" + demangle(gv->name()) + "'"); visitor.process_global_var_def(gv, EmptyCodeInvariants()); } else { visitor.process_global_var_decl(gv); } } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* fun = *it; if (fun->is_definition()) { progress->start_task("Generating pointer constraints for function '" + demangle(fun->name()) + "'"); visitor.process_function_def(fun, EmptyCodeInvariants()); } else { visitor.process_function_decl(fun); } } log::debug("Solving pointer constraints"); progress->start_task("Solving pointer constraints"); constraints.solve(); // Save information constraints.results(this->_info); } void FunctionPointerAnalysis::dump(std::ostream& o) const { o << "Function pointer analysis results:\n"; this->_info.dump(o); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/pointer/pointer.cpp000066400000000000000000000367261473507761200247370ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Implementation of the pointer analysis * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { PointerAnalysis::PointerAnalysis( Context& ctx, const FunctionPointerAnalysis& function_pointer) : _ctx(ctx), _function_pointer(function_pointer), _info(ctx.bundle->data_layout()) {} PointerAnalysis::~PointerAnalysis() = default; namespace { /// \brief Numerical abstract domain for the intra-procedural pointer analysis using MachineIntAbstractDomain = core::machine_int::IntervalDomain< Variable* >; /// \brief Uninitialized abstract domain for the intra-procedural pointer /// analysis using UninitializedAbstractDomain = core::uninitialized::SeparateDomain< Variable* >; /// \brief Scalar abstract domain for the intra-procedural pointer analysis using ScalarAbstractDomain = core::scalar::MachineIntDomain< Variable*, MemoryLocation*, UninitializedAbstractDomain, MachineIntAbstractDomain >; /// \brief Memory abstract domain for the intra-procedural pointer analysis using MemoryAbstractDomain = core::memory:: DummyDomain< Variable*, MemoryLocation*, ScalarAbstractDomain >; /// \brief Abstract domain for the intra-procedural pointer analysis using AbstractDomain = core::exception::ExceptionDomain< MemoryAbstractDomain >; /// \brief Create the bottom abstract value AbstractDomain make_bottom_abstract_value() { auto bottom = MemoryAbstractDomain( ScalarAbstractDomain(UninitializedAbstractDomain::bottom(), MachineIntAbstractDomain::bottom())); return AbstractDomain(/*normal = */ bottom, /*caught_exceptions = */ bottom, /*propagated_exceptions = */ bottom); } /// \brief Create the initial abstract value AbstractDomain make_initial_abstract_value() { auto top = MemoryAbstractDomain( ScalarAbstractDomain(UninitializedAbstractDomain::top(), MachineIntAbstractDomain::top())); auto bottom = MemoryAbstractDomain( ScalarAbstractDomain(UninitializedAbstractDomain::bottom(), MachineIntAbstractDomain::bottom())); return AbstractDomain(/*normal = */ top, /*caught_exceptions = */ bottom, /*propagated_exceptions = */ bottom); } /// \brief Numerical invariants on an ar::Code class NumericalCodeInvariants final : public core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomain > { public: using AbstractDomainT = AbstractDomain; private: /// \brief Parent class using FwdFixpointIterator = core::InterleavedFwdFixpointIterator< ar::Code*, AbstractDomainT >; private: /// \brief Analysis context Context& _ctx; /// \brief Empty call context CallContext* _empty_call_context; /// \brief Fixpoint parameters const CodeFixpointParameters& _fixpoint_parameters; /// \brief Previously computed function pointer analysis const FunctionPointerAnalysis& _function_pointer; public: /// \brief Constructor NumericalCodeInvariants(Context& ctx, const FunctionPointerAnalysis& function_pointer, ar::Code* code) : FwdFixpointIterator(code, make_bottom_abstract_value()), _ctx(ctx), _empty_call_context(ctx.call_context_factory->get_empty()), _fixpoint_parameters( code->is_function_body() ? ctx.fixpoint_parameters->get(code->function()) : ctx.fixpoint_parameters->default_params()), _function_pointer(function_pointer) {} /// \brief Extrapolate the new state after an increasing iteration AbstractDomainT extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomainT& before, const AbstractDomainT& after) override { if (iteration <= this->_fixpoint_parameters.widening_delay) { // Fixed number of iterations using join return before.join_iter(after); } iteration -= this->_fixpoint_parameters.widening_delay; iteration--; if (iteration % this->_fixpoint_parameters.widening_period != 0) { // Not the period, iteration using join return before.join_iter(after); } switch (this->_fixpoint_parameters.widening_strategy) { case WideningStrategy::Widen: { if (iteration == 0) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // One iteration using widening with threshold return before.widening_threshold(after, *threshold); } } // Iterations using widening until convergence return before.widening(after); } case WideningStrategy::Join: { // Iterations using join until convergence return before.join_iter(after); } default: { ikos_unreachable("unexpected strategy"); } } } /// \brief Refine the new state after a decreasing iteration AbstractDomainT refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomainT& before, const AbstractDomainT& after) override { switch (this->_fixpoint_parameters.narrowing_strategy) { case NarrowingStrategy::Narrow: { if (iteration == 1) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // First iteration using narrowing with threshold return before.narrowing_threshold(after, *threshold); } } // Iterations using narrowing return before.narrowing(after); } case NarrowingStrategy::Meet: { // Iterations using meet return before.meet(after); } default: { ikos_unreachable("unexpected strategy"); } } } bool is_decreasing_iterations_fixpoint( ar::BasicBlock* /*head*/, unsigned iteration, const AbstractDomainT& before, const AbstractDomainT& after) override { // Check if we reached the number of requested iterations, or convergence return (this->_fixpoint_parameters.narrowing_iterations && iteration >= *this->_fixpoint_parameters.narrowing_iterations) || before.leq(after); } /// \brief Propagate the invariant through the basic block AbstractDomainT analyze_node(ar::BasicBlock* bb, AbstractDomainT pre) override { NumericalExecutionEngine< AbstractDomainT > exec_engine(std::move(pre), _ctx, this->_empty_call_context, ExecutionEngine::NoOption, /* liveness = */ _ctx.liveness, /* pointer_info = */ &_function_pointer.results()); ContextInsensitiveCallExecutionEngine< AbstractDomainT > call_exec_engine( exec_engine); exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); return std::move(exec_engine.inv()); } /// \brief Propagate the invariant through an edge AbstractDomainT analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomainT pre) override { NumericalExecutionEngine< AbstractDomainT > exec_engine(std::move(pre), _ctx, this->_empty_call_context, ExecutionEngine::NoOption, /* liveness = */ _ctx.liveness, /* pointer_info = */ &_function_pointer.results()); exec_engine.exec_edge(src, dest); return std::move(exec_engine.inv()); } /// \brief Process the computed abstract value for a node void process_pre(ar::BasicBlock* /*bb*/, const AbstractDomainT& /*pre*/) override {} /// \brief Process the computed abstract value for a node void process_post(ar::BasicBlock* /*bb*/, const AbstractDomainT& /*post*/) override {} /// \brief Get the invariant at the entry of the given basic block AbstractDomainT entry(ar::BasicBlock* bb) const { NumericalExecutionEngine< AbstractDomainT > exec_engine(this->pre(bb), _ctx, this->_empty_call_context, ExecutionEngine::NoOption, /* liveness = */ _ctx.liveness, /* pointer_info = */ &_function_pointer.results()); exec_engine.exec_enter(bb); return std::move(exec_engine.inv()); } /// \brief Execute the given statement with the given invariant AbstractDomainT analyze_statement(ar::Statement* stmt, AbstractDomainT pre) const { NumericalExecutionEngine< AbstractDomainT > exec_engine(std::move(pre), _ctx, this->_empty_call_context, ExecutionEngine::NoOption, /* liveness = */ _ctx.liveness, /* pointer_info = */ &_function_pointer.results()); ContextInsensitiveCallExecutionEngine< AbstractDomainT > call_exec_engine( exec_engine); transfer_function(exec_engine, call_exec_engine, stmt); return std::move(exec_engine.inv()); } }; } // end anonymous namespace void PointerAnalysis::run() { ar::Bundle* bundle = _ctx.bundle; // Setup a progress logger std::unique_ptr< ProgressLogger > progress = make_progress_logger(_ctx.opts.progress, LogLevel::Info, /* num_tasks = */ 2 * std::count_if(bundle->global_begin(), bundle->global_end(), [](ar::GlobalVariable* gv) { return gv->is_definition(); }) + 2 * std::count_if(bundle->function_begin(), bundle->function_end(), [](ar::Function* fun) { return fun->is_definition(); }) + 1); ScopeLogger scope(*progress); log::debug("Generating pointer constraints"); PointerConstraints constraints(bundle->data_layout()); PointerConstraintsGenerator< NumericalCodeInvariants > visitor(_ctx, constraints, &_function_pointer.results()); for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { ar::GlobalVariable* gv = *it; if (gv->is_definition()) { progress->start_task( "Generating intra-procedural numerical invariant for initializer of " "global variable '" + demangle(gv->name()) + "'"); NumericalCodeInvariants invariants(_ctx, _function_pointer, gv->initializer()); invariants.run(make_initial_abstract_value()); progress->start_task( "Generating pointer constraints for initializer of global variable " "'" + demangle(gv->name()) + "'"); visitor.process_global_var_def(gv, invariants); } else { visitor.process_global_var_decl(gv); } } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* fun = *it; if (fun->is_definition()) { progress->start_task( "Generating intra-procedural numerical invariant for function '" + demangle(fun->name()) + "'"); NumericalCodeInvariants invariants(_ctx, _function_pointer, fun->body()); invariants.run(make_initial_abstract_value()); progress->start_task("Generating pointer constraints for function '" + demangle(fun->name()) + "'"); visitor.process_function_def(fun, invariants); } else { visitor.process_function_decl(fun); } } log::debug("Solving pointer constraints"); progress->start_task("Solving pointer constraints"); constraints.solve(); // Save information constraints.results(this->_info); } /// \brief Dump the pointer analysis results, for debugging purpose void PointerAnalysis::dump(std::ostream& o) const { o << "Pointer analysis results:\n"; this->_info.dump(o); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/pointer/value.cpp000066400000000000000000000060441473507761200243610ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Pointer abstractions implementation * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { PointerInfo::PointerInfo(const ar::DataLayout& data_layout) : _data_layout(data_layout) {} PointerInfo::~PointerInfo() = default; void PointerInfo::clear() { this->_map.clear(); } PointerAbsValue PointerInfo::get(Variable* v) const { auto it = this->_map.find(v); if (it != this->_map.end()) { return it->second; } else { return PointerAbsValue::top(this->_data_layout.pointers.bit_width, Unsigned); } } void PointerInfo::insert(Variable* v, const PointerAbsValue& value) { this->_map.insert({v, value}); } void PointerInfo::dump(std::ostream& o) const { for (const auto& ptr : this->_map) { ptr.first->dump(o); o << " -> "; ptr.second.dump(o); o << "\n"; } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/000077500000000000000000000000001473507761200221715ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/abstract_domain.cpp000066400000000000000000000137441473507761200260400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Abstract domain for the value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace { /// \brief Uninitialized abstract domain using UninitializedAbstractDomain = core::uninitialized::SeparateDomain< Variable* >; /// \brief Nullity abstract domain using NullityAbstractDomain = core::nullity::SeparateDomain< Variable* >; /// \brief Scalar abstract domain using ScalarAbstractDomain = core::scalar::CompositeDomain< Variable*, MemoryLocation*, UninitializedAbstractDomain, MachineIntAbstractDomain, NullityAbstractDomain >; /// \brief Lifetime abstract domain using LifetimeAbstractDomain = core::lifetime::SeparateDomain< MemoryLocation* >; /// \brief Value abstract domain using ValueAbstractDomain = core::memory::ValueDomain< Variable*, MemoryLocation*, VariableFactory*, ScalarAbstractDomain, LifetimeAbstractDomain >; /// \brief Partitioning abstract domain using PartitioningAbstractDomain = core::memory:: PartitioningDomain< Variable*, MemoryLocation*, ValueAbstractDomain >; /// \brief Create the bottom memory abstract value MemoryAbstractDomain make_bottom_memory_abstract_value(Context& ctx) { auto inv = ValueAbstractDomain( ctx.var_factory, ScalarAbstractDomain(UninitializedAbstractDomain::bottom(), make_bottom_machine_int_abstract_value( ctx.opts.machine_int_domain), NullityAbstractDomain::bottom()), LifetimeAbstractDomain::bottom()); if (ctx.opts.use_partitioning_domain) { return MemoryAbstractDomain(PartitioningAbstractDomain(inv)); } else { return MemoryAbstractDomain(inv); } } /// \brief Create the top memory abstract value MemoryAbstractDomain make_top_memory_abstract_value(Context& ctx) { auto inv = ValueAbstractDomain( ctx.var_factory, ScalarAbstractDomain(UninitializedAbstractDomain::top(), make_top_machine_int_abstract_value( ctx.opts.machine_int_domain), NullityAbstractDomain::top()), LifetimeAbstractDomain::top()); if (ctx.opts.use_partitioning_domain) { return MemoryAbstractDomain(PartitioningAbstractDomain(inv)); } else { return MemoryAbstractDomain(inv); } } } // end anonymous namespace AbstractDomain make_bottom_abstract_value(Context& ctx) { return AbstractDomain(/* normal = */ make_bottom_memory_abstract_value(ctx), /* caught_exceptions = */ make_bottom_memory_abstract_value(ctx), /* propagated_exceptions = */ make_bottom_memory_abstract_value(ctx)); } AbstractDomain make_initial_abstract_value(Context& ctx) { return AbstractDomain(/* normal = */ make_top_memory_abstract_value(ctx), /* caught_exceptions = */ make_bottom_memory_abstract_value(ctx), /* propagated_exceptions = */ make_bottom_memory_abstract_value(ctx)); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/global_variable.cpp000066400000000000000000000122741473507761200260100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Helpers for global variables for the value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { namespace value { bool is_initialized(ar::GlobalVariable* gv, GlobalsInitPolicy policy) { switch (policy) { case GlobalsInitPolicy::All: { // Initialize all global variables return true; } case GlobalsInitPolicy::SkipBigArrays: { // Initialize all global variables except arrays with more than 100 // elements ar::Type* type = gv->type()->pointee(); return !isa< ar::ArrayType >(type) || cast< ar::ArrayType >(type)->num_elements() <= 100; } case GlobalsInitPolicy::SkipStrings: { // Initialize all global variables except strings ([n x si8]*) ar::Type* type = gv->type()->pointee(); return !isa< ar::ArrayType >(type) || cast< ar::ArrayType >(type)->element_type() != ar::IntegerType::si8(gv->context()); } case GlobalsInitPolicy::None: { // Do not initialize any global variable return false; } default: { ikos_unreachable("unreachable"); } } } /// \brief Return the list of pair (function, priority) for arrays /// ar.global_ctors or ar.global_dtors, given the global variable static std::vector< std::pair< ar::Function*, MachineInt > > global_cdtors( ar::GlobalVariable* gv) { if (gv == nullptr || gv->is_declaration()) { return {}; } ar::BasicBlock* bb = gv->initializer()->entry_block(); if (bb->empty() || !isa< ar::Store >(bb->back())) { return {}; } auto store = cast< ar::Store >(bb->back()); if (store->pointer() != gv || !isa< ar::ArrayConstant >(store->value())) { return {}; } auto cst = cast< ar::ArrayConstant >(store->value()); std::vector< std::pair< ar::Function*, MachineInt > > entries; for (ar::Value* element : cst->values()) { if (!isa< ar::StructConstant >(element)) { continue; } auto e = cast< ar::StructConstant >(element); if (e->num_fields() != 3) { continue; } auto it = e->field_begin(); ar::Value* fst = it->value; ++it; ar::Value* snd = it->value; if (!isa< ar::IntegerConstant >(fst) || !isa< ar::FunctionPointerConstant >(snd)) { continue; } const MachineInt& priority = cast< ar::IntegerConstant >(fst)->value(); ar::Function* fun = cast< ar::FunctionPointerConstant >(snd)->function(); entries.emplace_back(fun, priority); } return entries; } std::vector< std::pair< ar::Function*, MachineInt > > global_ctors( ar::GlobalVariable* gv) { auto entries = global_cdtors(gv); std::sort(entries.begin(), entries.end(), [](const auto& a, const auto& b) { return a.second < b.second; }); return entries; } std::vector< std::pair< ar::Function*, MachineInt > > global_dtors( ar::GlobalVariable* gv) { auto entries = global_cdtors(gv); std::sort(entries.begin(), entries.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); return entries; } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/000077500000000000000000000000001473507761200253735ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/concurrent/000077500000000000000000000000001473507761200275555ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/concurrent/analysis.cpp000066400000000000000000000233201473507761200321040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Concurrent interprocedural value analysis implementation * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace concurrent { Analysis::Analysis(Context& ctx) : _ctx(ctx) {} Analysis::~Analysis() = default; void Analysis::run() { // Bundle ar::Bundle* bundle = _ctx.bundle; // Create checkers std::vector< std::unique_ptr< Checker > > checkers; if (_ctx.opts.use_checks) { for (CheckerName name : _ctx.opts.analyses) { checkers.emplace_back(make_checker(_ctx, name)); } } // Initialize the task scheduler if (_ctx.opts.num_threads > 0) { tbb::global_control init(tbb::global_control::max_allowed_parallelism, static_cast< std::size_t >(_ctx.opts.num_threads)); } // Initial invariant AbstractDomain init_inv = make_initial_abstract_value(_ctx); // Initialize global variables { log::debug("Computing global variable static initialization"); GlobalsInitPolicy policy = _ctx.opts.globals_init_policy; // Setup a progress logger std::unique_ptr< analyzer::ProgressLogger > logger = make_progress_logger(_ctx.opts.progress, LogLevel::Debug, /* num_tasks = */ std::count_if(bundle->global_begin(), bundle->global_end(), [=](ar::GlobalVariable* gv) { return gv->is_definition() && is_initialized(gv, policy); })); ScopeLogger scope(*logger); for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { ar::GlobalVariable* gv = *it; if (gv->is_definition() && is_initialized(gv, policy)) { logger->start_task("Initializing global variable '" + demangle(gv->name()) + "'"); sequential::GlobalVarInitializerFixpoint fixpoint(_ctx, gv); fixpoint.run(init_inv); init_inv = fixpoint.exit_invariant(); } } } if (_ctx.opts.display_invariants == DisplayOption::All) { LogMessage msg = log::msg(); msg << "Invariant after global variable static initialization:\n"; init_inv.dump(msg.stream()); msg << "\n"; } // Call global constructors ar::GlobalVariable* gv_ctors = bundle->global_or_null("ar.global_ctors"); if (gv_ctors != nullptr) { log::info("Computing global variable dynamic initialization"); std::vector< std::pair< ar::Function*, MachineInt > > ctors = global_ctors(gv_ctors); for (const auto& entry : ctors) { ar::Function* ctor = entry.first; if (ctor->is_declaration()) { log::error("global constructor '" + ctor->name() + "' is extern"); continue; } // Create a function fixpoint FunctionFixpoint fixpoint(_ctx, checkers, ctor); { log::info("Analyzing global constructor '" + demangle(ctor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + ctor->name()); fixpoint.run(init_inv); } if (!checkers.empty()) { log::info("Checking properties for global constructor '" + demangle(ctor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + ctor->name()); fixpoint.run_checks(); } init_inv = fixpoint.exit_invariant(); } if (_ctx.opts.display_invariants == DisplayOption::All) { LogMessage msg = log::msg(); msg << "Invariant after global variable dynamic initialization:\n"; init_inv.dump(msg.stream()); msg << "\n"; } } // Analyze each entry point for (ar::Function* entry_point : _ctx.opts.entry_points) { if (!entry_point->is_definition()) { log::error("missing implementation of function '" + entry_point->name() + "'"); continue; } // Entry point initial invariant AbstractDomain entry_inv = make_bottom_abstract_value(_ctx); if (std::find(_ctx.opts.no_init_globals.begin(), _ctx.opts.no_init_globals.end(), entry_point) == _ctx.opts.no_init_globals.end()) { // Use invariant with initialized global variables entry_inv = init_inv; } else { // Default invariant entry_inv = make_initial_abstract_value(_ctx); } if (entry_point->name() == "main" && entry_point->num_parameters() >= 2) { entry_inv = init_main_invariant(_ctx, entry_point, entry_inv); } // Create a function fixpoint FunctionFixpoint fixpoint(_ctx, checkers, entry_point); { log::info("Analyzing entry point '" + demangle(entry_point->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + entry_point->name()); fixpoint.run(entry_inv); } if (!checkers.empty()) { log::info("Checking properties for entry point '" + demangle(entry_point->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + entry_point->name()); fixpoint.run_checks(); } } // Call global destructors ar::GlobalVariable* gv_dtors = bundle->global_or_null("ar.global_dtors"); if (gv_dtors != nullptr) { log::info("Analyzing global destructors"); std::vector< std::pair< ar::Function*, MachineInt > > dtors = global_dtors(gv_dtors); for (const auto& entry : dtors) { ar::Function* dtor = entry.first; if (dtor->is_declaration()) { log::error("global destructor '" + dtor->name() + "' is extern"); continue; } // Create a function fixpoint FunctionFixpoint fixpoint(_ctx, checkers, dtor); { log::info("Analyzing global destructor '" + demangle(dtor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + dtor->name()); // Note: We currently analyze destructors with the initial invariant fixpoint.run(init_inv); } if (!checkers.empty()) { log::info("Checking properties for global destructor: '" + demangle(dtor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + dtor->name()); fixpoint.run_checks(); } init_inv = fixpoint.exit_invariant(); } } // Insert all functions in the database for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { _ctx.output_db->functions.insert(*it); } } } // end namespace concurrent } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.cpp000066400000000000000000000254621473507761200337600ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/concurrent/******************************************************************************* * * \file * \brief Concurrent fixpoint on a function body * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace concurrent { namespace { /// \brief Numerical execution engine using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; /// \brief Call execution engine using ConcurrentInlineCallExecutionEngineT = ConcurrentInlineCallExecutionEngine< FunctionFixpoint, AbstractDomain >; } // end anonymous namespace FunctionFixpoint::FunctionFixpoint( Context& ctx, const std::vector< std::unique_ptr< Checker > >& checkers, ar::Function* entry_point) : FwdFixpointIterator(entry_point->body(), make_bottom_abstract_value(ctx)), _ctx(ctx), _function(entry_point), _call_context(ctx.call_context_factory->get_empty()), _fixpoint_parameters(ctx.fixpoint_parameters->get(entry_point)), _checkers(checkers), _exit_invariant(make_bottom_abstract_value(ctx)), _return_stmt(nullptr) {} FunctionFixpoint::FunctionFixpoint(Context& ctx, const FunctionFixpoint& caller, ar::CallBase* call, ar::Function* callee) : FwdFixpointIterator(callee->body(), make_bottom_abstract_value(ctx)), _ctx(ctx), _function(callee), _call_context( ctx.call_context_factory->get_context(caller._call_context, call)), _fixpoint_parameters(ctx.fixpoint_parameters->get(callee)), _checkers(caller._checkers), _exit_invariant(make_bottom_abstract_value(ctx)), _return_stmt(nullptr) {} void FunctionFixpoint::run(AbstractDomain inv) { FwdFixpointIterator::run(std::move(inv)); } AbstractDomain FunctionFixpoint::extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { if (iteration <= this->_fixpoint_parameters.widening_delay) { // Fixed number of iterations using join return before.join_iter(after); } iteration -= this->_fixpoint_parameters.widening_delay; iteration--; if (iteration % this->_fixpoint_parameters.widening_period != 0) { // Not the period, iteration using join return before.join_iter(after); } switch (this->_fixpoint_parameters.widening_strategy) { case WideningStrategy::Widen: { if (iteration == 0) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // One iteration using widening with threshold return before.widening_threshold(after, *threshold); } } // Iterations using widening until convergence return before.widening(after); } case WideningStrategy::Join: { // Iterations using join until convergence return before.join_iter(after); } default: { ikos_unreachable("unexpected strategy"); } } } AbstractDomain FunctionFixpoint::refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { switch (this->_fixpoint_parameters.narrowing_strategy) { case NarrowingStrategy::Narrow: { if (iteration == 1) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // First iteration using narrowing with threshold return before.narrowing_threshold(after, *threshold); } } // Iterations using narrowing return before.narrowing(after); } case NarrowingStrategy::Meet: { // Iterations using meet return before.meet(after); } default: { ikos_unreachable("unexpected strategy"); } } } bool FunctionFixpoint::is_decreasing_iterations_fixpoint( ar::BasicBlock* /*head*/, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { // Check if we reached the number of requested iterations, or convergence return (this->_fixpoint_parameters.narrowing_iterations && iteration >= *this->_fixpoint_parameters.narrowing_iterations) || before.leq(after); } AbstractDomain FunctionFixpoint::analyze_node(ar::BasicBlock* bb, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); ConcurrentInlineCallExecutionEngineT call_exec_engine(this->_ctx, exec_engine, *this, this->_callees_cache); exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); return std::move(exec_engine.inv()); } AbstractDomain FunctionFixpoint::analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); exec_engine.exec_edge(src, dest); return std::move(exec_engine.inv()); } void FunctionFixpoint::process_pre(ar::BasicBlock* /*bb*/, const AbstractDomain& /*pre*/) {} void FunctionFixpoint::process_post(ar::BasicBlock* bb, const AbstractDomain& post) { if (this->_function->body()->exit_block_or_null() == bb) { NumericalExecutionEngineT exec_engine(post, this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); ConcurrentInlineCallExecutionEngineT call_exec_engine(this->_ctx, exec_engine, *this, this->_callees_cache); call_exec_engine.exec_exit(this->_function); } } void FunctionFixpoint::run_checks() { for (ar::BasicBlock* bb : *this->cfg()) { NumericalExecutionEngineT exec_engine(this->pre(bb), this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); ConcurrentInlineCallExecutionEngineT call_exec_engine(this->_ctx, exec_engine, *this, this->_callees_cache); // Check called functions during the transfer function call_exec_engine.mark_check_callees(); exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { // Check the statement if it's related to an llvm instruction if (stmt->has_frontend()) { exec_engine.inv().normalize(); for (const auto& checker : this->_checkers) { checker->check(stmt, exec_engine.inv(), this->_call_context); } } // Propagate transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); } } } // end namespace concurrent } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/init_invariant.cpp000066400000000000000000000110071473507761200311140ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Initial invariant for the interprocedural value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { AbstractDomain init_main_invariant(Context& ctx, ar::Function* main, AbstractDomain inv) { const ScalarLit& argc = ctx.lit_factory->get_scalar(main->param(0)); const ScalarLit& argv = ctx.lit_factory->get_scalar(main->param(1)); if (!argc.is_machine_int_var()) { log::warning("unexpected type for first argument of main"); return inv; } if (!argv.is_pointer_var()) { log::warning("unexpected type for second argument of main"); return inv; } // Set argc auto argc_type = cast< ar::IntegerType >(main->param(0)->type()); if (ctx.opts.argc) { // Add `argc = ctx.opts.argc` inv.normal().int_assign(argc.var(), MachineInt(*ctx.opts.argc, argc_type->bit_width(), argc_type->sign())); } else { // Add `argc >= 0` inv.normal().int_assign_nondet(argc.var()); inv.normal().int_add(core::machine_int::Predicate::GE, argc.var(), MachineInt::zero(argc_type->bit_width(), argc_type->sign())); } // Set argv ArgvMemoryLocation* argv_mem_loc = ctx.mem_factory->get_argv(); inv.normal().pointer_assign(argv.var(), argv_mem_loc, core::Nullity::non_null()); if (ctx.opts.argc) { // Add size of argv array const ar::DataLayout& dl = ctx.bundle->data_layout(); uint64_t pointer_size = dl.pointers.bit_width / 8; uint64_t argv_size = pointer_size * (static_cast< uint64_t >(*ctx.opts.argc) + 1U); Variable* alloc_size_var = ctx.var_factory->get_alloc_size(argv_mem_loc); inv.normal().int_assign(alloc_size_var, MachineInt(argv_size, dl.pointers.bit_width, Unsigned)); // TODO(marthaud): Create memory locations for argv[i] and set the size >= 1 } return inv; } } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/sequential/000077500000000000000000000000001473507761200275455ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/sequential/analysis.cpp000066400000000000000000000241311473507761200320750ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Interprocedural value analysis implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { Analysis::Analysis(Context& ctx) : _ctx(ctx) {} Analysis::~Analysis() = default; void Analysis::run() { // Bundle ar::Bundle* bundle = _ctx.bundle; // Create checkers std::vector< std::unique_ptr< Checker > > checkers; if (_ctx.opts.use_checks) { for (CheckerName name : _ctx.opts.analyses) { checkers.emplace_back(make_checker(_ctx, name)); } } // Initial invariant AbstractDomain init_inv = make_initial_abstract_value(_ctx); // Initialize global variables { log::debug("Computing global variable static initialization"); GlobalsInitPolicy policy = _ctx.opts.globals_init_policy; // Setup a progress logger std::unique_ptr< analyzer::ProgressLogger > logger = make_progress_logger(_ctx.opts.progress, LogLevel::Debug, /* num_tasks = */ std::count_if(bundle->global_begin(), bundle->global_end(), [=](ar::GlobalVariable* gv) { return gv->is_definition() && is_initialized(gv, policy); })); ScopeLogger scope(*logger); for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { ar::GlobalVariable* gv = *it; if (gv->is_definition() && is_initialized(gv, policy)) { logger->start_task("Initializing global variable '" + demangle(gv->name()) + "'"); GlobalVarInitializerFixpoint fixpoint(_ctx, gv); fixpoint.run(init_inv); init_inv = fixpoint.exit_invariant(); } } } if (_ctx.opts.display_invariants == DisplayOption::All) { LogMessage msg = log::msg(); msg << "Invariant after global variable static initialization:\n"; init_inv.dump(msg.stream()); msg << "\n"; } // Call global constructors ar::GlobalVariable* gv_ctors = bundle->global_or_null("ar.global_ctors"); if (gv_ctors != nullptr) { log::info("Computing global variable dynamic initialization"); std::vector< std::pair< ar::Function*, MachineInt > > ctors = global_ctors(gv_ctors); for (const auto& entry : ctors) { ar::Function* ctor = entry.first; if (ctor->is_declaration()) { log::error("global constructor '" + ctor->name() + "' is extern"); continue; } // Setup a progress logger std::unique_ptr< sequential::ProgressLogger > logger = make_progress_logger(_ctx, _ctx.opts.progress, LogLevel::Info); ScopeLogger scope(*logger); // Create a function fixpoint FunctionFixpoint fixpoint(_ctx, checkers, *logger, ctor); { log::info("Analyzing global constructor '" + demangle(ctor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + ctor->name()); fixpoint.run(init_inv); } if (!checkers.empty()) { log::info("Checking properties for global constructor '" + demangle(ctor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + ctor->name()); fixpoint.run_checks(); } init_inv = fixpoint.exit_invariant(); } if (_ctx.opts.display_invariants == DisplayOption::All) { LogMessage msg = log::msg(); msg << "Invariant after global variable dynamic initialization:\n"; init_inv.dump(msg.stream()); msg << "\n"; } } // Analyze each entry point for (ar::Function* entry_point : _ctx.opts.entry_points) { if (!entry_point->is_definition()) { log::error("missing implementation of function '" + entry_point->name() + "'"); continue; } // Entry point initial invariant AbstractDomain entry_inv = make_bottom_abstract_value(_ctx); if (std::find(_ctx.opts.no_init_globals.begin(), _ctx.opts.no_init_globals.end(), entry_point) == _ctx.opts.no_init_globals.end()) { // Use invariant with initialized global variables entry_inv = init_inv; } else { // Default invariant entry_inv = make_initial_abstract_value(_ctx); } if (entry_point->name() == "main" && entry_point->num_parameters() >= 2) { entry_inv = init_main_invariant(_ctx, entry_point, entry_inv); } // Setup a progress logger std::unique_ptr< sequential::ProgressLogger > logger = make_progress_logger(_ctx, _ctx.opts.progress, LogLevel::Info); ScopeLogger scope(*logger); // Create a function fixpoint FunctionFixpoint fixpoint(_ctx, checkers, *logger, entry_point); { log::info("Analyzing entry point '" + demangle(entry_point->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + entry_point->name()); fixpoint.run(entry_inv); } if (!checkers.empty()) { log::info("Checking properties for entry point '" + demangle(entry_point->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + entry_point->name()); fixpoint.run_checks(); } } // Call global destructors ar::GlobalVariable* gv_dtors = bundle->global_or_null("ar.global_dtors"); if (gv_dtors != nullptr) { log::info("Analyzing global destructors"); std::vector< std::pair< ar::Function*, MachineInt > > dtors = global_dtors(gv_dtors); for (const auto& entry : dtors) { ar::Function* dtor = entry.first; if (dtor->is_declaration()) { log::error("global destructor '" + dtor->name() + "' is extern"); continue; } // Setup a progress logger std::unique_ptr< sequential::ProgressLogger > logger = make_progress_logger(_ctx, _ctx.opts.progress, LogLevel::Info); ScopeLogger scope(*logger); // Create a function fixpoint FunctionFixpoint fixpoint(_ctx, checkers, *logger, dtor); { log::info("Analyzing global destructor '" + demangle(dtor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + dtor->name()); // Note: We currently analyze destructors with the initial invariant fixpoint.run(init_inv); } if (!checkers.empty()) { log::info("Checking properties for global destructor: '" + demangle(dtor->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + dtor->name()); fixpoint.run_checks(); } init_inv = fixpoint.exit_invariant(); } } // Insert all functions in the database for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { _ctx.output_db->functions.insert(*it); } } } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.cpp000066400000000000000000000350311473507761200337410ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/sequential/******************************************************************************* * * \file * \brief Sequential interprocedural fixpoint on a function body * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { namespace { /// \brief Numerical execution engine using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; /// \brief Call execution engine using InlineCallExecutionEngineT = InlineCallExecutionEngine< FunctionFixpoint, AbstractDomain >; } // end anonymous namespace FunctionFixpoint::FunctionFixpoint( Context& ctx, const std::vector< std::unique_ptr< Checker > >& checkers, ProgressLogger& logger, ar::Function* entry_point) : FwdFixpointIterator(entry_point->body(), make_bottom_abstract_value(ctx)), _ctx(ctx), _function(entry_point), _call_context(ctx.call_context_factory->get_empty()), _fixpoint_parameters(ctx.fixpoint_parameters->get(entry_point)), _checkers(checkers), _exit_invariant(make_bottom_abstract_value(ctx)), _return_stmt(nullptr), _logger(logger), _namer() { if (_ctx.opts.trace_ar_statements) { this->_namer = std::make_unique< ar::Namer >(entry_point->body()); auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << "\n>>>>>>>>>>>>>>\nEntering Interprocedural Sequential " "FunctionFixpoint for "; ar::TextFormatter().format_header(stream, _function, *_namer); stream << std::endl; } } FunctionFixpoint::FunctionFixpoint(Context& ctx, const FunctionFixpoint& caller, ar::CallBase* call, ar::Function* callee) : FwdFixpointIterator(callee->body(), make_bottom_abstract_value(ctx)), _ctx(ctx), _function(callee), _call_context( ctx.call_context_factory->get_context(caller._call_context, call)), _fixpoint_parameters(ctx.fixpoint_parameters->get(callee)), _checkers(caller._checkers), _exit_invariant(make_bottom_abstract_value(ctx)), _return_stmt(nullptr), _logger(caller._logger), _namer() { if (_ctx.opts.trace_ar_statements) { this->_namer = std::make_unique< ar::Namer >(callee->body()); ar::TextFormatter formatter{}; auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << "\n>>>>>>>>>>>>>>\nEntering Interprocedural Sequential " "FunctionFixpoint for "; formatter.format_header(stream, _function, *_namer); msg << "\n from caller "; formatter.format_header(stream, caller._function, *_namer); msg << "\n from call site "; call->dump(stream); stream << std::endl; } } FunctionFixpoint::~FunctionFixpoint() { if (_ctx.opts.trace_ar_statements) { auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << "\n<<<<<<<<<<\nExiting Interprocedural Sequential FunctionFixpoint " "for "; ar::TextFormatter().format_header(stream, _function, *_namer); stream << std::endl; } } void FunctionFixpoint::run(AbstractDomain inv) { if (!this->_call_context->empty()) { this->_logger.start_callee(this->_call_context, this->_function); } // Compute the fixpoint FwdFixpointIterator::run(std::move(inv)); // Clear post invariants, save a lot of memory this->clear_post(); if (!this->_call_context->empty()) { this->_logger.end_callee(this->_call_context, this->_function); } } AbstractDomain FunctionFixpoint::extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { if (iteration <= this->_fixpoint_parameters.widening_delay) { // Fixed number of iterations using join return before.join_iter(after); } iteration -= this->_fixpoint_parameters.widening_delay; iteration--; if (iteration % this->_fixpoint_parameters.widening_period != 0) { // Not the period, iteration using join return before.join_iter(after); } switch (this->_fixpoint_parameters.widening_strategy) { case WideningStrategy::Widen: { if (iteration == 0) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // One iteration using widening with threshold return before.widening_threshold(after, *threshold); } } // Iterations using widening until convergence return before.widening(after); } case WideningStrategy::Join: { // Iterations using join until convergence return before.join_iter(after); } default: { ikos_unreachable("unexpected strategy"); } } } AbstractDomain FunctionFixpoint::refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { switch (this->_fixpoint_parameters.narrowing_strategy) { case NarrowingStrategy::Narrow: { if (iteration == 1) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // First iteration using narrowing with threshold return before.narrowing_threshold(after, *threshold); } } // Iterations using narrowing return before.narrowing(after); } case NarrowingStrategy::Meet: { // Iterations using meet return before.meet(after); } default: { ikos_unreachable("unexpected strategy"); } } } bool FunctionFixpoint::is_decreasing_iterations_fixpoint( ar::BasicBlock* /*head*/, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { // Check if we reached the number of requested iterations, or convergence return (this->_fixpoint_parameters.narrowing_iterations && iteration >= *this->_fixpoint_parameters.narrowing_iterations) || before.leq(after); } AbstractDomain FunctionFixpoint::analyze_node(ar::BasicBlock* bb, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); InlineCallExecutionEngineT call_exec_engine(this->_ctx, exec_engine, *this, this->_callees_cache); exec_engine.exec_enter(bb); if (_ctx.opts.trace_ar_statements) { auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << "Entering basic block: "; bb->dump(stream); stream << std::endl; msg << " Invariant on entry to basic block:"; stream << std::endl; exec_engine.inv().dump(stream); stream << std::endl; } for (ar::Statement* stmt : *bb) { if (_ctx.opts.trace_ar_statements) { auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << "Processing: "; stmt->dump(stream); stream << std::endl; } transfer_function(exec_engine, call_exec_engine, stmt); if (_ctx.opts.trace_ar_statements) { auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << " Invariant after: "; exec_engine.inv().dump(stream); stream << std::endl; } } exec_engine.exec_leave(bb); return std::move(exec_engine.inv()); } AbstractDomain FunctionFixpoint::analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); exec_engine.exec_edge(src, dest); return std::move(exec_engine.inv()); } void FunctionFixpoint::notify_enter_cycle(ar::BasicBlock* head) { this->_logger.start_cycle(head); } void FunctionFixpoint::notify_cycle_iteration( ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) { this->_logger.start_cycle_iter(head, iteration, kind); } void FunctionFixpoint::notify_leave_cycle(ar::BasicBlock* head) { this->_logger.end_cycle(head); } void FunctionFixpoint::process_pre(ar::BasicBlock* /*bb*/, const AbstractDomain& /*pre*/) {} void FunctionFixpoint::process_post(ar::BasicBlock* bb, const AbstractDomain& post) { if (this->_function->body()->exit_block_or_null() == bb) { NumericalExecutionEngineT exec_engine(post, this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); InlineCallExecutionEngineT call_exec_engine(this->_ctx, exec_engine, *this, this->_callees_cache); call_exec_engine.exec_exit(this->_function); } } void FunctionFixpoint::run_checks() { if (!this->_call_context->empty()) { this->_logger.start_callee(this->_call_context, this->_function); } for (ar::BasicBlock* bb : *this->cfg()) { NumericalExecutionEngineT exec_engine(this->pre(bb), this->_ctx, this->_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); InlineCallExecutionEngineT call_exec_engine(this->_ctx, exec_engine, *this, this->_callees_cache); // Check called functions during the transfer function call_exec_engine.mark_check_callees(); exec_engine.exec_enter(bb); if (_ctx.opts.trace_ar_statements) { auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << "Entering basic block in run_checks: "; bb->dump(stream); stream << std::endl; msg << " Invariant on entry to basic block:"; stream << std::endl; exec_engine.inv().dump(stream); stream << std::endl; } for (ar::Statement* stmt : *bb) { if (_ctx.opts.trace_ar_statements) { auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << "Checking: "; stmt->dump(stream); stream << std::endl; } // Check the statement if it's related to an llvm instruction if (stmt->has_frontend()) { exec_engine.inv().normalize(); for (const auto& checker : this->_checkers) { checker->check(stmt, exec_engine.inv(), this->_call_context); } } // Propagate transfer_function(exec_engine, call_exec_engine, stmt); if (_ctx.opts.trace_ar_statements) { auto msg = analyzer::log::msg(); auto& stream = msg.stream(); msg << " In run_checks, invariant after: "; exec_engine.inv().dump(stream); stream << std::endl; } } exec_engine.exec_leave(bb); } if (!this->_call_context->empty()) { this->_logger.end_callee(this->_call_context, this->_function); } } } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos global_init_fixpoint.cpp000066400000000000000000000143141473507761200344000ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/sequential/******************************************************************************* * * \file * \brief Fixpoint on a global variable initializer * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { GlobalVarInitializerFixpoint::GlobalVarInitializerFixpoint( Context& ctx, ar::GlobalVariable* gv) : FwdFixpointIterator(gv->initializer(), make_bottom_abstract_value(ctx)), _gv(gv), _ctx(ctx), _empty_call_context(ctx.call_context_factory->get_empty()) {} void GlobalVarInitializerFixpoint::run(AbstractDomain inv) { // Allocate memory for the global variable NumericalExecutionEngineT exec_engine(std::move(inv), _ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ _ctx.liveness, /* pointer_info = */ _ctx.pointer == nullptr ? nullptr : &_ctx.pointer->results()); exec_engine .allocate_memory(_ctx.var_factory->get_global(_gv), _ctx.mem_factory->get_global(_gv), core::Nullity::non_null(), core::Lifetime::top(), NumericalExecutionEngineT::MemoryInitialValue::Zero); // Compute the fixpoint FwdFixpointIterator::run(std::move(exec_engine.inv())); } AbstractDomain GlobalVarInitializerFixpoint::analyze_node(ar::BasicBlock* bb, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), _ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ _ctx.liveness, /* pointer_info = */ _ctx.pointer == nullptr ? nullptr : &_ctx.pointer->results()); GlobalVarCallExecutionEngine call_exec_engine; exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); return std::move(exec_engine.inv()); } AbstractDomain GlobalVarInitializerFixpoint::analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), _ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ _ctx.liveness, /* pointer_info = */ _ctx.pointer == nullptr ? nullptr : &_ctx.pointer->results()); exec_engine.exec_edge(src, dest); return std::move(exec_engine.inv()); } void GlobalVarInitializerFixpoint::process_pre(ar::BasicBlock* /*bb*/, const AbstractDomain& /*pre*/) {} void GlobalVarInitializerFixpoint::process_post( ar::BasicBlock* /*bb*/, const AbstractDomain& /*post*/) {} const AbstractDomain& GlobalVarInitializerFixpoint::exit_invariant() const { ar::Code* code = this->cfg(); ikos_assert_msg(code->has_exit_block(), "initializer without exit block"); return this->post(code->exit_block()); } } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/interprocedural/sequential/progress.cpp000066400000000000000000000337221473507761200321240ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Progress logging utilities for the interprocedural value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace interprocedural { namespace sequential { // ProgressLogger ProgressLogger::ProgressLogger(std::ostream& out, Context& ctx) : Logger(out), _ctx(ctx) {} // InteractiveProgressLogger constexpr const std::chrono::seconds InteractiveProgressLogger::RefreshRate; InteractiveProgressLogger::InteractiveProgressLogger(std::ostream& out, Context& ctx, std::size_t out_columns) : ProgressLogger(out, ctx), _out_columns(std::max(out_columns, std::size_t{4})), _running(false) {} InteractiveProgressLogger::~InteractiveProgressLogger() { if (this->_thread.joinable()) { // Ask the thread to stop running this->_running = false; // Notify the thread this->_event.notify_all(); // Stop the progress thread nicely this->_thread.join(); } } void InteractiveProgressLogger::start_logger() { // Sanity checks ikos_assert(!this->_thread.joinable()); ikos_assert(!this->_running); ikos_assert(this->_current_stack_frame.empty()); ikos_assert(this->_displayed_stack_frame.empty()); // Notify the thread to keep running this->_running = true; // Start the progress thread this->_thread = std::thread(&InteractiveProgressLogger::run, this); } void InteractiveProgressLogger::end_logger() { // Sanity checks ikos_assert(this->_thread.joinable()); ikos_assert(this->_running); // Ask the thread to stop running this->_running = false; // Notify the thread this->_event.notify_all(); // Stop the progress thread nicely this->_thread.join(); // Clear the stack frames (no need to lock the mutex here) this->_current_stack_frame.clear(); this->_displayed_stack_frame.clear(); } void InteractiveProgressLogger::start_cycle(ar::BasicBlock* head) { std::lock_guard< std::mutex > lock(this->_mutex); this->_current_stack_frame.emplace_back( CycleFrame{head, 0, core::FixpointIterationKind::Increasing}); } void InteractiveProgressLogger::start_cycle_iter( ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) { std::lock_guard< std::mutex > lock(this->_mutex); this->_current_stack_frame.pop_back(); this->_current_stack_frame.emplace_back(CycleFrame{head, iteration, kind}); } void InteractiveProgressLogger::end_cycle(ar::BasicBlock* /*head*/) { std::lock_guard< std::mutex > lock(this->_mutex); this->_current_stack_frame.pop_back(); } void InteractiveProgressLogger::start_callee(CallContext* call_context, ar::Function* fun) { std::lock_guard< std::mutex > lock(this->_mutex); this->_current_stack_frame.emplace_back(CallFrame{call_context, fun}); } void InteractiveProgressLogger::end_callee(CallContext* /*call_context*/, ar::Function* /*fun*/) { std::lock_guard< std::mutex > lock(this->_mutex); this->_current_stack_frame.pop_back(); } void InteractiveProgressLogger::start_message() { // Lock the mutex, unlock in end_message() this->_mutex.lock(); // Clear the displayed stack frame this->clear_displayed_stack_frame(); } void InteractiveProgressLogger::end_message() { // Unlock the mutex this->_mutex.unlock(); } void InteractiveProgressLogger::run() { // Required by std::condition_variable std::mutex event_mutex; std::unique_lock< std::mutex > event_lock(event_mutex); while (this->_running) { this->_event.wait_for(event_lock, RefreshRate); if (!this->_running) { break; } { std::lock_guard< std::mutex > lock(this->_mutex); this->print_stack_frame(); } } { std::lock_guard< std::mutex > lock(this->_mutex); this->clear_displayed_stack_frame(); } } void InteractiveProgressLogger::print_stack_frame() { // Precondition: the current thread owns the mutex // Clear the previous stack frame this->clear_displayed_stack_frame(); // Print the new stack frame for (auto begin = this->_current_stack_frame.begin(), end = this->_current_stack_frame.end(), it = begin; it != end; ++it) { if (it != begin) { this->_out << "\n"; } this->print_frame(*it); } // Flush this->_out.flush(); // Update state this->_displayed_stack_frame = this->_current_stack_frame; } /// \brief Return the source location of the given statement using analyzer::source_location; /// \brief Return the source location of the given basic block static SourceLocation source_location(ar::BasicBlock* entry) { llvm::SmallVector< ar::BasicBlock*, 4 > worklist; llvm::SmallPtrSet< ar::BasicBlock*, 4 > seen; worklist.push_back(entry); // Find the first statement with a source location while (!worklist.empty()) { ar::BasicBlock* bb = worklist.back(); worklist.pop_back(); if (!seen.insert(bb).second) { continue; } for (ar::Statement* stmt : *bb) { SourceLocation loc = source_location(stmt); if (loc) { return loc; } } for (auto it = bb->predecessor_begin(), et = bb->predecessor_end(); it != et; ++it) { worklist.push_back(*it); } } return {}; } /// \brief Return a call frame as a string static std::string call_frame_string(CallContext* call_context, ar::Function* function, const boost::filesystem::path& wd) { auto loc = source_location(call_context->call()); std::string r = source_location_string(loc, wd); r += ": Analyzing called function '"; r += demangle(function->name()); r += "'"; return r; } /// \brief Return a cycle frame as a string static std::string cycle_frame_string(ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind, const boost::filesystem::path& wd) { auto loc = source_location(head); std::string r = source_location_string(loc, wd); r += ": Analyzing loop [iteration "; r += std::to_string(iteration); switch (kind) { case core::FixpointIterationKind::Increasing: { r += "↑"; } break; case core::FixpointIterationKind::Decreasing: { r += "↓"; } break; default: { ikos_unreachable("unreachable"); } } r += ']'; return r; } void InteractiveProgressLogger::print_frame(const Frame& frame) { // Return a string for the given frame struct FrameVisitor : public boost::static_visitor< std::string > { private: const boost::filesystem::path& _wd; public: explicit FrameVisitor(const boost::filesystem::path& wd) : _wd(wd) {} std::string operator()(const CallFrame& call) const { return call_frame_string(call.call_context, call.function, this->_wd); } std::string operator()(const CycleFrame& cycle) const { return cycle_frame_string(cycle.head, cycle.iteration, cycle.kind, this->_wd); } }; // Generate a string for the given frame FrameVisitor vis(this->_ctx.wd); std::string line = boost::apply_visitor(vis, frame); // Truncate, if needed if (line.length() + 2 > this->_out_columns) { line.resize(this->_out_columns - 4); line += ".."; } // Print the line this->_out << color::bold_blue() << "> " << color::off() << line; } void InteractiveProgressLogger::clear_displayed_stack_frame() { // Precondition: the current thread owns the mutex if (this->_displayed_stack_frame.empty()) { return; } // The cursor is at the end of the last line of the stack frame // Move cursor to the beginning of the line this->_out << "\r"; if (this->_displayed_stack_frame.size() > 1) { // Move cursor up `size - 1` lines this->_out << "\033[" << (this->_displayed_stack_frame.size() - 1) << "A"; } // Clear everything down this->_out << "\033[J"; this->_out.flush(); this->_displayed_stack_frame.clear(); } // LinearProgressLogger LinearProgressLogger::LinearProgressLogger(std::ostream& out, Context& ctx) : ProgressLogger(out, ctx) {} void LinearProgressLogger::start_cycle(ar::BasicBlock* /*head*/) {} void LinearProgressLogger::start_cycle_iter(ar::BasicBlock* head, unsigned iteration, core::FixpointIterationKind kind) { this->_out << color::bold_blue() << "> " << color::off() << cycle_frame_string(head, iteration, kind, this->_ctx.wd) << "\n" << std::flush; } void LinearProgressLogger::end_cycle(ar::BasicBlock* /*head*/) {} void LinearProgressLogger::start_callee(CallContext* call_context, ar::Function* fun) { this->_out << color::bold_blue() << "> " << color::off() << call_frame_string(call_context, fun, this->_ctx.wd) << "\n" << std::flush; } void LinearProgressLogger::end_callee(CallContext* /*call_context*/, ar::Function* /*fun*/) {} void LinearProgressLogger::start_logger() {} void LinearProgressLogger::end_logger() { this->_out.flush(); } void LinearProgressLogger::start_message() {} void LinearProgressLogger::end_message() { this->_out.flush(); } // NoProgressLogger NoProgressLogger::NoProgressLogger(std::ostream& out, Context& ctx) : ProgressLogger(out, ctx) {} void NoProgressLogger::start_cycle(ar::BasicBlock* /*head*/) {} void NoProgressLogger::start_cycle_iter(ar::BasicBlock* /*head*/, unsigned /*iteration*/, core::FixpointIterationKind /*kind*/) {} void NoProgressLogger::end_cycle(ar::BasicBlock* /*head*/) {} void NoProgressLogger::start_callee(CallContext* /*call_context*/, ar::Function* /*fun*/) {} void NoProgressLogger::end_callee(CallContext* /*call_context*/, ar::Function* /*fun*/) {} void NoProgressLogger::start_logger() {} void NoProgressLogger::end_logger() { this->_out.flush(); } void NoProgressLogger::start_message() {} void NoProgressLogger::end_message() { this->_out.flush(); } // make_progress_logger std::unique_ptr< ProgressLogger > make_progress_logger(Context& ctx, ProgressOption opt, LogLevel level) { if (!log::is_enabled_for(level)) { return std::make_unique< NoProgressLogger >(std::cout, ctx); } switch (opt) { case ProgressOption::Auto: { if (llvm::sys::Process::StandardOutIsDisplayed()) { return std::make_unique< InteractiveProgressLogger >(std::cout, ctx, llvm::sys::Process:: StandardOutColumns()); } else { return std::make_unique< NoProgressLogger >(std::cout, ctx); } } case ProgressOption::Interactive: { return std::make_unique< InteractiveProgressLogger >(std::cout, ctx, llvm::sys::Process::StandardOutColumns()); } case ProgressOption::Linear: { return std::make_unique< LinearProgressLogger >(std::cout, ctx); } case ProgressOption::None: { return std::make_unique< NoProgressLogger >(std::cout, ctx); } default: { ikos_unreachable("unreachable"); } } } } // end namespace sequential } // end namespace interprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/intraprocedural/000077500000000000000000000000001473507761200253675ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/intraprocedural/concurrent/000077500000000000000000000000001473507761200275515ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/intraprocedural/concurrent/analysis.cpp000066400000000000000000000115401473507761200321010ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Concurrent intraprocedural value analysis implementation * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace concurrent { Analysis::Analysis(Context& ctx) : _ctx(ctx) {} Analysis::~Analysis() = default; void Analysis::run() { // Bundle ar::Bundle* bundle = _ctx.bundle; // Create checkers std::vector< std::unique_ptr< Checker > > checkers; if (_ctx.opts.use_checks) { for (CheckerName name : _ctx.opts.analyses) { checkers.emplace_back(make_checker(_ctx, name)); } } // Initial invariant AbstractDomain init_inv = make_initial_abstract_value(_ctx); // Setup a progress logger std::unique_ptr< ProgressLogger > progress = make_progress_logger(_ctx.opts.progress, LogLevel::Info, /* num_tasks = */ 2 * std::count_if(bundle->function_begin(), bundle->function_end(), [](ar::Function* fun) { return fun->is_definition(); })); ScopeLogger scope(*progress); // Analyze every function in the bundle for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* function = *it; // Insert the function in the database _ctx.output_db->functions.insert(function); if (!function->is_definition()) { continue; } FunctionFixpoint fixpoint(_ctx, function); { progress->start_task("Analyzing function '" + demangle(function->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + function->name()); fixpoint.run(init_inv); } if (!checkers.empty()) { progress->start_task("Checking properties for function '" + demangle(function->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + function->name()); fixpoint.run_checks(checkers); } } } } // end namespace concurrent } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.cpp000066400000000000000000000215021473507761200337430ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/intraprocedural/concurrent/******************************************************************************* * * \file * \brief Concurrent intraprocedural fixpoint on a function body * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace concurrent { namespace { /// \brief Numerical execution engine using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; /// \brief Call execution engine using ContextInsensitiveCallExecutionEngineT = ContextInsensitiveCallExecutionEngine< AbstractDomain >; } // end anonymous namespace FunctionFixpoint::FunctionFixpoint(Context& ctx, ar::Function* function) : FwdFixpointIterator(function->body(), make_bottom_abstract_value(ctx)), _ctx(ctx), _empty_call_context(ctx.call_context_factory->get_empty()), _fixpoint_parameters(ctx.fixpoint_parameters->get(function)) {} void FunctionFixpoint::run(AbstractDomain inv) { FwdFixpointIterator::run(std::move(inv)); } AbstractDomain FunctionFixpoint::extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { if (iteration <= this->_fixpoint_parameters.widening_delay) { // Fixed number of iterations using join return before.join_iter(after); } iteration -= this->_fixpoint_parameters.widening_delay; iteration--; if (iteration % this->_fixpoint_parameters.widening_period != 0) { // Not the period, iteration using join return before.join_iter(after); } switch (this->_fixpoint_parameters.widening_strategy) { case WideningStrategy::Widen: { if (iteration == 0) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // One iteration using widening with threshold return before.widening_threshold(after, *threshold); } } // Iterations using widening until convergence return before.widening(after); } case WideningStrategy::Join: { // Iterations using join until convergence return before.join_iter(after); } default: { ikos_unreachable("unexpected strategy"); } } } AbstractDomain FunctionFixpoint::refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { switch (this->_fixpoint_parameters.narrowing_strategy) { case NarrowingStrategy::Narrow: { if (iteration == 1) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // First iteration using narrowing with threshold return before.narrowing_threshold(after, *threshold); } } // Iterations using narrowing return before.narrowing(after); } case NarrowingStrategy::Meet: { // Iterations using meet return before.meet(after); } default: { ikos_unreachable("unexpected strategy"); } } } bool FunctionFixpoint::is_decreasing_iterations_fixpoint( ar::BasicBlock* /*head*/, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { // Check if we reached the number of requested iterations, or convergence return (this->_fixpoint_parameters.narrowing_iterations && iteration >= *this->_fixpoint_parameters.narrowing_iterations) || before.leq(after); } AbstractDomain FunctionFixpoint::analyze_node(ar::BasicBlock* bb, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); ContextInsensitiveCallExecutionEngineT call_exec_engine(exec_engine); exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); return std::move(exec_engine.inv()); } AbstractDomain FunctionFixpoint::analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); exec_engine.exec_edge(src, dest); return std::move(exec_engine.inv()); } void FunctionFixpoint::process_pre(ar::BasicBlock* /*bb*/, const AbstractDomain& /*pre*/) {} void FunctionFixpoint::process_post(ar::BasicBlock* /*bb*/, const AbstractDomain& /*post*/) {} void FunctionFixpoint::run_checks( const std::vector< std::unique_ptr< Checker > >& checkers) { for (ar::BasicBlock* bb : *this->cfg()) { NumericalExecutionEngineT exec_engine(this->pre(bb), this->_ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); ContextInsensitiveCallExecutionEngineT call_exec_engine(exec_engine); exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { // Check the statement if it's related to an llvm instruction if (stmt->has_frontend()) { exec_engine.inv().normalize(); for (const auto& checker : checkers) { checker->check(stmt, exec_engine.inv(), this->_empty_call_context); } } // Propagate transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); } } } // end namespace concurrent } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/intraprocedural/sequential/000077500000000000000000000000001473507761200275415ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/intraprocedural/sequential/analysis.cpp000066400000000000000000000115041473507761200320710ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Sequential intraprocedural value analysis implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace sequential { Analysis::Analysis(Context& ctx) : _ctx(ctx) {} Analysis::~Analysis() = default; void Analysis::run() { // Bundle ar::Bundle* bundle = _ctx.bundle; // Create checkers std::vector< std::unique_ptr< Checker > > checkers; if (_ctx.opts.use_checks) { for (CheckerName name : _ctx.opts.analyses) { checkers.emplace_back(make_checker(_ctx, name)); } } // Initial invariant AbstractDomain init_inv = make_initial_abstract_value(_ctx); // Setup a progress logger std::unique_ptr< ProgressLogger > progress = make_progress_logger(_ctx.opts.progress, LogLevel::Info, /* num_tasks = */ 2 * std::count_if(bundle->function_begin(), bundle->function_end(), [](ar::Function* fun) { return fun->is_definition(); })); ScopeLogger scope(*progress); // Analyze every function in the bundle for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* function = *it; // Insert the function in the database _ctx.output_db->functions.insert(function); if (!function->is_definition()) { continue; } FunctionFixpoint fixpoint(_ctx, function); { progress->start_task("Analyzing function '" + demangle(function->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.value." + function->name()); fixpoint.run(init_inv); } if (!checkers.empty()) { progress->start_task("Checking properties for function '" + demangle(function->name()) + "'"); ScopeTimerDatabase t(_ctx.output_db->times, "ikos-analyzer.check." + function->name()); fixpoint.run_checks(checkers); } } } } // end namespace sequential } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos function_fixpoint.cpp000066400000000000000000000214411473507761200337350ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/intraprocedural/sequential/******************************************************************************* * * \file * \brief Sequential intraprocedural fixpoint on a function body * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { namespace value { namespace intraprocedural { namespace sequential { namespace { /// \brief Numerical execution engine using NumericalExecutionEngineT = NumericalExecutionEngine< AbstractDomain >; /// \brief Call execution engine using ContextInsensitiveCallExecutionEngineT = ContextInsensitiveCallExecutionEngine< AbstractDomain >; } // end anonymous namespace FunctionFixpoint::FunctionFixpoint(Context& ctx, ar::Function* function) : FwdFixpointIterator(function->body(), make_bottom_abstract_value(ctx)), _ctx(ctx), _empty_call_context(ctx.call_context_factory->get_empty()), _fixpoint_parameters(ctx.fixpoint_parameters->get(function)) {} void FunctionFixpoint::run(AbstractDomain inv) { FwdFixpointIterator::run(std::move(inv)); } AbstractDomain FunctionFixpoint::extrapolate(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { if (iteration <= this->_fixpoint_parameters.widening_delay) { // Fixed number of iterations using join return before.join_iter(after); } iteration -= this->_fixpoint_parameters.widening_delay; iteration--; if (iteration % this->_fixpoint_parameters.widening_period != 0) { // Not the period, iteration using join return before.join_iter(after); } switch (this->_fixpoint_parameters.widening_strategy) { case WideningStrategy::Widen: { if (iteration == 0) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // One iteration using widening with threshold return before.widening_threshold(after, *threshold); } } // Iterations using widening until convergence return before.widening(after); } case WideningStrategy::Join: { // Iterations using join until convergence return before.join_iter(after); } default: { ikos_unreachable("unexpected strategy"); } } } AbstractDomain FunctionFixpoint::refine(ar::BasicBlock* head, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { switch (this->_fixpoint_parameters.narrowing_strategy) { case NarrowingStrategy::Narrow: { if (iteration == 1) { if (auto threshold = this->_fixpoint_parameters.widening_hints.get(head)) { // First iteration using narrowing with threshold return before.narrowing_threshold(after, *threshold); } } // Iterations using narrowing return before.narrowing(after); } case NarrowingStrategy::Meet: { // Iterations using meet return before.meet(after); } default: { ikos_unreachable("unexpected strategy"); } } } bool FunctionFixpoint::is_decreasing_iterations_fixpoint( ar::BasicBlock* /*head*/, unsigned iteration, const AbstractDomain& before, const AbstractDomain& after) { // Check if we reached the number of requested iterations, or convergence return (this->_fixpoint_parameters.narrowing_iterations && iteration >= *this->_fixpoint_parameters.narrowing_iterations) || before.leq(after); } AbstractDomain FunctionFixpoint::analyze_node(ar::BasicBlock* bb, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); ContextInsensitiveCallExecutionEngineT call_exec_engine(exec_engine); exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); return std::move(exec_engine.inv()); } AbstractDomain FunctionFixpoint::analyze_edge(ar::BasicBlock* src, ar::BasicBlock* dest, AbstractDomain pre) { NumericalExecutionEngineT exec_engine(std::move(pre), this->_ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); exec_engine.exec_edge(src, dest); return std::move(exec_engine.inv()); } void FunctionFixpoint::process_pre(ar::BasicBlock* /*bb*/, const AbstractDomain& /*pre*/) {} void FunctionFixpoint::process_post(ar::BasicBlock* /*bb*/, const AbstractDomain& /*post*/) {} void FunctionFixpoint::run_checks( const std::vector< std::unique_ptr< Checker > >& checkers) { for (ar::BasicBlock* bb : *this->cfg()) { NumericalExecutionEngineT exec_engine(this->pre(bb), this->_ctx, this->_empty_call_context, ExecutionEngine::UpdateAllocSizeVar, /* liveness = */ this->_ctx.liveness, /* pointer_info = */ this->_ctx.pointer == nullptr ? nullptr : &this->_ctx.pointer->results()); ContextInsensitiveCallExecutionEngineT call_exec_engine(exec_engine); exec_engine.exec_enter(bb); for (ar::Statement* stmt : *bb) { // Check the statement if it's related to an llvm instruction if (stmt->has_frontend()) { exec_engine.inv().normalize(); for (const auto& checker : checkers) { checker->check(stmt, exec_engine.inv(), this->_empty_call_context); } } // Propagate transfer_function(exec_engine, call_exec_engine, stmt); } exec_engine.exec_leave(bb); } } } // end namespace sequential } // end namespace intraprocedural } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain.cpp000066400000000000000000000167211473507761200265110ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Machine integer abstract domain used by the value analysis * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { namespace value { MachineIntAbstractDomain make_top_machine_int_abstract_value( MachineIntDomainOption domain) { switch (domain) { case MachineIntDomainOption::Interval: return make_top_machine_int_interval(); case MachineIntDomainOption::Congruence: return make_top_machine_int_congruence(); case MachineIntDomainOption::IntervalCongruence: return make_top_machine_int_interval_congruence(); case MachineIntDomainOption::DBM: return make_top_machine_int_dbm(); case MachineIntDomainOption::VarPackDBM: return make_top_machine_int_var_pack_dbm(); case MachineIntDomainOption::VarPackDBMCongruence: return make_top_machine_int_var_pack_dbm_congruence(); case MachineIntDomainOption::Gauge: return make_top_machine_int_gauge(); case MachineIntDomainOption::GaugeIntervalCongruence: return make_top_machine_int_gauge_interval_congruence(); case MachineIntDomainOption::ApronInterval: return make_top_machine_int_apron_interval(); case MachineIntDomainOption::ApronOctagon: return make_top_machine_int_apron_octagon(); case MachineIntDomainOption::ApronPolkaPolyhedra: return make_top_machine_int_apron_polka_polyhedra(); case MachineIntDomainOption::ApronPolkaLinearEqualities: return make_top_machine_int_apron_polka_linear_equalities(); case MachineIntDomainOption::ApronPplPolyhedra: return make_top_machine_int_apron_ppl_polyhedra(); case MachineIntDomainOption::ApronPplLinearCongruences: return make_top_machine_int_apron_ppl_linear_congruences(); case MachineIntDomainOption::ApronPkgridPolyhedraLinearCongruences: return make_top_machine_int_apron_pkgrid_polyhedra_lin_cong(); case MachineIntDomainOption::VarPackApronOctagon: return make_top_machine_int_var_pack_apron_octagon(); case MachineIntDomainOption::VarPackApronPolkaPolyhedra: return make_top_machine_int_var_pack_apron_polka_polyhedra(); case MachineIntDomainOption::VarPackApronPolkaLinearEqualities: return make_top_machine_int_var_pack_apron_polka_linear_equalities(); case MachineIntDomainOption::VarPackApronPplPolyhedra: return make_top_machine_int_var_pack_apron_ppl_polyhedra(); case MachineIntDomainOption::VarPackApronPplLinearCongruences: return make_top_machine_int_var_pack_apron_ppl_linear_congruences(); case MachineIntDomainOption::VarPackApronPkgridPolyhedraLinearCongruences: return make_top_machine_int_var_pack_apron_pkgrid_polyhedra_lin_cong(); default: { ikos_unreachable("unreachable"); } } } MachineIntAbstractDomain make_bottom_machine_int_abstract_value( MachineIntDomainOption domain) { switch (domain) { case MachineIntDomainOption::Interval: return make_bottom_machine_int_interval(); case MachineIntDomainOption::Congruence: return make_bottom_machine_int_congruence(); case MachineIntDomainOption::IntervalCongruence: return make_bottom_machine_int_interval_congruence(); case MachineIntDomainOption::DBM: return make_bottom_machine_int_dbm(); case MachineIntDomainOption::VarPackDBM: return make_bottom_machine_int_var_pack_dbm(); case MachineIntDomainOption::VarPackDBMCongruence: return make_bottom_machine_int_var_pack_dbm_congruence(); case MachineIntDomainOption::Gauge: return make_bottom_machine_int_gauge(); case MachineIntDomainOption::GaugeIntervalCongruence: return make_bottom_machine_int_gauge_interval_congruence(); case MachineIntDomainOption::ApronInterval: return make_bottom_machine_int_apron_interval(); case MachineIntDomainOption::ApronOctagon: return make_bottom_machine_int_apron_octagon(); case MachineIntDomainOption::ApronPolkaPolyhedra: return make_bottom_machine_int_apron_polka_polyhedra(); case MachineIntDomainOption::ApronPolkaLinearEqualities: return make_bottom_machine_int_apron_polka_linear_equalities(); case MachineIntDomainOption::ApronPplPolyhedra: return make_bottom_machine_int_apron_ppl_polyhedra(); case MachineIntDomainOption::ApronPplLinearCongruences: return make_bottom_machine_int_apron_ppl_linear_congruences(); case MachineIntDomainOption::ApronPkgridPolyhedraLinearCongruences: return make_bottom_machine_int_apron_pkgrid_polyhedra_lin_cong(); case MachineIntDomainOption::VarPackApronOctagon: return make_bottom_machine_int_var_pack_apron_octagon(); case MachineIntDomainOption::VarPackApronPolkaPolyhedra: return make_bottom_machine_int_var_pack_apron_polka_polyhedra(); case MachineIntDomainOption::VarPackApronPolkaLinearEqualities: return make_bottom_machine_int_var_pack_apron_polka_linear_equalities(); case MachineIntDomainOption::VarPackApronPplPolyhedra: return make_bottom_machine_int_var_pack_apron_ppl_polyhedra(); case MachineIntDomainOption::VarPackApronPplLinearCongruences: return make_bottom_machine_int_var_pack_apron_ppl_linear_congruences(); case MachineIntDomainOption::VarPackApronPkgridPolyhedraLinearCongruences: return make_bottom_machine_int_var_pack_apron_pkgrid_polyhedra_lin_cong(); default: { ikos_unreachable("unreachable"); } } } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/000077500000000000000000000000001473507761200257765ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/apron_interval.cpp000066400000000000000000000064451473507761200315360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_apron_interval * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric:: ApronDomain< core::numeric::apron::Interval, ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_apron_interval() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_apron_interval() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/apron_octagon.cpp000066400000000000000000000064411473507761200313400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_apron_octagon * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric:: ApronDomain< core::numeric::apron::Octagon, ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_apron_octagon() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_apron_octagon() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos apron_pkgrid_polyhedra_lin_cong.cpp000066400000000000000000000065671473507761200350370ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement * make_(top|bottom)_machine_int_apron_pkgrid_polyhedra_lin_cong * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::ApronDomain< core::numeric::apron::PkgridPolyhedraLinCongruences, ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_apron_pkgrid_polyhedra_lin_cong() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_apron_pkgrid_polyhedra_lin_cong() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos apron_polka_linear_equalities.cpp000066400000000000000000000066361473507761200345220ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_apron_polka_linear_equalities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::ApronDomain< core::numeric::apron::PolkaLinearEqualities, ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_apron_polka_linear_equalities() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_apron_polka_linear_equalities() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/apron_polka_polyhedra.cpp000066400000000000000000000065001473507761200330570ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_apron_polka_polyhedra * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric:: ApronDomain< core::numeric::apron::PolkaPolyhedra, ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_apron_polka_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_apron_polka_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos apron_ppl_linear_congruences.cpp000066400000000000000000000066321473507761200343510ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_apron_ppl_linear_congruences * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::ApronDomain< core::numeric::apron::PplLinearCongruences, ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_apron_ppl_linear_congruences() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_apron_ppl_linear_congruences() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/apron_ppl_polyhedra.cpp000066400000000000000000000064701473507761200325520ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_apron_ppl_polyhedra * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric:: ApronDomain< core::numeric::apron::PplPolyhedra, ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_apron_ppl_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_apron_ppl_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/congruence.cpp000066400000000000000000000054061473507761200306370ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_congruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeMachineIntDomain = core::machine_int::CongruenceDomain< Variable* >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_congruence() { return MachineIntAbstractDomain(RuntimeMachineIntDomain::top()); } MachineIntAbstractDomain make_bottom_machine_int_congruence() { return MachineIntAbstractDomain(RuntimeMachineIntDomain::bottom()); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/dbm.cpp000066400000000000000000000057041473507761200272520ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_dbm * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeNumericDomain = core::numeric::DBM< ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_dbm() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); } MachineIntAbstractDomain make_bottom_machine_int_dbm() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/gauge.cpp000066400000000000000000000057241473507761200276020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_gauge * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeNumericDomain = core::numeric::GaugeDomain< ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_gauge() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); } MachineIntAbstractDomain make_bottom_machine_int_gauge() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); } } // end namespace value } // end namespace analyzer } // end namespace ikos gauge_interval_congruence.cpp000066400000000000000000000060721473507761200336340ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_gauge_interval_congruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeNumericDomain = core::numeric::GaugeIntervalCongruenceDomain< ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_gauge_interval_congruence() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); } MachineIntAbstractDomain make_bottom_machine_int_gauge_interval_congruence() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/interval.cpp000066400000000000000000000053701473507761200303330ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_interval * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeMachineIntDomain = core::machine_int::IntervalDomain< Variable* >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_interval() { return MachineIntAbstractDomain(RuntimeMachineIntDomain::top()); } MachineIntAbstractDomain make_bottom_machine_int_interval() { return MachineIntAbstractDomain(RuntimeMachineIntDomain::bottom()); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/interval_congruence.cpp000066400000000000000000000054621473507761200325450ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_interval_congruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeMachineIntDomain = core::machine_int::IntervalCongruenceDomain< Variable* >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_interval_congruence() { return MachineIntAbstractDomain(RuntimeMachineIntDomain::top()); } MachineIntAbstractDomain make_bottom_machine_int_interval_congruence() { return MachineIntAbstractDomain(RuntimeMachineIntDomain::bottom()); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/var_pack_apron_octagon.cpp000066400000000000000000000066761473507761200332200ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_var_pack_apron_octagon * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::VarPackingDomain< ZNumber, Variable*, core::numeric:: ApronDomain< core::numeric::apron::Octagon, ZNumber, Variable* > >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_var_pack_apron_octagon() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_octagon() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos var_pack_apron_pkgrid_polyhedra_lin_cong.cpp000066400000000000000000000070341473507761200366730ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement * make_(top|bottom)_machine_int_var_pack_apron_pkgrid_polyhedra_lin_cong * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::VarPackingDomain< ZNumber, Variable*, core::numeric::ApronDomain< core::numeric::apron::PkgridPolyhedraLinCongruences, ZNumber, Variable* > >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_var_pack_apron_pkgrid_polyhedra_lin_cong() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_pkgrid_polyhedra_lin_cong() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos var_pack_apron_polka_linear_equalities.cpp000066400000000000000000000070661473507761200363660ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement * make_(top|bottom)_machine_int_var_pack_apron_polka_linear_equalities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::VarPackingDomain< ZNumber, Variable*, core::numeric::ApronDomain< core::numeric::apron::PolkaLinearEqualities, ZNumber, Variable* > >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_var_pack_apron_polka_linear_equalities() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_polka_linear_equalities() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos var_pack_apron_polka_polyhedra.cpp000066400000000000000000000070241473507761200346500ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_var_pack_apron_polka_polyhedra * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::VarPackingDomain< ZNumber, Variable*, core::numeric::ApronDomain< core::numeric::apron::PolkaPolyhedra, ZNumber, Variable* > >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_var_pack_apron_polka_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_polka_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos var_pack_apron_ppl_linear_congruences.cpp000066400000000000000000000070621473507761200362150ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement * make_(top|bottom)_machine_int_var_pack_apron_ppl_linear_congruences * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::VarPackingDomain< ZNumber, Variable*, core::numeric::ApronDomain< core::numeric::apron::PplLinearCongruences, ZNumber, Variable* > >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_var_pack_apron_ppl_linear_congruences() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_ppl_linear_congruences() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos var_pack_apron_ppl_polyhedra.cpp000066400000000000000000000067251473507761200343440ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_var_pack_apron_ppl_polyhedra * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #ifdef HAS_APRON #include #include #include #endif #include #include namespace ikos { namespace analyzer { namespace value { #ifdef HAS_APRON namespace { using RuntimeNumericDomain = core::numeric::VarPackingDomain< ZNumber, Variable*, core::numeric:: ApronDomain< core::numeric::apron::PplPolyhedra, ZNumber, Variable* > >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace #endif MachineIntAbstractDomain make_top_machine_int_var_pack_apron_ppl_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); #else throw LogicError("ikos was compiled without apron support"); #endif } MachineIntAbstractDomain make_bottom_machine_int_var_pack_apron_ppl_polyhedra() { #ifdef HAS_APRON return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); #else throw LogicError("ikos was compiled without apron support"); #endif } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/var_pack_dbm.cpp000066400000000000000000000057651473507761200311270ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_var_pack_dbm * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeNumericDomain = core::numeric::VarPackingDBM< ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_var_pack_dbm() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); } MachineIntAbstractDomain make_bottom_machine_int_var_pack_dbm() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/value/machine_int_domain/var_pack_dbm_congruence.cpp000066400000000000000000000060571473507761200333320ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement make_(top|bottom)_machine_int_var_pack_dbm_congruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace value { namespace { using RuntimeNumericDomain = core::numeric::VarPackingDBMCongruence< ZNumber, Variable* >; using RuntimeMachineIntDomain = core::machine_int::NumericDomainAdapter< Variable*, RuntimeNumericDomain >; } // end anonymous namespace MachineIntAbstractDomain make_top_machine_int_var_pack_dbm_congruence() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::top())); } MachineIntAbstractDomain make_bottom_machine_int_var_pack_dbm_congruence() { return MachineIntAbstractDomain( RuntimeMachineIntDomain(RuntimeNumericDomain::bottom())); } } // end namespace value } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/variable.cpp000066400000000000000000000337711473507761200233610ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Variable implementation * * Author: Clement Decoodt * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { // Variable Variable::Variable(VariableKind kind, ar::Type* type) : _kind(kind), _type(type), _offset_var(nullptr) { ikos_assert(this->_type != nullptr); } Variable::~Variable() = default; // LocalVariable LocalVariable::LocalVariable(ar::LocalVariable* var) : Variable(LocalVariableKind, var->type()), _var(var) { ikos_assert(this->_var != nullptr); } void LocalVariable::dump(std::ostream& o) const { this->_var->dump(o); } // GlobalVariable GlobalVariable::GlobalVariable(ar::GlobalVariable* var) : Variable(GlobalVariableKind, var->type()), _var(var) { ikos_assert(this->_var != nullptr); } void GlobalVariable::dump(std::ostream& o) const { this->_var->dump(o); } // InternalVariable InternalVariable::InternalVariable(ar::InternalVariable* var) : Variable(InternalVariableKind, var->type()), _var(var) { ikos_assert(this->_var != nullptr); } void InternalVariable::dump(std::ostream& o) const { return this->_var->dump(o); } // InlineAssemblyPointerVariable InlineAssemblyPointerVariable::InlineAssemblyPointerVariable( ar::InlineAssemblyConstant* inline_asm) : Variable(InlineAssemblyPointerVariableKind, inline_asm->type()), _inline_asm(inline_asm) { ikos_assert(this->_inline_asm != nullptr); } void InlineAssemblyPointerVariable::dump(std::ostream& o) const { o << "%asm:" << this->_inline_asm; } // FunctionPointerVariable FunctionPointerVariable::FunctionPointerVariable(ar::Function* fun) : Variable(FunctionPointerVariableKind, ar::PointerType::get(fun->context(), fun->type())), _fun(fun) { ikos_assert(this->_fun != nullptr); } void FunctionPointerVariable::dump(std::ostream& o) const { o << "@" << this->_fun->name(); } // CellVariable CellVariable::CellVariable(ar::Type* type, MemoryLocation* address, MachineInt offset, MachineInt size) : Variable(CellVariableKind, type), _address(address), _offset(std::move(offset)), _size(std::move(size)) { ikos_assert(this->_address != nullptr); } void CellVariable::dump(std::ostream& o) const { o << "C{"; this->_address->dump(o); o << "," << this->_offset << "," << this->_size << "}"; } // OffsetVariable OffsetVariable::OffsetVariable(ar::Type* type, Variable* pointer) : Variable(OffsetVariableKind, type), _pointer(pointer) { ikos_assert(this->_pointer != nullptr); } void OffsetVariable::dump(std::ostream& o) const { this->_pointer->dump(o); o << ".offset"; } // AllocSizeVariable AllocSizeVariable::AllocSizeVariable(ar::Type* type, MemoryLocation* address) : Variable(AllocSizeVariableKind, type), _address(address) { ikos_assert(this->_address != nullptr); } void AllocSizeVariable::dump(std::ostream& o) const { this->_address->dump(o); o << ".size"; } // ReturnVariable ReturnVariable::ReturnVariable(ar::Function* fun) : Variable(ReturnVariableKind, fun->type()->return_type()), _fun(fun) { ikos_assert(this->_fun != nullptr); } void ReturnVariable::dump(std::ostream& o) const { o << this->_fun->name() << ".return"; } // NamedShadowVariable NamedShadowVariable::NamedShadowVariable(ar::Type* type, std::string name) : Variable(NamedShadowVariableKind, type), _name(std::move(name)) { ikos_assert(!this->_name.empty()); } void NamedShadowVariable::dump(std::ostream& o) const { o << this->_name; } // UnnamedShadowVariable UnnamedShadowVariable::UnnamedShadowVariable(ar::Type* type, std::size_t id) : Variable(UnnamedShadowVariableKind, type), _id(id) {} void UnnamedShadowVariable::dump(std::ostream& o) const { o << "unnamed." << this->_id; } // VariableFactory VariableFactory::VariableFactory(ar::Bundle* bundle) : _ar_context(bundle->context()), _size_type(ar::IntegerType::size_type(bundle)) {} VariableFactory::~VariableFactory() = default; LocalVariable* VariableFactory::get_local(ar::LocalVariable* var) { { boost::shared_lock< boost::shared_mutex > lock(this->_local_variable_mutex); auto it = this->_local_variable_map.find(var); if (it != this->_local_variable_map.end()) { return it->second.get(); } } auto vn = std::make_unique< LocalVariable >(var); vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); { boost::unique_lock< boost::shared_mutex > lock(this->_local_variable_mutex); auto res = this->_local_variable_map.try_emplace(var, std::move(vn)); return res.first->second.get(); } } GlobalVariable* VariableFactory::get_global(ar::GlobalVariable* var) { { boost::shared_lock< boost::shared_mutex > lock( this->_global_variable_mutex); auto it = this->_global_variable_map.find(var); if (it != this->_global_variable_map.end()) { return it->second.get(); } } auto vn = std::make_unique< GlobalVariable >(var); vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); { boost::unique_lock< boost::shared_mutex > lock( this->_global_variable_mutex); auto res = this->_global_variable_map.try_emplace(var, std::move(vn)); return res.first->second.get(); } } InternalVariable* VariableFactory::get_internal(ar::InternalVariable* var) { { boost::shared_lock< boost::shared_mutex > lock( this->_internal_variable_mutex); auto it = this->_internal_variable_map.find(var); if (it != this->_internal_variable_map.end()) { return it->second.get(); } } auto vn = std::make_unique< InternalVariable >(var); if (vn->type()->is_pointer() || vn->type()->is_aggregate()) { vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); } { boost::unique_lock< boost::shared_mutex > lock( this->_internal_variable_mutex); auto res = this->_internal_variable_map.try_emplace(var, std::move(vn)); return res.first->second.get(); } } InlineAssemblyPointerVariable* VariableFactory::get_asm_ptr( ar::InlineAssemblyConstant* cst) { { boost::shared_lock< boost::shared_mutex > lock( this->_inline_asm_pointer_mutex); auto it = this->_inline_asm_pointer_map.find(cst); if (it != this->_inline_asm_pointer_map.end()) { return it->second.get(); } } auto vn = std::make_unique< InlineAssemblyPointerVariable >(cst); vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); { boost::unique_lock< boost::shared_mutex > lock( this->_inline_asm_pointer_mutex); auto res = this->_inline_asm_pointer_map.try_emplace(cst, std::move(vn)); return res.first->second.get(); } } FunctionPointerVariable* VariableFactory::get_function_ptr(ar::Function* fun) { { boost::shared_lock< boost::shared_mutex > lock( this->_function_pointer_mutex); auto it = this->_function_pointer_map.find(fun); if (it != this->_function_pointer_map.end()) { return it->second.get(); } } auto vn = std::make_unique< FunctionPointerVariable >(fun); vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); { boost::unique_lock< boost::shared_mutex > lock( this->_function_pointer_mutex); auto res = this->_function_pointer_map.try_emplace(fun, std::move(vn)); return res.first->second.get(); } } FunctionPointerVariable* VariableFactory::get_function_ptr( ar::FunctionPointerConstant* cst) { return this->get_function_ptr(cst->function()); } CellVariable* VariableFactory::get_cell(MemoryLocation* address, const MachineInt& offset, const MachineInt& size, Signedness sign) { auto key = std::make_tuple(address, offset, size); { boost::shared_lock< boost::shared_mutex > lock(this->_cell_mutex); auto it = this->_cell_map.find(key); if (it != this->_cell_map.end()) { return it->second.get(); } } { // Create a memory cell variable // A cell can be either an integer, a float or a pointer // The integer type should have the right bit-width and the given signedness // The parameter `size` is in bytes, compute bit-width = size * 8 // // Note: IntegerType::get() is not thread safe, so lock the mutex here boost::unique_lock< boost::shared_mutex > lock(this->_cell_mutex); bool overflow; MachineInt eight(8, size.bit_width(), Unsigned); MachineInt bit_width = mul(size, eight, overflow); if (overflow || !bit_width.fits< uint64_t >()) { throw LogicError("variable factory: cell size too big"); } ar::Type* type = ar::IntegerType::get(this->_ar_context, bit_width.to< uint64_t >(), sign); auto vn = std::make_unique< CellVariable >(type, address, offset, size); vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); auto res = this->_cell_map.emplace(key, std::move(vn)); return res.first->second.get(); } } AllocSizeVariable* VariableFactory::get_alloc_size(MemoryLocation* address) { { boost::shared_lock< boost::shared_mutex > lock(this->_alloc_size_mutex); auto it = this->_alloc_size_map.find(address); if (it != this->_alloc_size_map.end()) { return it->second.get(); } } auto vn = std::make_unique< AllocSizeVariable >(this->_size_type, address); { boost::unique_lock< boost::shared_mutex > lock(this->_alloc_size_mutex); auto res = this->_alloc_size_map.try_emplace(address, std::move(vn)); return res.first->second.get(); } } ReturnVariable* VariableFactory::get_return(ar::Function* fun) { { boost::shared_lock< boost::shared_mutex > lock( this->_return_variable_mutex); auto it = this->_return_variable_map.find(fun); if (it != this->_return_variable_map.end()) { return it->second.get(); } } auto vn = std::make_unique< ReturnVariable >(fun); if (vn->type()->is_pointer() || vn->type()->is_aggregate()) { vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); } { boost::unique_lock< boost::shared_mutex > lock( this->_return_variable_mutex); auto res = this->_return_variable_map.try_emplace(fun, std::move(vn)); return res.first->second.get(); } } NamedShadowVariable* VariableFactory::get_named_shadow(ar::Type* type, llvm::StringRef name) { { boost::shared_lock< boost::shared_mutex > lock( this->_named_shadow_variable_mutex); auto it = this->_named_shadow_variable_map.find(name); if (it != this->_named_shadow_variable_map.end()) { return it->second.get(); } } auto vn = std::make_unique< NamedShadowVariable >(type, name.str()); if (vn->type()->is_pointer() || vn->type()->is_aggregate()) { vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); } { boost::unique_lock< boost::shared_mutex > lock( this->_named_shadow_variable_mutex); auto res = this->_named_shadow_variable_map.try_emplace(name, std::move(vn)); return res.first->second.get(); } } UnnamedShadowVariable* VariableFactory::create_unnamed_shadow(ar::Type* type) { boost::lock_guard< boost::mutex > lock(this->_unnamed_shadow_variable_mutex); std::size_t id = this->_unnamed_shadow_variable_vec.size(); auto vn = std::make_unique< UnnamedShadowVariable >(type, id); if (vn->type()->is_pointer() || vn->type()->is_aggregate()) { vn->set_offset_var( std::make_unique< OffsetVariable >(this->_size_type, vn.get())); } this->_unnamed_shadow_variable_vec.emplace_back(std::move(vn)); return this->_unnamed_shadow_variable_vec.back().get(); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/analysis/widening_hint.cpp000066400000000000000000000157401473507761200244160ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Widening hint analysis implementation * * Author: Thomas Bailleux * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include namespace ikos { namespace analyzer { namespace { /// \brief Weak topological visitor to find widening hints class WideningHintWtoVisitor : public core::WtoComponentVisitor< ar::Code* > { private: using WtoVertexT = core::WtoVertex< ar::Code* >; using WtoCycleT = core::WtoCycle< ar::Code* >; private: WideningHints& _hints; public: /// \brief Constructor explicit WideningHintWtoVisitor(WideningHints& hints) : _hints(hints) {} /// \brief No copy constructor WideningHintWtoVisitor(const WideningHintWtoVisitor&) = delete; /// \brief No move constructor WideningHintWtoVisitor(WideningHintWtoVisitor&&) = delete; /// \brief No copy assignment operator WideningHintWtoVisitor& operator=(const WideningHintWtoVisitor&) = delete; /// \brief No move assignment operator WideningHintWtoVisitor& operator=(WideningHintWtoVisitor&&) = delete; /// \brief Destructor ~WideningHintWtoVisitor() override = default; void visit(const WtoVertexT&) override {} void visit(const WtoCycleT& cycle) override { auto head = cycle.head(); if (head->num_successors() > 1) { auto successor = *(head->successor_begin()); if (auto constant = this->extract_constant(successor)) { this->_hints.add(head, *constant); } } for (auto it = cycle.begin(), et = cycle.end(); it != et; ++it) { it->accept(*this); } } boost::optional< ar::MachineInt > extract_constant(ar::BasicBlock* bb) const { if (bb->empty()) { return boost::none; } // we have a comparison, check if there is a constant if (auto cmp = dyn_cast< ar::Comparison >(bb->front())) { ar::IntegerConstant* constant = nullptr; bool cst_left; if (cmp->left()->is_integer_constant()) { constant = cast< ar::IntegerConstant >(cmp->left()); cst_left = true; } else if (cmp->right()->is_integer_constant()) { constant = cast< ar::IntegerConstant >(cmp->right()); cst_left = false; } else { return boost::none; } ar::MachineInt value = constant->value(); ar::MachineInt one(1, value.bit_width(), value.sign()); bool overflow = false; // check if the comparison is <= or >= if (cmp->predicate() == ar::Comparison::UIGE || cmp->predicate() == ar::Comparison::SIGE) { if (cst_left) { // case `cst >= var` <=> `cst + 1 > var` value = add(value, one, overflow); } else { // case `var >= cst` <=> `var > cst - 1` value = sub(value, one, overflow); } } else if (cmp->predicate() == ar::Comparison::UILE || cmp->predicate() == ar::Comparison::SILE) { if (cst_left) { // case `cst <= var` <=> `cst - 1 < var` value = sub(value, one, overflow); } else { // case `var <= cst` <=> `var < cst + 1` value = add(value, one, overflow); } } if (overflow) { return boost::none; } return std::move(value); } else { return boost::none; } } }; // end class WideningHintWtoVisitor } // end anonymous namespace WideningHintAnalysis::WideningHintAnalysis(Context& ctx) : _ctx(ctx) {} WideningHintAnalysis::~WideningHintAnalysis() = default; void WideningHintAnalysis::run() { ar::Bundle* bundle = this->_ctx.bundle; // Setup a progress logger std::unique_ptr< ProgressLogger > progress = make_progress_logger(_ctx.opts.progress, LogLevel::Info, /* num_tasks = */ std::count_if(bundle->function_begin(), bundle->function_end(), [](ar::Function* fun) { return fun->is_definition(); })); ScopeLogger scope(*progress); for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* fun = *it; if (fun->is_definition()) { progress->start_task("Running widening hint analysis on function '" + demangle(fun->name()) + "'"); this->run(fun); } } } void WideningHintAnalysis::run(ar::Function* fun) { if (!fun->is_definition()) { return; } CodeFixpointParameters& parameters = this->_ctx.fixpoint_parameters->get(fun); WideningHintWtoVisitor visitor(parameters.widening_hints); core::Wto< ar::Code* > wto(fun->body()); wto.accept(visitor); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/000077500000000000000000000000001473507761200206365ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/assert_prover.cpp000066400000000000000000000130331473507761200242400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Assertion prover checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { AssertProverChecker::AssertProverChecker(Context& ctx) : Checker(ctx) {} CheckerName AssertProverChecker::name() const { return CheckerName::AssertProver; } const char* AssertProverChecker::description() const { return "Assertion prover checker"; } void AssertProverChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto call = dyn_cast< ar::IntrinsicCall >(stmt)) { ar::Function* fun = call->called_function(); if (fun->intrinsic_id() == ar::Intrinsic::IkosAssert) { CheckResult check = this->check_assert(call, inv); this->display_invariant(check.result, call, inv); this->_checks.insert(check.kind, CheckerName::AssertProver, check.result, stmt, call_context, std::array< ar::Value*, 1 >{{call->argument(0)}}); } } } AssertProverChecker::CheckResult AssertProverChecker::check_assert( ar::IntrinsicCall* call, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_assert_check(Result::Unreachable, call)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable}; } const ScalarLit& cond = this->_lit_factory.get_scalar(call->argument(0)); if (cond.is_undefined() || (cond.is_machine_int_var() && inv.normal().uninit_is_uninitialized(cond.var()))) { // Undefined operand if (auto msg = this->display_assert_check(Result::Error, call)) { *msg << ": undefined operand\n"; } return {CheckKind::UninitializedVariable, Result::Error}; } auto flag = IntInterval::bottom(32, Unsigned); if (cond.is_machine_int()) { flag = IntInterval(cond.machine_int()); } else if (cond.is_machine_int_var()) { flag = inv.normal().int_to_interval(cond.var()); } else { log::error("unexpected argument to __ikos_assert()"); return {CheckKind::UnexpectedOperand, Result::Error}; } boost::optional< MachineInt > v = flag.singleton(); if (v && (*v).is_zero()) { // The condition is definitely 0 if (auto msg = this->display_assert_check(Result::Error, call)) { *msg << ": ∀x ∈ " << cond << ", x == 0\n"; } return {CheckKind::Assert, Result::Error}; } else if (flag.contains(MachineInt::zero(32, Unsigned))) { // The condition may be 0 if (auto msg = this->display_assert_check(Result::Warning, call)) { *msg << ": (∃x ∈ " << cond << ", x == 0) and (∃x ∈ " << cond << ", x != 0)\n"; } return {CheckKind::Assert, Result::Warning}; } else { // The condition cannot be 0 if (auto msg = this->display_assert_check(Result::Ok, call)) { *msg << ": ∀x ∈ " << cond << ", x != 0\n"; } return {CheckKind::Assert, Result::Ok}; } } llvm::Optional< LogMessage > AssertProverChecker::display_assert_check( Result result, ar::IntrinsicCall* call) const { auto msg = this->display_check(result, call); if (msg) { *msg << "__ikos_assert("; call->argument(0)->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/buffer_overflow.cpp000066400000000000000000001632011473507761200245410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Buffer overflow checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { BufferOverflowChecker::BufferOverflowChecker(Context& ctx) : Checker(ctx), _ar_context(ctx.bundle->context()), _data_layout(ctx.bundle->data_layout()), _size_type(ar::IntegerType::size_type(ctx.bundle)), _size_zero( ar::IntegerConstant::get(this->_ar_context, this->_size_type, 0)), _size_one( ar::IntegerConstant::get(this->_ar_context, this->_size_type, 1)) {} CheckerName BufferOverflowChecker::name() const { return CheckerName::BufferOverflow; } const char* BufferOverflowChecker::description() const { return "Buffer overflow checker"; } void BufferOverflowChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto load = dyn_cast< ar::Load >(stmt)) { CheckResult check = this->check_mem_access(load, load->operand(), this->store_size(load->result()->type()), /* if_null = */ Result::Error, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::BufferOverflow, check.result, stmt, call_context, check.operands, check.info); } else if (auto store = dyn_cast< ar::Store >(stmt)) { CheckResult check = this->check_mem_access(store, store->pointer(), this->store_size(store->value()->type()), /* if_null = */ Result::Error, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::BufferOverflow, check.result, stmt, call_context, check.operands, check.info); } else if (auto call = dyn_cast< ar::CallBase >(stmt)) { std::vector< CheckResult > checks = this->check_call(call, inv); for (const auto& check : checks) { this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::BufferOverflow, check.result, stmt, call_context, check.operands, check.info); } } } std::vector< BufferOverflowChecker::CheckResult > BufferOverflowChecker:: check_call(ar::CallBase* call, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_mem_access_check(Result::Unreachable, call)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}, {}}}; } const ScalarLit& called = this->_lit_factory.get_scalar(call->called()); // Check uninitialized if (called.is_undefined() || (called.is_pointer_var() && inv.normal().uninit_is_uninitialized(called.var()))) { // Undefined call pointer operand if (auto msg = this->display_mem_access_check(Result::Error, call)) { *msg << ": undefined call pointer operand\n"; } return {{CheckKind::UninitializedVariable, Result::Error, {call->called()}, {}}}; } // Check null pointer dereference if (called.is_null() || (called.is_pointer_var() && inv.normal().nullity_is_null(called.var()))) { // Null call pointer operand if (auto msg = this->display_mem_access_check(Result::Error, call)) { *msg << ": null call pointer operand\n"; } return {{CheckKind::NullPointerDereference, Result::Error, {call->called()}, {}}}; } // Collect potential callees auto callees = PointsToSet::bottom(); if (auto cst = dyn_cast< ar::FunctionPointerConstant >(call->called())) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(call->called())) { // call to inline assembly if (auto msg = this->display_mem_access_check(Result::Ok, call)) { *msg << ": call to inline assembly\n"; } return {{CheckKind::FunctionCallInlineAssembly, Result::Ok, {}, {}}}; } else if (auto gv = dyn_cast< ar::GlobalVariable >(call->called())) { callees = {_ctx.mem_factory->get_global(gv)}; } else if (auto lv = dyn_cast< ar::LocalVariable >(call->called())) { callees = {_ctx.mem_factory->get_local(lv)}; } else if (isa< ar::InternalVariable >(call->called())) { // Indirect call through a function pointer callees = inv.normal().pointer_to_points_to(called.var()); } else { log::error("unexpected call pointer operand"); return { {CheckKind::UnexpectedOperand, Result::Error, {call->called()}, {}}}; } // Check callees ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference if (auto msg = this->display_mem_access_check(Result::Error, call)) { *msg << ": points-to set of function pointer is empty\n"; } return {{CheckKind::InvalidPointerDereference, Result::Error, {call->called()}, {}}}; } else if (callees.is_top()) { // No points-to set if (auto msg = this->display_mem_access_check(Result::Warning, call)) { *msg << ": no points-to set for function pointer\n"; } return {{CheckKind::UnknownFunctionCallPointer, Result::Warning, {call->called()}, {}}}; } std::vector< CheckResult > checks; for (MemoryLocation* addr : callees) { if (!isa< FunctionMemoryLocation >(addr)) { // Not a call to a function memory location continue; } ar::Function* callee = cast< FunctionMemoryLocation >(addr)->function(); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call continue; } if (callee->is_intrinsic()) { for (const auto& check : this->check_intrinsic_call(call, callee, inv)) { checks.push_back(check); } } } return checks; } std::vector< BufferOverflowChecker::CheckResult > BufferOverflowChecker:: check_intrinsic_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv) { switch (fun->intrinsic_id()) { case ar::Intrinsic::MemoryCopy: case ar::Intrinsic::MemoryMove: { return {this->check_mem_access(call, call->argument(1), call->argument(2), /* if_null = */ Result::Error, inv), this->check_mem_access(call, call->argument(0), call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::MemorySet: { return {this->check_mem_access(call, call->argument(0), call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::VarArgStart: case ar::Intrinsic::VarArgEnd: case ar::Intrinsic::VarArgGet: { return {this->check_va_list_access(call, call->argument(0), inv)}; } case ar::Intrinsic::VarArgCopy: { return {this->check_va_list_access(call, call->argument(0), inv), this->check_va_list_access(call, call->argument(1), inv)}; } case ar::Intrinsic::StackSave: case ar::Intrinsic::StackRestore: case ar::Intrinsic::LifetimeStart: case ar::Intrinsic::LifetimeEnd: case ar::Intrinsic::EhTypeidFor: case ar::Intrinsic::Trap: { return {}; } // case ar::Intrinsic::IkosAssert: case ar::Intrinsic::IkosAssume: case ar::Intrinsic::IkosNonDet: case ar::Intrinsic::IkosCounterInit: case ar::Intrinsic::IkosCounterIncr: { return {}; } case ar::Intrinsic::IkosCheckMemAccess: { return {this->check_mem_access(call, call->argument(0), call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::IkosCheckStringAccess: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::IkosAssumeMemSize: { return {}; } case ar::Intrinsic::IkosForgetMemory: case ar::Intrinsic::IkosAbstractMemory: { return {this->check_mem_access(call, call->argument(0), call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::IkosWatchMemory: case ar::Intrinsic::IkosPartitioningVar: case ar::Intrinsic::IkosPartitioningJoin: case ar::Intrinsic::IkosPartitioningDisable: case ar::Intrinsic::IkosPrintInvariant: case ar::Intrinsic::IkosPrintValues: { return {}; } // case ar::Intrinsic::LibcMalloc: case ar::Intrinsic::LibcCalloc: case ar::Intrinsic::LibcValloc: case ar::Intrinsic::LibcAlignedAlloc: { return {}; } case ar::Intrinsic::LibcRealloc: { return {this->check_realloc(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcFree: case ar::Intrinsic::LibcAbs: case ar::Intrinsic::LibcRand: case ar::Intrinsic::LibcSrand: case ar::Intrinsic::LibcExit: case ar::Intrinsic::LibcAbort: { return {}; } // case ar::Intrinsic::LibcErrnoLocation: { return {}; } // case ar::Intrinsic::LibcOpen: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } // case ar::Intrinsic::LibcClose: { return {}; } case ar::Intrinsic::LibcRead: { return {this->check_mem_access(call, call->argument(1), call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcWrite: { return {this->check_mem_access(call, call->argument(1), call->argument(2), /* if_null = */ Result::Error, inv)}; } // case ar::Intrinsic::LibcGets: { return {{CheckKind::BufferOverflowGets, Result::Error, {call->argument(0)}, {}}}; } case ar::Intrinsic::LibcFgets: { return {this->check_mem_access(call, call->argument(0), call->argument(1), /* if_null = */ Result::Error, inv), this->check_file_access(call, call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcGetc: case ar::Intrinsic::LibcFgetc: { return {this->check_file_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcGetchar: { return {}; } case ar::Intrinsic::LibcPuts: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcFputs: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_file_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcPutc: case ar::Intrinsic::LibcFputc: { return {this->check_file_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcPrintf: { std::vector< CheckResult > checks = { this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; for (auto it = call->arg_begin() + 1, et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; if (arg->type()->is_pointer()) { checks.push_back(this->check_string_access(call, arg, /* if_null = */ Result::Ok, inv)); } } return checks; } case ar::Intrinsic::LibcFprintf: { std::vector< CheckResult > checks = {this->check_file_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; for (auto it = call->arg_begin() + 2, et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; if (arg->type()->is_pointer()) { checks.push_back(this->check_string_access(call, arg, /* if_null = */ Result::Ok, inv)); } } return checks; } case ar::Intrinsic::LibcSprintf: { std::vector< CheckResult > checks = {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; for (auto it = call->arg_begin() + 2, et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; if (arg->type()->is_pointer()) { checks.push_back(this->check_string_access(call, arg, /* if_null = */ Result::Ok, inv)); } } return checks; } case ar::Intrinsic::LibcSnprintf: { std::vector< CheckResult > checks = {}; // Calling snprintf with zero bufsz and null pointer buffer can be used // to determine the buffer size needed to contain the output. That case // is allowed. Otherwise, check first argument. auto bufsz = this->_lit_factory.get_scalar(call->argument(1)); if (!(bufsz.is_machine_int() && bufsz.machine_int().is_zero())) { checks.push_back(this->check_mem_access(call, call->argument(0), call->argument(1), /* if_null = */ Result::Error, inv)); } checks.push_back(this->check_string_access(call, call->argument(2), /* if_null = */ Result::Error, inv)); for (auto it = call->arg_begin() + 3, et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; if (arg->type()->is_pointer()) { checks.push_back(this->check_string_access(call, arg, /* if_null = */ Result::Ok, inv)); } } return checks; } case ar::Intrinsic::LibcScanf: { std::vector< CheckResult > checks = { this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; for (auto it = call->arg_begin() + 1, et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; ikos_assert(arg->type()->is_pointer()); checks.push_back( this->check_string_access(call, arg, /* if_null = */ Result::Error, inv)); } return checks; } case ar::Intrinsic::LibcFscanf: { std::vector< CheckResult > checks = { this->check_file_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv), }; for (auto it = call->arg_begin() + 2, et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; ikos_assert(arg->type()->is_pointer()); checks.push_back( this->check_string_access(call, arg, /* if_null = */ Result::Error, inv)); } return checks; } case ar::Intrinsic::LibcSscanf: { std::vector< CheckResult > checks = { this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv), }; for (auto it = call->arg_begin() + 2, et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; ikos_assert(arg->type()->is_pointer()); checks.push_back( this->check_string_access(call, arg, /* if_null = */ Result::Error, inv)); } return checks; } case ar::Intrinsic::LibcFopen: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcFclose: case ar::Intrinsic::LibcFflush: { return {this->check_file_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } // case ar::Intrinsic::LibcStrlen: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrnlen: { return {this->check_mem_access(call, call->argument(0), call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrcpy: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrncpy: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* max_access_size = */ call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrcat: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrncat: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* max_access_size = */ call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrcmp: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrncmp: { return {this->check_string_access(call, call->argument(0), /* max_access_size = */ call->argument(2), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* max_access_size = */ call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrstr: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrchr: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrdup: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrndup: { return {this->check_mem_access(call, call->argument(0), call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrcpyCheck: { return {this->check_mem_access(call, call->argument(0), call->argument(2), /* if_null = */ Result::Error, inv), this->check_mem_access(call, call->argument(1), call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcMemoryCopyCheck: case ar::Intrinsic::LibcMemoryMoveCheck: { return {this->check_mem_access(call, call->argument(1), call->argument(2), /* if_null = */ Result::Error, inv), this->check_mem_access(call, call->argument(0), call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcMemorySetCheck: { return {this->check_mem_access(call, call->argument(0), call->argument(2), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcStrcatCheck: { return {this->check_string_access(call, call->argument(0), /* if_null = */ Result::Error, inv), this->check_string_access(call, call->argument(1), /* if_null = */ Result::Error, inv)}; } case ar::Intrinsic::LibcppNew: case ar::Intrinsic::LibcppNewArray: case ar::Intrinsic::LibcppDelete: case ar::Intrinsic::LibcppDeleteArray: case ar::Intrinsic::LibcppAllocateException: case ar::Intrinsic::LibcppFreeException: case ar::Intrinsic::LibcppThrow: case ar::Intrinsic::LibcppBeginCatch: case ar::Intrinsic::LibcppEndCatch: { return {}; } default: { ikos_unreachable("unreachable"); } } } BufferOverflowChecker::CheckResult BufferOverflowChecker::check_mem_access( ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, Result if_null, value::AbstractDomain inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_mem_access_check(Result::Unreachable, stmt, pointer, access_size)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}, {}}; } const ScalarLit& ptr = this->_lit_factory.get_scalar(pointer); const ScalarLit& size = this->_lit_factory.get_scalar(access_size); // Check uninitialized if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined pointer operand if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size)) { *msg << ": undefined pointer operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {pointer}, {}}; } if (size.is_undefined() || (size.is_machine_int_var() && inv.normal().uninit_is_uninitialized(size.var()))) { // Undefined size operand if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size)) { *msg << ": undefined size operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {access_size}, {}}; } // Check null pointer dereference if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { // Null pointer operand if (auto msg = this->display_mem_access_check(if_null, stmt, pointer, access_size)) { *msg << ": null pointer dereference\n"; } return {CheckKind::NullPointerDereference, if_null, {pointer}, {}}; } // Check unexpected operand if (!ptr.is_pointer_var()) { log::error("unexpected pointer operand"); return {CheckKind::UnexpectedOperand, Result::Error, {pointer}, {}}; } if (!size.is_machine_int() && !size.is_machine_int_var()) { log::error("unexpected size operand"); return {CheckKind::UnexpectedOperand, Result::Error, {access_size}, {}}; } // Initialize global variable pointer and function pointer this->init_global_ptr(inv, pointer); // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_empty()) { // Pointer is invalid if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size)) { *msg << ": empty points-to set for pointer\n"; } return {CheckKind::InvalidPointerDereference, Result::Error, {pointer}, {}}; } else if (addrs.is_top()) { // Unknown points-to set if (auto msg = this->display_mem_access_check(Result::Warning, stmt, pointer, access_size)) { *msg << ": no points-to information for pointer\n"; } return {CheckKind::UnknownMemoryAccess, Result::Warning, {pointer}, {}}; } JsonDict info; JsonList points_to_info; IntInterval offset_intv = inv.normal().pointer_offset_to_interval(ptr.var()); info.put("offset", to_json(offset_intv)); auto size_intv = IntInterval::bottom(1, Signed); if (size.is_machine_int_var()) { size_intv = inv.normal().int_to_interval(size.var()); } else if (size.is_machine_int()) { size_intv = IntInterval(size.machine_int()); } else { ikos_unreachable("unexpected access size"); } info.put("access_size", to_json(size_intv)); // Variable representing the pointer offset Variable* offset_var = ptr.var()->offset_var(); inv.normal().pointer_offset_to_int(offset_var, ptr.var()); // Add a shadow variable `offset_plus_size = offset + access_size` Variable* offset_plus_size = _ctx.var_factory->get_named_shadow(this->_size_type, "shadow.offset_plus_size"); if (access_size->type() == this->_size_type) { if (size.is_machine_int_var()) { inv.normal().int_apply(IntBinaryOperator::Add, offset_plus_size, offset_var, size.var()); } else if (size.is_machine_int()) { inv.normal().int_apply(IntBinaryOperator::Add, offset_plus_size, offset_var, size.machine_int()); } else { ikos_unreachable("unexpected access size"); } } else { // This happens in LibcFgets for instance if (size.is_machine_int_var()) { inv.normal().int_apply(IntUnaryOperator::Cast, offset_plus_size, size.var()); inv.normal().int_apply(IntBinaryOperator::Add, offset_plus_size, offset_plus_size, offset_var); } else if (size.is_machine_int()) { inv.normal() .int_apply(IntBinaryOperator::Add, offset_plus_size, offset_var, size.machine_int().cast(this->_size_type->bit_width(), ar::Unsigned)); } else { ikos_unreachable("unexpected access size"); } } inv.normal().normalize(); if (auto element_size = this->is_array_access(stmt, inv, offset_intv, addrs)) { info.put("array_element_size", *element_size); } // Are all the points-to in/valid bool all_valid = true; bool all_invalid = true; for (auto addr : addrs) { AllocSizeVariable* size_var = _ctx.var_factory->get_alloc_size(addr); this->init_global_alloc_size(inv, addr, size_var); // Add block info JsonDict block_info = { {"id", _ctx.output_db->memory_locations.insert(addr)}}; // Perform analysis auto check = this->check_memory_location_access(stmt, pointer, access_size, inv, addr, size_var, offset_var, offset_plus_size, offset_intv, block_info); block_info.put("status", static_cast< int >(check.result)); block_info.put("kind", static_cast< int >(check.kind)); if (check.result == Result::Error) { all_valid = false; } else if (check.result == Result::Warning) { all_valid = false; all_invalid = false; } else { all_invalid = false; } points_to_info.add(block_info); } info.put("points_to", points_to_info); if (all_invalid) { return {CheckKind::BufferOverflow, Result::Error, {pointer, access_size}, info}; } else if (!all_valid) { return {CheckKind::BufferOverflow, Result::Warning, {pointer, access_size}, info}; } else { return {CheckKind::BufferOverflow, Result::Ok, {pointer, access_size}, {}}; } } BufferOverflowChecker::MemoryLocationCheckResult BufferOverflowChecker:: check_memory_location_access(ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, const value::AbstractDomain& inv, MemoryLocation* addr, AllocSizeVariable* size_var, Variable* offset_var, Variable* offset_plus_size, const IntInterval& offset_intv, JsonDict& block_info) { if (isa< FunctionMemoryLocation >(addr)) { // Try to dereference a function pointer, this is an error if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size, addr)) { *msg << ": dereferencing a function pointer\n"; } return {BufferOverflowCheckKind::Function, Result::Error}; } if (isa< DynAllocMemoryLocation >(addr)) { // Dynamic allocated memory location // Check for use after free auto lifetime = inv.normal().lifetime_to_lifetime(addr); if (lifetime.is_deallocated()) { // Use after free if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size, addr)) { *msg << ": use after free\n"; } return {BufferOverflowCheckKind::UseAfterFree, Result::Error}; } else if (lifetime.is_top()) { // Possible use after free if (auto msg = this->display_mem_access_check(Result::Warning, stmt, pointer, access_size, addr)) { *msg << ": possible use after free\n"; } return {BufferOverflowCheckKind::UseAfterFree, Result::Warning}; } else { ikos_assert(lifetime.is_allocated()); } } if (isa< LocalMemoryLocation >(addr)) { // Stack memory location // Check for dangling stack pointer auto lifetime = inv.normal().lifetime_to_lifetime(addr); if (lifetime.is_deallocated()) { // Access to a dangling stack pointer if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size, addr)) { *msg << ": access to a dangling stack pointer\n"; } return {BufferOverflowCheckKind::UseAfterReturn, Result::Error}; } else if (lifetime.is_top()) { // Possible access to a dangling stack pointer if (auto msg = this->display_mem_access_check(Result::Warning, stmt, pointer, access_size, addr)) { *msg << ": possible access to a dangling stack pointer\n"; } return {BufferOverflowCheckKind::UseAfterReturn, Result::Warning}; } else { ikos_assert(lifetime.is_allocated()); } } if (isa< AbsoluteZeroMemoryLocation >(addr)) { // Checks: hardware addresses // Compute the writable interval for offset o ([o, o + access_size]) auto offset_plus_size_intv = inv.normal().int_to_interval(offset_plus_size); auto one = IntInterval(MachineInt(1, offset_intv.bit_width(), Unsigned)); auto last_byte_offset_intv = sub_no_wrap(offset_plus_size_intv, one); auto writable_interval = last_byte_offset_intv.join(offset_intv); if (_ctx.opts.hardware_addresses.geq(writable_interval)) { // The offset_var is completely included in an hardware address range // specified by the user, so we're Ok if (auto msg = this->display_mem_access_check(Result::Ok, stmt, pointer, access_size, addr)) { *msg << "[hardware addresses]: ∀o ∈ offset, o <= "; access_size->dump(msg->stream()); *msg << " && o + access_size <= "; access_size->dump(msg->stream()); *msg << "\n"; } return {BufferOverflowCheckKind::HardwareAddresses, Result::Ok}; } else if (_ctx.opts.hardware_addresses.is_meet_bottom(offset_intv) || _ctx.opts.hardware_addresses.is_meet_bottom( last_byte_offset_intv)) { // The offset_var isn't included in an hardware address range at all. // This is an error if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size, addr)) { *msg << "[hardware addresses]: ∀o ∈ offset, o > "; access_size->dump(msg->stream()); *msg << " || o + access_size > "; access_size->dump(msg->stream()); *msg << "\n"; } return {BufferOverflowCheckKind::HardwareAddresses, Result::Error}; } else { // The offset_var isn't completely included in an hardware address range // specified by the user, so it could overflow somewhere // This is a warning if (auto msg = this->display_mem_access_check(Result::Warning, stmt, pointer, access_size, addr)) { *msg << "[hardware addresses]: ∃o ∈ offset, o > "; access_size->dump(msg->stream()); *msg << " || o + access_size > "; access_size->dump(msg->stream()); *msg << "\n"; } return {BufferOverflowCheckKind::HardwareAddresses, Result::Warning}; } } // add `size` (min, max) to block_info IntInterval size_intv = inv.normal().int_to_interval(size_var); block_info.put("size", to_json(size_intv)); // add `offset + access_size - size` (min, max) to block_info auto zero = MachineInt(0, this->_data_layout.pointers.bit_width, Unsigned); auto one = MachineInt(1, this->_data_layout.pointers.bit_width, Unsigned); auto expr = IntLinearExpression(zero); expr.add(one, offset_plus_size); expr.add(-one, size_var); IntInterval diff_intv = inv.normal().int_to_interval(expr); block_info.put("diff", to_json(diff_intv)); // Checks: `offset > mem_size || offset + access_size > mem_size` value::AbstractDomain tmp1 = inv; tmp1.normal().int_add(IntPredicate::GT, offset_var, size_var); tmp1.normal().normalize(); value::AbstractDomain tmp2 = inv; tmp2.normal().int_add(IntPredicate::GT, offset_plus_size, size_var); tmp2.normal().normalize(); bool is_bottom = tmp1.is_normal_flow_bottom() && tmp2.is_normal_flow_bottom(); if (is_bottom) { // offset_var <= size_var and offset_plus_size <= size_var, so we're // safe here if (auto msg = this->display_mem_access_check(Result::Ok, stmt, pointer, access_size, addr)) { *msg << ": ∀o ∈ offset, o <= "; access_size->dump(msg->stream()); *msg << " && o + access_size <= "; access_size->dump(msg->stream()); *msg << "\n"; } return {BufferOverflowCheckKind::OutOfBound, Result::Ok}; } // Check: `offset <= mem_size && offset + access_size <= mem_size` value::AbstractDomain tmp3 = inv; tmp3.normal().int_add(IntPredicate::LE, offset_var, size_var); tmp3.normal().int_add(IntPredicate::LE, offset_plus_size, size_var); tmp3.normal().normalize(); is_bottom = tmp3.is_normal_flow_bottom(); if (is_bottom) { if (auto msg = this->display_mem_access_check(Result::Error, stmt, pointer, access_size, addr)) { *msg << ": ∀o ∈ offset, o > "; access_size->dump(msg->stream()); *msg << " || o + access_size > "; access_size->dump(msg->stream()); *msg << "\n"; } return {BufferOverflowCheckKind::OutOfBound, Result::Error}; } else { if (auto msg = this->display_mem_access_check(Result::Warning, stmt, pointer, access_size, addr)) { *msg << ": ∃o ∈ offset, o <= "; access_size->dump(msg->stream()); *msg << " && o + access_size <= "; access_size->dump(msg->stream()); *msg << "\n"; } return {BufferOverflowCheckKind::OutOfBound, Result::Warning}; } } BufferOverflowChecker::CheckResult BufferOverflowChecker::check_string_access( ar::Statement* stmt, ar::Value* pointer, Result if_null, const value::AbstractDomain& inv) { /// Notes: /// /// Since we do not keep track of null-terminated string lengths, we cannot /// prove if a string access is safe. Thus, we use one for the access size, /// checking only if the first byte is accessible. /// /// ASSUMPTION: If the first byte of a string is accessible, the string is /// well-formed. /// /// TODO(marthaud): Improve checks for strings. return this->check_mem_access(stmt, pointer, this->_size_one, if_null, inv); } BufferOverflowChecker::CheckResult BufferOverflowChecker::check_string_access( ar::Statement* stmt, ar::Value* pointer, ar::Value* max_access_size, Result if_null, const value::AbstractDomain& inv) { /// Notes: /// /// Since we do not keep track of null-terminated string lengths, we cannot /// prove if a string access is safe. Thus, we use one for the access size, /// checking only if the first byte is accessible. /// /// ASSUMPTION: If the first byte of a string is accessible, the string is /// well-formed. /// /// TODO(marthaud): Improve checks for strings. ikos_ignore(max_access_size); return this->check_mem_access(stmt, pointer, this->_size_one, if_null, inv); } BufferOverflowChecker::CheckResult BufferOverflowChecker::check_va_list_access( ar::Statement* stmt, ar::Value* pointer, const value::AbstractDomain& inv) { /// Notes: /// /// Since we do not have the size of `va_list`, we cannot prove if a `va_list` /// is safe. Thus, we use zero for the access size. /// /// ASSUMPTION: calls to `va_start`, `va_end`, `va_arg` and `va_copy` are /// memory safe. return this->check_mem_access(stmt, pointer, this->_size_zero, /* if_null = */ Result::Error, inv); } BufferOverflowChecker::CheckResult BufferOverflowChecker::check_realloc( ar::CallBase* call, ar::Value* pointer, const value::AbstractDomain& inv) { /// Notes: /// /// Since `realloc` knows the size of the allocated memory block, we use zero /// for the access size. /// /// ASSUMPTION: calls to `realloc` are memory safe. /// /// TODO(marthaud): Add checks that the pointer offset is zero. /// TODO(marthaud): Add checks that the pointer was dynamically allocated. return this->check_mem_access(call, pointer, this->_size_zero, /* if_null = */ Result::Ok, inv); } BufferOverflowChecker::CheckResult BufferOverflowChecker::check_file_access( ar::Statement* stmt, ar::Value* pointer, Result if_null, const value::AbstractDomain& inv) { /// Notes: /// /// Since we do not have the size of `FILE*`, we cannot prove if a `FILE*` /// is safe. Thus, we use zero for the access size. /// /// ASSUMPTION: accesses of `FILE*` by libc functions are memory safe. return this->check_mem_access(stmt, pointer, this->_size_zero, if_null, inv); } ar::IntegerConstant* BufferOverflowChecker::store_size(ar::Type* type) const { return ar::IntegerConstant::get(this->_ar_context, this->_size_type, MachineInt(this->_data_layout .store_size_in_bytes(type), this->_size_type->bit_width(), this->_size_type->sign())); } void BufferOverflowChecker::init_global_ptr(value::AbstractDomain& inv, ar::Value* value) const { if (auto gv = dyn_cast< ar::GlobalVariable >(value)) { Variable* ptr = _ctx.var_factory->get_global(gv); MemoryLocation* addr = _ctx.mem_factory->get_global(gv); inv.normal().pointer_assign(ptr, addr, core::Nullity::non_null()); inv.normal().normalize(); } else if (auto cst = dyn_cast< ar::FunctionPointerConstant >(value)) { auto fun = cst->function(); Variable* ptr = _ctx.var_factory->get_function_ptr(fun); MemoryLocation* addr = _ctx.mem_factory->get_function(fun); inv.normal().pointer_assign(ptr, addr, core::Nullity::non_null()); inv.normal().normalize(); } } void BufferOverflowChecker::init_global_alloc_size( value::AbstractDomain& inv, MemoryLocation* addr, AllocSizeVariable* size_var) const { if (auto gv = dyn_cast< GlobalMemoryLocation >(addr)) { MachineInt size(this->_data_layout.store_size_in_bytes( gv->global_var()->type()->pointee()), this->_data_layout.pointers.bit_width, Unsigned); inv.normal().int_assign(size_var, size); inv.normal().normalize(); } else if (isa< FunctionMemoryLocation >(addr)) { MachineInt size(0, this->_data_layout.pointers.bit_width, Unsigned); inv.normal().int_assign(size_var, size); inv.normal().normalize(); } else if (isa< LibcErrnoMemoryLocation >(addr)) { MachineInt size(4, this->_data_layout.pointers.bit_width, Unsigned); inv.normal().int_assign(size_var, size); inv.normal().normalize(); } } /// \brief Check whether an interval is a multiple of a number static bool is_multiple(const core::machine_int::Interval& interval, const MachineInt& n) { return (mod(interval.lb(), n).is_zero() || interval.lb().is_min()) && (mod(interval.ub(), n).is_zero() || interval.ub().is_max()); } boost::optional< MachineInt > BufferOverflowChecker::is_array_access( ar::Statement* stmt, const value::AbstractDomain& inv, const IntInterval& offset_intv, const PointsToSet& addrs) const { // Use heuristics to determine if it is an array access ar::Type* access_type = nullptr; // Load or Store if (auto load = dyn_cast< ar::Load >(stmt)) { access_type = load->result()->type(); } else if (auto store = dyn_cast< ar::Store >(stmt)) { access_type = store->value()->type(); } else { return boost::none; } MachineInt element_size(this->_data_layout.store_size_in_bytes(access_type), this->_size_type->bit_width(), this->_size_type->sign()); // Offset is a multiple of the element size if (!is_multiple(offset_intv, element_size)) { return boost::none; } if (!std::all_of(addrs.begin(), addrs.end(), [&](MemoryLocation* addr) { if (auto local = dyn_cast< LocalMemoryLocation >(addr)) { // Local variable with an array type auto type = local->local_var()->type()->pointee(); return type->is_array() && cast< ar::ArrayType >(type)->element_type() == access_type; } else if (auto global = dyn_cast< GlobalMemoryLocation >(addr)) { // Global variable with an array type auto type = global->global_var()->type()->pointee(); return type->is_array() && cast< ar::ArrayType >(type)->element_type() == access_type; } else if (auto dyn_alloc = dyn_cast< DynAllocMemoryLocation >(addr)) { AllocSizeVariable* size_var = _ctx.var_factory->get_alloc_size(addr); IntInterval size_intv = inv.normal().int_to_interval(size_var); // At least >= 2 elements if (size_intv.ub() <= element_size) { return false; } // Size is a multiple of the element size if (!is_multiple(size_intv, element_size)) { return false; } // Check if the next instruction is a bitcast to `access_type*` auto call = dyn_alloc->call(); auto next_stmt = call->next_statement(); if (next_stmt == nullptr) { return false; } auto unary = dyn_cast< ar::UnaryOperation >(next_stmt); return unary != nullptr && unary->operand() == call->result() && unary->op() == ar::UnaryOperation::Bitcast && unary->result()->type()->is_pointer() && cast< ar::PointerType >(unary->result()->type())->pointee() == access_type; } return false; })) { return boost::none; } return std::move(element_size); } llvm::Optional< LogMessage > BufferOverflowChecker::display_mem_access_check( Result result, ar::Statement* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_mem_access("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } llvm::Optional< LogMessage > BufferOverflowChecker::display_mem_access_check( Result result, ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_mem_access(pointer="; pointer->dump(msg->stream()); *msg << ", access_size="; access_size->dump(msg->stream()); *msg << ")"; } return msg; } llvm::Optional< LogMessage > BufferOverflowChecker::display_mem_access_check( Result result, ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, MemoryLocation* addr) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_mem_access(pointer="; pointer->dump(msg->stream()); *msg << ", access_size="; access_size->dump(msg->stream()); *msg << ", address="; addr->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/checker.cpp000066400000000000000000000134711473507761200227540ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Base class for property checker and make_checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { // Checker void Checker::display_stmt_location(LogMessage& msg, ar::Statement* s) const { msg << color::bold() << source_location_string(s, _ctx.wd) << ": " << color::off(); } void Checker::display_result(LogMessage& msg, Result result) const { switch (result) { case Result::Ok: { msg << "[" << color::bold_green() << "ok" << color::off() << "] "; } break; case Result::Warning: { msg << "[" << color::bold_yellow() << "warning" << color::off() << "] "; } break; case Result::Error: { msg << "[" << color::bold_red() << "error" << color::off() << "] "; } break; case Result::Unreachable: { msg << "[" << color::bold_magenta() << "unreachable" << color::off() << "] "; } break; default: { ikos_unreachable("unreachable"); } } } // make_checker std::unique_ptr< Checker > make_checker(Context& ctx, CheckerName name) { switch (name) { case CheckerName::BufferOverflow: return std::make_unique< BufferOverflowChecker >(ctx); case CheckerName::DivisionByZero: return std::make_unique< DivisionByZeroChecker >(ctx); case CheckerName::NullPointerDereference: return std::make_unique< NullDereferenceChecker >(ctx); case CheckerName::AssertProver: return std::make_unique< AssertProverChecker >(ctx); case CheckerName::UnalignedPointer: return std::make_unique< PointerAlignmentChecker >(ctx); case CheckerName::UninitializedVariable: return std::make_unique< UninitializedVariableChecker >(ctx); case CheckerName::SignedIntOverflow: return std::make_unique< SignedIntOverflowChecker >(ctx); case CheckerName::UnsignedIntOverflow: return std::make_unique< UnsignedIntOverflowChecker >(ctx); case CheckerName::ShiftCount: return std::make_unique< ShiftCountChecker >(ctx); case CheckerName::PointerOverflow: return std::make_unique< PointerOverflowChecker >(ctx); case CheckerName::PointerCompare: return std::make_unique< PointerCompareChecker >(ctx); case CheckerName::Soundness: return std::make_unique< SoundnessChecker >(ctx); case CheckerName::FunctionCall: return std::make_unique< FunctionCallChecker >(ctx); case CheckerName::DeadCode: return std::make_unique< DeadCodeChecker >(ctx); case CheckerName::DoubleFree: return std::make_unique< DoubleFreeChecker >(ctx); case CheckerName::Debug: return std::make_unique< DebugChecker >(ctx); case CheckerName::MemoryWatch: return std::make_unique< MemoryWatchChecker >(ctx); default: ikos_unreachable("unreachable"); } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/dead_code.cpp000066400000000000000000000134331473507761200232350ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Dead code checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { DeadCodeChecker::DeadCodeChecker(Context& ctx) : Checker(ctx) {} CheckerName DeadCodeChecker::name() const { return CheckerName::DeadCode; } const char* DeadCodeChecker::description() const { return "Dead code checker"; } void DeadCodeChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (skip_check(stmt)) { return; } ar::Statement* prev_stmt = this->previous_statement(stmt); this->save_current_statement(stmt); // Check if the current statement needs a check if (!needs_check(prev_stmt, stmt->parent())) { return; } Result result = inv.is_normal_flow_bottom() ? Result::Unreachable : Result::Ok; this->display_dead_code_check(result, stmt); this->display_invariant(result, stmt, inv); this->_checks.insert(CheckKind::Unreachable, CheckerName::DeadCode, result, stmt, call_context); } ar::Statement* DeadCodeChecker::previous_statement(ar::Statement* stmt) const { auto it = this->_prev_stmts.find(stmt->parent()); if (it != this->_prev_stmts.end()) { return it->second; } else { return nullptr; // First statement in the basic block } } void DeadCodeChecker::save_current_statement(ar::Statement* stmt) { ar::BasicBlock* bb = stmt->parent(); if (bb->back() == stmt) { // Last statement in the basic block, no need to keep it in the map this->_prev_stmts.erase(bb); return; } this->_prev_stmts[bb] = stmt; } bool DeadCodeChecker::skip_check(ar::Statement* stmt) { if (!stmt->has_frontend()) { // No checks on statements without debug info return true; } if (ar::isa< ar::Unreachable >(stmt)) { // No checks on unreachable statements return true; } if (ar::isa< ar::Assignment >(stmt) || ar::isa< ar::UnaryOperation >(stmt)) { auto value = stmt->frontend< llvm::Value >(); if (llvm::isa< llvm::PHINode >(value) || llvm::isa< llvm::CmpInst >(value)) { // No checks on assignments for phi nodes and comparisons return true; } } return false; } bool DeadCodeChecker::needs_check(ar::Statement* prev_stmt, ar::BasicBlock* bb) { if (prev_stmt != nullptr) { return isa< ar::Comparison >(prev_stmt) || isa< ar::CallBase >(prev_stmt); } // First statement of the basic block, look for predecessors std::vector< ar::BasicBlock* > preds{bb->predecessor_begin(), bb->predecessor_end()}; while (!preds.empty()) { ar::BasicBlock* pred = preds.back(); preds.pop_back(); auto it = pred->rbegin(); auto et = pred->rend(); // Skip statements without debug info, as well as assignments while (it != et && skip_check(*it)) { ++it; } if (it == et) { // Predecessor is empty, look further up preds.insert(preds.end(), pred->predecessor_begin(), pred->predecessor_end()); continue; } ar::Statement* last_stmt = *it; if (isa< ar::Comparison >(last_stmt) || isa< ar::CallBase >(last_stmt)) { return true; } } return false; } void DeadCodeChecker::display_dead_code_check(Result result, ar::Statement* stmt) const { if (auto msg = this->display_check(result, stmt)) { *msg << "check_dead_code("; stmt->dump(msg->stream()); *msg << ")\n"; } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/debug.cpp000066400000000000000000000222221473507761200224300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Debug checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { DebugChecker::DebugChecker(Context& ctx) : Checker(ctx) {} CheckerName DebugChecker::name() const { return CheckerName::Debug; } const char* DebugChecker::description() const { return "Debug checker"; } void DebugChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* /*call_context*/) { if (auto call = dyn_cast< ar::IntrinsicCall >(stmt)) { ar::Function* fun = call->called_function(); switch (fun->intrinsic_id()) { case ar::Intrinsic::IkosPrintInvariant: { this->exec_print_invariant(call, inv); } break; case ar::Intrinsic::IkosPrintValues: { this->exec_print_values(call, inv); } break; default: { break; } } } } void DebugChecker::exec_print_invariant(ar::IntrinsicCall* call, const value::AbstractDomain& inv) { LogMessage msg = log::msg(); this->display_stmt_location(msg, call); msg << "__ikos_print_invariant():\n"; inv.dump(msg.stream()); msg << "\n"; } /// \brief Print the interval of an integer variable static void print_interval(LogMessage& msg, const std::string& repr, const core::machine_int::Interval& i) { msg << "\t" << repr; if (i.is_bottom()) { msg << " is bottom\n"; } else if (auto x = i.singleton()) { msg << " is " << *x << "\n"; } else { msg << " is in [" << i.lb() << ", " << i.ub() << "]\n"; } } /// \brief Remove the '&' at the beginning of a string static std::string deref(std::string s) { if (!s.empty() && s[0] == '&') { return s.substr(1); } else { return s; } } /// \brief Fix the string textual representations /// /// This transforms &"xxx"[0] into "xxx" static std::string fix_string_repr(std::string s) { if (boost::starts_with(s, "&\"") && boost::ends_with(s, "\"[0]")) { return s.substr(1, s.size() - 4); } else { return s; } } /// \brief Textual representation of a memory location static std::string memory_location_repr(MemoryLocation* mem) { if (auto local_mem = dyn_cast< LocalMemoryLocation >(mem)) { return deref(OperandsTable::repr(local_mem->local_var())); } else if (auto global_mem = dyn_cast< GlobalMemoryLocation >(mem)) { return deref(OperandsTable::repr(global_mem->global_var())); } else if (auto fun_mem = dyn_cast< FunctionMemoryLocation >(mem)) { return demangle(fun_mem->function()->name()); } else if (auto aggregate_mem = dyn_cast< AggregateMemoryLocation >(mem)) { return OperandsTable::repr(aggregate_mem->internal_var()); } else if (isa< AbsoluteZeroMemoryLocation >(mem)) { return "absolute zero"; } else if (isa< ArgvMemoryLocation >(mem)) { return "argv"; } else if (isa< LibcErrnoMemoryLocation >(mem)) { return "libc.errno"; } else if (auto dyn_alloc_mem = dyn_cast< DynAllocMemoryLocation >(mem)) { ar::CallBase* call = dyn_alloc_mem->call(); ar::Function* fun = call->code()->function(); std::string r = "dyn_alloc:" + demangle(fun->name()); SourceLocation loc = source_location(call); if (loc) { r += ':'; r += std::to_string(loc.line()); r += ':'; r += std::to_string(loc.column()); } return r; } else { ikos_unreachable("unexpected memory location"); } } /// \brief Print the points-to set of a pointer variable static void print_points_to( LogMessage& msg, const std::string& repr, const core::PointsToSet< MemoryLocation* >& points_to) { if (points_to.is_bottom()) { msg << "\t" << repr << " points-to set is bottom\n"; } else if (points_to.is_top()) { msg << "\t" << repr << " points-to set is unknown\n"; } else if (points_to.is_empty()) { msg << "\t" << repr << " points-to set is empty\n"; } else if (auto mem = points_to.singleton()) { msg << "\t" << repr << " points to " << memory_location_repr(*mem) << "\n"; } else { msg << "\t" << repr << " points to {"; for (auto it = points_to.begin(), et = points_to.end(); it != et;) { msg << memory_location_repr(*it); ++it; if (it != et) { msg << ", "; } } msg << "}\n"; } } /// \brief Print the nullity of a pointer variable static void print_nullity(LogMessage& msg, const std::string& repr, const core::Nullity& nullity) { msg << "\t" << repr; if (nullity.is_bottom()) { msg << " is bottom\n"; } else if (nullity.is_null()) { msg << " is null\n"; } else if (nullity.is_non_null()) { msg << " is non-null\n"; } else { msg << " may be null\n"; } } static void print_uninitialized(LogMessage& msg, const std::string& repr, const core::Uninitialized& uninitialized) { msg << "\t" << repr; if (uninitialized.is_bottom()) { msg << " is bottom\n"; } else if (uninitialized.is_uninitialized()) { msg << " is uninitialized\n"; } else if (uninitialized.is_initialized()) { msg << " is initialized\n"; } else { msg << " may be uninitialized\n"; } } void DebugChecker::exec_print_values(ar::IntrinsicCall* call, const value::AbstractDomain& inv) { LogMessage msg = log::msg(); this->display_stmt_location(msg, call); msg << "__ikos_print_values("; for (auto it = call->arg_begin(), et = call->arg_end(); it != et;) { msg << fix_string_repr(OperandsTable::repr(*it)); ++it; if (it != et) { msg << ", "; } } msg << "):\n"; if (inv.is_normal_flow_bottom()) { msg << "\tStatement is unreachable\n"; } else if (call->num_arguments() <= 1) { msg << "\tMissing arguments\n"; } else { for (auto it = call->arg_begin() + 1, et = call->arg_end(); it != et; ++it) { std::string repr = OperandsTable::repr(*it); const ScalarLit& v = this->_lit_factory.get_scalar(*it); if (v.is_machine_int_var()) { print_interval(msg, repr, inv.normal().int_to_interval(v.var())); } else if (v.is_floating_point_var()) { // ignored for now } else if (v.is_pointer_var()) { print_points_to(msg, repr, inv.normal().pointer_to_points_to(v.var())); print_interval(msg, "offset of " + repr, inv.normal().pointer_offset_to_interval(v.var())); print_nullity(msg, repr, inv.normal().nullity_to_nullity(v.var())); } else { msg << "\tArgument " << repr << " is not a variable\n"; continue; } print_uninitialized(msg, repr, inv.normal().uninit_to_uninitialized(v.var())); } } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/division_by_zero.cpp000066400000000000000000000135251473507761200247250ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Division by zero checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { DivisionByZeroChecker::DivisionByZeroChecker(Context& ctx) : Checker(ctx) {} CheckerName DivisionByZeroChecker::name() const { return CheckerName::DivisionByZero; } const char* DivisionByZeroChecker::description() const { return "Division by zero checker"; } void DivisionByZeroChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto bin = dyn_cast< ar::BinaryOperation >(stmt)) { if (bin->op() == ar::BinaryOperation::UDiv || bin->op() == ar::BinaryOperation::SDiv || bin->op() == ar::BinaryOperation::URem || bin->op() == ar::BinaryOperation::SRem) { CheckResult check = this->check_division(bin, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::DivisionByZero, check.result, stmt, call_context, std::array< ar::Value*, 1 >{{bin->right()}}, check.info); } } } DivisionByZeroChecker::CheckResult DivisionByZeroChecker::check_division( ar::BinaryOperation* stmt, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_division_check(Result::Unreachable, stmt)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}}; } const ScalarLit& lit = this->_lit_factory.get_scalar(stmt->right()); if (lit.is_undefined() || (lit.is_machine_int_var() && inv.normal().uninit_is_uninitialized(lit.var()))) { // Undefined operand if (auto msg = this->display_division_check(Result::Error, stmt)) { *msg << ": undefined operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {}}; } auto divisor = IntInterval::bottom(1, Signed); if (lit.is_machine_int()) { divisor = IntInterval(lit.machine_int()); } else if (lit.is_machine_int_var()) { divisor = inv.normal().int_to_interval(lit.var()); } else { log::error("unexpected operand to binary operation"); return {CheckKind::UnexpectedOperand, Result::Error, {}}; } boost::optional< MachineInt > d = divisor.singleton(); if (d && (*d).is_zero()) { // The second operand is definitely 0 if (auto msg = this->display_division_check(Result::Error, stmt)) { *msg << ": ∀d ∈ divisor, d == 0\n"; } return {CheckKind::DivisionByZero, Result::Error, {}}; } else if (divisor.contains( MachineInt::zero(divisor.bit_width(), divisor.sign()))) { // The second operand may be 0 if (auto msg = this->display_division_check(Result::Warning, stmt)) { *msg << ": ∃d ∈ divisor, d == 0\n"; } return {CheckKind::DivisionByZero, Result::Warning, to_json(divisor)}; } else { // The second operand cannot be definitely 0 if (auto msg = this->display_division_check(Result::Ok, stmt)) { *msg << ": ∀d ∈ divisor, d != 0\n"; } return {CheckKind::DivisionByZero, Result::Ok, {}}; } } llvm::Optional< LogMessage > DivisionByZeroChecker::display_division_check( Result result, ar::BinaryOperation* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_dbz("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/double_free.cpp000066400000000000000000000276231473507761200236270ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Double free checker implementation * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { DoubleFreeChecker::DoubleFreeChecker(Context& ctx) : Checker(ctx) {} CheckerName DoubleFreeChecker::name() const { return CheckerName::DoubleFree; } const char* DoubleFreeChecker::description() const { return "Double free checker"; } void DoubleFreeChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto call = dyn_cast< ar::CallBase >(stmt)) { std::vector< CheckResult > checks = this->check_call(call, inv); for (const auto& check : checks) { this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::DoubleFree, check.result, stmt, call_context, check.operands, check.info); } } } std::vector< DoubleFreeChecker::CheckResult > DoubleFreeChecker::check_call( ar::CallBase* call, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_double_free_check(Result::Unreachable, call)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}, {}}}; } const ScalarLit& called = this->_lit_factory.get_scalar(call->called()); // Check uninitialized if (called.is_undefined() || (called.is_pointer_var() && inv.normal().uninit_is_uninitialized(called.var()))) { // Undefined call pointer operand if (auto msg = this->display_double_free_check(Result::Error, call)) { *msg << ": undefined call pointer operand\n"; } return {{CheckKind::UninitializedVariable, Result::Error, {call->called()}, {}}}; } // Check null pointer dereference if (called.is_null() || (called.is_pointer_var() && inv.normal().nullity_is_null(called.var()))) { // Null call pointer operand if (auto msg = this->display_double_free_check(Result::Error, call)) { *msg << ": null call pointer operand\n"; } return {{CheckKind::NullPointerDereference, Result::Error, {call->called()}, {}}}; } // Collect potential callees auto callees = PointsToSet::bottom(); if (auto cst = dyn_cast< ar::FunctionPointerConstant >(call->called())) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(call->called())) { // call to inline assembly if (auto msg = this->display_double_free_check(Result::Ok, call)) { *msg << ": call to inline assembly\n"; } return {{CheckKind::FunctionCallInlineAssembly, Result::Ok, {}, {}}}; } else if (auto gv = dyn_cast< ar::GlobalVariable >(call->called())) { callees = {_ctx.mem_factory->get_global(gv)}; } else if (auto lv = dyn_cast< ar::LocalVariable >(call->called())) { callees = {_ctx.mem_factory->get_local(lv)}; } else if (isa< ar::InternalVariable >(call->called())) { // Indirect call through a function pointer callees = inv.normal().pointer_to_points_to(called.var()); } else { log::error("unexpected call pointer operand"); return { {CheckKind::UnexpectedOperand, Result::Error, {call->called()}, {}}}; } // Check callees ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference if (auto msg = this->display_double_free_check(Result::Error, call)) { *msg << ": points-to set of function pointer is empty\n"; } return {{CheckKind::InvalidPointerDereference, Result::Error, {call->called()}, {}}}; } else if (callees.is_top()) { // No points-to set if (auto msg = this->display_double_free_check(Result::Warning, call)) { *msg << ": no points-to set for function pointer\n"; } return {{CheckKind::UnknownFunctionCallPointer, Result::Warning, {call->called()}, {}}}; } std::vector< CheckResult > checks; for (MemoryLocation* addr : callees) { if (!isa< FunctionMemoryLocation >(addr)) { // Not a call to a function memory location continue; } ar::Function* callee = cast< FunctionMemoryLocation >(addr)->function(); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call continue; } if (callee->is_intrinsic()) { boost::optional< CheckResult > check = this->check_intrinsic_call(call, callee, inv); if (check) { checks.push_back(*check); } } } return checks; } boost::optional< DoubleFreeChecker::CheckResult > DoubleFreeChecker:: check_intrinsic_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv) { switch (fun->intrinsic_id()) { case ar::Intrinsic::LibcRealloc: case ar::Intrinsic::LibcFree: case ar::Intrinsic::LibcFclose: case ar::Intrinsic::LibcppDelete: case ar::Intrinsic::LibcppDeleteArray: case ar::Intrinsic::LibcppFreeException: { return this->check_double_free(call, call->argument(0), inv); } default: { return boost::none; } } } DoubleFreeChecker::CheckResult DoubleFreeChecker::check_double_free( ar::CallBase* call, ar::Value* pointer, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_double_free_check(Result::Unreachable, call)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}, {}}; } const ScalarLit& ptr = this->_lit_factory.get_scalar(pointer); if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { if (auto msg = this->display_double_free_check(Result::Error, call)) { *msg << ": undefined operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {pointer}, {}}; } if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { if (auto msg = this->display_double_free_check(Result::Ok, call)) { *msg << ": safe call to free with NULL value\n"; } return {CheckKind::Free, Result::Ok, {pointer}, {}}; } PointsToSet addrs = inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_empty()) { if (auto msg = this->display_double_free_check(Result::Error, call)) { *msg << ": empty points-to set for pointer\n"; } return {CheckKind::InvalidPointerDereference, Result::Error, {pointer}, {}}; } else if (addrs.is_top()) { if (auto msg = this->display_double_free_check(Result::Warning, call)) { *msg << ": no points-to information for pointer\n"; } return {CheckKind::IgnoredFree, Result::Warning, {pointer}, {}}; } bool all_error = true; bool all_ok = true; JsonDict info; JsonList points_to_info; for (const auto& addr : addrs) { JsonDict block_info = { {"id", _ctx.output_db->memory_locations.insert(addr)}}; Result result = this->check_memory_location_free(call, inv, addr); block_info.put("status", static_cast< int >(result)); if (result == Result::Ok) { all_error = false; } else if (result == Result::Warning) { all_error = false; all_ok = false; } else { all_ok = false; } points_to_info.add(block_info); } info.put("points_to", points_to_info); if (all_error) { // Unsafe return {CheckKind::Free, Result::Error, {pointer}, info}; } else if (all_ok) { // Safe return {CheckKind::Free, Result::Ok, {pointer}, {}}; } else { // Warning return {CheckKind::Free, Result::Warning, {pointer}, info}; } } Result DoubleFreeChecker::check_memory_location_free( ar::CallBase* call, const value::AbstractDomain& inv, MemoryLocation* addr) { if (isa< DynAllocMemoryLocation >(addr)) { auto lifetime = inv.normal().lifetime_to_lifetime(addr); if (lifetime.is_deallocated()) { // This is a double free if (auto msg = this->display_double_free_check(Result::Error, call, addr)) { *msg << ": double free\n"; } return Result::Error; } else if (lifetime.is_top()) { // A double free could be possible if (auto msg = this->display_double_free_check(Result::Warning, call, addr)) { *msg << ": possible double free\n"; } return Result::Warning; } else { // Safe if (auto msg = this->display_double_free_check(Result::Ok, call, addr)) { *msg << ": safe call to free()\n"; } return Result::Ok; } } else { // This is a free() call on something which isn't a dynamic allocated // memory. // This is an error if (auto msg = this->display_double_free_check(Result::Error, call, addr)) { *msg << ": free() called on a non-dynamic allocated memory\n"; } return Result::Error; } } llvm::Optional< LogMessage > DoubleFreeChecker::display_double_free_check( Result result, ar::Statement* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_dfa("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } llvm::Optional< LogMessage > DoubleFreeChecker::display_double_free_check( Result result, ar::CallBase* call, MemoryLocation* addr) const { auto msg = this->display_check(result, call); if (msg) { *msg << "check_dfa("; call->dump(msg->stream()); *msg << ", addr="; addr->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/function_call.cpp000066400000000000000000000210161473507761200241620ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Function call checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { FunctionCallChecker::FunctionCallChecker(Context& ctx) : Checker(ctx) {} CheckerName FunctionCallChecker::name() const { return CheckerName::FunctionCall; } const char* FunctionCallChecker::description() const { return "Function call checker"; } void FunctionCallChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto call = dyn_cast< ar::CallBase >(stmt)) { CheckResult check = this->check_call(call, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::FunctionCall, check.result, stmt, call_context, check.operands, check.info); } } FunctionCallChecker::CheckResult FunctionCallChecker::check_call( ar::CallBase* call, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_call_check(Result::Unreachable, call)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}, {}}; } const ScalarLit& called = this->_lit_factory.get_scalar(call->called()); // Check uninitialized if (called.is_undefined() || (called.is_pointer_var() && inv.normal().uninit_is_uninitialized(called.var()))) { // Undefined call pointer operand if (auto msg = this->display_call_check(Result::Error, call)) { *msg << ": undefined call pointer operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {call->called()}, {}}; } // Check null pointer dereference if (called.is_null() || (called.is_pointer_var() && inv.normal().nullity_is_null(called.var()))) { // Null call pointer operand if (auto msg = this->display_call_check(Result::Error, call)) { *msg << ": null call pointer operand\n"; } return {CheckKind::NullPointerDereference, Result::Error, {call->called()}, {}}; } // Collect potential callees auto callees = PointsToSet::bottom(); if (auto cst = dyn_cast< ar::FunctionPointerConstant >(call->called())) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(call->called())) { // call to inline assembly if (auto msg = this->display_call_check(Result::Ok, call)) { *msg << ": call to inline assembly\n"; } return {CheckKind::FunctionCallInlineAssembly, Result::Ok, {}, {}}; } else if (auto gv = dyn_cast< ar::GlobalVariable >(call->called())) { callees = {_ctx.mem_factory->get_global(gv)}; } else if (auto lv = dyn_cast< ar::LocalVariable >(call->called())) { callees = {_ctx.mem_factory->get_local(lv)}; } else if (isa< ar::InternalVariable >(call->called())) { // Indirect call through a function pointer callees = inv.normal().pointer_to_points_to(called.var()); } else { log::error("unexpected call pointer operand"); return {CheckKind::UnexpectedOperand, Result::Error, {call->called()}, {}}; } // Check callees ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference if (auto msg = this->display_call_check(Result::Error, call)) { *msg << ": points-to set of function pointer is empty\n"; } return {CheckKind::InvalidPointerDereference, Result::Error, {call->called()}, {}}; } else if (callees.is_top()) { // No points-to set if (auto msg = this->display_call_check(Result::Warning, call)) { *msg << ": no points-to set for function pointer\n"; } return {CheckKind::UnknownFunctionCallPointer, Result::Warning, {call->called()}, {}}; } // Are all the callees valid/invalid bool all_valid = true; bool all_invalid = true; JsonList points_to_info; for (MemoryLocation* addr : callees) { JsonDict block_info = { {"id", _ctx.output_db->memory_locations.insert(addr)}}; if (!isa< FunctionMemoryLocation >(addr)) { // Not a call to a function memory location, emit a warning if (auto msg = this->display_call_check(Result::Error, call)) { *msg << ": potential call to "; addr->dump(msg->stream()); *msg << ", which is not a function\n"; } block_info.put("kind", static_cast< int >(FunctionCallCheckKind::NotFunction)); all_valid = false; } else { ar::Function* callee = cast< FunctionMemoryLocation >(addr)->function(); block_info.put("fun_id", _ctx.output_db->functions.insert(callee)); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call // This could be because of an imprecision of the pointer analysis. if (auto msg = this->display_call_check(Result::Error, call)) { *msg << ": potential call to " << callee->name() << ", wrong signature\n"; } block_info.put("kind", static_cast< int >( FunctionCallCheckKind::WrongSignature)); all_valid = false; } else { if (auto msg = this->display_call_check(Result::Ok, call)) { *msg << ": potential call to " << callee->name() << "\n"; } block_info.put("kind", static_cast< int >(FunctionCallCheckKind::Ok)); all_invalid = false; } } points_to_info.add(block_info); } JsonDict info; info.put("points_to", points_to_info); if (all_invalid) { return {CheckKind::FunctionCall, Result::Error, {call->called()}, info}; } else if (!all_valid) { return {CheckKind::FunctionCall, Result::Warning, {call->called()}, info}; } else { return {CheckKind::FunctionCall, Result::Ok, {call->called()}, info}; } } llvm::Optional< LogMessage > FunctionCallChecker::display_call_check( Result result, ar::CallBase* call) const { auto msg = this->display_check(result, call); if (msg) { *msg << "check_call("; call->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/int_overflow_base.cpp000066400000000000000000000237051473507761200250600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Base for integer overflow checker implementation * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { /// \brief Return a text representation of the given binary operator static char op_char(ar::BinaryOperation::Operator op) { switch (op) { case ar::BinaryOperation::SAdd: case ar::BinaryOperation::UAdd: return '+'; case ar::BinaryOperation::SSub: case ar::BinaryOperation::USub: return '-'; case ar::BinaryOperation::SMul: case ar::BinaryOperation::UMul: return '*'; case ar::BinaryOperation::SDiv: case ar::BinaryOperation::UDiv: return '/'; case ar::BinaryOperation::SRem: case ar::BinaryOperation::URem: return '%'; default: ikos_unreachable("unexpected binary operator"); } } IntOverflowCheckerBase::IntOverflowCheckerBase(Context& ctx) : Checker(ctx) {} void IntOverflowCheckerBase::check_integer_overflow( ar::BinaryOperation* stmt, const value::AbstractDomain& inv, CallContext* call_context) { llvm::SmallVector< CheckResult, 2 > checks = this->check_integer_overflow(stmt, inv); for (const auto& check : checks) { this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, this->name(), check.result, stmt, call_context, check.operands, check.info); } } llvm::SmallVector< IntOverflowCheckerBase::CheckResult, 2 > IntOverflowCheckerBase::check_integer_overflow( ar::BinaryOperation* stmt, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_int_overflow_check(Result::Unreachable, stmt)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}, {}}}; } if (stmt->result()->type()->is_vector()) { return {}; // TODO(marthaud): Support checks on vector operations } const ScalarLit& left_lit = this->_lit_factory.get_scalar(stmt->left()); const ScalarLit& right_lit = this->_lit_factory.get_scalar(stmt->right()); auto left_interval = IntInterval::bottom(1, Signed); auto right_interval = IntInterval::bottom(1, Signed); if (left_lit.is_undefined() || (left_lit.is_machine_int_var() && inv.normal().uninit_is_uninitialized(left_lit.var()))) { // Undefined operand if (auto msg = this->display_int_overflow_check(Result::Error, stmt)) { *msg << ": undefined left operand\n"; } return { {CheckKind::UninitializedVariable, Result::Error, {stmt->left()}, {}}}; } else if (left_lit.is_machine_int()) { left_interval = IntInterval(left_lit.machine_int()); } else if (left_lit.is_machine_int_var()) { left_interval = inv.normal().int_to_interval(left_lit.var()); } else { log::error("unexpected operand to binary operation"); return {{CheckKind::UnexpectedOperand, Result::Error, {stmt->left()}, {}}}; } if (right_lit.is_undefined() || (right_lit.is_machine_int_var() && inv.normal().uninit_is_uninitialized(right_lit.var()))) { // Undefined operand if (auto msg = this->display_int_overflow_check(Result::Error, stmt)) { *msg << ": undefined right operand\n"; } return { {CheckKind::UninitializedVariable, Result::Error, {stmt->right()}, {}}}; } else if (right_lit.is_machine_int()) { right_interval = IntInterval(right_lit.machine_int()); } else if (right_lit.is_machine_int_var()) { right_interval = inv.normal().int_to_interval(right_lit.var()); } else { log::error("unexpected operand to binary operation"); return {{CheckKind::UnexpectedOperand, Result::Error, {stmt->right()}, {}}}; } auto result_interval = ZInterval::bottom(); // Computes final interval, depending on the binary operator if (stmt->op() == ar::BinaryOperation::SAdd || stmt->op() == ar::BinaryOperation::UAdd) { result_interval = left_interval.to_z_interval() + right_interval.to_z_interval(); } else if (stmt->op() == ar::BinaryOperation::SSub || stmt->op() == ar::BinaryOperation::USub) { result_interval = left_interval.to_z_interval() - right_interval.to_z_interval(); } else if (stmt->op() == ar::BinaryOperation::SMul || stmt->op() == ar::BinaryOperation::UMul) { result_interval = left_interval.to_z_interval() * right_interval.to_z_interval(); } else if (stmt->op() == ar::BinaryOperation::SDiv || stmt->op() == ar::BinaryOperation::UDiv) { result_interval = left_interval.to_z_interval() / right_interval.to_z_interval(); } else if (stmt->op() == ar::BinaryOperation::URem || stmt->op() == ar::BinaryOperation::SRem) { // signed remainder INT_MIN % -1 is undefined behavior // we're using division to check this case, because // we're checking INT_MIN / -1 result_interval = left_interval.to_z_interval() / right_interval.to_z_interval(); } else { ikos_unreachable("unexpected operator"); } // No result because of division by zero if (result_interval.is_bottom()) { if (auto msg = this->display_int_overflow_check(Result::Error, stmt)) { *msg << ": division by zero\n"; } return {{CheckKind::DivisionByZero, Result::Error, {stmt->right()}, {}}}; } auto type = cast< ar::IntegerType >(stmt->result()->type()); ZBound max(MachineInt::max(type->bit_width(), type->sign()).to_z_number()); ZBound min(MachineInt::min(type->bit_width(), type->sign()).to_z_number()); const ZBound& lb = result_interval.lb(); const ZBound& ub = result_interval.ub(); Result result_underflow; Result result_overflow; JsonDict info; info.put("left", to_json(left_interval)); info.put("right", to_json(right_interval)); if (lb > max) { result_underflow = Result::Ok; result_overflow = Result::Error; if (auto msg = this->display_int_overflow_check(Result::Error, stmt)) { *msg << ": ∀ a, b ∈ left x right, left " << op_char(stmt->op()) << " right > INT_MAX\n"; } } else if (ub < min) { result_underflow = Result::Error; result_overflow = Result::Ok; if (auto msg = this->display_int_overflow_check(Result::Error, stmt)) { *msg << ": ∀ a, b ∈ left x right, left " << op_char(stmt->op()) << " right < INT_MIN\n"; } } else { result_underflow = (lb < min) ? Result::Warning : Result::Ok; result_overflow = (ub > max) ? Result::Warning : Result::Ok; if (auto msg = this->display_int_overflow_check(result_underflow, stmt)) { *msg << " [underflow]: "; if (result_underflow == Result::Warning) { *msg << "lower_bound < min\n"; } else { *msg << "lower_bound >= min\n"; } } if (auto msg = this->display_int_overflow_check(result_overflow, stmt)) { *msg << " [overflow]: "; if (result_overflow == Result::Warning) { *msg << "upper_bound > max\n"; } else { *msg << "upper_bound <= max\n"; } } } return {{this->underflow_check_kind(), result_underflow, {stmt->left(), stmt->right()}, ((result_underflow != Result::Ok) ? info : JsonDict())}, {this->overflow_check_kind(), result_overflow, {stmt->left(), stmt->right()}, ((result_overflow != Result::Ok) ? info : JsonDict())}}; } llvm::Optional< LogMessage > IntOverflowCheckerBase::display_int_overflow_check( Result result, ar::BinaryOperation* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_" << this->short_name() << "("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/memory_watch.cpp000066400000000000000000000605251473507761200240500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Memory watch checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { MemoryWatchChecker::MemoryWatchChecker(Context& ctx) : Checker(ctx), _ar_context(ctx.bundle->context()), _data_layout(ctx.bundle->data_layout()), _size_type(ar::IntegerType::size_type(ctx.bundle)) { ar::Type* void_ty = ar::VoidType::get(this->_ar_context); ar::Type* void_ptr_ty = ar::PointerType::get(this->_ar_context, void_ty); this->_watch_mem_ptr = ctx.var_factory->get_named_shadow(void_ptr_ty, "shadow.watch_mem.ptr"); this->_watch_mem_size = ctx.var_factory->get_named_shadow(this->_size_type, "shadow.watch_mem.size"); } CheckerName MemoryWatchChecker::name() const { return CheckerName::MemoryWatch; } const char* MemoryWatchChecker::description() const { return "Memory watch checker"; } void MemoryWatchChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto store = dyn_cast< ar::Store >(stmt)) { this->check_store(store, inv); } else if (auto call = dyn_cast< ar::CallBase >(stmt)) { this->check_call(call, inv, call_context); } } void MemoryWatchChecker::check_store(ar::Store* store, const value::AbstractDomain& inv) { this->check_mem_write(store, store->pointer(), this->store_size(store->value()->type()), inv); } void MemoryWatchChecker::check_call(ar::CallBase* call, const value::AbstractDomain& inv, CallContext* call_context) { if (inv.is_normal_flow_bottom()) { // Statement unreachable return; } const ScalarLit& called = this->_lit_factory.get_scalar(call->called()); if (called.is_undefined() || (called.is_pointer_var() && inv.normal().uninit_is_uninitialized(called.var()))) { // Undefined call pointer operand return; } if (called.is_null() || (called.is_pointer_var() && inv.normal().nullity_is_null(called.var()))) { // Null call pointer operand return; } // Collect potential callees auto callees = PointsToSet::bottom(); if (auto cst = dyn_cast< ar::FunctionPointerConstant >(call->called())) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(call->called())) { // Call to assembly this->check_unknown_extern_call(call, inv); return; } else if (isa< ar::GlobalVariable >(call->called())) { // Call to global variable: error return; } else if (isa< ar::LocalVariable >(call->called())) { // Call to local variable: error return; } else if (isa< ar::InternalVariable >(call->called())) { // Indirect call through a function pointer callees = inv.normal().pointer_to_points_to(called.var()); } else { log::error("unexpected call pointer operand"); return; } // Check callees ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference return; } else if (callees.is_top()) { // No points-to information this->check_unknown_extern_call(call, inv); return; } ar::Function* caller = call->code()->function_or_null(); for (MemoryLocation* addr : callees) { if (!isa< FunctionMemoryLocation >(addr)) { // Not a call to a function memory location continue; } ar::Function* callee = cast< FunctionMemoryLocation >(addr)->function(); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call continue; } else if (caller == callee || call_context->contains(callee)) { // Recursive function call this->check_recursive_call(call, callee, inv); } else if (callee->is_intrinsic()) { this->check_intrinsic_call(call, callee, inv); } else if (callee->is_declaration()) { this->check_unknown_extern_call(call, inv); } } } void MemoryWatchChecker::check_recursive_call( ar::CallBase* call, ar::Function* /*fun*/, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable return; } // Watched addresses PointsToSet watch_addrs = inv.normal().pointer_to_points_to(this->_watch_mem_ptr); if (watch_addrs.is_empty() || watch_addrs.is_top()) { // Not watching anything, __ikos_watch_mem was not called return; } LogMessage msg = log::msg(); this->display_stmt_location(msg, call); msg << "potential memory write at a watched memory location\n"; } void MemoryWatchChecker::check_intrinsic_call( ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv) { switch (fun->intrinsic_id()) { case ar::Intrinsic::MemoryCopy: case ar::Intrinsic::MemoryMove: case ar::Intrinsic::MemorySet: { this->check_mem_write(call, call->argument(0), call->argument(2), inv); } break; case ar::Intrinsic::VarArgStart: case ar::Intrinsic::VarArgEnd: case ar::Intrinsic::VarArgGet: case ar::Intrinsic::VarArgCopy: { this->check_unknown_call(call, inv, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::StackSave: case ar::Intrinsic::StackRestore: case ar::Intrinsic::LifetimeStart: case ar::Intrinsic::LifetimeEnd: case ar::Intrinsic::EhTypeidFor: case ar::Intrinsic::Trap: { } break; // case ar::Intrinsic::IkosAssert: case ar::Intrinsic::IkosAssume: case ar::Intrinsic::IkosNonDet: case ar::Intrinsic::IkosCounterInit: case ar::Intrinsic::IkosCounterIncr: case ar::Intrinsic::IkosCheckMemAccess: case ar::Intrinsic::IkosCheckStringAccess: case ar::Intrinsic::IkosAssumeMemSize: { } break; case ar::Intrinsic::IkosForgetMemory: case ar::Intrinsic::IkosAbstractMemory: { this->check_mem_write(call, call->argument(0), call->argument(1), inv); } break; case ar::Intrinsic::IkosWatchMemory: case ar::Intrinsic::IkosPartitioningVar: case ar::Intrinsic::IkosPartitioningJoin: case ar::Intrinsic::IkosPartitioningDisable: case ar::Intrinsic::IkosPrintInvariant: case ar::Intrinsic::IkosPrintValues: { } break; // case ar::Intrinsic::LibcMalloc: case ar::Intrinsic::LibcCalloc: case ar::Intrinsic::LibcValloc: case ar::Intrinsic::LibcAlignedAlloc: case ar::Intrinsic::LibcRealloc: case ar::Intrinsic::LibcFree: case ar::Intrinsic::LibcAbs: case ar::Intrinsic::LibcRand: case ar::Intrinsic::LibcSrand: case ar::Intrinsic::LibcExit: case ar::Intrinsic::LibcAbort: { } break; // case ar::Intrinsic::LibcErrnoLocation: { } break; // case ar::Intrinsic::LibcOpen: { } break; // case ar::Intrinsic::LibcClose: { } break; case ar::Intrinsic::LibcRead: { this->check_mem_write(call, call->argument(1), call->argument(2), inv); } break; case ar::Intrinsic::LibcWrite: { } break; // case ar::Intrinsic::LibcGets: { this->check_mem_write(call, call->argument(0), inv); } break; case ar::Intrinsic::LibcFgets: { this->check_mem_write(call, call->argument(0), call->argument(1), inv); } break; case ar::Intrinsic::LibcGetc: case ar::Intrinsic::LibcFgetc: case ar::Intrinsic::LibcGetchar: case ar::Intrinsic::LibcPuts: case ar::Intrinsic::LibcFputs: case ar::Intrinsic::LibcPutc: case ar::Intrinsic::LibcFputc: case ar::Intrinsic::LibcPrintf: case ar::Intrinsic::LibcFprintf: { } break; case ar::Intrinsic::LibcSprintf: { this->check_mem_write(call, call->argument(0), inv); } break; case ar::Intrinsic::LibcSnprintf: { this->check_mem_write(call, call->argument(0), call->argument(1), inv); } break; case ar::Intrinsic::LibcScanf: { this->check_unknown_call(call, inv, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFscanf: { this->check_unknown_call(call, inv, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcSscanf: { this->check_unknown_call(call, inv, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ false); } break; case ar::Intrinsic::LibcFopen: case ar::Intrinsic::LibcFclose: case ar::Intrinsic::LibcFflush: { } break; // case ar::Intrinsic::LibcStrlen: case ar::Intrinsic::LibcStrnlen: { } break; case ar::Intrinsic::LibcStrcpy: { this->check_mem_write(call, call->argument(0), inv); } break; case ar::Intrinsic::LibcStrncpy: { this->check_mem_write(call, call->argument(0), call->argument(2), inv); } break; case ar::Intrinsic::LibcStrcat: { this->check_mem_write(call, call->argument(0), inv); } break; case ar::Intrinsic::LibcStrncat: { this->check_mem_write(call, call->argument(0), inv); } break; case ar::Intrinsic::LibcStrcmp: case ar::Intrinsic::LibcStrncmp: case ar::Intrinsic::LibcStrstr: case ar::Intrinsic::LibcStrchr: case ar::Intrinsic::LibcStrdup: case ar::Intrinsic::LibcStrndup: { } break; case ar::Intrinsic::LibcStrcpyCheck: { this->check_mem_write(call, call->argument(0), inv); } break; case ar::Intrinsic::LibcMemoryCopyCheck: case ar::Intrinsic::LibcMemoryMoveCheck: case ar::Intrinsic::LibcMemorySetCheck: { this->check_mem_write(call, call->argument(0), call->argument(2), inv); } break; case ar::Intrinsic::LibcStrcatCheck: { this->check_mem_write(call, call->argument(0), inv); } break; case ar::Intrinsic::LibcppNew: case ar::Intrinsic::LibcppNewArray: case ar::Intrinsic::LibcppDelete: case ar::Intrinsic::LibcppDeleteArray: case ar::Intrinsic::LibcppAllocateException: case ar::Intrinsic::LibcppFreeException: case ar::Intrinsic::LibcppThrow: case ar::Intrinsic::LibcppBeginCatch: case ar::Intrinsic::LibcppEndCatch: { } break; default: { ikos_unreachable("unreachable"); } } } void MemoryWatchChecker::check_unknown_extern_call( ar::CallBase* call, const value::AbstractDomain& inv) { this->check_unknown_call(call, inv, /* may_write_params = */ true, /* ignore_unknown_write = */ true, /* may_write_globals = */ false, /* may_throw_exc = */ true); } void MemoryWatchChecker::check_unknown_call(ar::CallBase* call, value::AbstractDomain inv, bool may_write_params, bool ignore_unknown_write, bool may_write_globals, bool /*may_throw_exc*/) { if (inv.is_normal_flow_bottom()) { // Statement unreachable return; } // Watched addresses PointsToSet watch_addrs = inv.normal().pointer_to_points_to(this->_watch_mem_ptr); if (watch_addrs.is_empty() || watch_addrs.is_top()) { // Not watching anything, __ikos_watch_mem was not called return; } if (may_write_globals) { // May write on global variables LogMessage msg = log::msg(); this->display_stmt_location(msg, call); msg << "potential memory write at a watched memory location\n"; return; } if (!may_write_params) { // Won't write on pointer parameters return; } for (auto it = call->arg_begin(), et = call->arg_end(); it != et; ++it) { ar::Value* arg = *it; if (!isa< ar::InternalVariable >(arg) || !isa< ar::PointerType >(arg->type())) { continue; } auto iv = cast< ar::InternalVariable >(arg); Variable* ptr = _ctx.var_factory->get_internal(iv); this->init_global_ptr(inv, arg); if (inv.normal().nullity_is_null(ptr)) { // Null pointer parameter continue; } // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr); if (addrs.is_empty()) { // Pointer is invalid continue; } else if (addrs.is_top()) { if (ignore_unknown_write) { // Ignored side effect on the memory continue; } else { LogMessage msg = log::msg(); this->display_stmt_location(msg, call); msg << "potential memory write at a watched memory location\n"; return; } } else if (addrs.meet(watch_addrs).is_empty()) { // Not writing on a watched address continue; } else { LogMessage msg = log::msg(); this->display_stmt_location(msg, call); msg << "potential memory write at a watched memory location\n"; return; } } } void MemoryWatchChecker::check_mem_write(ar::Statement* stmt, ar::Value* pointer, ar::Value* access_size, value::AbstractDomain inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable return; } // Watched addresses PointsToSet watch_addrs = inv.normal().pointer_to_points_to(this->_watch_mem_ptr); if (watch_addrs.is_empty() || watch_addrs.is_top()) { // Not watching anything, __ikos_watch_mem was not called return; } const ScalarLit& ptr = this->_lit_factory.get_scalar(pointer); const ScalarLit& size = this->_lit_factory.get_scalar(access_size); if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined pointer operand return; } if (size.is_undefined() || (size.is_machine_int_var() && inv.normal().uninit_is_uninitialized(size.var()))) { // Undefined pointer operand return; } if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { // Null pointer operand return; } // Check unexpected operand if (!ptr.is_pointer_var()) { log::error("unexpected pointer operand"); return; } if (!size.is_machine_int() && !size.is_machine_int_var()) { log::error("unexpected size operand"); return; } // Initialize global variable pointer and function pointer this->init_global_ptr(inv, pointer); // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_empty()) { // Pointer is invalid return; } else if (addrs.is_top()) { // Ignored memory write return; } else if (addrs.meet(watch_addrs).is_empty()) { // Not writing on a watched address return; } // Variable representing the pointer offset Variable* offset = ptr.var()->offset_var(); inv.normal().pointer_offset_to_int(offset, ptr.var()); // Add a shadow variable `offset_plus_size = offset + access_size` Variable* offset_plus_size = _ctx.var_factory->get_named_shadow(this->_size_type, "shadow.offset_plus_size"); if (access_size->type() == this->_size_type) { if (size.is_machine_int_var()) { inv.normal().int_apply(IntBinaryOperator::Add, offset_plus_size, offset, size.var()); } else if (size.is_machine_int()) { inv.normal().int_apply(IntBinaryOperator::Add, offset_plus_size, offset, size.machine_int()); } else { ikos_unreachable("unexpected access size"); } } else { // This happens in LibcFgets for instance if (size.is_machine_int_var()) { inv.normal().int_apply(IntUnaryOperator::Cast, offset_plus_size, size.var()); inv.normal().int_apply(IntBinaryOperator::Add, offset_plus_size, offset_plus_size, offset); } else if (size.is_machine_int()) { inv.normal() .int_apply(IntBinaryOperator::Add, offset_plus_size, offset, size.machine_int().cast(this->_size_type->bit_width(), ar::Unsigned)); } else { ikos_unreachable("unexpected access size"); } } // Variable representing the watched pointer offset Variable* watch_offset = this->_watch_mem_ptr->offset_var(); inv.normal().pointer_offset_to_int(watch_offset, this->_watch_mem_ptr); // Add a shadow variable `watch_offset_plus_size = watch_offset + watch_size` Variable* watch_offset_plus_size = _ctx.var_factory->get_named_shadow(this->_size_type, "shadow.watch_offset_plus_size"); inv.normal().int_apply(IntBinaryOperator::Add, watch_offset_plus_size, watch_offset, this->_watch_mem_size); // Add a shadow variable that represents an offset in bytes Variable* x = _ctx.var_factory->get_named_shadow(this->_size_type, "shadow.watch_mem.x"); // Check if it might overlap // Check if there exists an integer x such that: // x is in [offset, offset + size - 1] // x is in [watch_offset, watch_offset + watch_size - 1] value::AbstractDomain tmp1 = inv; tmp1.normal().int_add(IntPredicate::GE, x, offset); tmp1.normal().int_add(IntPredicate::LT, x, offset_plus_size); tmp1.normal().int_add(IntPredicate::GE, x, watch_offset); tmp1.normal().int_add(IntPredicate::LT, x, watch_offset_plus_size); tmp1.normal().normalize(); if (tmp1.is_normal_flow_bottom()) { // Overlap not possible return; } // Check if it always overlaps // Check if all offset + size - 1 >= watch_offset value::AbstractDomain tmp2 = inv; tmp2.normal().int_add(IntPredicate::LE, offset_plus_size, watch_offset); tmp2.normal().normalize(); // Check if all offset < watch_offset + watch_size value::AbstractDomain tmp3 = inv; tmp3.normal().int_add(IntPredicate::GE, offset, watch_offset_plus_size); tmp3.normal().normalize(); LogMessage msg = log::msg(); this->display_stmt_location(msg, stmt); if (tmp2.is_normal_flow_bottom() && tmp3.is_normal_flow_bottom()) { // Always overlaps msg << "memory write at a watched memory location\n"; } else { // Might overlap msg << "potential memory write at a watched memory location\n"; } } void MemoryWatchChecker::check_mem_write(ar::Statement* stmt, ar::Value* pointer, value::AbstractDomain inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable return; } // Watched addresses PointsToSet watch_addrs = inv.normal().pointer_to_points_to(this->_watch_mem_ptr); if (watch_addrs.is_empty() || watch_addrs.is_top()) { // Not watching anything, __ikos_watch_mem was not called return; } const ScalarLit& ptr = this->_lit_factory.get_scalar(pointer); if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined pointer operand return; } if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { // Null pointer operand return; } // Check unexpected operand if (!ptr.is_pointer_var()) { log::error("unexpected pointer operand"); return; } // Initialize global variable pointer and function pointer this->init_global_ptr(inv, pointer); // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_empty()) { // Pointer is invalid return; } else if (addrs.is_top()) { // Ignored memory write return; } else if (addrs.meet(watch_addrs).is_empty()) { // Not writing on a watched address return; } else { LogMessage msg = log::msg(); this->display_stmt_location(msg, stmt); msg << "potential memory write at a watched memory location\n"; } } void MemoryWatchChecker::init_global_ptr(value::AbstractDomain& inv, ar::Value* value) const { if (auto gv = dyn_cast< ar::GlobalVariable >(value)) { Variable* ptr = _ctx.var_factory->get_global(gv); MemoryLocation* addr = _ctx.mem_factory->get_global(gv); inv.normal().pointer_assign(ptr, addr, core::Nullity::non_null()); } else if (auto cst = dyn_cast< ar::FunctionPointerConstant >(value)) { auto fun = cst->function(); Variable* ptr = _ctx.var_factory->get_function_ptr(fun); MemoryLocation* addr = _ctx.mem_factory->get_function(fun); inv.normal().pointer_assign(ptr, addr, core::Nullity::non_null()); } } ar::IntegerConstant* MemoryWatchChecker::store_size(ar::Type* type) const { return ar::IntegerConstant::get(this->_ar_context, this->_size_type, MachineInt(this->_data_layout .store_size_in_bytes(type), this->_size_type->bit_width(), this->_size_type->sign())); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/null_dereference.cpp000066400000000000000000000465671473507761200246650ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Null dereference checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { NullDereferenceChecker::NullDereferenceChecker(Context& ctx) : Checker(ctx) {} CheckerName NullDereferenceChecker::name() const { return CheckerName::NullPointerDereference; } const char* NullDereferenceChecker::description() const { return "Null dereference checker"; } void NullDereferenceChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto load = dyn_cast< ar::Load >(stmt)) { CheckResult check = this->check_null(stmt, load->operand(), inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::NullPointerDereference, check.result, stmt, call_context, check.operands); } else if (auto store = dyn_cast< ar::Store >(stmt)) { CheckResult check = this->check_null(stmt, store->pointer(), inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::NullPointerDereference, check.result, stmt, call_context, check.operands); } else if (auto call = dyn_cast< ar::CallBase >(stmt)) { std::vector< CheckResult > checks = this->check_call(call, inv); for (const auto& check : checks) { this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::NullPointerDereference, check.result, stmt, call_context, check.operands); } } } std::vector< NullDereferenceChecker::CheckResult > NullDereferenceChecker:: check_call(ar::CallBase* call, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_null_check(Result::Unreachable, call)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}}}; } const ScalarLit& called = this->_lit_factory.get_scalar(call->called()); // Check uninitialized if (called.is_undefined() || (called.is_pointer_var() && inv.normal().uninit_is_uninitialized(called.var()))) { // Undefined call pointer operand if (auto msg = this->display_null_check(Result::Error, call, call->called())) { *msg << ": undefined call pointer operand\n"; } return { {CheckKind::UninitializedVariable, Result::Error, {call->called()}}}; } // Check null pointer dereference if (called.is_null() || (called.is_pointer_var() && inv.normal().nullity_is_null(called.var()))) { // Null call pointer operand if (auto msg = this->display_null_check(Result::Error, call, call->called())) { *msg << ": null call pointer operand\n"; } return { {CheckKind::NullPointerDereference, Result::Error, {call->called()}}}; } // Collect potential callees auto callees = PointsToSet::bottom(); if (auto cst = dyn_cast< ar::FunctionPointerConstant >(call->called())) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(call->called())) { // call to inline assembly if (auto msg = this->display_null_check(Result::Ok, call, call->called())) { *msg << ": call to inline assembly\n"; } return {{CheckKind::FunctionCallInlineAssembly, Result::Ok, {}}}; } else if (auto gv = dyn_cast< ar::GlobalVariable >(call->called())) { callees = {_ctx.mem_factory->get_global(gv)}; } else if (auto lv = dyn_cast< ar::LocalVariable >(call->called())) { callees = {_ctx.mem_factory->get_local(lv)}; } else if (isa< ar::InternalVariable >(call->called())) { // Indirect call through a function pointer callees = inv.normal().pointer_to_points_to(called.var()); } else { log::error("unexpected call pointer operand"); return {{CheckKind::UnexpectedOperand, Result::Error, {call->called()}}}; } // Check callees ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference if (auto msg = this->display_null_check(Result::Error, call, call->called())) { *msg << ": points-to set of function pointer is empty\n"; } return {{CheckKind::InvalidPointerDereference, Result::Error, {call->called()}}}; } std::vector< CheckResult > checks = { this->check_null(call, call->called(), inv)}; if (callees.is_top()) { // No points-to set if (auto msg = this->display_null_check(Result::Warning, call, call->called())) { *msg << ": no points-to set for function pointer\n"; } checks.push_back({CheckKind::UnknownFunctionCallPointer, Result::Warning, {call->called()}}); return checks; } for (MemoryLocation* addr : callees) { if (!isa< FunctionMemoryLocation >(addr)) { // Not a call to a function memory location continue; } ar::Function* callee = cast< FunctionMemoryLocation >(addr)->function(); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call continue; } if (callee->is_intrinsic()) { for (const auto& check : this->check_intrinsic_call(call, callee, inv)) { checks.push_back(check); } } } return checks; } std::vector< NullDereferenceChecker::CheckResult > NullDereferenceChecker:: check_intrinsic_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv) { switch (fun->intrinsic_id()) { case ar::Intrinsic::MemoryCopy: case ar::Intrinsic::MemoryMove: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::MemorySet: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::VarArgStart: case ar::Intrinsic::VarArgEnd: case ar::Intrinsic::VarArgGet: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::VarArgCopy: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::StackSave: case ar::Intrinsic::StackRestore: case ar::Intrinsic::LifetimeStart: case ar::Intrinsic::LifetimeEnd: case ar::Intrinsic::EhTypeidFor: case ar::Intrinsic::Trap: { return {}; } // case ar::Intrinsic::IkosAssert: case ar::Intrinsic::IkosAssume: case ar::Intrinsic::IkosNonDet: case ar::Intrinsic::IkosCounterInit: case ar::Intrinsic::IkosCounterIncr: { return {}; } case ar::Intrinsic::IkosCheckMemAccess: case ar::Intrinsic::IkosCheckStringAccess: case ar::Intrinsic::IkosAssumeMemSize: case ar::Intrinsic::IkosForgetMemory: case ar::Intrinsic::IkosAbstractMemory: case ar::Intrinsic::IkosWatchMemory: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::IkosPartitioningVar: case ar::Intrinsic::IkosPartitioningJoin: case ar::Intrinsic::IkosPartitioningDisable: case ar::Intrinsic::IkosPrintInvariant: case ar::Intrinsic::IkosPrintValues: { return {}; } // case ar::Intrinsic::LibcMalloc: case ar::Intrinsic::LibcCalloc: case ar::Intrinsic::LibcValloc: case ar::Intrinsic::LibcAlignedAlloc: case ar::Intrinsic::LibcRealloc: case ar::Intrinsic::LibcFree: case ar::Intrinsic::LibcAbs: case ar::Intrinsic::LibcRand: case ar::Intrinsic::LibcSrand: case ar::Intrinsic::LibcExit: case ar::Intrinsic::LibcAbort: { return {}; } // case ar::Intrinsic::LibcErrnoLocation: { return {}; } // case ar::Intrinsic::LibcOpen: { return {this->check_null(call, call->argument(0), inv)}; } // case ar::Intrinsic::LibcClose: { return {}; } case ar::Intrinsic::LibcRead: { return {this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcWrite: { return {this->check_null(call, call->argument(1), inv)}; } // case ar::Intrinsic::LibcGets: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcFgets: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(2), inv)}; } case ar::Intrinsic::LibcGetc: case ar::Intrinsic::LibcFgetc: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcGetchar: { return {}; } case ar::Intrinsic::LibcPuts: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcFputs: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcPutc: case ar::Intrinsic::LibcFputc: { return {this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcPrintf: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcFprintf: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcSprintf: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcSnprintf: { std::vector< CheckResult > checks = {}; // Calling snprintf with zero bufsz and null pointer buffer can be used // to determine the buffer size needed to contain the output. That case // is allowed. Otherwise, check first argument. auto bufsz = this->_lit_factory.get_scalar(call->argument(1)); if (!(bufsz.is_machine_int() && bufsz.machine_int().is_zero())) { checks.push_back(this->check_null(call, call->argument(0), inv)); } checks.push_back(this->check_null(call, call->argument(2), inv)); return checks; } case ar::Intrinsic::LibcScanf: case ar::Intrinsic::LibcFscanf: case ar::Intrinsic::LibcSscanf: { std::vector< CheckResult > checks; std::transform(call->arg_begin(), call->arg_end(), std::back_inserter(checks), [=](ar::Value* arg) { return this->check_null(call, arg, inv); }); return checks; } case ar::Intrinsic::LibcFopen: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcFclose: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcFflush: { return {this->check_null(call, call->argument(0), inv)}; } // case ar::Intrinsic::LibcStrlen: case ar::Intrinsic::LibcStrnlen: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcStrcpy: case ar::Intrinsic::LibcStrncpy: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcStrcat: case ar::Intrinsic::LibcStrncat: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcStrcmp: case ar::Intrinsic::LibcStrncmp: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcStrstr: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcStrchr: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcStrdup: case ar::Intrinsic::LibcStrndup: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcStrcpyCheck: case ar::Intrinsic::LibcMemoryCopyCheck: case ar::Intrinsic::LibcMemoryMoveCheck: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcMemorySetCheck: { return {this->check_null(call, call->argument(0), inv)}; } case ar::Intrinsic::LibcStrcatCheck: { return {this->check_null(call, call->argument(0), inv), this->check_null(call, call->argument(1), inv)}; } case ar::Intrinsic::LibcppNew: case ar::Intrinsic::LibcppNewArray: case ar::Intrinsic::LibcppDelete: case ar::Intrinsic::LibcppDeleteArray: case ar::Intrinsic::LibcppAllocateException: case ar::Intrinsic::LibcppFreeException: case ar::Intrinsic::LibcppThrow: case ar::Intrinsic::LibcppBeginCatch: case ar::Intrinsic::LibcppEndCatch: { return {}; } default: { ikos_unreachable("unreachable"); } } } NullDereferenceChecker::CheckResult NullDereferenceChecker::check_null( ar::Statement* stmt, ar::Value* operand, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_null_check(Result::Unreachable, stmt, operand)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}}; } const ScalarLit& ptr = this->_lit_factory.get_scalar(operand); if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined operand if (auto msg = this->display_null_check(Result::Error, stmt, operand)) { *msg << ": undefined operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {operand}}; } if (ptr.is_null()) { // Null operand if (auto msg = this->display_null_check(Result::Error, stmt, operand)) { *msg << ": null operand\n"; } return {CheckKind::NullPointerDereference, Result::Error, {operand}}; } if (!ptr.is_pointer_var()) { log::error("unexpected pointer operand"); return {CheckKind::UnexpectedOperand, Result::Error, {operand}}; } if (isa< ar::LocalVariable >(operand)) { // Local variable if (auto msg = this->display_null_check(Result::Ok, stmt, operand)) { *msg << ": dereferencing a local variable\n"; } return {CheckKind::NullPointerDereference, Result::Ok, {operand}}; } else if (isa< ar::GlobalVariable >(operand)) { // Global variable if (auto msg = this->display_null_check(Result::Ok, stmt, operand)) { *msg << ": dereferencing a global variable\n"; } return {CheckKind::NullPointerDereference, Result::Ok, {operand}}; } else if (isa< ar::InlineAssemblyConstant >(operand)) { // Inline Assembly if (auto msg = this->display_null_check(Result::Ok, stmt, operand)) { *msg << ": dereferencing an inline assembly\n"; } return {CheckKind::NullPointerDereference, Result::Ok, {operand}}; } else if (isa< ar::FunctionPointerConstant >(operand)) { // Function pointer constant if (auto msg = this->display_null_check(Result::Ok, stmt, operand)) { *msg << ": dereferencing a function pointer\n"; } return {CheckKind::NullPointerDereference, Result::Ok, {operand}}; } core::Nullity nullity = inv.normal().nullity_to_nullity(ptr.var()); if (nullity.is_null()) { // Pointer is definitely null if (auto msg = this->display_null_check(Result::Error, stmt, operand)) { *msg << ": pointer is null\n"; } return {CheckKind::NullPointerDereference, Result::Error, {operand}}; } else if (nullity.is_non_null()) { // Pointer is definitely non-null if (auto msg = this->display_null_check(Result::Ok, stmt, operand)) { *msg << ": pointer is non null\n"; } return {CheckKind::NullPointerDereference, Result::Ok, {operand}}; } else { // Pointer may be null if (auto msg = this->display_null_check(Result::Warning, stmt, operand)) { *msg << ": pointer may be null\n"; } return {CheckKind::NullPointerDereference, Result::Warning, {operand}}; } } llvm::Optional< LogMessage > NullDereferenceChecker::display_null_check( Result result, ar::Statement* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_null_dereference("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } llvm::Optional< LogMessage > NullDereferenceChecker::display_null_check( Result result, ar::Statement* stmt, ar::Value* operand) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_null_dereference("; operand->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/pointer_alignment.cpp000066400000000000000000000352401473507761200250640ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer alignment checker implementation * * Author: Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { PointerAlignmentChecker::PointerAlignmentChecker(Context& ctx) : Checker(ctx), _data_layout(ctx.bundle->data_layout()) {} CheckerName PointerAlignmentChecker::name() const { return CheckerName::UnalignedPointer; } const char* PointerAlignmentChecker::description() const { return "pointer alignment checker"; } void PointerAlignmentChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto store = dyn_cast< ar::Store >(stmt)) { this->check_alignment(store, store->pointer(), store->alignment(), inv, call_context); } else if (auto load = dyn_cast< ar::Load >(stmt)) { this->check_alignment(load, load->operand(), load->alignment(), inv, call_context); } else if (auto memcpy = dyn_cast< ar::MemoryCopy >(stmt)) { this->check_alignment(memcpy, memcpy->source(), memcpy->source_alignment(), inv, call_context); this->check_alignment(memcpy, memcpy->destination(), memcpy->destination_alignment(), inv, call_context); } else if (auto memmove = dyn_cast< ar::MemoryMove >(stmt)) { this->check_alignment(memmove, memmove->source(), memmove->source_alignment(), inv, call_context); this->check_alignment(memmove, memmove->destination(), memmove->destination_alignment(), inv, call_context); } else if (auto memset = dyn_cast< ar::MemorySet >(stmt)) { this->check_alignment(memset, memset->pointer(), memset->alignment(), inv, call_context); } } void PointerAlignmentChecker::check_alignment(ar::Statement* stmt, ar::Value* operand, uint64_t alignment_req, const value::AbstractDomain& inv, CallContext* call_context) { CheckResult check = this->check_alignment(stmt, operand, alignment_req, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::UnalignedPointer, check.result, stmt, call_context, std::array< ar::Value*, 1 >{{operand}}, check.info); } PointerAlignmentChecker::CheckResult PointerAlignmentChecker::check_alignment( ar::Statement* stmt, ar::Value* operand, uint64_t alignment_req, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_alignment_check(Result::Unreachable, stmt, operand)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}}; } const ScalarLit& ptr = this->_lit_factory.get_scalar(operand); if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined operand if (auto msg = this->display_alignment_check(Result::Error, stmt, operand)) { *msg << ": undefined operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {}}; } if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { // Null operand if (auto msg = this->display_alignment_check(Result::Error, stmt, operand)) { *msg << ": null operand\n"; } return {CheckKind::NullPointerDereference, Result::Error, {}}; } if (!ptr.is_pointer_var()) { log::error("unexpected pointer operand"); return {CheckKind::UnexpectedOperand, Result::Error, {}}; } if (alignment_req == 0 || alignment_req == 1) { // No alignment requirement found, or always-safe alignment requirement if (auto msg = this->display_alignment_check(Result::Ok, stmt, operand)) { *msg << ": pointer alignment always safe\n"; } return {CheckKind::UnalignedPointer, Result::Ok, {}}; } // Pointer variable Variable* ptr_var = ptr.var(); // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr_var); if (auto gv = dyn_cast< ar::GlobalVariable >(operand)) { addrs = PointsToSet{_ctx.mem_factory->get_global(gv)}; } if (addrs.is_empty()) { // Pointer is invalid if (auto msg = this->display_alignment_check(Result::Error, stmt, operand)) { *msg << ": empty points-to set for pointer\n"; } return {CheckKind::InvalidPointerDereference, Result::Error, {}}; } if (addrs.is_top()) { // Unknown points-to set if (auto msg = this->display_alignment_check(Result::Warning, stmt, operand)) { *msg << ": no points-to information for pointer\n"; } return {CheckKind::UnknownMemoryAccess, Result::Warning, {}}; } Congruence alignment_req_c = to_congruence(alignment_req, 0); Congruence offset_c = inv.normal().pointer_offset_to_congruence(ptr_var); if (isa< ar::GlobalVariable >(operand)) { offset_c = to_congruence(0, 0); } JsonDict info; JsonList points_to_info; info.put("requirement", to_json(alignment_req_c)); info.put("offset", to_json(offset_c)); // Are all the points-to in/valid bool all_valid = true; bool all_invalid = true; // The goal is to check the following property: // points_to(ptr) != TOP && // ∀a ∈ points_to_set(ptr), ∀o ∈ offset, a + o ≡ 0 [alignment_req] // (eq. to a + o % alignment_req == 0) // // Iterate through the points-to set of the pointer // - If every memory location has an alignment greater or equal to the // requirement, then it's OK. // - If every memory location is unaligned based on the requirement, // set to ERROR state. // - Otherwise, it's a WARNING for (MemoryLocation* addr : addrs) { // Add info to json JsonDict block_info = { {"id", _ctx.output_db->memory_locations.insert(addr)}}; // Is the points_to correctly aligned? Result is_correctly_aligned = this->check_memory_location_alignment(addr, offset_c, alignment_req_c, block_info); if (is_correctly_aligned == Result::Ok) { all_invalid = false; if (auto msg = this->display_alignment_check(is_correctly_aligned, stmt, operand)) { *msg << ": memory location ("; addr->dump(msg->stream()); *msg << ") with offset (" << offset_c << ") is correctly aligned\n"; } } else if (is_correctly_aligned == Result::Error) { all_valid = false; if (auto msg = this->display_alignment_check(is_correctly_aligned, stmt, operand)) { *msg << ": memory location ("; addr->dump(msg->stream()); *msg << ") with offset (" << offset_c << ") is unaligned\n"; } } else { all_valid = false; all_invalid = false; if (auto msg = this->display_alignment_check(is_correctly_aligned, stmt, operand)) { *msg << ": memory location ("; addr->dump(msg->stream()); *msg << ") with offset (" << offset_c << ") may be unaligned\n"; } } points_to_info.add(block_info); } info.put("points_to", points_to_info); if (all_valid) { if (auto msg = this->display_alignment_check(Result::Ok, stmt, operand)) { *msg << ": pointer is aligned\n"; } return {CheckKind::UnalignedPointer, Result::Ok, {}}; } else if (all_invalid) { if (auto msg = this->display_alignment_check(Result::Error, stmt, operand)) { *msg << ": pointer is unaligned\n"; } return {CheckKind::UnalignedPointer, Result::Error, info}; } else { if (auto msg = this->display_alignment_check(Result::Warning, stmt, operand)) { *msg << ": pointer may be unaligned\n"; } return {CheckKind::UnalignedPointer, Result::Warning, info}; } } Result PointerAlignmentChecker::check_memory_location_alignment( MemoryLocation* memloc, const Congruence& offset_c, const Congruence& alignment_req_c, JsonDict& block_info) { // Get the alignment of the memory_location bool pto_in_alignment_req = false; bool alignment_req_in_pto = true; if (auto local_memloc = dyn_cast< LocalMemoryLocation >(memloc)) { ar::LocalVariable* lv = local_memloc->local_var(); Congruence local_alignment_c = to_congruence(lv->has_alignment() ? lv->alignment() : 1, 0); pto_in_alignment_req = add(local_alignment_c, offset_c).leq(alignment_req_c); alignment_req_in_pto = alignment_req_c.leq(add(local_alignment_c, offset_c)); block_info.put("congruence", to_json(local_alignment_c)); } else if (auto global_memloc = dyn_cast< GlobalMemoryLocation >(memloc)) { ar::GlobalVariable* gv = global_memloc->global_var(); Congruence global_alignment_c = to_congruence(gv->has_alignment() ? gv->alignment() : 1, 0); pto_in_alignment_req = add(global_alignment_c, offset_c).leq(alignment_req_c); alignment_req_in_pto = alignment_req_c.leq(add(global_alignment_c, offset_c)); block_info.put("congruence", to_json(global_alignment_c)); } else if (isa< FunctionMemoryLocation >(memloc)) { return Result::Error; } else if (isa< AggregateMemoryLocation >(memloc)) { return Result::Error; } else if (isa< AbsoluteZeroMemoryLocation >(memloc)) { pto_in_alignment_req = offset_c.leq(alignment_req_c); alignment_req_in_pto = alignment_req_c.leq(offset_c); } else if (isa< ArgvMemoryLocation >(memloc)) { // We suppose that argv has the best possible alignment pto_in_alignment_req = offset_c.leq(alignment_req_c); alignment_req_in_pto = alignment_req_c.leq(offset_c); } else if (isa< LibcErrnoMemoryLocation >(memloc)) { // We suppose that errno has the best possible alignment pto_in_alignment_req = offset_c.leq(alignment_req_c); alignment_req_in_pto = alignment_req_c.leq(offset_c); } else if (isa< DynAllocMemoryLocation >(memloc)) { // We suppose a dynamic allocation like malloc always returns the best // possible alignment for every type, even for vectors pto_in_alignment_req = offset_c.leq(alignment_req_c); alignment_req_in_pto = alignment_req_c.leq(offset_c); } else { ikos_unreachable("unexpected memory location"); } // - If the alignment is in the requirement, we are sure the requirement // is met // - If the alignment contains the requirement (meaning the requirement is // in the alignment), this may be a precision issue // - Otherwise, there is no common part between the found alignment and // the requirement, thus we are sure the requirement is not met if (pto_in_alignment_req) { return Result::Ok; } else if (alignment_req_in_pto) { return Result::Warning; } else { return Result::Error; } } core::machine_int::Congruence PointerAlignmentChecker::to_congruence( uint64_t a, uint64_t b) const { return Congruence(ZNumber(a), ZNumber(b), this->_data_layout.pointers.bit_width, Unsigned); } llvm::Optional< LogMessage > PointerAlignmentChecker::display_alignment_check( Result result, ar::Statement* stmt, ar::Value* operand) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_pointer_alignment("; operand->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/pointer_compare.cpp000066400000000000000000000215061473507761200245340ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer compare checker implementation * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { PointerCompareChecker::PointerCompareChecker(Context& ctx) : Checker(ctx) {} CheckerName PointerCompareChecker::name() const { return CheckerName::PointerCompare; } const char* PointerCompareChecker::description() const { return "Pointer compare checker"; } void PointerCompareChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto cmp = dyn_cast< ar::Comparison >(stmt)) { if (cmp->is_pointer_predicate() && cmp->predicate() != ar::Comparison::PEQ && cmp->predicate() != ar::Comparison::PNE) { CheckResult check = this->check_pointer_compare(cmp, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::PointerCompare, check.result, stmt, call_context, check.operands, check.info); } } } PointerCompareChecker::CheckResult PointerCompareChecker::check_pointer_compare( ar::Comparison* stmt, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_pointer_compare_check(Result::Unreachable, stmt)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}, {}}; } const ScalarLit& left_ptr = this->_lit_factory.get_scalar(stmt->left()); const ScalarLit& right_ptr = this->_lit_factory.get_scalar(stmt->right()); // Check uninitialized operands if (left_ptr.is_undefined() || (left_ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(left_ptr.var()))) { if (auto msg = this->display_pointer_compare_check(Result::Error, stmt)) { *msg << ": undefined left operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {stmt->left()}, {}}; } else if (right_ptr.is_undefined() || (right_ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(right_ptr.var()))) { if (auto msg = this->display_pointer_compare_check(Result::Error, stmt)) { *msg << ": undefined right operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {stmt->right()}, {}}; } // Check for null operands if (left_ptr.is_null() || (left_ptr.is_pointer_var() && inv.normal().nullity_is_null(left_ptr.var()))) { if (auto msg = this->display_pointer_compare_check(Result::Error, stmt)) { *msg << ": null left operand\n"; } return {CheckKind::NullPointerComparison, Result::Error, {stmt->left()}, {}}; } else if (right_ptr.is_null() || (right_ptr.is_pointer_var() && inv.normal().nullity_is_null(right_ptr.var()))) { if (auto msg = this->display_pointer_compare_check(Result::Error, stmt)) { *msg << ": null right operand\n"; } return {CheckKind::NullPointerComparison, Result::Error, {stmt->right()}, {}}; } if (!left_ptr.is_pointer_var()) { log::error("unexpected operand to comparison"); return {CheckKind::UnexpectedOperand, Result::Error, {stmt->left()}, {}}; } else if (!right_ptr.is_pointer_var()) { log::error("unexpected operand to comparison"); return {CheckKind::UnexpectedOperand, Result::Error, {stmt->right()}, {}}; } auto left_addrs = PointsToSet::bottom(); if (auto gv = dyn_cast< ar::GlobalVariable >(stmt->left())) { left_addrs = {_ctx.mem_factory->get_global(gv)}; } else if (auto cst = dyn_cast< ar::FunctionPointerConstant >(stmt->left())) { left_addrs = {_ctx.mem_factory->get_function(cst->function())}; } else { left_addrs = inv.normal().pointer_to_points_to(left_ptr.var()); } auto right_addrs = PointsToSet::bottom(); if (auto gv = dyn_cast< ar::GlobalVariable >(stmt->right())) { right_addrs = {_ctx.mem_factory->get_global(gv)}; } else if (auto cst = dyn_cast< ar::FunctionPointerConstant >(stmt->right())) { right_addrs = {_ctx.mem_factory->get_function(cst->function())}; } else { right_addrs = inv.normal().pointer_to_points_to(right_ptr.var()); } if (left_addrs.is_empty()) { if (auto msg = this->display_pointer_compare_check(Result::Error, stmt)) { *msg << ": empty points-to set for left operand\n"; } return {CheckKind::InvalidPointerComparison, Result::Error, {stmt->left()}, {}}; } else if (right_addrs.is_empty()) { if (auto msg = this->display_pointer_compare_check(Result::Error, stmt)) { *msg << ": empty points-to set for right operand\n"; } return {CheckKind::InvalidPointerComparison, Result::Error, {stmt->right()}, {}}; } PointsToSet join_addrs = left_addrs.join(right_addrs); PointsToSet meet_addrs = left_addrs.meet(right_addrs); Result result; if (meet_addrs.is_empty()) { result = Result::Error; } else if (join_addrs.is_top() || join_addrs.size() > 1) { result = Result::Warning; } else { result = Result::Ok; } if (auto msg = this->display_pointer_compare_check(result, stmt)) { *msg << ": left addresses=" << left_addrs << " right addresses=" << right_addrs << "\n"; } JsonDict info; if (result != Result::Ok) { if (left_addrs.is_set()) { JsonList left_points_to; for (MemoryLocation* mem_loc : left_addrs) { left_points_to.add(_ctx.output_db->memory_locations.insert(mem_loc)); } info.put("left_points_to", left_points_to); } else { ikos_assert(left_addrs.is_top()); } if (right_addrs.is_set()) { JsonList right_points_to; for (MemoryLocation* mem_loc : right_addrs) { right_points_to.add(_ctx.output_db->memory_locations.insert(mem_loc)); } info.put("right_points_to", right_points_to); } else { ikos_assert(right_addrs.is_top()); } } return {CheckKind::PointerComparison, result, {stmt->left(), stmt->right()}, info}; } llvm::Optional< LogMessage > PointerCompareChecker:: display_pointer_compare_check(Result result, ar::Comparison* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_pcmp("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/pointer_overflow.cpp000066400000000000000000000162311473507761200247500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer overflow checker implementation * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { PointerOverflowChecker::PointerOverflowChecker(Context& ctx) : Checker(ctx), _data_layout(ctx.bundle->data_layout()) {} CheckerName PointerOverflowChecker::name() const { return CheckerName::PointerOverflow; } const char* PointerOverflowChecker::description() const { return "Pointer overflow checker"; } void PointerOverflowChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto bin = dyn_cast< ar::PointerShift >(stmt)) { CheckResult check = this->check_pointer_overflow(bin, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::PointerOverflow, check.result, stmt, call_context, check.operands); } } PointerOverflowChecker::CheckResult PointerOverflowChecker:: check_pointer_overflow(ar::PointerShift* stmt, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_pointer_overflow_check(Result::Unreachable, stmt)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}}; } const ScalarLit& base = this->_lit_factory.get_scalar(stmt->pointer()); if (base.is_undefined() || (base.is_pointer_var() && inv.normal().uninit_is_uninitialized(base.var()))) { if (auto msg = this->display_pointer_overflow_check(Result::Error, stmt)) { *msg << ": undefined base operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {stmt->pointer()}}; } auto base_interval = ZInterval::bottom(); if (isa< ar::NullConstant >(stmt->pointer()) || isa< ar::GlobalVariable >(stmt->pointer()) || isa< ar::LocalVariable >(stmt->pointer()) || isa< ar::FunctionPointerConstant >(stmt->pointer())) { base_interval = ZInterval(0); } else if (isa< ar::InternalVariable >(stmt->pointer())) { base_interval = inv.normal().pointer_offset_to_interval(base.var()).to_z_interval(); } else { log::error("unexpected operand to ptrshift"); return {CheckKind::UnexpectedOperand, Result::Error, {stmt->pointer()}}; } Result result = Result::Ok; auto top = IntInterval::top(this->_data_layout.pointers.bit_width, Unsigned) .to_z_interval(); ZBound max(MachineInt::max(this->_data_layout.pointers.bit_width, Unsigned) .to_z_number()); for (auto it = stmt->term_begin(), et = stmt->term_end(); it != et && result != Result::Error; it++) { auto term = *it; auto factor_interval = ZInterval(term.first.to_z_number()); const ScalarLit& offset = this->_lit_factory.get_scalar(term.second); auto offset_interval = ZInterval::bottom(); if (offset.is_undefined() || (offset.is_machine_int_var() && inv.normal().uninit_is_uninitialized(offset.var()))) { if (auto msg = this->display_pointer_overflow_check(Result::Error, stmt)) { *msg << ": undefined operand\n"; } return {CheckKind::UninitializedVariable, Result::Error, {term.second}}; } else if (offset.is_machine_int()) { offset_interval = ZInterval(offset.machine_int().to_z_number()); } else if (offset.is_machine_int_var()) { offset_interval = inv.normal().int_to_interval(offset.var()).to_z_interval(); } else { log::error("unexpected operand to ptrshift"); return {CheckKind::UnexpectedOperand, Result::Error, {term.second}}; } base_interval += factor_interval * offset_interval; if (!base_interval.leq(top)) { // possible overflow if (base_interval.lb() <= max) { result = Result::Warning; if (auto msg = this->display_pointer_overflow_check(result, stmt)) { *msg << ": ∃ p ∈ base_interval | p > " << max << "\n"; } } else { result = Result::Error; if (auto msg = this->display_pointer_overflow_check(result, stmt)) { *msg << ": ∀ p ∈ base_interval, p > " << max << "\n"; } break; } } else { if (auto msg = this->display_pointer_overflow_check(result, stmt)) { *msg << ": ∀ p ∈ base_interval, p < " << max << "\n"; } } } return {CheckKind::PointerOverflow, result, {stmt->op_begin(), stmt->op_end()}}; } llvm::Optional< LogMessage > PointerOverflowChecker:: display_pointer_overflow_check(Result result, ar::PointerShift* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_poa("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/shift_count.cpp000066400000000000000000000152761473507761200237020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Shift count checker implementation * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace analyzer { ShiftCountChecker::ShiftCountChecker(Context& ctx) : Checker(ctx) {} CheckerName ShiftCountChecker::name() const { return CheckerName::ShiftCount; } const char* ShiftCountChecker::description() const { return "Shift count checker"; } void ShiftCountChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto bin = dyn_cast< ar::BinaryOperation >(stmt)) { if (bin->op() == ar::BinaryOperation::SShl || bin->op() == ar::BinaryOperation::UShl || bin->op() == ar::BinaryOperation::SLShr || bin->op() == ar::BinaryOperation::ULShr || bin->op() == ar::BinaryOperation::SAShr || bin->op() == ar::BinaryOperation::UAShr) { CheckResult check = this->check_shift_count(bin, inv); this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::ShiftCount, check.result, stmt, call_context, std::array< ar::Value*, 1 >{{bin->right()}}, check.info); } } } ShiftCountChecker::CheckResult ShiftCountChecker::check_shift_count( ar::BinaryOperation* stmt, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_shift_count_check(Result::Unreachable, stmt)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}}; } const ScalarLit& shift_count = this->_lit_factory.get_scalar(stmt->right()); auto shift_count_interval = IntInterval::bottom(1, Signed); if (shift_count.is_undefined() || (shift_count.is_machine_int_var() && inv.normal().uninit_is_uninitialized(shift_count.var()))) { if (auto msg = this->display_shift_count_check(Result::Error, stmt)) { *msg << ": undefined shift count\n"; } return {CheckKind::UninitializedVariable, Result::Error, {}}; } else if (shift_count.is_machine_int()) { shift_count_interval = IntInterval(shift_count.machine_int()); } else if (shift_count.is_machine_int_var()) { shift_count_interval = inv.normal().int_to_interval(shift_count.var()); } else { log::error("unexpected shit count operand"); return {CheckKind::UnexpectedOperand, Result::Error, {}}; } auto type = cast< ar::IntegerType >(stmt->result()->type()); MachineInt zero = MachineInt::zero(type->bit_width(), type->sign()); MachineInt limit = MachineInt(type->bit_width() - 1, type->bit_width(), type->sign()); if (shift_count_interval.ub() < zero) { if (auto msg = this->display_shift_count_check(Result::Error, stmt)) { *msg << ": ∀c ∈ shift_count, c < 0\n"; } return {CheckKind::ShiftCount, Result::Error, to_json(shift_count_interval)}; } else if (shift_count_interval.lb() < zero) { if (auto msg = this->display_shift_count_check(Result::Warning, stmt)) { *msg << ": ∃c ∈ shift_count, c < 0\n"; } return {CheckKind::ShiftCount, Result::Warning, to_json(shift_count_interval)}; } else if (shift_count_interval.lb() > limit) { if (auto msg = this->display_shift_count_check(Result::Error, stmt)) { *msg << ": ∀c ∈ shift_count, c >= " << type->bit_width() << "\n"; } return {CheckKind::ShiftCount, Result::Error, to_json(shift_count_interval)}; } else if (shift_count_interval.ub() > limit) { if (auto msg = this->display_shift_count_check(Result::Warning, stmt)) { *msg << ": ∃c ∈ shift_count, c >= " << type->bit_width() << "\n"; } return {CheckKind::ShiftCount, Result::Warning, to_json(shift_count_interval)}; } else { if (auto msg = this->display_shift_count_check(Result::Ok, stmt)) { *msg << ": ∀c ∈ shift_count, 0 <= c < " << type->bit_width() << "\n"; } return {CheckKind::ShiftCount, Result::Ok, {}}; } } llvm::Optional< LogMessage > ShiftCountChecker::display_shift_count_check( Result result, ar::BinaryOperation* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_shc("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/signed_int_overflow.cpp000066400000000000000000000065311473507761200254150ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Signed integer overflow checker implementation * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { SignedIntOverflowChecker::SignedIntOverflowChecker(Context& ctx) : IntOverflowCheckerBase(ctx) {} CheckerName SignedIntOverflowChecker::name() const { return CheckerName::SignedIntOverflow; } const char* SignedIntOverflowChecker::description() const { return "Signed integer overflow checker"; } void SignedIntOverflowChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto bin = dyn_cast< ar::BinaryOperation >(stmt)) { if (bin->op() == ar::BinaryOperation::SAdd || bin->op() == ar::BinaryOperation::SSub || bin->op() == ar::BinaryOperation::SMul || bin->op() == ar::BinaryOperation::SDiv || bin->op() == ar::BinaryOperation::SRem) { this->check_integer_overflow(bin, inv, call_context); } } } CheckKind SignedIntOverflowChecker::underflow_check_kind() const { return CheckKind::SignedIntUnderflow; } CheckKind SignedIntOverflowChecker::overflow_check_kind() const { return CheckKind::SignedIntOverflow; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/soundness.cpp000066400000000000000000000633561473507761200234000ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Soundness checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { SoundnessChecker::SoundnessChecker(Context& ctx) : Checker(ctx) {} CheckerName SoundnessChecker::name() const { return CheckerName::Soundness; } const char* SoundnessChecker::description() const { return "Soundness checker"; } void SoundnessChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto store = dyn_cast< ar::Store >(stmt)) { boost::optional< CheckResult > check = this->check_mem_write(store, store->pointer(), CheckKind::IgnoredStore, inv); if (check) { this->display_invariant(check->result, stmt, inv); this->_checks.insert(check->kind, CheckerName::Soundness, check->result, stmt, call_context, check->operands, check->info); } } else if (auto call = dyn_cast< ar::CallBase >(stmt)) { std::vector< CheckResult > checks = this->check_call(call, inv, call_context); for (const auto& check : checks) { this->display_invariant(check.result, stmt, inv); this->_checks.insert(check.kind, CheckerName::Soundness, check.result, stmt, call_context, check.operands, check.info); } } } std::vector< SoundnessChecker::CheckResult > SoundnessChecker::check_call( ar::CallBase* call, const value::AbstractDomain& inv, CallContext* call_context) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_soundness_check(Result::Unreachable, call)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}, {}}}; } const ScalarLit& called = this->_lit_factory.get_scalar(call->called()); // Check uninitialized if (called.is_undefined() || (called.is_pointer_var() && inv.normal().uninit_is_uninitialized(called.var()))) { // Undefined call pointer operand if (auto msg = this->display_soundness_check(Result::Error, call)) { *msg << ": undefined call pointer operand\n"; } return {{CheckKind::UninitializedVariable, Result::Error, {call->called()}, {}}}; } // Check null pointer dereference if (called.is_null() || (called.is_pointer_var() && inv.normal().nullity_is_null(called.var()))) { // Null call pointer operand if (auto msg = this->display_soundness_check(Result::Error, call)) { *msg << ": null call pointer operand\n"; } return {{CheckKind::NullPointerDereference, Result::Error, {call->called()}, {}}}; } // Collect potential callees auto callees = PointsToSet::bottom(); if (auto cst = dyn_cast< ar::FunctionPointerConstant >(call->called())) { callees = {_ctx.mem_factory->get_function(cst->function())}; } else if (isa< ar::InlineAssemblyConstant >(call->called())) { // call to inline assembly if (auto msg = this->display_soundness_check(Result::Ok, call)) { *msg << ": call to inline assembly\n"; } return {{CheckKind::FunctionCallInlineAssembly, Result::Ok, {}, {}}}; } else if (auto gv = dyn_cast< ar::GlobalVariable >(call->called())) { callees = {_ctx.mem_factory->get_global(gv)}; } else if (auto lv = dyn_cast< ar::LocalVariable >(call->called())) { callees = {_ctx.mem_factory->get_local(lv)}; } else if (isa< ar::InternalVariable >(call->called())) { // Indirect call through a function pointer callees = inv.normal().pointer_to_points_to(called.var()); } else { log::error("unexpected call pointer operand"); return { {CheckKind::UnexpectedOperand, Result::Error, {call->called()}, {}}}; } // Check callees ikos_assert(!callees.is_bottom()); if (callees.is_empty()) { // Invalid pointer dereference if (auto msg = this->display_soundness_check(Result::Error, call)) { *msg << ": points-to set of function pointer is empty\n"; } return {{CheckKind::InvalidPointerDereference, Result::Error, {call->called()}, {}}}; } else if (callees.is_top()) { // No points-to set if (auto msg = this->display_soundness_check(Result::Warning, call)) { *msg << ": no points-to set for function pointer\n"; } return {{CheckKind::UnknownFunctionCallPointer, Result::Warning, {call->called()}, {}}}; } ar::Function* caller = call->code()->function_or_null(); std::vector< CheckResult > checks; for (MemoryLocation* addr : callees) { if (!isa< FunctionMemoryLocation >(addr)) { // Not a call to a function memory location continue; } ar::Function* callee = cast< FunctionMemoryLocation >(addr)->function(); if (!ar::TypeVerifier::is_valid_call(call, callee->type())) { // Ill-formed function call continue; } else if (caller == callee || call_context->contains(callee)) { // Recursive function call checks.push_back(this->check_recursive_call(call, callee, inv)); } else if (callee->is_intrinsic()) { for (const auto& check : this->check_intrinsic_call(call, callee, inv)) { checks.push_back(check); } } else if (callee->is_declaration()) { checks.push_back(this->check_unknown_extern_call(call, callee, inv)); } else if (callee->is_definition()) { // This is sound continue; } else { ikos_unreachable("unreachable"); } } return checks; } SoundnessChecker::CheckResult SoundnessChecker::check_recursive_call( ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_soundness_check(Result::Unreachable, call)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}, {}}; } if (auto msg = this->display_soundness_check(Result::Warning, call)) { *msg << ": call to a recursive function\n"; } return {CheckKind::RecursiveFunctionCall, Result::Warning, {}, JsonDict{{"fun_id", _ctx.output_db->functions.insert(fun)}}}; } namespace { /// \brief Convert a boost::optional to a std::vector template < typename T > inline std::vector< T > to_vector(boost::optional< T > check) { if (check) { return {std::move(*check)}; } else { return {}; } } } // end anonymous namespace std::vector< SoundnessChecker::CheckResult > SoundnessChecker:: check_intrinsic_call(ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv) { switch (fun->intrinsic_id()) { case ar::Intrinsic::MemoryCopy: { return to_vector(this->check_mem_write(call, call->argument(0), CheckKind::IgnoredMemoryCopy, inv)); } case ar::Intrinsic::MemoryMove: { return to_vector(this->check_mem_write(call, call->argument(0), CheckKind::IgnoredMemoryMove, inv)); } case ar::Intrinsic::MemorySet: { return to_vector(this->check_mem_write(call, call->argument(0), CheckKind::IgnoredMemorySet, inv)); } case ar::Intrinsic::VarArgStart: case ar::Intrinsic::VarArgEnd: case ar::Intrinsic::VarArgGet: case ar::Intrinsic::VarArgCopy: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::StackSave: case ar::Intrinsic::StackRestore: case ar::Intrinsic::LifetimeStart: case ar::Intrinsic::LifetimeEnd: case ar::Intrinsic::EhTypeidFor: case ar::Intrinsic::Trap: { return {}; } // case ar::Intrinsic::IkosAssert: case ar::Intrinsic::IkosAssume: case ar::Intrinsic::IkosNonDet: case ar::Intrinsic::IkosCounterInit: case ar::Intrinsic::IkosCounterIncr: case ar::Intrinsic::IkosCheckMemAccess: case ar::Intrinsic::IkosCheckStringAccess: case ar::Intrinsic::IkosAssumeMemSize: case ar::Intrinsic::IkosForgetMemory: case ar::Intrinsic::IkosAbstractMemory: case ar::Intrinsic::IkosWatchMemory: case ar::Intrinsic::IkosPartitioningVar: case ar::Intrinsic::IkosPartitioningJoin: case ar::Intrinsic::IkosPartitioningDisable: case ar::Intrinsic::IkosPrintInvariant: case ar::Intrinsic::IkosPrintValues: { return {}; } // case ar::Intrinsic::LibcMalloc: case ar::Intrinsic::LibcCalloc: case ar::Intrinsic::LibcValloc: case ar::Intrinsic::LibcAlignedAlloc: { return {}; } case ar::Intrinsic::LibcRealloc: { return to_vector(this->check_free(call, call->argument(0), inv)); } case ar::Intrinsic::LibcFree: { return to_vector(this->check_free(call, call->argument(0), inv)); } case ar::Intrinsic::LibcAbs: case ar::Intrinsic::LibcRand: case ar::Intrinsic::LibcSrand: case ar::Intrinsic::LibcExit: case ar::Intrinsic::LibcAbort: { return {}; } // case ar::Intrinsic::LibcErrnoLocation: { return {}; } // case ar::Intrinsic::LibcOpen: { return {}; } // case ar::Intrinsic::LibcClose: { return {}; } case ar::Intrinsic::LibcRead: { return this->check_call_pointer_params(call, fun, {call->argument(1)}, inv); } case ar::Intrinsic::LibcWrite: { return {}; } // case ar::Intrinsic::LibcGets: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::LibcFgets: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::LibcGetc: case ar::Intrinsic::LibcFgetc: case ar::Intrinsic::LibcGetchar: case ar::Intrinsic::LibcPuts: case ar::Intrinsic::LibcFputs: case ar::Intrinsic::LibcPutc: case ar::Intrinsic::LibcFputc: case ar::Intrinsic::LibcPrintf: case ar::Intrinsic::LibcFprintf: { return {}; } case ar::Intrinsic::LibcSprintf: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::LibcSnprintf: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::LibcScanf: { return this->check_call_pointer_params(call, fun, {call->arg_begin() + 1, call->arg_end()}, inv); } case ar::Intrinsic::LibcFscanf: { return this->check_call_pointer_params(call, fun, {call->arg_begin() + 2, call->arg_end()}, inv); } case ar::Intrinsic::LibcSscanf: { return this->check_call_pointer_params(call, fun, {call->arg_begin() + 2, call->arg_end()}, inv); } case ar::Intrinsic::LibcFopen: { return {}; } case ar::Intrinsic::LibcFclose: { return to_vector(this->check_free(call, call->argument(0), inv)); } case ar::Intrinsic::LibcFflush: { return {}; } // case ar::Intrinsic::LibcStrlen: case ar::Intrinsic::LibcStrnlen: { return {}; } case ar::Intrinsic::LibcStrcpy: case ar::Intrinsic::LibcStrncpy: case ar::Intrinsic::LibcStrcat: case ar::Intrinsic::LibcStrncat: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::LibcStrcmp: case ar::Intrinsic::LibcStrncmp: case ar::Intrinsic::LibcStrstr: case ar::Intrinsic::LibcStrchr: case ar::Intrinsic::LibcStrdup: case ar::Intrinsic::LibcStrndup: { return {}; } case ar::Intrinsic::LibcStrcpyCheck: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::LibcMemoryCopyCheck: { return to_vector(this->check_mem_write(call, call->argument(0), CheckKind::IgnoredMemoryCopy, inv)); } case ar::Intrinsic::LibcMemoryMoveCheck: { return to_vector(this->check_mem_write(call, call->argument(0), CheckKind::IgnoredMemoryMove, inv)); } case ar::Intrinsic::LibcMemorySetCheck: { return to_vector(this->check_mem_write(call, call->argument(0), CheckKind::IgnoredMemorySet, inv)); } case ar::Intrinsic::LibcStrcatCheck: { return this->check_call_pointer_params(call, fun, {call->argument(0)}, inv); } case ar::Intrinsic::LibcppNew: case ar::Intrinsic::LibcppNewArray: { return {}; } case ar::Intrinsic::LibcppDelete: case ar::Intrinsic::LibcppDeleteArray: { return to_vector(this->check_free(call, call->argument(0), inv)); } case ar::Intrinsic::LibcppAllocateException: { return {}; } case ar::Intrinsic::LibcppFreeException: { return to_vector(this->check_free(call, call->argument(0), inv)); } case ar::Intrinsic::LibcppThrow: case ar::Intrinsic::LibcppBeginCatch: case ar::Intrinsic::LibcppEndCatch: { return {}; } default: { ikos_unreachable("unreachable"); } } } SoundnessChecker::CheckResult SoundnessChecker::check_unknown_extern_call( ar::CallBase* call, ar::Function* fun, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_soundness_check(Result::Unreachable, call)) { *msg << "\n"; } return {CheckKind::Unreachable, Result::Unreachable, {}, {}}; } if (auto msg = this->display_soundness_check(Result::Warning, call)) { *msg << ": call to an unknown extern function\n"; } return {CheckKind::IgnoredCallSideEffect, Result::Warning, {}, JsonDict{{"fun_id", _ctx.output_db->functions.insert(fun)}}}; } boost::optional< SoundnessChecker::CheckResult > SoundnessChecker:: check_mem_write(ar::Statement* stmt, ar::Value* pointer, CheckKind access_kind, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_soundness_check(Result::Unreachable, stmt)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}, {}}}; } const ScalarLit& ptr = this->_lit_factory.get_scalar(pointer); // Check uninitialized if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined pointer operand if (auto msg = this->display_soundness_check(Result::Error, stmt)) { *msg << ": undefined pointer operand\n"; } return {{CheckKind::UninitializedVariable, Result::Error, {pointer}, {}}}; } // Check null pointer dereference if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { // Null pointer operand if (auto msg = this->display_soundness_check(Result::Error, stmt)) { *msg << ": null pointer dereference\n"; } return {{CheckKind::NullPointerDereference, Result::Error, {pointer}, {}}}; } // Check unexpected operand if (!ptr.is_pointer_var()) { log::error("unexpected pointer operand"); return {{CheckKind::UnexpectedOperand, Result::Error, {pointer}, {}}}; } if (isa< ar::GlobalVariable >(pointer) || isa< ar::FunctionPointerConstant >(pointer)) { // Points-to set is a singleton return boost::none; } // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_empty()) { // Pointer is invalid if (auto msg = this->display_soundness_check(Result::Error, stmt)) { *msg << ": empty points-to set for pointer\n"; } return { {CheckKind::InvalidPointerDereference, Result::Error, {pointer}, {}}}; } if (addrs.is_top()) { // Ignored memory access because points-to set is top if (auto msg = this->display_soundness_check(Result::Warning, stmt)) { *msg << ": ignored memory write because points-to set is top\n"; } return {{access_kind, Result::Warning, {pointer}, {}}}; } return boost::none; } std::vector< SoundnessChecker::CheckResult > SoundnessChecker:: check_call_pointer_params(ar::CallBase* call, ar::Function* fun, const std::vector< ar::Value* >& pointers, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_soundness_check(Result::Unreachable, call)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}, {}}}; } std::vector< CheckResult > checks; // Check for unknown pointer arguments for (ar::Value* pointer : pointers) { ikos_assert(pointer->type()->is_pointer()); const ScalarLit& ptr = this->_lit_factory.get_scalar(pointer); // Check uninitialized argument if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined pointer argument if (auto msg = this->display_soundness_check(Result::Error, call)) { *msg << ": undefined pointer argument\n"; } return {{CheckKind::UninitializedVariable, Result::Error, {pointer}, {}}}; } // Check null pointer argument if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { // This is sound continue; } // Check unexpected argument if (!ptr.is_pointer_var()) { log::error("unexpected pointer argument"); return {{CheckKind::UnexpectedOperand, Result::Error, {pointer}, {}}}; } if (isa< ar::GlobalVariable >(pointer) || isa< ar::FunctionPointerConstant >(pointer)) { // Points-to set is a singleton // This is sound continue; } // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_empty()) { // Pointer is invalid if (auto msg = this->display_soundness_check(Result::Error, call)) { *msg << ": empty points-to set for pointer\n"; } return { {CheckKind::InvalidPointerDereference, Result::Error, {pointer}, {}}}; } if (addrs.is_top()) { // Ignored memory access because points-to set is top if (auto msg = this->display_soundness_check(Result::Warning, call)) { *msg << ": ignored call side effect on pointer "; pointer->dump(msg->stream()); *msg << " because points-to set is top\n"; } checks.push_back( {CheckKind::IgnoredCallSideEffectOnPointerParameter, Result::Warning, {pointer}, JsonDict{{"fun_id", _ctx.output_db->functions.insert(fun)}}}); } } return checks; } boost::optional< SoundnessChecker::CheckResult > SoundnessChecker::check_free( ar::CallBase* call, ar::Value* pointer, const value::AbstractDomain& inv) { if (inv.is_normal_flow_bottom()) { // Statement unreachable if (auto msg = this->display_soundness_check(Result::Unreachable, call)) { *msg << "\n"; } return {{CheckKind::Unreachable, Result::Unreachable, {}, {}}}; } const ScalarLit& ptr = this->_lit_factory.get_scalar(pointer); // Check uninitialized if (ptr.is_undefined() || (ptr.is_pointer_var() && inv.normal().uninit_is_uninitialized(ptr.var()))) { // Undefined pointer operand if (auto msg = this->display_soundness_check(Result::Error, call)) { *msg << ": undefined pointer operand\n"; } return {{CheckKind::UninitializedVariable, Result::Error, {pointer}, {}}}; } // Check null pointer dereference if (ptr.is_null() || (ptr.is_pointer_var() && inv.normal().nullity_is_null(ptr.var()))) { // Null pointer argument, safe if (auto msg = this->display_soundness_check(Result::Ok, call)) { *msg << ": safe call to free with NULL value\n"; } return {{CheckKind::Free, Result::Ok, {pointer}, {}}}; } // Check unexpected operand if (!ptr.is_pointer_var()) { log::error("unexpected pointer operand"); return {{CheckKind::UnexpectedOperand, Result::Error, {pointer}, {}}}; } if (isa< ar::GlobalVariable >(pointer) || isa< ar::FunctionPointerConstant >(pointer)) { // Points-to set is a singleton return boost::none; } // Points-to set of the pointer PointsToSet addrs = inv.normal().pointer_to_points_to(ptr.var()); if (addrs.is_top()) { // Ignored memory deallocation because points-to set is top if (auto msg = this->display_soundness_check(Result::Warning, call)) { *msg << ": ignored memory deallocation because points-to set is top\n"; } return {{CheckKind::IgnoredFree, Result::Warning, {pointer}, {}}}; } return boost::none; } llvm::Optional< LogMessage > SoundnessChecker::display_soundness_check( Result result, ar::Statement* stmt) const { auto msg = this->display_check(result, stmt); if (msg) { *msg << "check_soundness("; stmt->dump(msg->stream()); *msg << ")"; } return msg; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/uninitialized_variable.cpp000066400000000000000000000146371473507761200260720ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Uninitialized variable checker implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { UninitializedVariableChecker::UninitializedVariableChecker(Context& ctx) : Checker(ctx) {} CheckerName UninitializedVariableChecker::name() const { return CheckerName::UninitializedVariable; } const char* UninitializedVariableChecker::description() const { return "Uninitialized variable checker"; } void UninitializedVariableChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (inv.is_normal_flow_bottom()) { // Statement is unreachable // No checks return; } if (isa< ar::Assignment >(stmt)) { // Assignment propagate the undefinedness // No checks return; } // Exempt "And" and "Or" if one operand is constant. if (ar::BinaryOperation* inst = dyn_cast< ar::BinaryOperation >(stmt)) { auto op = inst->op(); switch (op) { case ar::BinaryOperation::Operator::UAnd: case ar::BinaryOperation::Operator::UOr: case ar::BinaryOperation::Operator::SAnd: case ar::BinaryOperation::Operator::SOr: { auto left = inst->left(); auto right = inst->right(); if (left->is_integer_constant() || right->is_integer_constant()) { return; } break; } default: { break; } } } if (auto insert = dyn_cast< ar::InsertElement >(stmt)) { // InsertElement accepts undefined aggregate operands this->check_initialized(stmt, insert->offset(), inv, call_context); this->check_initialized(stmt, insert->element(), inv, call_context); return; } // Check each operand for (auto it = stmt->op_begin(), et = stmt->op_end(); it != et; ++it) { this->check_initialized(stmt, *it, inv, call_context); } } void UninitializedVariableChecker::check_initialized( ar::Statement* stmt, ar::Value* operand, const value::AbstractDomain& inv, CallContext* call_context) { if (auto result = this->check_initialized(operand, inv)) { this->display_initialized_check(*result, stmt, operand); this->display_invariant(*result, stmt, inv); this->_checks.insert(CheckKind::UninitializedVariable, CheckerName::UninitializedVariable, *result, stmt, call_context, std::array< ar::Value*, 1 >{{operand}}); } } boost::optional< Result > UninitializedVariableChecker::check_initialized( ar::Value* operand, const value::AbstractDomain& inv) { if (isa< ar::UndefinedConstant >(operand)) { return Result::Error; } else if (isa< ar::IntegerConstant >(operand)) { return boost::none; } else if (isa< ar::FloatConstant >(operand)) { return boost::none; } else if (isa< ar::NullConstant >(operand)) { return boost::none; } else if (isa< ar::StructConstant >(operand)) { return boost::none; } else if (isa< ar::ArrayConstant >(operand)) { return boost::none; } else if (isa< ar::VectorConstant >(operand)) { return boost::none; } else if (isa< ar::AggregateZeroConstant >(operand)) { return boost::none; } else if (isa< ar::FunctionPointerConstant >(operand)) { return Result::Ok; } else if (isa< ar::InlineAssemblyConstant >(operand)) { return Result::Ok; } else if (isa< ar::GlobalVariable >(operand)) { return Result::Ok; } else if (isa< ar::LocalVariable >(operand)) { return Result::Ok; } else if (auto iv = dyn_cast< ar::InternalVariable >(operand)) { Variable* var = _ctx.var_factory->get_internal(iv); core::Uninitialized uninit = inv.normal().uninit_to_uninitialized(var); if (uninit.is_uninitialized()) { return Result::Error; } else if (uninit.is_initialized()) { return Result::Ok; } else { return Result::Warning; } } else { ikos_unreachable("unreachable"); } } void UninitializedVariableChecker::display_initialized_check( Result result, ar::Statement* stmt, ar::Value* operand) const { if (auto msg = this->display_check(result, stmt)) { *msg << "check_initialized("; operand->dump(msg->stream()); *msg << ")\n"; } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/checker/unsigned_int_overflow.cpp000066400000000000000000000065051473507761200257610ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Unsigned integer overflow checker implementation * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { UnsignedIntOverflowChecker::UnsignedIntOverflowChecker(Context& ctx) : IntOverflowCheckerBase(ctx) {} CheckerName UnsignedIntOverflowChecker::name() const { return CheckerName::UnsignedIntOverflow; } const char* UnsignedIntOverflowChecker::description() const { return "Unsigned integer overflow checker"; } void UnsignedIntOverflowChecker::check(ar::Statement* stmt, const value::AbstractDomain& inv, CallContext* call_context) { if (auto bin = dyn_cast< ar::BinaryOperation >(stmt)) { if (bin->op() == ar::BinaryOperation::UAdd || bin->op() == ar::BinaryOperation::USub || bin->op() == ar::BinaryOperation::UMul || bin->op() == ar::BinaryOperation::UDiv) { this->check_integer_overflow(bin, inv, call_context); } } } CheckKind UnsignedIntOverflowChecker::underflow_check_kind() const { return CheckKind::UnsignedIntUnderflow; } CheckKind UnsignedIntOverflowChecker::overflow_check_kind() const { return CheckKind::UnsignedIntOverflow; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/000077500000000000000000000000001473507761200207765ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/output.cpp000066400000000000000000000052661473507761200230530ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Output database implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { OutputDatabase::OutputDatabase(sqlite::DbConnection& db_) : db(db_), settings(db_), times(db_), files(db_), functions(db_, files), statements(db_, files, functions), operands(db_), call_contexts(db_, functions, statements), memory_locations(db_, functions, statements, call_contexts), checks(db_, statements, operands, call_contexts) { this->db.set_commit_policy(sqlite::CommitPolicy::Auto); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/sqlite.cpp000066400000000000000000000361231473507761200230100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of SQLite3 wrapper * * Authors: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { namespace sqlite { // DbError /// \brief Return the error message for the given code /// /// Taken from the SQLite online documentation. static const char* error_code_message(int code) noexcept { switch (code) { case SQLITE_ERROR: return "SQL error or missing database"; case SQLITE_INTERNAL: return "Internal logic error in SQLite"; case SQLITE_PERM: return "Access permission denied"; case SQLITE_ABORT: return "Callback routine requested an abort"; case SQLITE_BUSY: return "The database file is locked"; case SQLITE_LOCKED: return "A table in the database is locked"; case SQLITE_NOMEM: return "A malloc() failed"; case SQLITE_READONLY: return "Attempt to write a readonly database"; case SQLITE_INTERRUPT: return "Operation terminated by sqlite3_interrupt()"; case SQLITE_IOERR: return "Some kind of disk I/O error occurred"; case SQLITE_CORRUPT: return "The database disk image is malformed"; case SQLITE_NOTFOUND: return "Unknown opcode in sqlite3_file_control()"; case SQLITE_FULL: return "Insertion failed because database is full"; case SQLITE_CANTOPEN: return "Unable to open the database file"; case SQLITE_PROTOCOL: return "Database lock protocol error"; case SQLITE_EMPTY: return "Database is empty"; case SQLITE_SCHEMA: return "The database schema changed"; case SQLITE_TOOBIG: return "String or BLOB exceeds size limit"; case SQLITE_CONSTRAINT: return "Abort due to constraint violation"; case SQLITE_MISMATCH: return "Data type mismatch"; case SQLITE_MISUSE: return "Library used incorrectly"; case SQLITE_NOLFS: return "Uses OS features not supported on host"; case SQLITE_AUTH: return "Authorization denied"; case SQLITE_FORMAT: return "Auxiliary database format error"; case SQLITE_RANGE: return "2nd parameter to sqlite3_bind out of range"; case SQLITE_NOTADB: return "File opened that is not a database file"; case SQLITE_ROW: return "sqlite3_step() has another row ready"; case SQLITE_DONE: return "sqlite3_step() has finished executing"; default: return "Unknown error code"; } } DbError::DbError(int code) : _code(code), _context(std::make_shared< const std::string >()), _what(std::make_shared< const std::string >( "[" + std::to_string(code) + "] " + error_code_message(code))) {} DbError::DbError(int code, const std::string& context) : _code(code), _context(std::make_shared< const std::string >(context)), _what(std::make_shared< const std::string >(context + "\n[" + std::to_string(code) + "] " + error_code_message(code))) {} const char* DbError::error_msg() const noexcept { return error_code_message(this->_code); } const char* DbError::what() const noexcept { return this->_what->c_str(); } DbError::~DbError() = default; // DbColumnType const char* column_type_str(DbColumnType t) { switch (t) { case DbColumnType::Text: return "TEXT"; case DbColumnType::Integer: return "INTEGER"; case DbColumnType::Real: return "REAL"; case DbColumnType::Blob: return "BLOB"; default: ikos_unreachable("unreachable"); } } // DbConnection DbConnection::DbConnection(std::string filename) : _filename(std::move(filename)) { int status = sqlite3_open_v2(this->_filename.c_str(), &this->_handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr); if (status != SQLITE_OK) { throw DbError(status, "DbConnection: cannot open database: " + this->_filename); } } DbConnection::~DbConnection() { // The destructor shall not throw an exception. No error check. if (this->_commit_policy == CommitPolicy::Auto) { sqlite3_exec(this->_handle, "COMMIT", nullptr, nullptr, nullptr); } sqlite3_close(this->_handle); } void DbConnection::exec_command(const char* cmd) { ikos_assert_msg(cmd != nullptr, "cmd is null"); int status = sqlite3_exec(this->_handle, cmd, nullptr, nullptr, nullptr); if (status != SQLITE_OK) { throw DbError(status, "DbConnection::exec_command(): " + std::string(cmd)); } } void DbConnection::exec_command(const std::string& cmd) { this->exec_command(cmd.c_str()); } void DbConnection::begin_transaction() { ikos_assert(this->_commit_policy == CommitPolicy::Manual); this->exec_command("BEGIN"); } void DbConnection::commit_transaction() { ikos_assert(this->_commit_policy == CommitPolicy::Manual); this->exec_command("COMMIT"); } void DbConnection::rollback_transaction() { ikos_assert(this->_commit_policy == CommitPolicy::Manual); this->exec_command("ROLLBACK"); } void DbConnection::set_commit_policy(CommitPolicy policy) { if (this->_commit_policy == CommitPolicy::Auto) { this->exec_command("COMMIT"); this->_inserted_rows = 0; } this->_commit_policy = policy; if (this->_commit_policy == CommitPolicy::Auto) { this->exec_command("BEGIN"); this->_inserted_rows = 0; } } void DbConnection::row_inserted() { if (this->_commit_policy == CommitPolicy::Auto) { this->_inserted_rows++; if (this->_inserted_rows >= MaxRowsPerTransaction) { this->exec_command("COMMIT"); this->_inserted_rows = 0; this->exec_command("BEGIN"); } } } void DbConnection::drop_table(StringRef name) { std::string cmd("DROP TABLE IF EXISTS "); cmd += name; this->exec_command(cmd); } DbInt64 DbConnection::last_insert_rowid() const { return sqlite3_last_insert_rowid(this->_handle); } void DbConnection::create_table( StringRef name, llvm::ArrayRef< std::pair< StringRef, DbColumnType > > columns) { ikos_assert_msg(!columns.empty(), "columns is empty"); std::string cmd("CREATE TABLE IF NOT EXISTS "); cmd += name; cmd += '('; for (auto it = columns.begin(), et = columns.end(); it != et;) { cmd += it->first; cmd += ' '; cmd += column_type_str(it->second); if (it->first == "id") { cmd += " PRIMARY KEY"; } ++it; if (it != et) { cmd += ','; } } cmd += ')'; this->exec_command(cmd.c_str()); } void DbConnection::create_index(StringRef index, StringRef table, StringRef column) { std::string cmd("CREATE INDEX IF NOT EXISTS "); cmd += index; cmd += " ON "; cmd += table; cmd += '('; cmd += column; cmd += ')'; this->exec_command(cmd.c_str()); } void DbConnection::set_journal_mode(JournalMode mode) { switch (mode) { case JournalMode::Delete: { this->exec_command("PRAGMA journal_mode = DELETE"); } break; case JournalMode::Truncate: { this->exec_command("PRAGMA journal_mode = TRUNCATE"); } break; case JournalMode::Persist: { this->exec_command("PRAGMA journal_mode = PERSIST"); } break; case JournalMode::Memory: { this->exec_command("PRAGMA journal_mode = MEMORY"); } break; case JournalMode::WAL: { this->exec_command("PRAGMA journal_mode = WAL"); } break; case JournalMode::Off: { this->exec_command("PRAGMA journal_mode = OFF"); } break; } } void DbConnection::set_synchronous_flag(SynchronousFlag flag) { switch (flag) { case SynchronousFlag::Off: { this->exec_command("PRAGMA synchronous = OFF"); } break; case SynchronousFlag::Normal: { this->exec_command("PRAGMA synchronous = NORMAL"); } break; case SynchronousFlag::Full: { this->exec_command("PRAGMA synchronous = FULL"); } break; case SynchronousFlag::Extra: { this->exec_command("PRAGMA synchronous = EXTRA"); } break; } } // DbOstream DbOstream::DbOstream(DbConnection& db, StringRef table_name, int columns) : _db(db), _columns(columns) { ikos_assert_msg(columns > 0, "invalid number of columns"); // Create SQL command std::string insert("INSERT INTO "); insert += table_name; insert += " VALUES ("; for (int i = 0; i < columns; i++) { insert += '?'; insert += (i + 1 < columns) ? ',' : ')'; } int status = sqlite3_prepare_v2(this->_db._handle, insert.c_str(), -1, &this->_stmt, nullptr); if (status != SQLITE_OK) { throw DbError(status, "DbOstream: cannot populate " + table_name.to_string() + " in database " + this->_db.filename()); } } DbOstream::~DbOstream() { // The destructor shall not throw an exception. No error check is performed. sqlite3_finalize(_stmt); } void DbOstream::add(StringRef s) { ikos_assert(s.size() <= static_cast< std::size_t >(std::numeric_limits< int >::max())); int status = sqlite3_bind_text(this->_stmt, this->_current_column++, s.data(), static_cast< int >(s.size()), SQLITE_TRANSIENT); if (status != SQLITE_OK) { throw DbError(status, "DbOstream::add(StringRef)"); } } void DbOstream::add_null() { int status = sqlite3_bind_null(this->_stmt, this->_current_column++); if (status != SQLITE_OK) { throw DbError(status, "DbOstream::add_null()"); } } void DbOstream::add(DbInt64 n) { int status = sqlite3_bind_int64(this->_stmt, this->_current_column++, n); if (status != SQLITE_OK) { throw DbError(status, "DbOstream::add(DbInt64)"); } } void DbOstream::add(DbDouble d) { int status = sqlite3_bind_double(this->_stmt, this->_current_column++, d); if (status != SQLITE_OK) { throw DbError(status, "DbOstream::add(DbDouble)"); } } void DbOstream::flush() { ikos_assert_msg(this->_current_column == this->_columns + 1, "incomplete row"); ikos_ignore(this->_columns); int status = sqlite3_step(this->_stmt); if (status != SQLITE_DONE) { throw DbError(status, "DbOstream::flush(): step failed"); } status = sqlite3_clear_bindings(this->_stmt); if (status != SQLITE_OK) { throw DbError(status, "DbOstream::flush(): clear bindings failed"); } status = sqlite3_reset(this->_stmt); if (status != SQLITE_OK) { throw DbError(status, "DbOstream::flush(): reset failed"); } this->_current_column = 1; this->_db.row_inserted(); } // DbIstream DbIstream::DbIstream(DbConnection& db, std::string query) : _db(db), _query(std::move(query)) { int status = sqlite3_prepare_v2(this->_db._handle, this->_query.c_str(), -1, &this->_stmt, nullptr); if (status != SQLITE_OK) { throw DbError(status, "DbIstream: cannot prepare query '" + this->_query + "' in database " + this->_db.filename()); } this->step(); this->_columns = sqlite3_column_count(_stmt); if (this->_columns == 0) { throw DbError(SQLITE_MISMATCH, "DbIstream: malformed query '" + this->_query + "': no column in result"); } this->_current_column = 0; } DbIstream::~DbIstream() { // The destructor shall not throw an exception. No error check. sqlite3_finalize(this->_stmt); } void DbIstream::step() { int status = sqlite3_step(this->_stmt); if (status == SQLITE_DONE) { this->_done = true; } else if (status != SQLITE_ROW) { throw DbError(status, "DbIstream::step(): query " + this->_query); } } void DbIstream::skip_column() { this->_current_column++; if (!this->_done && (this->_current_column == this->_columns)) { this->step(); this->_current_column = 0; } } DbIstream& operator>>(DbIstream& i, std::string& s) { if (i.empty()) { throw DbError(SQLITE_MISUSE, "DbIstream::>>: no more data for query '" + i.query() + "'"); } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) s.assign(reinterpret_cast< const char* >( sqlite3_column_text(i._stmt, i._current_column))); i.skip_column(); return i; } } DbIstream& operator>>(DbIstream& i, DbInt64& n) { if (i.empty()) { throw DbError(SQLITE_MISUSE, "DbIstream::>>: no more data for query '" + i.query() + "'"); } else { n = sqlite3_column_int64(i._stmt, i._current_column); i.skip_column(); return i; } } DbIstream& operator>>(DbIstream& i, DbDouble& d) { if (i.empty()) { throw DbError(SQLITE_MISUSE, "DbIstream::>>: no more data for query '" + i.query() + "'"); } else { d = sqlite3_column_double(i._stmt, i._current_column); i.skip_column(); return i; } } } // end namespace sqlite } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table.cpp000066400000000000000000000054021473507761200225720ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief DatabaseTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { DatabaseTable::DatabaseTable( sqlite::DbConnection& db, std::string name, llvm::ArrayRef< std::pair< StringRef, sqlite::DbColumnType > > cols, llvm::ArrayRef< StringRef > indexes) : _db(db), _name(std::move(name)) { this->_db.drop_table(this->_name); this->_db.create_table(this->_name, cols); for (const auto& col : indexes) { std::string index_name("index_"); index_name += this->_name; index_name += '_'; index_name += col; this->_db.create_index(index_name, this->_name, col); } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/000077500000000000000000000000001473507761200220655ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/call_contexts.cpp000066400000000000000000000076261473507761200254460ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief CallContextsTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { CallContextsTable::CallContextsTable(sqlite::DbConnection& db, FunctionsTable& functions, StatementsTable& statements) : DatabaseTable(db, "call_contexts", {{"id", sqlite::DbColumnType::Integer}, {"call_id", sqlite::DbColumnType::Integer}, {"function_id", sqlite::DbColumnType::Integer}, {"parent_id", sqlite::DbColumnType::Integer}}, {"call_id", "function_id", "parent_id"}), _functions(functions), _statements(statements), _row(db, "call_contexts", 4) {} sqlite::DbInt64 CallContextsTable::insert(CallContext* call_context) { ikos_assert(call_context != nullptr); auto it = this->_map.find(call_context); if (it != this->_map.end()) { return it->second; } // Insert the parent first sqlite::DbInt64 parent_id = 0; if (call_context->has_parent()) { parent_id = this->insert(call_context->parent()); } // Insert row sqlite::DbInt64 id = this->_last_insert_id++; this->_row << id; if (call_context->empty()) { this->_row << sqlite::null; this->_row << sqlite::null; this->_row << sqlite::null; } else { // call_id ar::CallBase* call = call_context->call(); this->_row << this->_statements.insert(call); // function_id ar::Code* code = call->code(); ikos_assert(code->is_function_body()); this->_row << this->_functions.insert(code->function()); // parent_id this->_row << parent_id; } this->_row << sqlite::end_row; this->_map.try_emplace(call_context, id); return id; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/checks.cpp000066400000000000000000000110631473507761200240320ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief ChecksTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { ChecksTable::ChecksTable(sqlite::DbConnection& db, StatementsTable& statements, OperandsTable& operands, CallContextsTable& call_contexts) : DatabaseTable(db, "checks", {{"id", sqlite::DbColumnType::Integer}, {"kind", sqlite::DbColumnType::Integer}, {"checker", sqlite::DbColumnType::Integer}, {"status", sqlite::DbColumnType::Integer}, {"statement_id", sqlite::DbColumnType::Integer}, {"operands", sqlite::DbColumnType::Text}, {"call_context_id", sqlite::DbColumnType::Integer}, {"info", sqlite::DbColumnType::Text}}, {"statement_id", "call_context_id"}), _statements(statements), _operands(operands), _call_contexts(call_contexts), _row(db, "checks", 8) {} void ChecksTable::insert(CheckKind kind, CheckerName checker, Result status, ar::Statement* stmt, CallContext* call_context, llvm::ArrayRef< ar::Value* > operands, const JsonDict& info) { sqlite::DbInt64 id = this->_last_insert_id++; this->_row << id; this->_row << static_cast< sqlite::DbInt64 >(kind); this->_row << static_cast< sqlite::DbInt64 >(checker); this->_row << static_cast< sqlite::DbInt64 >(status); this->_row << this->_statements.insert(stmt); if (!operands.empty() && (status == Result::Warning || status == Result::Error)) { JsonList json_operands; for (auto operand : operands) { // Find operand number auto it = std::find(stmt->op_begin(), stmt->op_end(), operand); sqlite::DbInt64 operand_no = -1; if (it != stmt->op_end()) { operand_no = static_cast< sqlite::DbInt64 >(it - stmt->op_begin()); } json_operands.add(JsonList{operand_no, this->_operands.insert(operand)}); } this->_row << json_operands.str(); } else { this->_row << sqlite::null; } this->_row << this->_call_contexts.insert(call_context); if (!info.empty()) { this->_row << info.str(); } else { this->_row << sqlite::null; } this->_row << sqlite::end_row; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/files.cpp000066400000000000000000000065261473507761200237040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief FilesTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { FilesTable::FilesTable(sqlite::DbConnection& db) : DatabaseTable(db, "files", {{"id", sqlite::DbColumnType::Integer}, {"path", sqlite::DbColumnType::Text}}, {}), _row(db, "files", 2) {} sqlite::DbInt64 FilesTable::insert(llvm::DIFile* file) { ikos_assert(file != nullptr); // Check in _di_file_map { auto it = this->_di_file_map.find(file); if (it != this->_di_file_map.end()) { return it->second; } } // llvm::DIFile* are not unique, use _path_map boost::filesystem::path path = source_path(file); // Check in _path_map { auto it = this->_path_map.find(path.string()); if (it != this->_path_map.end()) { this->_di_file_map.try_emplace(file, it->second); return it->second; } } sqlite::DbInt64 id = this->_last_insert_id++; this->_row << id; this->_row << path.string(); this->_row << sqlite::end_row; this->_di_file_map.try_emplace(file, id); this->_path_map.try_emplace(path.string(), id); return id; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/functions.cpp000066400000000000000000000105211473507761200246000ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief FunctionsTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace analyzer { FunctionsTable::FunctionsTable(sqlite::DbConnection& db, FilesTable& files) : DatabaseTable(db, "functions", {{"id", sqlite::DbColumnType::Integer}, {"name", sqlite::DbColumnType::Text}, {"demangled", sqlite::DbColumnType::Text}, {"definition", sqlite::DbColumnType::Integer}, {"file_id", sqlite::DbColumnType::Integer}, {"line", sqlite::DbColumnType::Integer}}, {"file_id"}), _files(files), _row(db, "functions", 6) {} sqlite::DbInt64 FunctionsTable::insert(ar::Function* fun) { ikos_assert(fun != nullptr); auto it = this->_map.find(fun); if (it != this->_map.end()) { return it->second; } sqlite::DbInt64 id = this->_last_insert_id++; StringRef fun_name = name(fun); this->_row << id; this->_row << fun_name; if (is_mangled(fun_name)) { this->_row << demangle(fun_name); } else { this->_row << sqlite::null; } this->_row << (fun->is_definition() ? sqlite::DbInt64(1) : sqlite::DbInt64(0)); if (fun->has_frontend()) { auto llvm_fun = fun->frontend< llvm::Function >(); llvm::DISubprogram* dbg = llvm_fun->getSubprogram(); if (dbg != nullptr) { this->_row << this->_files.insert(dbg->getFile()); this->_row << static_cast< sqlite::DbInt64 >(dbg->getLine()); } else { this->_row << sqlite::null; this->_row << sqlite::null; } } else { ikos_assert(fun->is_intrinsic()); this->_row << sqlite::null; this->_row << sqlite::null; } this->_row << sqlite::end_row; this->_map.try_emplace(fun, id); return id; } StringRef FunctionsTable::name(ar::Function* fun) { if (!fun->has_frontend()) { return fun->name(); } return name(fun->frontend< llvm::Function >()); } StringRef FunctionsTable::name(llvm::Function* fun) { ikos_assert(fun->hasName()); return to_string_ref(fun->getName()); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/memory_locations.cpp000066400000000000000000000166271473507761200261700ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief MemoryLocationsTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { MemoryLocationsTable::MemoryLocationsTable(sqlite::DbConnection& db, FunctionsTable& functions, StatementsTable& statements, CallContextsTable& call_contexts) : DatabaseTable(db, "memory_locations", {{"id", sqlite::DbColumnType::Integer}, {"kind", sqlite::DbColumnType::Integer}, {"info", sqlite::DbColumnType::Text}}, {}), _functions(functions), _statements(statements), _call_contexts(call_contexts), _row(db, "memory_locations", 3) {} sqlite::DbInt64 MemoryLocationsTable::insert(MemoryLocation* mem_loc) { ikos_assert(mem_loc != nullptr); auto it = this->_map.find(mem_loc); if (it != this->_map.end()) { return it->second; } sqlite::DbInt64 id = this->_last_insert_id++; this->_row << id; this->_row << static_cast< sqlite::DbInt64 >(mem_loc->kind()); JsonDict info = this->info(mem_loc); if (!info.empty()) { this->_row << info.str(); } else { this->_row << sqlite::null; } this->_row << sqlite::end_row; this->_map.try_emplace(mem_loc, id); return id; } JsonDict MemoryLocationsTable::info(MemoryLocation* mem_loc) { if (auto local_mem_loc = dyn_cast< LocalMemoryLocation >(mem_loc)) { ar::LocalVariable* lv = local_mem_loc->local_var(); ikos_assert(lv->has_frontend()); auto value = lv->frontend< llvm::Value >(); auto alloca = llvm::cast< llvm::AllocaInst >(value); // Check for llvm.dbg.declare and llvm.dbg.addr llvm::TinyPtrVector< llvm::DbgVariableIntrinsic* > dbg_addrs = llvm::FindDbgAddrUses(alloca); auto dbg_addr = std::find_if(dbg_addrs.begin(), dbg_addrs.end(), [](llvm::DbgVariableIntrinsic* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_addr != dbg_addrs.end()) { llvm::DILocalVariable* di_var = (*dbg_addr)->getVariable(); llvm::StringRef name = di_var->getName(); if (!name.empty()) { return {{"name", name.str()}}; } } // Check for llvm.dbg.value llvm::SmallVector< llvm::DbgValueInst*, 1 > dbg_values; llvm::findDbgValues(dbg_values, alloca); auto dbg_value = std::find_if(dbg_values.begin(), dbg_values.end(), [](llvm::DbgValueInst* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_value != dbg_values.end()) { llvm::DILocalVariable* di_var = (*dbg_value)->getVariable(); llvm::StringRef name = di_var->getName(); if (!name.empty()) { return {{"name", name.str()}}; } } // Last chance, use llvm variable name if (alloca->hasName()) { return {{"name", alloca->getName().str()}}; } return {}; } else if (auto global_mem_loc = dyn_cast< GlobalMemoryLocation >(mem_loc)) { ar::GlobalVariable* gv = global_mem_loc->global_var(); ikos_assert(gv->has_frontend()); auto llvm_gv = gv->frontend< llvm::GlobalVariable >(); // Check for debug info llvm::SmallVector< llvm::DIGlobalVariableExpression*, 1 > dbgs; llvm_gv->getDebugInfo(dbgs); if (!dbgs.empty()) { llvm::DIGlobalVariable* di_gv = dbgs[0]->getVariable(); llvm::StringRef name = di_gv->getName(); if (!name.empty()) { return {{"name", name.str()}}; } } // If it's a constant (e.g, a string) if (llvm_gv->isConstant() && llvm_gv->hasInitializer()) { return {{"cst", OperandsTable::repr(llvm_gv->getInitializer())}}; } // Last chance, use llvm variable name if (llvm_gv->hasName()) { std::string name = llvm_gv->getName().str(); if (is_mangled(name)) { return {{"name", name}, {"demangle", demangle(name)}}; } else { return {{"name", name}}; } } return {}; } else if (auto fun_mem_loc = dyn_cast< FunctionMemoryLocation >(mem_loc)) { ar::Function* fun = fun_mem_loc->function(); return {{"id", this->_functions.insert(fun)}}; } else if (isa< AggregateMemoryLocation >(mem_loc)) { return {}; } else if (isa< AbsoluteZeroMemoryLocation >(mem_loc)) { return {}; } else if (isa< ArgvMemoryLocation >(mem_loc)) { return {}; } else if (isa< LibcErrnoMemoryLocation >(mem_loc)) { return {}; } else if (auto dyn_alloc_mem_loc = dyn_cast< DynAllocMemoryLocation >(mem_loc)) { ar::CallBase* call = dyn_alloc_mem_loc->call(); CallContext* context = dyn_alloc_mem_loc->context(); return {{"call_id", this->_statements.insert(call)}, {"context_id", this->_call_contexts.insert(context)}}; } else { ikos_unreachable("unexpected memory location"); } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/operands.cpp000066400000000000000000001072731473507761200244160ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief OperandsTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace analyzer { OperandsTable::OperandsTable(sqlite::DbConnection& db) : DatabaseTable(db, "operands", {{"id", sqlite::DbColumnType::Integer}, {"kind", sqlite::DbColumnType::Integer}, {"repr", sqlite::DbColumnType::Text}}, {}), _row(db, "operands", 3) {} sqlite::DbInt64 OperandsTable::insert(ar::Value* value) { ikos_assert(value != nullptr); auto it = this->_map.find(value); if (it != this->_map.end()) { return it->second; } sqlite::DbInt64 id = this->_last_insert_id++; this->_row << id; this->_row << static_cast< sqlite::DbInt64 >(value->kind()); this->_row << repr(value); this->_row << sqlite::end_row; this->_map.try_emplace(value, id); return id; } namespace detail { namespace { /// \brief Return true if the given expression has parentheses bool has_parentheses(StringRef s) { return s.size() > 2 && *s.begin() == '(' && *s.rbegin() == ')'; } /// \brief Add parentheses around the given expression std::string add_parentheses(StringRef s) { ikos_assert(!s.empty()); static std::regex ArrayPattern( "&?[a-zA-Z0-9_]+(" "(\\[.*\\])" "|(\\->[a-zA-Z0-9_]+)" "|(\\.[a-zA-Z0-9_]+)" ")*"); static std::regex FunctionPattern( "&?[a-zA-Z0-9_]+\\(([a-zA-Z0-9_]+(, )?)*\\)"); static std::regex DerefPattern("\\*[a-zA-Z0-9_]+"); if (std::regex_match(s.begin(), s.end(), ArrayPattern) || std::regex_match(s.begin(), s.end(), FunctionPattern) || std::regex_match(s.begin(), s.end(), DerefPattern)) { // no need for parentheses return s.to_string(); } // else return "(" + s.to_string() + ")"; } /// \brief Remove parentheses around the given expression StringRef remove_parentheses(StringRef s) { ikos_assert(!s.empty()); if (has_parentheses(s)) { s = s.substr(1, s.size() - 2); } return s; } /// \brief Return true if the given expression is an address bool is_address(StringRef s) { return !s.empty() && s[0] == '&'; } /// \brief Add a dereference std::string add_deref(StringRef s) { ikos_assert(!s.empty()); if (is_address(s)) { // s = `&x` return remove_parentheses(s.substr(1)).to_string(); } else { return "*" + add_parentheses(s); } } /// \brief Convert a llvm::APInt to a string std::string to_string(const llvm::APInt& n) { llvm::SmallString< 16 > str; n.toString(str, /*radix=*/10, /*signed=*/true); return str.str().str(); } /// \brief Convert a llvm::APFloat to a string std::string to_string(const llvm::APFloat& f) { llvm::SmallString< 16 > str; f.toString(str, /*FormatPrecision=*/0, /*FormatMaxPadding=*/0); return str.str().str(); } /// \brief Return the hexadecimal character for the given number char hexdigit(unsigned n, bool lower_case = false) { if (n < 10U) { return static_cast< char >('0' + n); } else if (n < 16U) { return static_cast< char >((lower_case ? 'a' : 'A') + (n - 10)); } else { ikos_unreachable("invalid argument"); } } /// \brief Return the escaped string std::string escape_string(llvm::StringRef s) { std::string r; r.reserve(s.size() + 2); r.push_back('"'); for (auto it = s.begin(), et = s.end(); it != et; ++it) { const char c = *it; if (c == '"' || c == '\\') { r.push_back('\\'); r.push_back(c); } else if (std::isprint(c) != 0) { r.push_back(c); } else if (c == '\b') { r.append("\\b"); } else if (c == '\t') { r.append("\\t"); } else if (c == '\n') { r.append("\\n"); } else if (c == '\f') { r.append("\\f"); } else if (c == '\r') { r.append("\\r"); } else if (c == '\0' && std::next(it) == et) { continue; // Skip ending null-byte } else { r.push_back('\\'); r.push_back(hexdigit(static_cast< unsigned char >(c) >> 4U)); r.push_back(hexdigit(static_cast< unsigned char >(c) & 0x0FU)); } } r.push_back('"'); return r; } /// \brief Return the textual representation of a binary operator StringRef repr(llvm::Instruction::BinaryOps op) { switch (op) { case llvm::Instruction::Add: return "+"; case llvm::Instruction::FAdd: return "+"; case llvm::Instruction::Sub: return "-"; case llvm::Instruction::FSub: return "-"; case llvm::Instruction::Mul: return "*"; case llvm::Instruction::FMul: return "*"; case llvm::Instruction::UDiv: return "/"; case llvm::Instruction::SDiv: return "/"; case llvm::Instruction::FDiv: return "/"; case llvm::Instruction::URem: return "%"; case llvm::Instruction::SRem: return "%"; case llvm::Instruction::FRem: return "%"; case llvm::Instruction::Shl: return "<<"; case llvm::Instruction::LShr: return ">>"; case llvm::Instruction::AShr: return ">>"; case llvm::Instruction::And: return "&"; case llvm::Instruction::Or: return "|"; case llvm::Instruction::Xor: return "^"; default: throw FrontendError("unsupported llvm binary operator"); } } /// \brief Return the textual representation of a CmpInst predicate StringRef repr(llvm::CmpInst::Predicate pred) { switch (pred) { case llvm::CmpInst::FCMP_FALSE: return "false"; case llvm::CmpInst::FCMP_OEQ: return "=="; case llvm::CmpInst::FCMP_OGT: return ">"; case llvm::CmpInst::FCMP_OGE: return ">="; case llvm::CmpInst::FCMP_OLT: return "<"; case llvm::CmpInst::FCMP_OLE: return "<="; case llvm::CmpInst::FCMP_ONE: return "!="; case llvm::CmpInst::FCMP_ORD: return "not_nan"; case llvm::CmpInst::FCMP_UNO: return "is_nan"; case llvm::CmpInst::FCMP_UEQ: return "=="; case llvm::CmpInst::FCMP_UGT: return ">"; case llvm::CmpInst::FCMP_UGE: return ">="; case llvm::CmpInst::FCMP_ULT: return "<"; case llvm::CmpInst::FCMP_ULE: return "<="; case llvm::CmpInst::FCMP_UNE: return "!="; case llvm::CmpInst::FCMP_TRUE: return "true"; case llvm::CmpInst::ICMP_EQ: return "=="; case llvm::CmpInst::ICMP_NE: return "!="; case llvm::CmpInst::ICMP_UGT: return ">"; case llvm::CmpInst::ICMP_UGE: return ">="; case llvm::CmpInst::ICMP_ULT: return "<"; case llvm::CmpInst::ICMP_ULE: return "<="; case llvm::CmpInst::ICMP_SGT: return ">"; case llvm::CmpInst::ICMP_SGE: return ">="; case llvm::CmpInst::ICMP_SLT: return "<"; case llvm::CmpInst::ICMP_SLE: return "<="; default: throw FrontendError("unsupported llvm cmp predicate"); } } /// \brief Set of types using TypeSet = boost::container::flat_set< llvm::Type* >; /// \brief Set of values using ValueSet = boost::container::flat_set< llvm::Value* >; /// \brief Return the textual representation of a llvm::Type* std::string repr(llvm::Type* type, TypeSet seen) { ikos_assert(type != nullptr); if (type->isVoidTy()) { return "void"; } else if (auto int_type = llvm::dyn_cast< llvm::IntegerType >(type)) { if (int_type->getBitWidth() == 1) { return "bool"; } else { return "int" + std::to_string(int_type->getBitWidth()) + "_t"; } } else if (type->isFloatingPointTy()) { if (type->isHalfTy()) { return "half_t"; } else if (type->isFloatTy()) { return "float"; } else if (type->isDoubleTy()) { return "double"; } else if (type->isX86_FP80Ty()) { return "fp80_t"; } else if (type->isFP128Ty()) { return "fp128_t"; } else if (type->isPPC_FP128Ty()) { return "ppc_fp128_t"; } else { throw FrontendError("unsupported llvm floating point type"); } } else if (auto ptr_type = llvm::dyn_cast< llvm::PointerType >(type)) { return repr(ptr_type->getPointerElementType(), seen) + "*"; } else if (auto array_type = llvm::dyn_cast< llvm::ArrayType >(type)) { return repr(array_type->getElementType(), seen) + "[" + std::to_string(array_type->getNumElements()) + "]"; } else if (auto vector_type = llvm::dyn_cast< llvm::VectorType >(type)) { return repr(vector_type->getElementType(), seen) + "[" + std::to_string(vector_type->getElementCount().getFixedValue()) + "]"; } else if (auto struct_type = llvm::dyn_cast< llvm::StructType >(type)) { if (struct_type->hasName()) { llvm::StringRef name = struct_type->getName(); name.consume_front("struct."); name.consume_front("class."); return name.str(); } if (struct_type->isOpaque()) { return "{...}"; } // Avoid infinite recursion auto p = seen.insert(type); if (!p.second) { return "{...}"; // already processing } std::string r = "{"; for (auto it = struct_type->element_begin(), et = struct_type->element_end(); it != et;) { r += repr(*it, seen); ++it; if (it != et) { r += ", "; } } r += "}"; return r; } else if (auto fun_type = llvm::dyn_cast< llvm::FunctionType >(type)) { std::string r = repr(fun_type->getReturnType(), seen); r += "("; for (auto it = fun_type->param_begin(), et = fun_type->param_end(); it != et;) { r += repr(*it, seen); ++it; if (it != et) { r += ", "; } } r += ")"; return r; } else { throw FrontendError("unsupported llvm type"); } } /// \brief Remove any typedef/const/volatile/etc. qualifier llvm::DIType* remove_qualifiers(llvm::DIType* type) { while (type != nullptr && !type->isForwardDecl() && llvm::isa< llvm::DIDerivedType >(type)) { auto derived_type = llvm::cast< llvm::DIDerivedType >(type); if (derived_type->getTag() == llvm::dwarf::DW_TAG_typedef || derived_type->getTag() == llvm::dwarf::DW_TAG_const_type || derived_type->getTag() == llvm::dwarf::DW_TAG_volatile_type || derived_type->getTag() == llvm::dwarf::DW_TAG_restrict_type || derived_type->getTag() == llvm::dwarf::DW_TAG_atomic_type) { type = llvm::cast_or_null< llvm::DIType >(derived_type->getRawBaseType()); } else { break; } } return type; } /// \brief Return the pointee type of a pointer type, or nullptr llvm::DIType* pointee_type(llvm::DIType* type) { type = remove_qualifiers(type); if (type == nullptr) { return nullptr; } if (auto derived_type = llvm::dyn_cast< llvm::DIDerivedType >(type)) { if (derived_type->getTag() == llvm::dwarf::DW_TAG_pointer_type) { return llvm::cast_or_null< llvm::DIType >(derived_type->getRawBaseType()); } } return nullptr; } /// \brief Result of a repr() function struct ReprResult { public: /// \brief Textual representation std::string str; /// \brief Debug info pointee type (or nullptr) llvm::DIType* pointee_type; public: /// \brief Constructor explicit ReprResult(std::string str_, llvm::DIType* pointee_type_ = nullptr) : str(std::move(str_)), pointee_type(pointee_type_) { ikos_assert(!this->str.empty()); } }; // end struct ReprResult // Forward declaration ReprResult repr(llvm::Constant*, ValueSet seen); ReprResult repr(llvm::Value*, ValueSet seen); /// \brief Return the textual representation of a llvm::Constant* ReprResult repr(llvm::Constant* cst, ValueSet seen) { if (auto gv_alias = llvm::dyn_cast< llvm::GlobalAlias >(cst)) { return repr(gv_alias->getAliasee(), seen); } else if (auto gv = llvm::dyn_cast< llvm::GlobalVariable >(cst)) { // Check for debug info llvm::SmallVector< llvm::DIGlobalVariableExpression*, 1 > dbgs; gv->getDebugInfo(dbgs); if (!dbgs.empty()) { llvm::DIGlobalVariable* di_gv = dbgs[0]->getVariable(); auto di_type = llvm::cast_or_null< llvm::DIType >(di_gv->getRawType()); llvm::StringRef name = di_gv->getName(); if (!name.empty()) { return ReprResult{"&" + demangle(name), di_type}; } } // If it's a constant (e.g, a string) if (gv->isConstant() && gv->hasInitializer()) { return ReprResult{"&" + repr(gv->getInitializer(), seen).str}; } // Last chance, use llvm variable name if (gv->hasName()) { return ReprResult{"&" + demangle(gv->getName())}; } return ReprResult{"&__unnamed_global_var"}; } else if (auto fun = llvm::dyn_cast< llvm::Function >(cst)) { return ReprResult{"&" + demangle(FunctionsTable::name(fun))}; } else if (auto cst_int = llvm::dyn_cast< llvm::ConstantInt >(cst)) { return ReprResult{detail::to_string(cst_int->getValue())}; } else if (auto cst_fp = llvm::dyn_cast< llvm::ConstantFP >(cst)) { return ReprResult{detail::to_string(cst_fp->getValueAPF())}; } else if (llvm::isa< llvm::ConstantPointerNull >(cst)) { return ReprResult{"NULL"}; } else if (llvm::isa< llvm::UndefValue >(cst)) { return ReprResult{"undefined"}; } else if (llvm::isa< llvm::ConstantAggregateZero >(cst)) { return ReprResult{"{0}"}; } else if (auto cst_array = llvm::dyn_cast< llvm::ConstantArray >(cst)) { std::string r = "["; for (auto it = cst_array->op_begin(), et = cst_array->op_end(); it != et;) { r += repr(*it, seen).str; ++it; if (it != et) { r += ", "; } } r += "]"; return ReprResult{r}; } else if (auto cst_struct = llvm::dyn_cast< llvm::ConstantStruct >(cst)) { std::string r = "{"; for (auto it = cst_struct->op_begin(), et = cst_struct->op_end(); it != et;) { r += repr(*it, seen).str; ++it; if (it != et) { r += ", "; } } r += "}"; return ReprResult{r}; } else if (auto cst_vector = llvm::dyn_cast< llvm::ConstantVector >(cst)) { std::string r = "["; for (auto it = cst_vector->op_begin(), et = cst_vector->op_end(); it != et;) { r += repr(*it, seen).str; ++it; if (it != et) { r += ", "; } } r += "]"; return ReprResult{r}; } else if (auto cst_data_seq = llvm::dyn_cast< llvm::ConstantDataSequential >(cst)) { if (cst_data_seq->isString()) { return ReprResult{detail::escape_string(cst_data_seq->getAsString())}; } std::string r = "["; auto ty = cst_data_seq->getElementType(); for (unsigned i = 0, n = cst_data_seq->getNumElements(); i < n;) { if (ty->isIntegerTy()) { r += std::to_string(cst_data_seq->getElementAsInteger(i)); } else if (ty->isFloatingPointTy()) { r += detail::to_string(cst_data_seq->getElementAsAPFloat(i)); } else { ikos_unreachable("unreachable"); } i++; if (i != n) { r += ", "; } } r += "]"; return ReprResult{r}; } else if (auto cst_expr = llvm::dyn_cast< llvm::ConstantExpr >(cst)) { auto inst_deleter = [](llvm::Instruction* inst) { inst->deleteValue(); }; std::unique_ptr< llvm::Instruction, decltype(inst_deleter) > inst(cst_expr->getAsInstruction(), inst_deleter); return repr(inst.get(), seen); } else { throw FrontendError("unsupported llvm constant"); } } /// \brief Return the fields of a structure type std::vector< llvm::DIDerivedType* > struct_fields(llvm::DICompositeType* type) { ikos_assert(type != nullptr); ikos_assert(type->getTag() == llvm::dwarf::DW_TAG_structure_type || type->getTag() == llvm::dwarf::DW_TAG_class_type); if (type->getRawElements() == nullptr) { return {}; // e.g, a forward declaration } std::vector< llvm::DIDerivedType* > fields; for (llvm::DINode* member : type->getElements()) { if (llvm::isa< llvm::DISubprogram >(member)) { // Skip methods continue; } if (llvm::cast< llvm::DIType >(member)->isStaticMember()) { // Skip static members continue; } ikos_assert(llvm::isa< llvm::DIDerivedType >(member)); auto derived_type = llvm::cast< llvm::DIDerivedType >(member); if (derived_type->getTag() == llvm::dwarf::DW_TAG_inheritance) { // Base class ikos_assert(derived_type->getRawBaseType() != nullptr); auto base = llvm::cast< llvm::DIType >(derived_type->getRawBaseType()); base = remove_qualifiers(base); ikos_assert(base != nullptr); ikos_assert(llvm::isa< llvm::DICompositeType >(base)); auto parent = llvm::cast< llvm::DICompositeType >(base); auto parent_fields = struct_fields(parent); fields.insert(fields.end(), parent_fields.begin(), parent_fields.end()); continue; } ikos_assert(derived_type->getTag() == llvm::dwarf::DW_TAG_member); fields.push_back(derived_type); } return fields; } /// \brief Add a structure field access `addr->field` or `addr.field` ReprResult add_struct_access(const ReprResult& addr, const llvm::APInt& offset) { llvm::DIDerivedType* field = nullptr; auto type = remove_qualifiers(addr.pointee_type); if (type != nullptr && llvm::isa< llvm::DICompositeType >(type)) { auto comp_type = llvm::cast< llvm::DICompositeType >(type); if (comp_type->getTag() == llvm::dwarf::DW_TAG_structure_type || comp_type->getTag() == llvm::dwarf::DW_TAG_class_type) { std::vector< llvm::DIDerivedType* > fields = struct_fields(comp_type); uint64_t index = offset.getZExtValue(); if (index < fields.size()) { field = fields[index]; } } } std::string s; if (is_address(addr.str)) { s = "&" + add_deref(addr.str) + "."; } else { s = "&" + add_parentheses(addr.str) + "->"; } if (field != nullptr) { s += field->getName(); return ReprResult{s, llvm::cast< llvm::DIType >(field->getRawBaseType())}; } else { // Could not guess the field type s += to_string(offset); return ReprResult{s}; } } /// \brief Add an array access `addr[index]` ReprResult add_array_access(const ReprResult& addr, const ReprResult& index) { llvm::DIType* element_type = nullptr; auto type = remove_qualifiers(addr.pointee_type); if (type != nullptr) { if (auto derived_type = llvm::dyn_cast< llvm::DIDerivedType >(type)) { if (derived_type->getTag() == llvm::dwarf::DW_TAG_pointer_type) { element_type = llvm::cast_or_null< llvm::DIType >(derived_type->getRawBaseType()); } } else if (auto comp_type = llvm::dyn_cast< llvm::DICompositeType >(type)) { if (comp_type->getTag() == llvm::dwarf::DW_TAG_array_type) { element_type = llvm::cast_or_null< llvm::DIType >(comp_type->getRawBaseType()); } } } std::string s; if (is_address(addr.str)) { s = "&" + add_deref(addr.str); } else { s = "&" + add_parentheses(addr.str); } s += "[" + index.str + "]"; return ReprResult{s, element_type}; } /// \brief Return the textual representation of a llvm::Value* ReprResult repr(llvm::Value* value, ValueSet seen) { ikos_assert(value != nullptr); // Check for llvm.dbg.value if (!llvm::isa< llvm::Constant >(value)) { llvm::SmallVector< llvm::DbgValueInst*, 1 > dbg_values; llvm::findDbgValues(dbg_values, value); auto dbg_value = std::find_if(dbg_values.begin(), dbg_values.end(), [](llvm::DbgValueInst* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_value != dbg_values.end()) { llvm::DILocalVariable* di_var = (*dbg_value)->getVariable(); auto di_type = llvm::cast_or_null< llvm::DIType >(di_var->getRawType()); llvm::StringRef name = di_var->getName(); if (!name.empty()) { return ReprResult{name.str(), pointee_type(di_type)}; } } } if (auto arg = llvm::dyn_cast< llvm::Argument >(value)) { // Check for llvm.dbg.declare and llvm.dbg.addr llvm::TinyPtrVector< llvm::DbgVariableIntrinsic* > dbg_addrs = llvm::FindDbgAddrUses(arg); auto dbg_addr = std::find_if(dbg_addrs.begin(), dbg_addrs.end(), [](llvm::DbgVariableIntrinsic* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_addr != dbg_addrs.end()) { llvm::DILocalVariable* di_var = (*dbg_addr)->getVariable(); auto di_type = llvm::cast_or_null< llvm::DIType >(di_var->getRawType()); llvm::StringRef name = di_var->getName(); if (!name.empty()) { return ReprResult{"&" + demangle(name), di_type}; } } return ReprResult{"__arg" + std::to_string(arg->getArgNo())}; } if (auto inline_asm = llvm::dyn_cast< llvm::InlineAsm >(value)) { return ReprResult{"asm " + detail::escape_string(inline_asm->getAsmString())}; } if (auto cst = llvm::dyn_cast< llvm::Constant >(value)) { return repr(cst, seen); } if (auto inst = llvm::dyn_cast< llvm::Instruction >(value)) { if (auto alloca = llvm::dyn_cast< llvm::AllocaInst >(inst)) { // Check for llvm.dbg.declare and llvm.dbg.addr llvm::TinyPtrVector< llvm::DbgVariableIntrinsic* > dbg_addrs = llvm::FindDbgAddrUses(alloca); auto dbg_addr = std::find_if(dbg_addrs.begin(), dbg_addrs.end(), [](llvm::DbgVariableIntrinsic* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_addr != dbg_addrs.end()) { llvm::DILocalVariable* di_var = (*dbg_addr)->getVariable(); auto di_type = llvm::cast_or_null< llvm::DIType >(di_var->getRawType()); llvm::StringRef name = di_var->getName(); if (!name.empty()) { return ReprResult{"&" + demangle(name), alloca->isArrayAllocation() ? pointee_type(di_type) : di_type}; } } // Last chance, use llvm variable name if (alloca->hasName()) { return ReprResult{"&" + demangle(alloca->getName())}; } return ReprResult{"&__unnamed_local_var"}; } else if (auto load = llvm::dyn_cast< llvm::LoadInst >(inst)) { ReprResult r = repr(load->getPointerOperand(), seen); return ReprResult{detail::add_deref(r.str), pointee_type(r.pointee_type)}; } else if (auto call = llvm::dyn_cast< llvm::CallInst >(inst)) { std::string r = detail::add_deref(repr(call->getCalledOperand(), seen).str); r += "("; for (auto it = call->arg_begin(), et = call->arg_end(); it != et;) { r += repr(*it, seen).str; ++it; if (it != et) { r += ", "; } } r += ")"; return ReprResult{r}; } else if (auto invoke = llvm::dyn_cast< llvm::InvokeInst >(inst)) { std::string r = detail::add_deref(repr(invoke->getCalledOperand(), seen).str); r += "("; for (auto it = invoke->arg_begin(), et = invoke->arg_end(); it != et;) { r += repr(*it, seen).str; ++it; if (it != et) { r += ", "; } } r += ")"; return ReprResult{r}; } else if (auto cast = llvm::dyn_cast< llvm::CastInst >(inst)) { std::string r; if (cast->getOpcode() == llvm::Instruction::ZExt || cast->getOpcode() == llvm::Instruction::FPToUI) { auto int_type = llvm::cast< llvm::IntegerType >(cast->getType()); r += "(uint" + std::to_string(int_type->getBitWidth()) + "_t)"; } else if (cast->getOpcode() == llvm::Instruction::SExt || cast->getOpcode() == llvm::Instruction::FPToSI) { auto int_type = llvm::cast< llvm::IntegerType >(cast->getType()); r += "(int" + std::to_string(int_type->getBitWidth()) + "_t)"; } else { TypeSet types_seen; std::string t = repr(cast->getType(), types_seen); r += "(" + t + ")"; } r += detail::add_parentheses(repr(cast->getOperand(0), seen).str); return ReprResult{r}; } else if (auto gep = llvm::dyn_cast< llvm::GetElementPtrInst >(inst)) { ReprResult r = repr(gep->getPointerOperand(), seen); auto begin = llvm::gep_type_begin(gep); auto end = llvm::gep_type_end(gep); for (auto it = begin; it != end; ++it) { llvm::Value* op = it.getOperand(); if (it.getStructTypeOrNull() != nullptr) { // Shift to get a structure field llvm::APInt offset = llvm::cast< llvm::ConstantInt >(op)->getValue(); r = detail::add_struct_access(r, offset); } else if (auto cst = llvm::dyn_cast< llvm::ConstantInt >(op)) { // Shift in a sequential type if (it == begin && cst->isZero()) { continue; // skip } else { r = detail::add_array_access(r, repr(op, seen)); } } else { r = detail::add_array_access(r, repr(op, seen)); } } return r; } else if (auto bin_op = llvm::dyn_cast< llvm::BinaryOperator >(inst)) { std::string r; r += detail::add_parentheses(repr(bin_op->getOperand(0), seen).str); r += ' '; r += detail::repr(bin_op->getOpcode()); r += ' '; r += detail::add_parentheses(repr(bin_op->getOperand(1), seen).str); return ReprResult{r}; } else if (auto cmp = llvm::dyn_cast< llvm::CmpInst >(inst)) { std::string r; r += detail::add_parentheses(repr(cmp->getOperand(0), seen).str); r += ' '; r += detail::repr(cmp->getPredicate()); r += ' '; r += detail::add_parentheses(repr(cmp->getOperand(1), seen).str); return ReprResult{r}; } else if (auto phi = llvm::dyn_cast< llvm::PHINode >(inst)) { // Avoid infinite recursion auto p = seen.insert(phi); if (!p.second) { return ReprResult{"..."}; // already processing } // Simple heuristic to detect a ternary `cond ? a : b` if (phi->getNumIncomingValues() == 2) { auto first = phi->getIncomingBlock(0); auto second = phi->getIncomingBlock(1); if (first->getUniquePredecessor() != nullptr && second->getUniquePredecessor() != nullptr && first->getUniquePredecessor() == second->getUniquePredecessor()) { auto br = llvm::dyn_cast< llvm::BranchInst >( first->getUniquePredecessor()->getTerminator()); if (br != nullptr && br->isConditional()) { std::string r; r += detail::add_parentheses(repr(br->getCondition(), seen).str); r += " ? "; r += repr(phi->getIncomingValueForBlock(br->getSuccessor(0)), seen) .str; r += " : "; r += repr(phi->getIncomingValueForBlock(br->getSuccessor(1)), seen) .str; return ReprResult{r}; } } } // Else std::string r = "{"; for (unsigned i = 0, n = phi->getNumIncomingValues(); i < n;) { llvm::BasicBlock* bb = phi->getIncomingBlock(i); if (bb->hasName()) { r += bb->getName(); } else { r += std::to_string(i); } r += ": "; r += repr(phi->getIncomingValue(i), seen).str; i++; if (i != n) { r += ", "; } } r += "}"; return ReprResult{r}; } else if (auto extractvalue = llvm::dyn_cast< llvm::ExtractValueInst >(inst)) { std::string r; r += detail::add_parentheses( repr(extractvalue->getAggregateOperand(), seen).str); for (auto it = extractvalue->idx_begin(), et = extractvalue->idx_end(); it != et; ++it) { r += '.'; r += std::to_string(*it); } return ReprResult{r}; } else if (auto insertvalue = llvm::dyn_cast< llvm::InsertValueInst >(inst)) { std::string r; r += detail::add_parentheses( repr(insertvalue->getAggregateOperand(), seen).str); r += '['; for (auto it = insertvalue->idx_begin(), et = insertvalue->idx_end(); it != et;) { r += std::to_string(*it); ++it; if (it != et) { r += '.'; } } r += ": "; r += repr(insertvalue->getInsertedValueOperand(), seen).str; r += ']'; return ReprResult{r}; } else if (llvm::isa< llvm::LandingPadInst >(inst)) { return ReprResult{"__current_exception"}; } else { std::ostringstream buf; buf << "unsupported llvm instruction: " << inst->getOpcodeName(); throw FrontendError(buf.str()); } } throw FrontendError("unsupported llvm value"); } /// \brief ar::Value visitor returning a textual representation struct OperandReprVisitor { using ResultType = std::string; std::string operator()(ar::UndefinedConstant*) const { return "undefined"; } std::string operator()(ar::IntegerConstant* c) const { return c->value().str(); } std::string operator()(ar::FloatConstant* c) const { return c->value(); } std::string operator()(ar::NullConstant*) const { return "NULL"; } std::string operator()(ar::StructConstant* c) const { std::string r = "{"; for (auto it = c->field_begin(), et = c->field_end(); it != et;) { r += ar::apply_visitor(*this, it->value); ++it; if (it != et) { r += ", "; } } r += "}"; return r; } std::string operator()(ar::ArrayConstant* c) const { std::string r = "["; for (auto it = c->element_begin(), et = c->element_end(); it != et;) { r += ar::apply_visitor(*this, *it); ++it; if (it != et) { r += ", "; } } r += "]"; return r; } std::string operator()(ar::VectorConstant* c) const { std::string r = "["; for (auto it = c->element_begin(), et = c->element_end(); it != et;) { r += ar::apply_visitor(*this, *it); ++it; if (it != et) { r += ", "; } } r += "]"; return r; } std::string operator()(ar::AggregateZeroConstant*) const { return "{0}"; } std::string operator()(ar::FunctionPointerConstant* c) const { ar::Function* fun = c->function(); return "&" + demangle(FunctionsTable::name(fun)); } std::string operator()(ar::InlineAssemblyConstant* c) const { return "asm " + escape_string(c->code()); } std::string operator()(ar::GlobalVariable* gv) const { ikos_assert(gv->has_frontend()); auto llvm_gv = gv->frontend< llvm::GlobalVariable >(); // Check for debug info llvm::SmallVector< llvm::DIGlobalVariableExpression*, 1 > dbgs; llvm_gv->getDebugInfo(dbgs); if (!dbgs.empty()) { llvm::DIGlobalVariable* di_gv = dbgs[0]->getVariable(); llvm::StringRef name = di_gv->getName(); if (!name.empty()) { return "&" + demangle(name); } } // If it's a constant (e.g, a string) if (llvm_gv->isConstant() && llvm_gv->hasInitializer()) { return "&" + OperandsTable::repr(llvm_gv->getInitializer()); } // Last chance, use llvm variable name if (llvm_gv->hasName()) { return "&" + demangle(llvm_gv->getName()); } return "&__unnamed_global_var"; } std::string operator()(ar::LocalVariable* lv) const { ikos_assert(lv->has_frontend()); auto value = lv->frontend< llvm::Value >(); ikos_assert(llvm::isa< llvm::AllocaInst >(value)); auto alloca = llvm::cast< llvm::AllocaInst >(value); // Check for llvm.dbg.declare and llvm.dbg.addr llvm::TinyPtrVector< llvm::DbgVariableIntrinsic* > dbg_addrs = llvm::FindDbgAddrUses(alloca); auto dbg_addr = std::find_if(dbg_addrs.begin(), dbg_addrs.end(), [](llvm::DbgVariableIntrinsic* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_addr != dbg_addrs.end()) { llvm::DILocalVariable* di_var = (*dbg_addr)->getVariable(); llvm::StringRef name = di_var->getName(); if (!name.empty()) { return "&" + demangle(name); } } // Check for llvm.dbg.value llvm::SmallVector< llvm::DbgValueInst*, 1 > dbg_values; llvm::findDbgValues(dbg_values, alloca); auto dbg_value = std::find_if(dbg_values.begin(), dbg_values.end(), [](llvm::DbgValueInst* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_value != dbg_values.end()) { llvm::DILocalVariable* di_var = (*dbg_value)->getVariable(); llvm::StringRef name = di_var->getName(); if (!name.empty()) { return "&" + demangle(name); } } // Last chance, use llvm variable name if (alloca->hasName()) { return "&" + demangle(alloca->getName()); } return "&__unnamed_local_var"; } std::string operator()(ar::InternalVariable* iv) const { ikos_assert(iv->has_frontend()); auto value = iv->frontend< llvm::Value >(); return OperandsTable::repr(value); } }; // end struct OperandReprVisitor } // end anonymous namespace } // end namespace detail std::string OperandsTable::repr(llvm::Type* type) { return detail::repr(type, detail::TypeSet{}); } std::string OperandsTable::repr(llvm::Constant* cst) { return detail::repr(cst, detail::ValueSet{}).str; } std::string OperandsTable::repr(llvm::Value* value) { return detail::repr(value, detail::ValueSet{}).str; } std::string OperandsTable::repr(ar::Value* value) { return ar::apply_visitor(detail::OperandReprVisitor{}, value); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/settings.cpp000066400000000000000000000057741473507761200244460ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief SettingsTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { SettingsTable::SettingsTable(sqlite::DbConnection& db) : DatabaseTable(db, "settings", {{"name", sqlite::DbColumnType::Text}, {"value", sqlite::DbColumnType::Text}}, {"name"}), _row(db, "settings", 2) {} void SettingsTable::insert(StringRef name, const char* value) { this->_row << name << StringRef(value) << sqlite::end_row; } void SettingsTable::insert(StringRef name, StringRef value) { this->_row << name << value << sqlite::end_row; } void SettingsTable::insert(StringRef name, const JsonNode& value) { this->insert(name, value.str()); } void SettingsTable::insert(StringRef name, bool value) { this->insert(name, value ? StringRef("true") : StringRef("false")); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/statements.cpp000066400000000000000000000077001473507761200247640ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief StatementsTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { StatementsTable::StatementsTable(sqlite::DbConnection& db, FilesTable& files, FunctionsTable& functions) : DatabaseTable(db, "statements", {{"id", sqlite::DbColumnType::Integer}, {"kind", sqlite::DbColumnType::Integer}, {"function_id", sqlite::DbColumnType::Integer}, {"file_id", sqlite::DbColumnType::Integer}, {"line", sqlite::DbColumnType::Integer}, {"column", sqlite::DbColumnType::Integer}}, {"function_id", "file_id"}), _files(files), _functions(functions), _row(db, "statements", 6) {} sqlite::DbInt64 StatementsTable::insert(ar::Statement* stmt) { ikos_assert(stmt != nullptr); auto it = this->_map.find(stmt); if (it != this->_map.end()) { return it->second; } sqlite::DbInt64 id = this->_last_insert_id++; this->_row << id; this->_row << static_cast< sqlite::DbInt64 >(stmt->kind()); ar::Code* code = stmt->parent()->code(); ikos_assert(code->is_function_body()); this->_row << this->_functions.insert(code->function()); ikos_assert(stmt->has_frontend()); SourceLocation loc = source_location(stmt); if (loc) { this->_row << this->_files.insert(loc.file()); this->_row << static_cast< sqlite::DbInt64 >(loc.line()); this->_row << static_cast< sqlite::DbInt64 >(loc.column()); } else { this->_row << sqlite::null; this->_row << sqlite::null; this->_row << sqlite::null; } this->_row << sqlite::end_row; this->_map.try_emplace(stmt, id); return id; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/database/table/times.cpp000066400000000000000000000051771473507761200237240ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief TimesTable implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { TimesTable::TimesTable(sqlite::DbConnection& db) : DatabaseTable(db, "times", {{"pass", sqlite::DbColumnType::Text}, {"time", sqlite::DbColumnType::Real}}, {"pass"}), _row(db, "times", 2) {} void TimesTable::insert(StringRef name, sqlite::DbDouble time) { this->_row << name << time << sqlite::end_row; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/exception.cpp000066400000000000000000000053761473507761200217470ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Exception implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { // Exception const char* Exception::what() const noexcept { return ""; } Exception::~Exception() = default; // LogicError const char* LogicError::what() const noexcept { return this->_msg->c_str(); } LogicError::~LogicError() = default; // ArgumentError const char* ArgumentError::what() const noexcept { return this->_msg->c_str(); } ArgumentError::~ArgumentError() = default; // FrontendError const char* FrontendError::what() const noexcept { return this->_msg->c_str(); } FrontendError::~FrontendError() = default; } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/ikos_analyzer.cpp000066400000000000000000001324401473507761200226140ustar00rootroot00000000000000/******************************************************************************* * * ikos-analyzer -- IKOS static analyzer * * This is the entry point for all analyses. * * Authors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ar = ikos::ar; namespace llvm_to_ar = ikos::frontend::import; namespace analyzer = ikos::analyzer; /// \name Main options /// @{ static llvm::cl::OptionCategory MainCategory("Main Options"); static llvm::cl::opt< std::string > InputFilename( llvm::cl::Positional, llvm::cl::desc(""), llvm::cl::Required, llvm::cl::value_desc("file")); static llvm::cl::opt< std::string > OutputFilename( "o", llvm::cl::desc("Output database filename (default: output.db)"), llvm::cl::value_desc("file"), llvm::cl::init("output.db"), llvm::cl::cat(MainCategory)); static llvm::cl::opt< analyzer::LogLevel > LogLevel( "log", llvm::cl::desc("Log level:"), llvm::cl::values( clEnumValN(analyzer::LogLevel::None, "none", "Disable logging"), clEnumValN(analyzer::LogLevel::Critical, "critical", "Critical level"), clEnumValN(analyzer::LogLevel::Error, "error", "Error level"), clEnumValN(analyzer::LogLevel::Warning, "warning", "Warning level (default)"), clEnumValN(analyzer::LogLevel::Info, "info", "Informative level"), clEnumValN(analyzer::LogLevel::Debug, "debug", "Debug level"), clEnumValN(analyzer::LogLevel::All, "all", "Show all messages")), llvm::cl::init(analyzer::LogLevel::Warning), llvm::cl::cat(MainCategory)); static llvm::cl::opt< analyzer::ProgressOption > Progress( "progress", llvm::cl::desc("Progress report:"), llvm::cl::values( clEnumValN(analyzer::ProgressOption::Auto, "auto", "Interactive if the output is a terminal (default)"), clEnumValN(analyzer::ProgressOption::Interactive, "interactive", "Interactive"), clEnumValN(analyzer::ProgressOption::Linear, "linear", "Linear"), clEnumValN(analyzer::ProgressOption::None, "no", "Disable progress report")), llvm::cl::init(analyzer::ProgressOption::Auto), llvm::cl::cat(MainCategory)); /// @} /// \name Analysis options /// @{ static llvm::cl::OptionCategory AnalysisCategory("Analysis Options"); static llvm::cl::list< analyzer::CheckerName > Analyses( "a", llvm::cl::desc("Available analyses:"), llvm::cl::CommaSeparated, llvm::cl::OneOrMore, llvm::cl::values( clEnumValN(analyzer::CheckerName::BufferOverflow, checker_short_name(analyzer::CheckerName::BufferOverflow), checker_long_name(analyzer::CheckerName::BufferOverflow)), clEnumValN(analyzer::CheckerName::DivisionByZero, checker_short_name(analyzer::CheckerName::DivisionByZero), checker_long_name(analyzer::CheckerName::DivisionByZero)), clEnumValN( analyzer::CheckerName::NullPointerDereference, checker_short_name(analyzer::CheckerName::NullPointerDereference), checker_long_name(analyzer::CheckerName::NullPointerDereference)), clEnumValN(analyzer::CheckerName::AssertProver, checker_short_name(analyzer::CheckerName::AssertProver), checker_long_name(analyzer::CheckerName::AssertProver)), clEnumValN(analyzer::CheckerName::UnalignedPointer, checker_short_name(analyzer::CheckerName::UnalignedPointer), checker_long_name(analyzer::CheckerName::UnalignedPointer)), clEnumValN( analyzer::CheckerName::UninitializedVariable, checker_short_name(analyzer::CheckerName::UninitializedVariable), checker_long_name(analyzer::CheckerName::UninitializedVariable)), clEnumValN(analyzer::CheckerName::SignedIntOverflow, checker_short_name(analyzer::CheckerName::SignedIntOverflow), checker_long_name(analyzer::CheckerName::SignedIntOverflow)), clEnumValN( analyzer::CheckerName::UnsignedIntOverflow, checker_short_name(analyzer::CheckerName::UnsignedIntOverflow), checker_long_name(analyzer::CheckerName::UnsignedIntOverflow)), clEnumValN(analyzer::CheckerName::ShiftCount, checker_short_name(analyzer::CheckerName::ShiftCount), checker_long_name(analyzer::CheckerName::ShiftCount)), clEnumValN(analyzer::CheckerName::PointerOverflow, checker_short_name(analyzer::CheckerName::PointerOverflow), checker_long_name(analyzer::CheckerName::PointerOverflow)), clEnumValN(analyzer::CheckerName::PointerCompare, checker_short_name(analyzer::CheckerName::PointerCompare), checker_long_name(analyzer::CheckerName::PointerCompare)), clEnumValN(analyzer::CheckerName::Soundness, checker_short_name(analyzer::CheckerName::Soundness), checker_long_name(analyzer::CheckerName::Soundness)), clEnumValN(analyzer::CheckerName::FunctionCall, checker_short_name(analyzer::CheckerName::FunctionCall), checker_long_name(analyzer::CheckerName::FunctionCall)), clEnumValN(analyzer::CheckerName::DeadCode, checker_short_name(analyzer::CheckerName::DeadCode), checker_long_name(analyzer::CheckerName::DeadCode)), clEnumValN(analyzer::CheckerName::DoubleFree, checker_short_name(analyzer::CheckerName::DoubleFree), checker_long_name(analyzer::CheckerName::DoubleFree)), clEnumValN(analyzer::CheckerName::Debug, checker_short_name(analyzer::CheckerName::Debug), checker_long_name(analyzer::CheckerName::Debug)), clEnumValN(analyzer::CheckerName::MemoryWatch, checker_short_name(analyzer::CheckerName::MemoryWatch), checker_long_name(analyzer::CheckerName::MemoryWatch))), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< analyzer::MachineIntDomainOption > Domain( "d", llvm::cl::desc("Available abstract domains:"), llvm::cl::values( clEnumValN(analyzer::MachineIntDomainOption::Interval, machine_int_domain_option_str( analyzer::MachineIntDomainOption::Interval), "Interval domain"), clEnumValN(analyzer::MachineIntDomainOption::Congruence, machine_int_domain_option_str( analyzer::MachineIntDomainOption::Congruence), "Congruence domain"), clEnumValN(analyzer::MachineIntDomainOption::IntervalCongruence, machine_int_domain_option_str( analyzer::MachineIntDomainOption::IntervalCongruence), "Reduced product of Interval and Congruence"), clEnumValN(analyzer::MachineIntDomainOption::DBM, machine_int_domain_option_str( analyzer::MachineIntDomainOption::DBM), "Difference-Bound Matrices domain"), clEnumValN(analyzer::MachineIntDomainOption::VarPackDBM, machine_int_domain_option_str( analyzer::MachineIntDomainOption::VarPackDBM), "Difference-Bound Matrices domain with variable packing"), clEnumValN( analyzer::MachineIntDomainOption::VarPackDBMCongruence, machine_int_domain_option_str( analyzer::MachineIntDomainOption::VarPackDBMCongruence), "Reduced product of DBM with variable packing and Congruence"), clEnumValN(analyzer::MachineIntDomainOption::Gauge, machine_int_domain_option_str( analyzer::MachineIntDomainOption::Gauge), "Gauge domain"), clEnumValN( analyzer::MachineIntDomainOption::GaugeIntervalCongruence, machine_int_domain_option_str( analyzer::MachineIntDomainOption::GaugeIntervalCongruence), "Reduced product of Gauge, Interval and Congruence"), clEnumValN(analyzer::MachineIntDomainOption::ApronInterval, machine_int_domain_option_str( analyzer::MachineIntDomainOption::ApronInterval), "APRON Interval domain"), clEnumValN(analyzer::MachineIntDomainOption::ApronOctagon, machine_int_domain_option_str( analyzer::MachineIntDomainOption::ApronOctagon), "APRON Octagon domain"), clEnumValN(analyzer::MachineIntDomainOption::ApronPolkaPolyhedra, machine_int_domain_option_str( analyzer::MachineIntDomainOption::ApronPolkaPolyhedra), "APRON Polka Polyhedra domain"), clEnumValN( analyzer::MachineIntDomainOption::ApronPolkaLinearEqualities, machine_int_domain_option_str( analyzer::MachineIntDomainOption::ApronPolkaLinearEqualities), "APRON Polka Linear Equalities domain"), clEnumValN(analyzer::MachineIntDomainOption::ApronPplPolyhedra, machine_int_domain_option_str( analyzer::MachineIntDomainOption::ApronPplPolyhedra), "APRON PPL Polyhedra domain"), clEnumValN( analyzer::MachineIntDomainOption::ApronPplLinearCongruences, machine_int_domain_option_str( analyzer::MachineIntDomainOption::ApronPplLinearCongruences), "APRON PPL Linear Congruences domain"), clEnumValN(analyzer::MachineIntDomainOption:: ApronPkgridPolyhedraLinearCongruences, machine_int_domain_option_str( analyzer::MachineIntDomainOption:: ApronPkgridPolyhedraLinearCongruences), "APRON Pkgrid Polyhedra and Linear Congruences domain"), clEnumValN(analyzer::MachineIntDomainOption::VarPackApronOctagon, machine_int_domain_option_str( analyzer::MachineIntDomainOption::VarPackApronOctagon), "APRON Octagon domain with variable packing"), clEnumValN( analyzer::MachineIntDomainOption::VarPackApronPolkaPolyhedra, machine_int_domain_option_str( analyzer::MachineIntDomainOption::VarPackApronPolkaPolyhedra), "APRON Polka Polyhedra domain with variable packing"), clEnumValN( analyzer::MachineIntDomainOption::VarPackApronPolkaLinearEqualities, machine_int_domain_option_str( analyzer::MachineIntDomainOption:: VarPackApronPolkaLinearEqualities), "APRON Polka Linear Equalities domain with variable packing"), clEnumValN( analyzer::MachineIntDomainOption::VarPackApronPplPolyhedra, machine_int_domain_option_str( analyzer::MachineIntDomainOption::VarPackApronPplPolyhedra), "APRON PPL Polyhedra domain with variable packing"), clEnumValN( analyzer::MachineIntDomainOption::VarPackApronPplLinearCongruences, machine_int_domain_option_str(analyzer::MachineIntDomainOption:: VarPackApronPplLinearCongruences), "APRON PPL Linear Congruences domain with variable packing"), clEnumValN(analyzer::MachineIntDomainOption:: VarPackApronPkgridPolyhedraLinearCongruences, machine_int_domain_option_str( analyzer::MachineIntDomainOption:: VarPackApronPkgridPolyhedraLinearCongruences), "APRON Pkgrid Polyhedra and Linear Congruences domain with " "variable packing")), llvm::cl::init(analyzer::MachineIntDomainOption::Interval), llvm::cl::cat(AnalysisCategory)); static llvm::cl::list< std::string > EntryPoints( "entry-points", llvm::cl::desc("List of program entry points (ex: main)"), llvm::cl::CommaSeparated, llvm::cl::OneOrMore, llvm::cl::value_desc("function"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::list< std::string > NoInitGlobals( "no-init-globals", llvm::cl::desc( "Global variables should not be initialized\nfor these entry points"), llvm::cl::CommaSeparated, llvm::cl::value_desc("function"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< analyzer::Procedural > Procedural( "proc", llvm::cl::desc("Procedurality:"), llvm::cl::values(clEnumValN(analyzer::Procedural::Interprocedural, "inter", "Interprocedural analysis (default)"), clEnumValN(analyzer::Procedural::Intraprocedural, "intra", "Intraprocedural analysis")), llvm::cl::init(analyzer::Procedural::Interprocedural), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< int > Jobs("j", llvm::cl::desc("Number of threads"), llvm::cl::init(1), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< analyzer::WideningStrategy > WideningStrategy( "widening-strategy", llvm::cl::desc("Strategy for increasing iterations"), llvm::cl::values( clEnumValN(analyzer::WideningStrategy::Widen, widening_strategy_str(analyzer::WideningStrategy::Widen), "Widening operator (default)"), clEnumValN(analyzer::WideningStrategy::Join, widening_strategy_str(analyzer::WideningStrategy::Join), "Join operator")), llvm::cl::init(analyzer::WideningStrategy::Widen), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< analyzer::NarrowingStrategy > NarrowingStrategy( "narrowing-strategy", llvm::cl::desc("Strategy for decreasing iterations"), llvm::cl::values( clEnumValN(analyzer::NarrowingStrategy::Narrow, narrowing_strategy_str(analyzer::NarrowingStrategy::Narrow), "Narrowing operator (default)"), clEnumValN(analyzer::NarrowingStrategy::Meet, narrowing_strategy_str(analyzer::NarrowingStrategy::Meet), "Meet operator")), llvm::cl::init(analyzer::NarrowingStrategy::Narrow), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< unsigned > WideningDelay( "widening-delay", llvm::cl::desc( "Number of loop iterations before using the widening strategy"), llvm::cl::init(1), llvm::cl::value_desc("int"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::list< std::string > WideningDelayFunctions( "widening-delay-functions", llvm::cl::desc("Widening delay for specific functions"), llvm::cl::CommaSeparated, llvm::cl::value_desc("function:int"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< unsigned > WideningPeriod( "widening-period", llvm::cl::desc("Number of loop iterations between each widening"), llvm::cl::init(1), llvm::cl::value_desc("int"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< int > NarrowingIterations( "narrowing-iterations", llvm::cl::desc("Perform a fixed number of narrowing iterations"), llvm::cl::init(-1), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< bool > NoLiveness( "no-liveness", llvm::cl::desc("Disable the liveness analysis"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< bool > NoPointer( "no-pointer", llvm::cl::desc("Disable the pointer analysis"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< bool > NoWideningHints( "no-widening-hints", llvm::cl::desc("Disable the widening hint analysis"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< bool > EnablePartitioningDomain( "enable-partitioning-domain", llvm::cl::desc("Enable the partitioning abstract domain"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< bool > NoFixpointCache( "no-fixpoint-cache", llvm::cl::desc("Disable the cache of fixpoints"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< bool > NoChecks("no-checks", llvm::cl::desc("Disable all the checks"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< analyzer::GlobalsInitPolicy > GlobalsInitPolicy( "globals-init", llvm::cl::desc("Policy of initialization for global variables"), llvm::cl::values( clEnumValN(analyzer::GlobalsInitPolicy::All, "all", "Initialize all global variables"), clEnumValN( analyzer::GlobalsInitPolicy::SkipBigArrays, "skip-big-arrays", "Initialize all global variables except big arrays (default)"), clEnumValN(analyzer::GlobalsInitPolicy::SkipStrings, "skip-strings", "Initialize all global variables except strings"), clEnumValN(analyzer::GlobalsInitPolicy::None, "none", "Do not initialize any global variable")), llvm::cl::init(analyzer::GlobalsInitPolicy::SkipBigArrays), llvm::cl::cat(AnalysisCategory)); static llvm::cl::list< std::string > HardwareAddresses( "hardware-addresses", llvm::cl::desc( "Specify ranges (x-y) of hardware addresses, separated by a comma"), llvm::cl::CommaSeparated, llvm::cl::value_desc("range"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< std::string > HardwareAddressesFile( "hardware-addresses-file", llvm::cl::desc("Specify ranges (x-y) of hardware addresses from a file " "(one range per line)"), llvm::cl::value_desc("file"), llvm::cl::cat(AnalysisCategory)); static llvm::cl::opt< int > Argc("argc", llvm::cl::desc("Specify a value for argc"), llvm::cl::init(-1), llvm::cl::cat(AnalysisCategory)); /// @} /// \name Import options /// @{ static llvm::cl::OptionCategory ImportCategory( "Import Options", "Options for the translation from LLVM to AR"); static llvm::cl::opt< bool > NoVerify( "no-verify", llvm::cl::desc("Do not run the LLVM bitcode verifier")); static llvm::cl::opt< bool > NoLibIkos( "no-libikos", llvm::cl::desc("Do not use ikos intrinsics (__ikos_assert, etc.)"), llvm::cl::cat(ImportCategory)); static llvm::cl::opt< bool > NoLibc( "no-libc", llvm::cl::desc("Do not use libc intrinsics (malloc, free, etc.)"), llvm::cl::cat(ImportCategory)); static llvm::cl::opt< bool > NoLibcpp( "no-libcpp", llvm::cl::desc("Do not use libcpp intrinsics (__cxa_throw, etc.)"), llvm::cl::cat(ImportCategory)); static llvm::cl::opt< bool > AllowDebugInfoMismatch( "allow-dbg-mismatch", llvm::cl::desc("Allow incorrect debug information in the module"), llvm::cl::cat(ImportCategory)); /// @} /// \name Passes options /// @{ static llvm::cl::OptionCategory PassCategory("AR Passes Options"); static llvm::cl::opt< bool > NoTypeCheck( "no-type-check", llvm::cl::desc("Do not run the type checker"), llvm::cl::cat(PassCategory)); static llvm::cl::opt< bool > NoSimplifyCFG( "no-simplify-cfg", llvm::cl::desc("Do not run the simplify-cfg pass"), llvm::cl::cat(PassCategory)); static llvm::cl::opt< bool > AddLoopCounters( "add-loop-counters", llvm::cl::desc("Add a loop counter in each cycle"), llvm::cl::cat(PassCategory)); static llvm::cl::opt< bool > AddPartitioningVariables( "add-partitioning-variables", llvm::cl::desc("Add partitioning variable annotations on return variables"), llvm::cl::cat(PassCategory)); static llvm::cl::opt< bool > NameValues( "name-values", llvm::cl::desc("Give names to variables and basic blocks"), llvm::cl::cat(PassCategory)); static llvm::cl::opt< bool > NoNamePrefix( "no-name-prefix", llvm::cl::desc("Do not prefix variable names (if -name-values)"), llvm::cl::cat(PassCategory)); static llvm::cl::opt< bool > NoSimplifyUpcastComparison( "no-simplify-upcast-comparison", llvm::cl::desc("Do not simplify the implicit upcast before a comparison"), llvm::cl::cat(PassCategory)); /// @} /// \name Debug options /// @{ static llvm::cl::OptionCategory DebugCategory( "Debug Options", "Options to print analysis informations"); static llvm::cl::opt< bool > DisplayLiveness( "display-liveness", llvm::cl::desc("Display liveness analysis results"), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< bool > DisplayFunctionPointer( "display-function-pointer", llvm::cl::desc("Display function pointer analysis results"), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< bool > DisplayPointer( "display-pointer", llvm::cl::desc("Display pointer analysis results"), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< bool > DisplayFixpointParameters( "display-fixpoint-parameters", llvm::cl::desc("Display fixpoint parameters"), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< bool > DisplayAR( "display-ar", llvm::cl::desc("Display the Abstract Representation as text"), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< bool > TraceARStmts( "trace-ar-stmts", llvm::cl::desc("Trace Abstract Representation statements during analysis"), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< bool > GenerateDot( "generate-dot", llvm::cl::desc("Generate a .dot file for each function"), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< std::string > GenerateDotDirectory( "generate-dot-dir", llvm::cl::desc("Output directory for .dot files"), llvm::cl::value_desc("directory"), llvm::cl::init("."), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< analyzer::DisplayOption > DisplayInvariants( "display-inv", llvm::cl::desc("Display computed invariants"), llvm::cl::values(clEnumValN(analyzer::DisplayOption::All, "all", "Display all invariants"), clEnumValN(analyzer::DisplayOption::Fail, "fail", "Display invariants for failed checks"), clEnumValN(analyzer::DisplayOption::None, "no", "Do not display invariants (default)")), llvm::cl::init(analyzer::DisplayOption::None), llvm::cl::cat(DebugCategory)); static llvm::cl::opt< analyzer::DisplayOption > DisplayChecks( "display-checks", llvm::cl::desc("Display checks"), llvm::cl::values( clEnumValN(analyzer::DisplayOption::All, "all", "Display all checks"), clEnumValN(analyzer::DisplayOption::Fail, "fail", "Display only failed checks"), clEnumValN(analyzer::DisplayOption::None, "no", "Do not display checks (default)")), llvm::cl::init(analyzer::DisplayOption::None), llvm::cl::cat(DebugCategory)); /// @} /// \name Formatting options /// @{ static llvm::cl::OptionCategory FormatCategory("Formatting Options"); static llvm::cl::opt< bool > NoShowResultType( "no-show-result-type", llvm::cl::desc("Do not show the result type of statements"), llvm::cl::cat(FormatCategory)); static llvm::cl::opt< bool > ShowOperandTypes( "show-operand-types", llvm::cl::desc("Show the operand types of statements"), llvm::cl::cat(FormatCategory)); static llvm::cl::opt< bool > OrderGlobals( "order-globals", llvm::cl::desc("Order global variables and functions by name"), llvm::cl::cat(FormatCategory)); /// @} /// \brief Return true if colors are enabled static bool colors_enabled() { // Use a function from llvm/lib/Support/WithColor.cpp so that the global // constructors are called, and the 'color' option is registered. llvm::WithColor x(llvm::outs(), llvm::HighlightColor::String); const llvm::StringMap< llvm::cl::Option* >& opts = llvm::cl::getRegisteredOptions(); auto it = opts.find("color"); ikos_assert_msg(it != opts.end(), "Option 'color' is not registered"); auto opt = static_cast< llvm::cl::opt< llvm::cl::boolOrDefault >* >(it->second); if (opt->getValue() == llvm::cl::BOU_UNSET) { return llvm::sys::Process::StandardOutIsDisplayed(); } else { return opt->getValue() == llvm::cl::BOU_TRUE; } } /// \brief Build LLVM to AR import options from command line arguments static llvm_to_ar::Importer::ImportOptions make_import_options() { llvm_to_ar::Importer::ImportOptions opts; opts.set(llvm_to_ar::Importer::EnableLibIkos, !NoLibIkos); opts.set(llvm_to_ar::Importer::EnableLibc, !NoLibc); opts.set(llvm_to_ar::Importer::EnableLibcpp, !NoLibcpp); opts.set(llvm_to_ar::Importer::AllowMismatchDebugInfo, AllowDebugInfoMismatch); return opts; } /// \brief Build format options from command line arguments static ar::Formatter::FormatOptions make_format_options() { ar::Formatter::FormatOptions opts; opts.set(ar::Formatter::ShowResultType, !NoShowResultType); opts.set(ar::Formatter::ShowOperandTypes, ShowOperandTypes); opts.set(ar::Formatter::OrderGlobals, OrderGlobals); return opts; } /// \brief Parse a list of function names and return a list of functions static std::vector< ar::Function* > parse_function_names( const llvm::cl::list< std::string >& opt, ar::Bundle* bundle) { std::vector< ar::Function* > functions; if (std::find(opt.begin(), opt.end(), "*") != opt.end()) { // Wildcard: all functions std::copy_if(bundle->function_begin(), bundle->function_end(), std::back_inserter(functions), [](ar::Function* fun) { return fun->is_definition(); }); return functions; } for (std::string name : opt) { boost::trim(name); ar::Function* fun = bundle->function_or_null(name); if (fun == nullptr) { std::ostringstream buf; buf << "could not find function '" << name << "'"; throw analyzer::ArgumentError(buf.str()); } if (!fun->is_definition()) { std::ostringstream buf; buf << "missing implementation for function '" << name << "'"; throw analyzer::ArgumentError(buf.str()); } functions.push_back(fun); } return functions; } /// \brief Interpret an unsigned integer value in the string `str` static unsigned stou(const std::string& str, size_t* pos = nullptr, int base = 10) { // NOLINTNEXTLINE(google-runtime-int) long long n = std::stoll(str, pos, base); if (n < 0 || n > std::numeric_limits< unsigned >::max()) { throw std::out_of_range("stou: out of range"); } return static_cast< unsigned >(n); } /// \brief Parse a list of "function:unsigned" and return a map static boost::container::flat_map< ar::Function*, unsigned > parse_function_names_to_unsigned(const llvm::cl::list< std::string >& opt, ar::Bundle* bundle) { boost::container::flat_map< ar::Function*, unsigned > map; for (const auto& str : opt) { size_t colon = str.find(':'); if (colon == std::string::npos) { std::ostringstream buf; buf << "could not find separator ':' in '" << str << "'"; throw analyzer::ArgumentError(buf.str()); } std::string name = str.substr(0, colon); boost::trim(name); ar::Function* fun = bundle->function_or_null(name); if (fun == nullptr) { std::ostringstream buf; buf << "could not find function '" << name << "'"; throw analyzer::ArgumentError(buf.str()); } std::string number_str = str.substr(colon + 1); boost::trim(number_str); unsigned number; try { number = stou(number_str, nullptr, 0); } catch (const std::invalid_argument&) { std::ostringstream buf; buf << "could not parse integer '" << number_str << "'"; throw analyzer::ArgumentError(buf.str()); } catch (const std::out_of_range&) { std::ostringstream buf; buf << "integer out of range '" << number_str << "'"; throw analyzer::ArgumentError(buf.str()); } map[fun] = number; } return map; } /// \brief Build analysis options from command line arguments static analyzer::AnalysisOptions make_analysis_options(ar::Bundle* bundle) { return analyzer::AnalysisOptions{ .analyses = {Analyses.begin(), Analyses.end()}, .entry_points = parse_function_names(EntryPoints, bundle), .no_init_globals = parse_function_names(NoInitGlobals, bundle), .machine_int_domain = Domain, .procedural = Procedural, .num_threads = Jobs, .widening_strategy = WideningStrategy, .narrowing_strategy = NarrowingStrategy, .widening_delay = WideningDelay, .widening_delay_functions = parse_function_names_to_unsigned(WideningDelayFunctions, bundle), .widening_period = WideningPeriod, .narrowing_iterations = ((NarrowingIterations >= 0) ? boost::optional< unsigned >(NarrowingIterations) : boost::none), .use_liveness = !NoLiveness, .use_pointer = !NoPointer, .use_widening_hints = !NoWideningHints, .use_partitioning_domain = EnablePartitioningDomain, .use_fixpoint_cache = !NoFixpointCache, .use_checks = !NoChecks, .trace_ar_statements = TraceARStmts, .globals_init_policy = GlobalsInitPolicy, .progress = Progress, .display_invariants = DisplayInvariants, .display_checks = DisplayChecks, .hardware_addresses = {bundle, HardwareAddresses, HardwareAddressesFile}, .argc = ((Argc >= 0) ? boost::optional< int >(Argc) : boost::none), }; } /// \brief Generate a .dot file for each function in the given Bundle static void generate_dot(ar::Bundle* bundle, const boost::filesystem::path& directory) { boost::system::error_code err; ar::DotFormatter formatter(make_format_options()); if (!boost::filesystem::exists(directory)) { if (!boost::filesystem::create_directories(directory, err)) { analyzer::log::error(directory.string() + ": " + err.message()); return; } } if (!boost::filesystem::is_directory(directory, err)) { analyzer::log::error(directory.string() + ": not a directory"); return; } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* fun = *it; if (!fun->is_definition()) { continue; } std::string filename = fun->name() + ".dot"; boost::filesystem::path filepath = directory / filename; analyzer::log::debug("Creating " + ((directory == ".") ? filename : filepath.string())); boost::filesystem::ofstream output(filepath); if (!output.is_open()) { analyzer::log::error(filepath.string() + ": " + strerror(errno)); return; } formatter.format(output, fun); } } /// \brief Main for ikos-analyzer int main(int argc, char** argv) { llvm::InitLLVM x(argc, argv); // Program name // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) std::string progname = boost::filesystem::path(argv[0]).filename().string(); // Enable debug stream buffering llvm::EnableDebugBuffering = true; // LLVM context llvm::LLVMContext llvm_context; /* * Parse parameters */ const char* overview = "ikos-analyzer -- IKOS static analyzer"; llvm::cl::ParseCommandLineOptions(argc, argv, overview); // Set log level analyzer::log::Level = LogLevel; // Enable colors, if asked analyzer::color::Enable = colors_enabled(); try { // Initialize output database // This might throw DbError, see catch() analyzer::log::debug("Creating output database '" + OutputFilename + "'"); analyzer::sqlite::DbConnection db(OutputFilename); db.set_journal_mode(analyzer::sqlite::JournalMode::Off); db.set_synchronous_flag(analyzer::sqlite::SynchronousFlag::Off); analyzer::OutputDatabase output_db(db); // Load the input module std::unique_ptr< llvm::Module > module = nullptr; { analyzer::log::debug("Loading LLVM bitcode"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.load-bc"); llvm::SMDiagnostic err; // Error diagnostic module = llvm::parseIRFile(InputFilename, err, llvm_context); if (!module) { err.print(progname.c_str(), llvm::errs()); return 2; } } // Immediately run the verifier to catch any problems if (!NoVerify) { analyzer::log::debug("Verifying integrity of LLVM bitcode"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.verify-bc"); if (verifyModule(*module, &llvm::errs())) { llvm::errs() << progname << ": " << InputFilename << ": error: input module is broken!\n"; return 3; } } // Check for debug information in LLVM { analyzer::log::debug("Checking for debug information"); if (!llvm_to_ar::has_debug_info(*module)) { // We warn but allow analysis to proceed. llvm::errs() << progname << ": " << InputFilename << ": warning: llvm bitcode has no debug information\n"; } } // AR context ar::Context ar_context; // Translate LLVM bitcode into AR // This might throw ImportError, see catch() ar::Bundle* bundle = nullptr; { analyzer::log::info("Translating LLVM bitcode to AR"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.llvm-to-ar"); llvm_to_ar::Importer importer(ar_context); bundle = importer.import(*module, make_import_options()); } // Run type checker if (!NoTypeCheck) { analyzer::log::debug("Running type verifier on AR"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.type-checker"); if (!ar::TypeVerifier(/*all = */ true).verify(bundle, std::cerr)) { llvm::errs() << progname << ": " << InputFilename << ": error: type checker\n"; return 7; } } // Check for debug information in AR if (!ar::FrontendVerifier(/*all = */ true).verify(bundle, std::cerr)) { return 8; } // Simplify the control flow graph if (!NoSimplifyCFG) { analyzer::log::debug("Running simplify-cfg pass on AR"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.simplify-cfg"); ar::SimplifyCFGPass().run(bundle); } // Add a loop counter in each cycle, for the Gauge domain if (AddLoopCounters) { analyzer::log::debug("Running add-loop-counters pass on AR"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.add-loop-counters"); ar::AddLoopCountersPass().run(bundle); } // Add partitioning variable annotations, for the Partitioning domain if (AddPartitioningVariables) { analyzer::log::debug("Running add-partitioning-variables pass on AR"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.add-partitioning-variables"); ar::AddPartitioningVariablesPass().run(bundle); } // Simplify upcast comparison loop if (!NoSimplifyUpcastComparison) { analyzer::log::debug("Running simplify-upcast-comparison pass on AR"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.simplify-upcast-comparison"); ar::SimplifyUpcastComparisonPass().run(bundle); } // Name variables and basic block, for debugging purpose only if (NameValues) { analyzer::log::debug("Running name-values pass on AR"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.name-values"); ar::NameValuesPass(!NoNamePrefix).run(bundle); } // Display the abstract representation if (DisplayAR) { analyzer::log::info("Printing Abstract Representation"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.display-ar"); ar::TextFormatter formatter(make_format_options()); formatter.format(analyzer::log::msg().stream(), bundle); } // Generate .dot files if (GenerateDot) { analyzer::log::info("Generating .dot files"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.generate-dot"); generate_dot(bundle, GenerateDotDirectory.getValue()); } // Save analysis options in the database analyzer::AnalysisOptions opts = make_analysis_options(bundle); opts.save(output_db.settings); // Initialize factories analyzer::MemoryFactory mem_factory; analyzer::VariableFactory var_factory(bundle); analyzer::LiteralFactory lit_factory(var_factory, bundle->data_layout()); analyzer::CallContextFactory call_context_factory; // Fixpoint parameters analyzer::FixpointParameters fixpoint_parameters(opts); // Analysis context analyzer::Context ctx(bundle, opts, boost::filesystem::current_path(), output_db, mem_factory, var_factory, lit_factory, call_context_factory, fixpoint_parameters); // Run a liveness analysis // // The goal is to detect unused variables to speed up the following // analyses analyzer::LivenessAnalysis liveness(ctx); if (!NoLiveness) { analyzer::log::info("Running liveness analysis"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.liveness-analysis"); liveness.run(); ctx.liveness = &liveness; } if (DisplayLiveness) { liveness.dump(analyzer::log::msg().stream()); } // Run a widening hint analysis // // This is used to detect widening hints, useful for other analyses if (!NoWideningHints) { analyzer::WideningHintAnalysis widening_hint(ctx); analyzer::log::info("Running widening hint analysis"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.widening-hint-analysis"); widening_hint.run(); } if (DisplayFixpointParameters) { fixpoint_parameters.dump(analyzer::log::msg().stream()); } // Run a fast intraprocedural function pointer analysis // // The goal here is to get all function pointers so that we can analyse // precisely indirect calls in the following analyses analyzer::FunctionPointerAnalysis function_pointer(ctx); if (Procedural == analyzer::Procedural::Intraprocedural && !NoPointer) { analyzer::log::info("Running function pointer analysis"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.function-pointer-analysis"); function_pointer.run(); ctx.function_pointer = &function_pointer; } if (DisplayFunctionPointer) { function_pointer.dump(analyzer::log::msg().stream()); } // Run a deep (still intraprocedural) pointer analysis // // That step uses the result of the previous function pointer analysis. analyzer::PointerAnalysis pointer(ctx, function_pointer); if (Procedural == analyzer::Procedural::Intraprocedural && !NoPointer) { analyzer::log::info("Running pointer analysis"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.pointer-analysis"); pointer.run(); ctx.pointer = &pointer; } if (DisplayPointer) { pointer.dump(analyzer::log::msg().stream()); } // Final step, run a value analysis, and check properties on the results if (Procedural == analyzer::Procedural::Interprocedural) { analyzer::log::info("Running interprocedural value analysis"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.value-analysis"); if (Jobs == 1) { analyzer::value::interprocedural::sequential::Analysis(ctx).run(); } else { analyzer::value::interprocedural::concurrent::Analysis(ctx).run(); } } else if (Procedural == analyzer::Procedural::Intraprocedural) { analyzer::log::info("Running intraprocedural value analysis"); analyzer::ScopeTimerDatabase t(output_db.times, "ikos-analyzer.value-analysis"); if (Jobs == 1) { analyzer::value::intraprocedural::sequential::Analysis(ctx).run(); } else { analyzer::value::intraprocedural::concurrent::Analysis(ctx).run(); } } else { ikos_unreachable("unreachable"); } return 0; } catch (analyzer::sqlite::DbError& err) { llvm::errs() << progname << ": " << OutputFilename << ": error: " << err.what() << "\n"; return 1; } catch (llvm_to_ar::ImportError& err) { llvm::errs() << progname << ": " << InputFilename << ": error: " << err.what() << "\n"; return 5; } catch (std::exception& err) { // catch any std::exception, core::Exception or analyzer::Exception llvm::errs() << progname << ": " << InputFilename << ": error: " << err.what() << "\n"; return 9; } } NASA-SW-VnV-ikos-1d98c65/analyzer/src/json/000077500000000000000000000000001473507761200202035ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/json/json.cpp000066400000000000000000000100511473507761200216550ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of data structures for the manipulation of JSON objects * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2016-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { // JsonNode JsonNode::~JsonNode() = default; // JsonInteger std::string JsonInteger::str() const { return this->_n.str(); } // JsonFloat std::string JsonFloat::str() const { return std::to_string(this->_d); } // JsonBool std::string JsonBool::str() const { if (this->_b) { return "true"; } else { return "false"; } } // JsonString /// \brief Return the hexadecimal character for the given number static char hexdigit(unsigned n, bool lower_case = false) { if (n < 10U) { return static_cast< char >('0' + n); } else if (n < 16U) { return static_cast< char >((lower_case ? 'a' : 'A') + (n - 10)); } else { ikos_unreachable("invalid argument"); } } std::string JsonString::str() const { std::string r; r.reserve(this->_s.size() + 2); r.push_back('"'); for (const char c : this->_s) { if (c == '"' || c == '\\') { r.push_back('\\'); r.push_back(c); } else if (std::isprint(c) != 0) { r.push_back(c); } else if (c == '\b') { r.append("\\b"); } else if (c == '\t') { r.append("\\t"); } else if (c == '\n') { r.append("\\n"); } else if (c == '\f') { r.append("\\f"); } else if (c == '\r') { r.append("\\r"); } else { r.append("\\u00"); r.push_back(hexdigit(static_cast< unsigned char >(c) >> 4U)); r.push_back(hexdigit(static_cast< unsigned char >(c) & 0x0FU)); } } r.push_back('"'); return r; } // JsonList std::string JsonList::str() const { std::string r; r.reserve(this->_buf.size() + 2); r.push_back('['); r.append(this->_buf); r.push_back(']'); return r; } // JsonDict std::string JsonDict::str() const { std::string r; r.reserve(this->_buf.size() + 2); r.push_back('{'); r.append(this->_buf); r.push_back('}'); return r; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/util/000077500000000000000000000000001473507761200202075ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/src/util/color.cpp000066400000000000000000000044651473507761200220420ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Color utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { namespace color { /// \brief Default value bool Enable = false; } // end namespace color } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/util/log.cpp000066400000000000000000000064511473507761200215020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Logging utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { // LoggerOutputStream void LogMessage::start() { this->_logger->start_message(); } void LogMessage::end() { this->_logger->end_message(); } // TerminalLogger TerminalLogger::TerminalLogger(std::ostream& out) noexcept : Logger(out) {} void TerminalLogger::start_logger() {} void TerminalLogger::end_logger() { this->_out.flush(); } void TerminalLogger::start_message() {} void TerminalLogger::end_message() { this->_out.flush(); } // ScopeLogger ScopeLogger::ScopeLogger(Logger& logger) : _previous_logger(log::get_logger()) { // Set the new logger log::set_logger(logger); } ScopeLogger::~ScopeLogger() { // Restore the previous logger log::set_logger(this->_previous_logger); } namespace log { // Default global logging level LogLevel Level = LogLevel::All; // Default logger static TerminalLogger DefaultLogger(std::cout); /// \brief Global logger static Logger* Log = &DefaultLogger; void set_logger(Logger& logger) { Log->end_logger(); Log = &logger; Log->start_logger(); } Logger& get_logger() { return *Log; } } // end namespace log } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/util/progress.cpp000066400000000000000000000142621473507761200225640ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Progress logging utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace analyzer { // ProgressLogger ProgressLogger::ProgressLogger(std::ostream& out) : Logger(out) {} // InteractiveProgressLogger InteractiveProgressLogger::InteractiveProgressLogger(std::ostream& out, std::size_t num_tasks, std::size_t out_columns) : ProgressLogger(out), _current_task(0), _num_tasks(num_tasks), _out_columns(std::max(out_columns, std::size_t{3})) {} void InteractiveProgressLogger::start_task(StringRef status) { // Update the current task this->_current_task++; // Update the status this->_status.clear(); this->_status += '['; this->_status += std::to_string(this->_current_task); this->_status += '/'; this->_status += std::to_string(this->_num_tasks); this->_status += "] "; this->_status += status; // Truncate status if (this->_status.length() > this->_out_columns) { this->_status.resize(this->_out_columns - 2); this->_status += ".."; } // Print the state this->erase_line(); this->print_status(); this->_out.flush(); } void InteractiveProgressLogger::start_logger() {} void InteractiveProgressLogger::end_logger() { this->erase_line(); this->_out.flush(); } void InteractiveProgressLogger::start_message() { this->erase_line(); } void InteractiveProgressLogger::end_message() { this->print_status(); this->_out.flush(); } void InteractiveProgressLogger::erase_line() { this->_out << "\r\033[K"; } void InteractiveProgressLogger::print_status() { this->_out << this->_status; } // LinearProgressLogger LinearProgressLogger::LinearProgressLogger(std::ostream& out, std::size_t num_tasks) : ProgressLogger(out), _current_task(0), _num_tasks(num_tasks) {} void LinearProgressLogger::start_task(StringRef status) { this->_current_task++; this->_out << "[" << this->_current_task << "/" << this->_num_tasks << "] " << status << "\n"; this->_out.flush(); } void LinearProgressLogger::start_logger() {} void LinearProgressLogger::end_logger() { this->_out.flush(); } void LinearProgressLogger::start_message() {} void LinearProgressLogger::end_message() { this->_out.flush(); } // NoProgressLogger NoProgressLogger::NoProgressLogger(std::ostream& out) : ProgressLogger(out) {} void NoProgressLogger::start_task(StringRef /*status*/) {} void NoProgressLogger::start_logger() {} void NoProgressLogger::end_logger() { this->_out.flush(); } void NoProgressLogger::start_message() {} void NoProgressLogger::end_message() { this->_out.flush(); } // make_progress_logger std::unique_ptr< ProgressLogger > make_progress_logger(ProgressOption opt, LogLevel level, std::size_t num_tasks) { if (!log::is_enabled_for(level)) { return std::make_unique< NoProgressLogger >(std::cout); } switch (opt) { case ProgressOption::Auto: { if (llvm::sys::Process::StandardOutIsDisplayed()) { return std::make_unique< InteractiveProgressLogger >(std::cout, num_tasks, llvm::sys::Process:: StandardOutColumns()); } else { return std::make_unique< NoProgressLogger >(std::cout); } } case ProgressOption::Interactive: { return std::make_unique< InteractiveProgressLogger >(std::cout, num_tasks, llvm::sys::Process::StandardOutColumns()); } case ProgressOption::Linear: { return std::make_unique< LinearProgressLogger >(std::cout, num_tasks); } case ProgressOption::None: { return std::make_unique< NoProgressLogger >(std::cout); } default: { ikos_unreachable("unreachable"); } } } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/util/source_location.cpp000066400000000000000000000067411473507761200241130ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implement utilities for source code locations * * Authors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace analyzer { /// \brief Return the relative path between `from` and `to` static boost::filesystem::path relative_to(const boost::filesystem::path& from, const boost::filesystem::path& to) { auto from_it = from.begin(); auto to_it = to.begin(); // loop through both while (from_it != from.end() && to_it != to.end() && *to_it == *from_it) { ++to_it; ++from_it; } boost::filesystem::path final_path; while (from_it != from.end()) { final_path /= ".."; ++from_it; } while (to_it != to.end()) { final_path /= *to_it; ++to_it; } return final_path; } std::string source_location_string(SourceLocation loc, const boost::filesystem::path& wd) { if (!loc) { return "?:?:?"; } boost::filesystem::path abs_path = loc.path(); boost::filesystem::path rel_path = relative_to(wd, abs_path); boost::filesystem::path pretty_path = (rel_path.native().size() < abs_path.native().size()) ? rel_path : abs_path; std::string r; r += pretty_path.string(); r += ':'; r += std::to_string(loc.line()); r += ':'; r += std::to_string(loc.column()); return r; } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/src/util/timer.cpp000066400000000000000000000050471473507761200220410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Timer utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace analyzer { ScopeTimerDatabase::ScopeTimerDatabase(TimesTable& table, std::string name) : _table(table), _name(std::move(name)) { this->_timer.start(); } ScopeTimerDatabase::~ScopeTimerDatabase() { this->_timer.stop(); this->_table.insert(this->_name, this->_timer.elapsed().count()); } } // end namespace analyzer } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/analyzer/test/000077500000000000000000000000001473507761200174225ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/000077500000000000000000000000001473507761200216025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/CMakeLists.txt000066400000000000000000000020671473507761200243470ustar00rootroot00000000000000# Dependencies to run the tests add_dependencies(build-analyzer-tests ikos-analyzer) function(add_analysis_test test_name test_directory) add_test(NAME "analysis-${test_name}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${test_directory}" COMMAND ${PYTHON_EXECUTABLE} runtest --clang "${CLANG_EXECUTABLE}" --ikos-pp "${FRONTEND_LLVM_IKOS_PP_EXECUTABLE}" --ikos-analyzer "$") endfunction() add_analysis_test(buffer-overflow boa) add_analysis_test(division-by-zero dbz) add_analysis_test(memory mem) add_analysis_test(null-pointer-dereference null) add_analysis_test(assert-prover prover) add_analysis_test(uninitialized-variable uva) add_analysis_test(unaligned-pointer upa) add_analysis_test(signed-int-overflow sio) add_analysis_test(unsigned-int-overflow uio) add_analysis_test(shift-count shc) add_analysis_test(pointer-overflow poa) add_analysis_test(pointer-compare pcmp) add_analysis_test(function-call fca) add_analysis_test(double-free dfa) add_analysis_test(soundness sound) NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/000077500000000000000000000000001473507761200223435ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/astree-ex.c000066400000000000000000000005271473507761200244100ustar00rootroot00000000000000// SAFE struct s { struct s* next; int data; }; struct s A[100]; int main() { int i = 0; struct s* ptr; for (i = 0; i < 199; i++) { if (i < 99) A[i].next = &(A[i + 1]); else A[i - 99].data = i; } A[99].next = 0; A[99].data = 99; ptr = &(A[0]); while (ptr != 0) { ptr = ptr->next; } return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/runtest000077500000000000000000000414201473507761200237760ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the buffer overflow analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the buffer overflow analysis') t = TestManager(root=current_dir) t.add(Test('test-1.c', 'test-1.c', 'boa', 'safe')) t.add(Test('test-1-unsafe.c', 'test-1-unsafe.c', 'boa', 'error', line_checks=[(18, 'error')])) t.add(Test('test-2.c', 'test-2.c', 'boa', 'safe')) t.add(Test('test-2-unsafe.c', 'test-2-unsafe.c', 'boa', 'error', line_checks=[(10, 'error')])) t.add(Test('test-3.c', 'test-3.c', 'boa', 'safe')) t.add(Test('test-3-unsafe.c', 'test-3-unsafe.c', 'boa', 'error', line_checks=[(14, 'error'), (16, 'error')])) t.add(Test('test-4.c', 'test-4.c', 'boa', 'safe')) t.add(Test('test-4-unsafe-1.c', 'test-4-unsafe-1.c', 'boa', 'error', line_checks=[(13, 'error')])) t.add(Test('test-4-unsafe-2.c', 'test-4-unsafe-2.c', 'boa', 'error', line_checks=[(15, 'error')])) t.add(Test('test-5.c', 'test-5.c', 'boa', 'safe')) t.add(Test('test-5-unsafe-1.c', 'test-5-unsafe-1.c', 'boa', 'error', expected='unsafe', line_checks=[(12, 'error', 'warning')])) t.add(Test('test-5-unsafe-2.c', 'test-5-unsafe-2.c', 'boa', 'error', expected='unsafe', line_checks=[(12, 'error', 'warning')])) t.add(Test('test-5-unsafe-3.c', 'test-5-unsafe-3.c', 'boa', 'error', expected='unsafe', line_checks=[(12, 'error', 'warning')])) t.add(Test('test-5-unsafe-4.c', 'test-5-unsafe-4.c', 'boa', 'error', expected='unsafe', line_checks=[(12, 'error', 'warning')])) t.add(Test('test-6.c', 'test-6.c', 'boa', 'safe')) t.add(Test('test-6-unsafe.c', 'test-6-unsafe.c', 'boa', 'error', expected='unsafe', line_checks=[(20, 'error', 'warning')])) t.add(Test('test-7.c', 'test-7.c', 'boa', 'safe')) t.add(Test('test-7-unsafe.c', 'test-7-unsafe.c', 'boa', 'error', expected='unsafe', line_checks=[(30, 'error', 'warning')])) t.add(Test('test-8.c', 'test-8.c', 'boa', 'safe')) t.add(Test('test-8-unsafe.c', 'test-8-unsafe.c', 'boa', 'error', line_checks=[(20, 'error')])) t.add(Test('test-9a.c', 'test-9a.c', 'boa', 'safe')) t.add(Test('test-9a-unsafe.c', 'test-9a-unsafe.c', 'boa', 'error', line_checks=[(12, 'error')])) t.add(Test('test-9b.c', 'test-9b.c', 'boa', 'safe')) t.add(Test('test-9b-unsafe.c', 'test-9b-unsafe.c', 'boa', 'error', line_checks=[(13, 'error')])) t.add(Test('test-10.c', 'test-10.c (intraprocedural)', 'boa', 'unsafe', procedural='intra')) t.add(Test('test-10.c', 'test-10.c (interprocedural)', 'boa', 'safe', procedural='inter')) t.add(Test('test-10-unsafe.c', 'test-10-unsafe.c', 'boa', 'error', line_checks=[(18, 'error')])) t.add(Test('test-11.c', 'test-11.c (intraprocedural)', 'boa', 'unsafe', procedural='intra')) t.add(Test('test-11.c', 'test-11.c (interprocedural)', 'boa', 'safe', procedural='inter')) t.add(Test('test-11-unsafe.c', 'test-11-unsafe.c', 'boa', 'error', line_checks=[(24, 'error')])) t.add(Test('test-12-unsafe.c', 'test-12-unsafe.c', 'boa', 'error', line_checks=[(39, 'error'), (52, 'error')])) t.add(Test('test-13.c', 'test-13.c', 'boa', 'safe', )) t.add(Test('test-14.c', 'test-14.c', 'boa', 'safe', expected='unsafe', line_checks=[(9, 'ok', 'warning')])) t.add(Test('test-15.c', 'test-15.c (interval)', 'boa', 'safe', expected='error', line_checks=[(13, 'unreachable', 'error')], domain='interval')) t.add(Test('test-15.c', 'test-15.c (interval-congruence)', 'boa', 'safe', expected='safe', line_checks=[(13, 'unreachable')], domain='interval-congruence')) t.add(Test('test-16.c', 'test-16.c', 'boa', 'safe')) t.add(Test('test-17.c', 'test-17.c', 'boa', 'safe', expected='unsafe')) t.add(Test('test-17-simpler.c', 'test-17-simpler.c', 'boa', 'safe', expected='unsafe')) t.add(Test('test-18.c', 'test-18.c', 'boa', 'safe')) t.add(Test('test-18-unsafe.c', 'test-18-unsafe.c', 'boa', 'error', line_checks=[(21, 'error')])) t.add(Test('test-19a.c', 'test-19a.c (interval)', 'boa', 'safe', expected='unsafe', domain='interval')) t.add(Test('test-19a.c', 'test-19a.c (gauge-interval-congruence)', 'boa', 'safe', expected='unsafe', domain='gauge-interval-congruence')) t.add(Test('test-19b.c', 'test-19b.c (interval)', 'boa', 'safe', expected='unsafe', domain='interval')) t.add(Test('test-19b.c', 'test-19b.c (gauge-interval-congruence)', 'boa', 'safe', expected='safe', domain='gauge-interval-congruence')) t.add(Test('test-20.c', 'test-20.c', 'boa', 'safe', expected='unsafe', line_checks=[(16, 'ok', 'warning'), (20, 'ok', 'warning'), (23, 'ok', 'warning')])) t.add(Test('test-21.c', 'test-21.c', 'boa', 'safe')) t.add(Test('test-22-safe.c', 'test-22-safe.c', 'boa', 'safe')) t.add(Test('test-22-unsafe.c', 'test-22-unsafe.c', 'boa', 'error', expected='unsafe', line_checks=[(16, 'error', 'warning')])) t.add(Test('test-23-safe.c', 'test-23-safe.c', 'boa', 'safe')) t.add(Test('test-23-unsafe-1.c', 'test-23-unsafe-1.c', 'boa', 'error', line_checks=[(18, 'error')])) t.add(Test('test-23-unsafe-2.c', 'test-23-unsafe-2.c', 'boa', 'error', line_checks=[(22, 'error')])) t.add(Test('test-23-unsafe-3.c', 'test-23-unsafe-3.c', 'boa', 'error', expected='unsafe', line_checks=[(8, 'error', 'warning')])) t.add(Test('test-24-safe.c', 'test-24-safe.c', 'boa', 'safe')) t.add(Test('test-25.c', 'test-25.c (interval)', 'boa', 'safe')) t.add(Test('test-25.c', 'test-25.c (dbm)', 'boa', 'safe', domain='dbm')) t.add(Test('test-26-volatile-safe.c', 'test-26-volatile-safe.c', 'boa', 'safe')) t.add(Test('test-26-volatile-unsafe.c', 'test-26-volatile-unsafe.c', 'boa', 'unsafe')) t.add(Test('test-27.c', 'test-27.c', 'boa', 'safe')) t.add(Test('test-27.c', 'test-27.c (no simplify upcast comparison)', 'boa', 'safe', options=['--no-simplify-upcast-comparison'], line_checks=[(13, 'ok'), (21, 'ok', 'warning'), (29, 'ok'), (37, 'ok', 'warning'), (45, 'ok')], expected='unsafe')) t.add(Test('test-27.c', 'test-27.c (no widening hints)', 'boa', 'safe', options=['--no-widening-hints'], line_checks=[(13, 'ok'), (21, 'ok'), (29, 'ok', 'warning'), (37, 'ok', 'warning'), (45, 'ok', 'warning')], expected='unsafe')) t.add(Test('test-28.c', 'test-28.c (hardware addresses)', 'boa', 'safe', options=['--hardware-addresses=0x40-0x45'])) t.add(Test('test-28.c', 'test-28.c (hardware addresses)', 'boa', 'error', options=['--hardware-addresses=0x41-0x42'])) t.add(Test('test-28.c', 'test-28.c (hardware addresses)', 'boa', 'error', options=['--hardware-addresses=0x40-0x42'])) t.add(Test('test-29.c', 'test-29.c (hardware addresses)', 'boa', 'unsafe', options=['--hardware-addresses=0x40-0x55'])) t.add(Test('test-30-use-after-free.c', 'test-30-use-after-free.c', 'boa', 'error')) t.add(Test('test-31-use-after-free.c', 'test-31-use-after-free.c', 'boa', 'unsafe')) t.add(Test('test-32-use-after-return.c', 'test-32-use-after-return.c', 'boa', 'error')) t.add(Test('test-33.c', 'test-33.c', 'boa', 'safe')) t.add(Test('test-34.c', 'test-34.c', 'boa', 'safe')) t.add(Test('test-35.c', 'test-35.c', 'boa', 'safe')) t.add(Test('test-36.c', 'test-36.c', 'boa', 'safe')) t.add(Test('test-37.c', 'test-37.c', 'boa', 'safe')) t.add(Test('test-38-argv.c', 'test-38-argv.c', 'boa', 'error', options=['--argc=4'], line_checks=[(7, 'ok', 'warning'), (8, 'ok', 'warning'), (9, 'ok', 'warning'), (10, 'error')])) t.add(Test('test-39.c', 'test-39.c', 'boa', 'safe')) t.add(Test('test-40.c', 'test-40.c', 'boa', 'safe')) t.add(Test('test-41.c', 'test-41.c', 'boa', 'safe')) t.add(Test('test-42.c', 'test-42.c', 'boa', 'safe')) t.add(Test('test-43.c', 'test-43.c', 'boa', 'safe', line_checks=[(19, 'unreachable'), (21, 'unreachable')])) t.add(Test('test-44.c', 'test-44.c', 'boa', 'safe')) t.add(Test('test-44-unsafe.c', 'test-44-unsafe.c', 'boa', 'unsafe')) t.add(Test('test-45.c', 'test-45.c', 'boa', 'safe')) t.add(Test('test-45-unsafe.c', 'test-45-unsafe.c', 'boa', 'error', line_checks=[(7, 'ok'), (15, 'error'), (16, 'error')])) t.add(Test('test-46.c', 'test-46.c', 'boa', 'safe')) t.add(Test('test-46-unsafe.c', 'test-46-unsafe.c', 'boa', 'error', line_checks=[(11, 'error')])) t.add(Test('test-47.cpp', 'test-47.cpp', 'boa', 'safe')) t.add(Test('test-47-unsafe.cpp', 'test-47-unsafe.cpp', 'boa', 'unsafe', line_checks=[(25, 'warning')])) t.add(Test('test-48.c', 'test-48.c', 'boa', 'safe')) t.add(Test('test-48-unsafe-1.c', 'test-48-unsafe-1.c', 'boa', 'error', expected='unsafe', line_checks=[(7, 'error', 'warning')])) t.add(Test('test-48-unsafe-2.c', 'test-48-unsafe-2.c', 'boa', 'error')) t.add(Test('test-49.c', 'test-49.c', 'boa', 'safe')) t.add(Test('test-49-unsafe-1.c', 'test-49-unsafe-1.c', 'boa', 'error')) t.add(Test('test-49-unsafe-2.c', 'test-49-unsafe-2.c', 'boa', 'error', expected='safe', line_checks=[(7, 'error', 'ok')])) t.add(Test('test-50.c', 'test-50.c', 'boa', 'safe')) t.add(Test('test-50-unsafe.c', 'test-50-unsafe.c', 'boa', 'error')) t.add(Test('test-51.c', 'test-51.c', 'boa', 'safe', expected='unsafe')) t.add(Test('test-51-unsafe.c', 'test-51-unsafe.c', 'boa', 'unsafe', line_checks=[(14, 'warning'), (18, 'warning'), (23, 'warning'), (27, 'warning')])) t.add(Test('test-52.c', 'test-52.c', ['boa', 'uva'], 'error')) t.add(Test('test-53.c', 'test-53.c (interval)', 'boa', 'safe', expected='unsafe', domain='interval')) t.add(Test('test-53.c', 'test-53.c (gauge-interval-congruence)', 'boa', 'safe', expected='safe', domain='gauge-interval-congruence')) t.add(Test('test-54.c', 'test-54.c', 'boa', 'safe', expected='unsafe')) t.add(Test('test-55.cpp', 'test-55.cpp', 'boa', 'safe', expected='unsafe', line_checks=[(2, 'ok', 'warning'), (7, 'ok')])) t.add(Test('test-56.cpp', 'test-56.cpp', ['boa','uva'], 'error')) t.add(Test('astree-ex.c', 'astree-ex.c', 'boa', 'safe', expected='unsafe', line_checks=[(20, 'ok', 'warning')])) t.add(Test('test-57.c', 'test-57.c', 'boa', 'safe')) t.add(Test('test-57-unsafe.c', 'test-57-unsafe.c', 'boa', 'error')) t.add(Test('test-58.c', 'test-58.c', 'boa', 'safe')) t.add(Test('test-59.c', 'test-59.c', 'boa', 'safe')) t.add(Test('test-59-unsafe.c', 'test-59-unsafe.c', 'boa', 'error')) t.add(Test('test-60.c', 'test-60.c', 'boa', 'safe')) t.add(Test('test-61.c', 'test-61.c', 'boa', 'error', line_checks=[(7, 'ok'), (10, 'ok'), (13, 'warning', 'ok'), (16, 'ok'), (19, 'warning', 'ok'), (21, 'error')])) t.add(Test('test-62.c', 'test-62.c', 'boa', 'error', line_checks=[(11, 'warning'), (13, 'ok'), (15, 'error')])) t.add(Test('test-63.c', 'test-63.c', 'boa', 'safe')) t.add(Test('test-64.c', 'test-64.c', 'boa', 'safe')) t.add(Test('test-65.c', 'test-65.c (interval)', 'boa', 'safe', expected='unsafe', domain='interval')) t.add(Test('test-65.c', 'test-65.c (var-pack-dbm)', 'boa', 'safe', domain='var-pack-dbm')) t.add(Test('test-65.c', 'test-65.c (dbm)', 'boa', 'safe', domain='dbm')) t.add(Test('test-66.c', 'test-66.c (interval)', ['boa', 'uva'], 'error', domain='interval')) t.add(Test('test-66.c', 'test-66.c (var-pack-dbm)', 'boa', 'safe', domain='var-pack-dbm')) t.add(Test('test-66.c', 'test-66.c (dbm)', 'boa', 'safe', domain='dbm')) t.add(Test('test-67.c', 'test-67.c (interval)', 'boa', 'safe', expected='unsafe', domain='interval')) t.add(Test('test-67.c', 'test-67.c (var-pack-dbm)', 'boa', 'safe', domain='var-pack-dbm')) t.add(Test('test-67.c', 'test-67.c (dbm)', 'boa', 'safe', domain='dbm')) t.add(Test('test-68.c', 'test-68.c (interval)', 'boa', 'safe', expected='unsafe', domain='interval')) t.add(Test('test-68.c', 'test-68.c (interval-congruence)', 'boa', 'safe', expected='unsafe', domain='interval-congruence')) t.add(Test('test-68.c', 'test-68.c (interval-congruence, widening delay 10)', 'boa', 'safe', expected='unsafe', domain='interval-congruence', options=['--widening-delay=10'], line_checks=[(6, 'ok'), (15, 'ok', 'warning')])) t.add(Test('test-68.c', 'test-68.c (interval-congruence, widening delay 100)', 'boa', 'safe', domain='interval-congruence', options=['--widening-delay=100'])) t.add(Test('test-68.c', 'test-68.c (interval-congruence, widening delay f1=10)', 'boa', 'safe', expected='unsafe', domain='interval-congruence', options=['--widening-delay-functions=f1:10'], line_checks=[(6, 'ok'), (15, 'ok', 'warning')])) t.add(Test('test-68.c', 'test-68.c (interval-congruence, widening delay f2=100)', 'boa', 'safe', expected='unsafe', domain='interval-congruence', options=['--widening-delay-functions=f2:100'], line_checks=[(6, 'ok', 'warning'), (15, 'ok')])) t.add(Test('test-69.c', 'test-69.c', 'boa', 'safe', expected='unsafe')) t.add(Test('test-69.c', 'test-69.c (partitioning=return)', 'boa', 'safe', options=['-add-partitioning-variables', '-enable-partitioning-domain'])) t.add(Test('test-70.c', 'test-70.c', 'boa', 'safe')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-1-unsafe.c000066400000000000000000000004461473507761200251070ustar00rootroot00000000000000// DEFINITE UNSAFE // See how we treat global variables, struct and one-dimensional arrays int x = 6; struct foo { int x; }; int B[10]; int main(int argc, char** argv) { int A[5] = {0}; struct foo a; a.x = 59; x++; B[8] = 23; int z = x + 7 + a.x + A[5] + B[10]; return z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-1.c000066400000000000000000000006341473507761200236270ustar00rootroot00000000000000// SAFE // See how we treat global variables, struct and one-dimensional arrays // The program is safe in terms of buffer overflow although A is // uninitialized. B is uninitialized since it is a global array. int x = 6; struct foo { int x; }; int B[10]; int main(int argc, char** argv) { int A[5] = {0}; struct foo a; a.x = 59; x++; B[8] = 23; int z = x + 7 + a.x + A[4] + B[9]; return z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-10-unsafe.c000066400000000000000000000004611473507761200251640ustar00rootroot00000000000000// DEFINITE UNSAFE // Interprocedural analysis is needed. #include int foo(int k, int N) { return k + N; } int bar(int p) { return p + foo(p, 10); } int main(int argc, char** argv) { int a[56]; int x = foo(5, 10); // x=15 int y = x + bar(x); // y=55 a[y + 1] = 67; return y; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-10.c000066400000000000000000000004421473507761200237040ustar00rootroot00000000000000// SAFE // Interprocedural analysis is needed. #include int foo(int k, int N) { return k + N; } int bar(int p) { return p + foo(p, 10); } int main(int argc, char** argv) { int a[56]; int x = foo(5, 10); // x=15 int y = x + bar(x); // y=55 a[y] = 67; return y; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-11-unsafe.c000066400000000000000000000006001473507761200251600ustar00rootroot00000000000000// DEFINITE UNSAFE // interprocedural analysis is needed. #include int a[100][100]; int init = 5; int foo(int k) { while (k < 100) { int i = 0; int j = k; while (i < j) { i = i + 1; j = j - 1; a[i][j] = init; } k = k + 1; } return k; } int main(int argc, char** argv) { int ind = foo(0); printf("%d\n", a[ind - 1][ind]); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-11.c000066400000000000000000000005451473507761200237110ustar00rootroot00000000000000// SAFE if interprocedural #include int a[100][100]; int init = 5; int foo(int k) { while (k < 100) { int i = 0; int j = k; while (i < j) { i = i + 1; j = j - 1; a[i][j] = init; } k = k + 1; } return k; } int main(int argc, char** argv) { int ind = foo(0); printf("%d\n", a[ind - 1][ind - 1]); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-12-unsafe.c000066400000000000000000000015761473507761200251760ustar00rootroot00000000000000// DEFINITE UNSAFE #include // If the multidimensional array is global then LLVM generates a // single GetElementPtr instruction /* int p[2][2]; */ /* void kalman_global( void ) { */ /* p[0][3]=1; */ /* } */ /* int main(int arg, char **argv){ */ /* kalman_global(); */ /* return 0; */ /* } */ // This example to show how arrays, pointer, and integers are passed // 'by reference' /* Total number of checks : 14 Total number of safe : 7 Total number of definite unsafe : 1 Total number of potentially unsafe: 6 */ int id(int x) { return x; } void foo(int* rtmSampleHitPtr) { rtmSampleHitPtr[2] = id(3); } void bar(int* x) { *x = 5; } void bar2(int x[4][4]) { x[3][2] = 5; } int main(int arg, char** argv) { int a[5]; int b[4][4]; foo(a); int x; bar(&x); bar2(b); int* p; bar2(&p); printf("%d\n", a[x]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-13.c000066400000000000000000000022371473507761200237130ustar00rootroot00000000000000// SAFE // This example is to make sure that ARBOS computes struct sizes // properly even if some types are defined recursively. struct SimStruct_tag { int elem; struct SimStruct_tag* next; }; // size=4+8+4(padding)=16 --> 128 bits // (without padding) size=4+8=12 ---> 88 bits struct FOO_BAR { struct SimStruct_tag* childSfunctions; // size=8 struct { struct { unsigned char TID[3]; // size=3 } TaskCounters; double tFinal; // size=8 } Timing; }; // size=8+(3+8+5(padding))=24 --> 192 bits // (without padding) size=8+3+8=19 ---> 152 bits // v0.size = 88 | 152 <==== // v0.offset = 0 | 0 // v1.size = 88 | 152 // v1.offset = 88 | 64 <===== // v2.size = 88 | 152 // v2.offset = 88+24=112 | 64+24 = 88 #define bar1(s, val) ((s)->Timing.tFinal = (val)) #define bar2(s, idx) ((s)->Timing.TaskCounters.TID[(idx)] == 0) #define bar3(s, idx) ((s)->Timing.TaskCounters.TID[(idx)]) struct FOO_BAR foo_M_; struct FOO_BAR* foo_M = &foo_M_; struct FOO_BAR* foo(void) { return foo_M; } int main(int argc, char** argv) { struct FOO_BAR* S; S = foo(); bar1(S, 1.5); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-14.c000066400000000000000000000002601473507761200237060ustar00rootroot00000000000000// SAFE // from King and Simon void main() { char s[32] = "the string"; int i = 0; char c; while (1) { c = s[i]; if (c == 0) break; i = i + 1; } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-15.c000066400000000000000000000004331473507761200237110ustar00rootroot00000000000000// SAFE if --domain=interval-congruence int main(int argc, char** argv) { int k = 0; int i = 0; int j = 1; int A[10]; for (k = 0; k < 10; k++) { A[k] = 0; i = i + 2; j = j + 2; } if (i % 2 == 1) { A[k] = 1; // unsafe but dead code } return i + j; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-16.c000066400000000000000000000003041473507761200237070ustar00rootroot00000000000000// SAFE struct foo { int x; int y; int z; }; void init(struct foo* f) { f->x = 5; f->y = 6; f->z = 7; } int main(int argc, char** argv) { struct foo a; init(&a); return a.x; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-17-simpler.c000066400000000000000000000006761473507761200253750ustar00rootroot00000000000000// SAFE int foo(const float* x, int xlen, float u) { int idx = 0; int bottom = 0; int top = xlen - 1; int retValue = 0; for (;;) { idx = (bottom + top) / 2; if (u <= x[idx]) top = idx - 1; else if (u > x[idx + 1]) bottom = idx + 1; else { retValue = idx; break; } } return retValue; } int main(int argc, char** argv) { int xlen = 100; float A[100]; return foo(&A, xlen, 34.0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-17.c000066400000000000000000000030401473507761200237100ustar00rootroot00000000000000// SAFE int foo(const float* x, int xlen, float u) { int idx = 0; int bottom = 0; int top = xlen - 1; int retValue = 0; unsigned int returnStatus = 0U; /* * Deal with the extreme cases first: * if u <= x[bottom] then return idx = bottom * if u >= x[top] then return idx = top-1 */ if (u <= x[bottom]) { retValue = bottom; returnStatus = 1U; } else if (u >= x[top]) { retValue = top - 1; returnStatus = 1U; } else { /* else required to ensure safe programming, even * * if it's expected that it will never be reached */ } if (returnStatus == 0U) { if (u < 0) { /* For negative input find index such that: x[idx] <= u < x[idx+1] */ for (;;) { idx = (bottom + top) / 2; if (u < x[idx]) { top = idx - 1; } else if (u >= x[idx + 1]) { bottom = idx + 1; } else { /* we have x[idx] <= u < x[idx+1], return idx */ retValue = idx; break; } } } else { /* For non-negative input find index such that: x[idx] < u <= x[idx+1] */ for (;;) { idx = (bottom + top) / 2; if (u <= x[idx]) { top = idx - 1; } else if (u > x[idx + 1]) { bottom = idx + 1; } else { /* we have x[idx] < u <= x[idx+1], return idx */ retValue = idx; break; } } } } return retValue; } int main(int argc, char** argv) { int xlen = 100; float A[100]; float elem = 34.0; return foo(&A, xlen, elem); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-18-unsafe.c000066400000000000000000000010041473507761200251660ustar00rootroot00000000000000// DEFINITE UNSAFE #include #include // We just use a pointer as an array // Same as test-8-unsafe.c but using calloc #define MAX_ARRAY 10 // To test loops that decrements a counter int main(int argc, char** argv) { int n = MAX_ARRAY - 1; int* p = (int*)calloc(n, sizeof(int)); int i; if (!p) return 1; for (i = n - 1; i >= 0; i--) { p[i] = i; } // for underflow check // printf("%d\n", p[i+1]); // for overflow check printf("%d\n", p[MAX_ARRAY - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-18.c000066400000000000000000000007521473507761200237200ustar00rootroot00000000000000// SAFE #include #include // We just use a pointer as an array // Same as test-8.c, but using calloc #define MAX_ARRAY 10 // To test loops that decrements a counter int main(int argc, char** argv) { int* p = (int*)calloc(MAX_ARRAY, sizeof(int)); int i; if (!p) return 1; for (i = MAX_ARRAY - 1; i >= 0; i--) { p[i] = i; } // for underflow check // printf("%d\n", p[i+1]); // for overflow check printf("%d\n", p[MAX_ARRAY - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-19a.c000066400000000000000000000014461473507761200240630ustar00rootroot00000000000000// SAFE // It should be safe with the Gauge domain. // Basically, we need to relate the offsets of A and B with the loop counter. // Otherwise, we get [0, +oo] for both offsets. // With Gauge, we get something like // A.offset = B.offset = (n-1) - \lambda and \lambda=[0,n-1] // Unfortunately, ikos cannot currently infer that the loop counter is in // [0, n-1] because of the pattern `while(numNonZero--)`, // equivalent to `while(numNonZero-- != 0)`. // We would need `while(numNonZero-- >= 0)` to be more precise. see test-19b.c float foo(float* p, const float* A, const float* B, int n) { int numNonZero = n - 1; while (numNonZero--) { *p *= (*A++) * (*B++); } return *p; } int main(int argc, char** argv) { float p; float A[10]; float B[10]; return (int)foo(&p, &A, &B, 10); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-19b.c000066400000000000000000000011171473507761200240570ustar00rootroot00000000000000// SAFE if --domain=gauge-interval-congruence // It should be safe with the Gauge domain. // Basically, we need to relate the offsets of A and B with the loop counter. // Otherwise, we get [0, +oo] for both offsets. // With Gauge, we get something like // A.offset = B.offset = (n-1) - \lambda and \lambda=[0,n-1] float foo(float* p, const float* A, const float* B, int n) { int numNonZero = n - 1; while (numNonZero-- >= 0) { *p *= (*A++) * (*B++); } return *p; } int main(int argc, char** argv) { float p; float A[10]; float B[10]; return (int)foo(&p, &A, &B, 10); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-2-unsafe.c000066400000000000000000000002631473507761200251050ustar00rootroot00000000000000// DEFINITE UNSAFE #include // To test loops int main(int argc, char** argv) { int i, a[10]; for (i = 0; i < 10; i++) { a[i] = i; } printf("%d\n", a[i]); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-2.c000066400000000000000000000002761473507761200236320ustar00rootroot00000000000000// SAFE #include // To test loops int main(int argc, char** argv) { int i; int a[10]; for (i = 0; i < 10; i++) { a[i] = i; } printf("%d\n", a[i - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-20.c000066400000000000000000000010651473507761200237070ustar00rootroot00000000000000#include #include #include extern int __ikos_nondet_int(void); float readFloatSerial() { uint8_t index = 0; uint8_t timeout = 0; char data[15] = ""; do { if (__ikos_nondet_int() == 0) { timeout++; } else { data[index] = __ikos_nondet_int(); timeout = 0; index++; } } while ((index == 0 || data[index - 1] != ';') && (timeout < 10) && (index < sizeof(data) - 1)); data[index] = '\0'; return atof(data); } int main() { printf("%f", readFloatSerial()); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-21.c000066400000000000000000000005221473507761200237050ustar00rootroot00000000000000// SAFE #include #include int bar(int* a, int sz) { int i; for (i = 0; i < sz; i++) { a[i] = i; } printf("%d\n", a[i - 1]); return 42; } int foo(int sz) { int* a = (int*)malloc(sizeof(int) * sz); if (!a) return -1; return bar(a, sz); } int main(int argc, char** argv) { return foo(10); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-22-safe.c000066400000000000000000000003571473507761200246300ustar00rootroot00000000000000// SAFE #include struct foo { int a; int b; }; struct foo x; int main(int argc, char** argv) { int i; int a[10]; for (i = 0; i < 10; i++) { x.a = i; a[x.a] = i; } printf("%d\n", a[i - 1]); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-22-unsafe.c000066400000000000000000000003761473507761200251740ustar00rootroot00000000000000// DEFINITE UNSAFE #include struct foo { int a; int b; }; struct foo x; int main(int argc, char** argv) { int i; int a[10]; for (i = 0; i < 10; i++) { x.a = i + 1; a[x.a] = i; } printf("%d\n", a[i - 1]); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-23-safe.c000066400000000000000000000006671473507761200246350ustar00rootroot00000000000000// SAFE #include #include char* foo(char* a, int n) { int i; for (i = 0; i < n; i++) a[i] = 'A'; return a; } int main() { char str[50]; strcpy(str, "This is string.h library function"); puts(str); memset(str, '$', 50); // SAFE char* A = foo(str, 10); // char * B; <- B will be undefined char B[10]; memcpy(B, A, 10); // SAFE char* C = foo(B, 10); // SAFE puts(C); return (0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-23-unsafe-1.c000066400000000000000000000006661473507761200253350ustar00rootroot00000000000000// DEFINITE UNSAFE #include #include char* foo(char* a, int n) { int i; for (i = 0; i < n; i++) a[i] = 'A'; return a; } int main() { char str[50]; strcpy(str, "This is string.h library function"); puts(str); memset(str, '$', 100); // DEFINITE ERROR char* A = foo(str, 7); // char * B; <- B will be undefined char B[50]; memcpy(B, A, 5); char* C = foo(B, 6); puts(C); return (0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-23-unsafe-2.c000066400000000000000000000007141473507761200253300ustar00rootroot00000000000000// DEFINITE UNSAFE #include #include char* foo(char* a, int n) { int i; for (i = 0; i < n; i++) a[i] = 'A'; return a; } int main() { char str[50]; strcpy(str, "This is string.h library function"); puts(str); memset(str, '$', 50); // SAFE char* A = foo(str, 10); // char * B; <- B will be undefined char B[10]; memcpy(B, A, 11); // DEFINITE ERROR char* C = foo(B, 10); // SAFE puts(C); return (0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-23-unsafe-3.c000066400000000000000000000007051473507761200253310ustar00rootroot00000000000000// DEFINITE UNSAFE #include #include char* foo(char* a, int n) { int i; for (i = 0; i < n; i++) a[i] = 'A'; return a; } int main() { char str[50]; strcpy(str, "This is string.h library function"); puts(str); memset(str, '$', 50); // SAFE char* A = foo(str, 10); // char * B; <- B will be undefined char B[10]; memcpy(B, A, 10); // SAFE char* C = foo(B, 11); // WARNING puts(C); return (0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-24-safe.c000066400000000000000000000004541473507761200246300ustar00rootroot00000000000000// SAFE #include struct Foo { int a; // 4 int b; // 4 int c[5]; // 20 char* s; // 8 // + padding of 4 in my 64bit machine }; // sizeof (struct Foo) = 40 int foo(struct Foo f) { return f.b; } int main() { struct Foo f; memset(&f, 0, sizeof(f)); return foo(f); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-25.c000066400000000000000000000002241473507761200237100ustar00rootroot00000000000000#include int main() { int accelSample[3]; for (uint8_t axis = 0; axis < 3; axis++) { accelSample[axis] = 0; } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-26-volatile-safe.c000066400000000000000000000002751473507761200264500ustar00rootroot00000000000000#include extern unsigned __ikos_nondet_uint(void); int main() { int values[5] = {0}; // not volatile unsigned i = __ikos_nondet_uint() % 5; printf("%d\n", values[i]); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-26-volatile-unsafe.c000066400000000000000000000003331473507761200270060ustar00rootroot00000000000000#include extern unsigned __ikos_nondet_uint(void); int main() { int values[5] = {0}; // volatile should trigger a warning volatile unsigned i = __ikos_nondet_uint() % 5; printf("%d\n", values[i]); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-27.c000066400000000000000000000013331473507761200237140ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); extern unsigned __ikos_nondet_uint(void); extern void __ikos_assert(int); char buffer[40] = {0}; void f1() { uint8_t i = 40; while (i) { printf("%d\n", buffer[i - 1]); i--; } } void f1p() { uint8_t i = 40; while (i != 0) { printf("%d\n", buffer[i - 1]); i--; } } void f2() { int8_t i = 40; while (i) { printf("%d\n", buffer[i - 1]); i = i - 1; } } void f2p() { int8_t i = 40; while (i != 0) { printf("%d\n", buffer[i - 1]); i = i - 1; } } void f3() { unsigned i = 0; while (i != 40) { printf("%d\n", buffer[i]); i++; } } int main() { f1(); f1p(); f2(); f2p(); f3(); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-28.c000066400000000000000000000001521473507761200237130ustar00rootroot00000000000000#include #include #define HWADDR_1 0x40 int main() { (*(int*)HWADDR_1) = 0x41; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-29.c000066400000000000000000000004171473507761200237200ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int* hwaddr; if (__ikos_nondet_int()) { hwaddr = 0x42; } else if (__ikos_nondet_int() == 42) { hwaddr = 0x47; } else { hwaddr = 0x99; } *hwaddr = 142857; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-3-unsafe.c000066400000000000000000000005231473507761200251050ustar00rootroot00000000000000// DEFINITE UNSAFE #include #define MAX_ARRAY 10 // To test loops that decrements a counter int main(int argc, char** argv) { int a[MAX_ARRAY]; int i; for (i = MAX_ARRAY - 1; i >= 0; i--) { a[i] = i; } // buffer underflow printf("%d\n", a[i]); // buffer overflow printf("%d\n", a[MAX_ARRAY]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-3.c000066400000000000000000000005261473507761200236310ustar00rootroot00000000000000// SAFE #include #define MAX_ARRAY 10 // To test loops that decrements a counter int main(int argc, char** argv) { int a[MAX_ARRAY]; int i; for (i = MAX_ARRAY - 1; i >= 0; i--) { a[i] = i; } // for underflow check printf("%d\n", a[i + 1]); // for overflow check printf("%d\n", a[MAX_ARRAY - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-30-use-after-free.c000066400000000000000000000002121473507761200265110ustar00rootroot00000000000000#include int main() { int* p = calloc(10, sizeof(int)); if (p != NULL) { p[5] = 17; free(p); p[5] = 18; } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-31-use-after-free.c000066400000000000000000000004261473507761200265210ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int* p = calloc(10, sizeof(int)); if (p != NULL) { if (__ikos_nondet_int()) { free(p); } else { p[5] = __ikos_nondet_int(); } printf("p=%d\n", p[5]); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-32-use-after-return.c000066400000000000000000000005641473507761200271230ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int* f() { int array[10]; for (int i = 0; i < 10; i++) { array[i] = __ikos_nondet_int(); } for (int i = 0; i < 10; i++) { if (array[i] == 42) { return &array[i]; } } return NULL; } int main() { int* ret = f(); if (ret != NULL) { return *ret; } else { return 0; } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-33.c000066400000000000000000000015501473507761200237120ustar00rootroot00000000000000// SAFE #include typedef enum { ABS_RR_ERR_NO_ERROR = 0, ABS_RR_ERR_COUNT } foo_bar_err_t; typedef unsigned int __uint32_t; typedef void* foo_bar_t; foo_bar_err_t test_seize_resource(const foo_bar_t resource); foo_bar_err_t test_relinquish_resource(const foo_bar_t resource); foo_bar_t test_get_resource(__uint32_t); static struct { __uint32_t sampling_interval_seconds; } g = {0}; //// // Note that test_get_resource is not defined! //// static inline foo_bar_t get_resource(void) { static foo_bar_t resource = 0; if (!resource) { resource = test_get_resource(12U); } return resource; } int main(int argc, char** argv) { const foo_bar_err_t test_err = test_seize_resource(get_resource()); if (ABS_RR_ERR_NO_ERROR == test_err) { g.sampling_interval_seconds = argc; test_relinquish_resource(get_resource()); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-34.c000066400000000000000000000025411473507761200237140ustar00rootroot00000000000000// SAFE typedef enum { CONST_4_I = 3, CONST_3_I, CONST_2_I, CONST_1_I, } cnst_t; typedef unsigned int __uint32_t; typedef long unsigned int size_t; typedef unsigned short int __uint16_t; typedef __uint16_t env_t; static const char PACKET_URL[] = "foo.org"; typedef struct { char url[sizeof PACKET_URL]; __uint32_t timestamp; } pkt_hdr_t; typedef env_t pkt_env_tbl_t[4]; typedef struct { pkt_hdr_t header; pkt_env_tbl_t environment_table; } types_packet_t; static struct { types_packet_t packet_structure; } g; __uint16_t abs_bb_get(const cnst_t cnst_id, const int err); void fill_env_tbl(void) { static const cnst_t CONSTANTS[] = {CONST_1_I, CONST_2_I, CONST_3_I, CONST_4_I}; static const size_t N = sizeof(CONSTANTS) / sizeof(cnst_t); size_t i = 0; for (; i < N; i++) { g.packet_structure.environment_table[i] = abs_bb_get(CONSTANTS[i], 0); } } // BEGIN MODIFICATION // We need to have a main function, otherwise the variable N will be // ignored so the value of "i" cannot be determined. // The variable N is declared as static so it's translated by the // front-end as a global variable. If N wouldn't be static then we // wouldn't need the main function. int main() { fill_env_tbl(); return 42; } // END MODIFICATION NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-35.c000066400000000000000000000024031473507761200237120ustar00rootroot00000000000000// SAFE #include typedef unsigned int __uint32_t; typedef enum { RESET_BOR, RESET_CMR, RESET_MCLR, RESET_POR, RESET_SWR, RESET_WDTR, RESET_COUNT } types_reset_t; typedef enum { ERROR = 0, INFO, TRACE, LOG_LEVEL_COUNT } util_log_level_t; void util_log(util_log_level_t const level, const char* const file, __uint32_t const line, const char* const format, ...); types_reset_t bsp_reset_get(); int main(int argc, char** argv) { const types_reset_t reset = bsp_reset_get(); static const char* const STRING_MAP[] = {"brown-out", "configuration mismatch", "master clear", "power on", "software", "watchdog timeout"}; const char* const reset_string = (((types_reset_t)0 <= reset) && (reset < RESET_COUNT)) ? STRING_MAP[reset] : "unknown"; char msg[55]; strcpy(msg, "The cause of the last reset was "); strcat(msg, reset_string); { util_log(INFO, "../../src/init/init.c", 356, msg, ""); }; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-36.c000066400000000000000000000020561473507761200237170ustar00rootroot00000000000000// SAFE typedef unsigned char __uint8_t; typedef unsigned int __uint32_t; typedef long unsigned int size_t; typedef void (*entry_t)(void*); typedef struct { entry_t entry_point; __uint8_t priority; __uint32_t* stack; __uint32_t stack_size; const char* name; } foo_bar_ts_t; typedef const foo_bar_ts_t* (*ts_getter_t)(void); void foo_bar_create_task(const foo_bar_ts_t* const p_ts); const foo_bar_ts_t* get_shell_ts(void); const foo_bar_ts_t* get_controller_ts(void); static const ts_getter_t TS_GETTERS[] = { get_shell_ts, get_controller_ts, }; const foo_bar_ts_t* start_get_ts(void); static void create_application_tasks(void); int main(int argc, char** argv) { create_application_tasks(); return 0; } static void create_application_tasks(void) { const size_t n = sizeof(TS_GETTERS) / sizeof(ts_getter_t); size_t getter_index; for (getter_index = 0; getter_index < n; getter_index++) { const ts_getter_t getter_fn = TS_GETTERS[getter_index]; const foo_bar_ts_t* const p_ts = getter_fn(); foo_bar_create_task(p_ts); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-37.c000066400000000000000000000040661473507761200237230ustar00rootroot00000000000000// SAFE #include typedef unsigned char __uint8_t; typedef unsigned int __uint32_t; typedef __uint32_t uint32_t; typedef enum { FOO_BAR_ERR_NO_ERROR = 0, FOO_BAR_ERR_PEX, FOO_BAR_ERR_NULL, FOO_BAR_ERR_OS_ERR, FOO_BAR_ERR_BAD_SIZE, FOO_BAR_ERR_BAR_CREATE_FAIL } foo_bar_err_t; typedef struct { uint32_t last_comm_time; uint32_t dep_time; uint32_t start_timeout_sec; int valid; } start_t; typedef enum { COMMAND_OPCODE_RESET = 3, COMMAND_OPCODE_START_EXPERIMENT = 9, COMMAND_OPCODE_CANCEL_EXPERIMENT = 22, COMMAND_OPCODE_SET_EXPERIMENT = 24 } code_t; typedef struct { __uint32_t command_id; __uint32_t execution_time; code_t command_opcode; __uint8_t command_parameters[115U]; } types_command_packet_t; extern void* barset(void*, int, size_t); int do_something(types_command_packet_t* const p_command_packet); extern start_t fetch_values(void); // void * foo_bar_malloc (const size_t size, foo_bar_err_t * const perr); // BEGIN MODIFICATION // We had the prototype for foo_bar_malloc but not its // implementation. Without it, we cannot say anything about the void * // returned by the function. void* foo_bar_malloc(const size_t size, foo_bar_err_t* const perr) { return (void*)malloc(size); } // END MODIFICATION foo_bar_err_t foo_bar_free(void* const block); void start(void) { const start_t values = fetch_values(); if ((values.valid) && (values.dep_time > values.last_comm_time)) { foo_bar_err_t bar_err; types_command_packet_t* const command_packet = foo_bar_malloc(sizeof(types_command_packet_t), &bar_err); if (command_packet) { command_packet->command_id = 1; command_packet->execution_time = values.dep_time + values.start_timeout_sec; command_packet->command_opcode = COMMAND_OPCODE_START_EXPERIMENT; barset(command_packet->command_parameters, 0, 115U); command_packet->command_parameters[0] = 0xBC; int const done = do_something(command_packet); if (!done) { bar_err = foo_bar_free(command_packet); } } } } int main(void) { start(); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-38-argv.c000066400000000000000000000005411473507761200246530ustar00rootroot00000000000000#include extern void __ikos_assert(int); int main(int argc, char** argv) { // we assume argc == 4 printf("argv[argc-1]=%s\n", argv[argc - 1]); // Last argument printf("argv[3]=%s\n", argv[3]); // Last argument printf("argv[4]=%s\n", argv[4]); // NULL printf("argv[5]=%s\n", argv[5]); // Error } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-39.c000066400000000000000000000027231473507761200237230ustar00rootroot00000000000000// SAFE typedef unsigned int __uint32_t; typedef __uint32_t uint32_t; uint32_t E(uint32_t); uint32_t abs_rtos_get_time(void); static inline __uint32_t get_stuff_thing_index(const __uint32_t thing_index) { const __uint32_t result = thing_index % 19U; return result; } void start(const __uint32_t thing_index, __uint32_t* const p_foo_stuff_time, __uint32_t* const p_start_time, const __uint32_t current_time); void handle(uint32_t* const p_thing_index, uint32_t* const p_start_time, uint32_t* const p_foo_stuff_time) { if (*p_thing_index < E(3U * 19U)) { const uint32_t thing_index = get_stuff_thing_index(*p_thing_index); const uint32_t current_time = abs_rtos_get_time(); if (0 == *p_start_time) { start(*p_thing_index, p_foo_stuff_time, p_start_time, current_time); } } } // BEGIN MODIFICATION // Need to call handle with three initialized pointers. // Otherwise, no assumption about the pointer addresses can be made so // pointer dereference such as "*p_thing_index" will raise warnings. extern uint32_t NONDET(); // this is used to initialize variables // assuming that it can take any possible value. int main() { // Here arbitrary values to these three uint32_t p_thing_index = NONDET(); uint32_t p_start_time = NONDET(); uint32_t p_foo_stuff_time = NONDET(); handle(&p_thing_index, &p_start_time, &p_foo_stuff_time); return 42; } // END MODIFICATION NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-4-unsafe-1.c000066400000000000000000000005111473507761200252410ustar00rootroot00000000000000#include int MAX_ARRAY = 10; // To test loops that decrements a counter int main(int argc, char** argv) { int a[MAX_ARRAY]; int i; for (i = MAX_ARRAY - 1; i >= 0; i--) { a[i] = i; } // for underflow check printf("%d\n", a[i]); // for overflow check printf("%d\n", a[MAX_ARRAY - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-4-unsafe-2.c000066400000000000000000000005111473507761200252420ustar00rootroot00000000000000#include int MAX_ARRAY = 10; // To test loops that decrements a counter int main(int argc, char** argv) { int a[MAX_ARRAY]; int i; for (i = MAX_ARRAY - 1; i >= 0; i--) { a[i] = i; } // for underflow check printf("%d\n", a[i + 1]); // for overflow check printf("%d\n", a[MAX_ARRAY]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-4.c000066400000000000000000000005151473507761200236300ustar00rootroot00000000000000#include int MAX_ARRAY = 10; // To test loops that decrements a counter int main(int argc, char** argv) { int a[MAX_ARRAY]; int i; for (i = MAX_ARRAY - 1; i >= 0; i--) { a[i] = i; } // for underflow check printf("%d\n", a[i + 1]); // for overflow check printf("%d\n", a[MAX_ARRAY - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-40.c000066400000000000000000000041421473507761200237100ustar00rootroot00000000000000// SAFE #include typedef __signed char __int8_t; typedef unsigned char __uint8_t; typedef unsigned short int __uint16_t; typedef unsigned int __uint32_t; typedef __uint32_t uint32_t; typedef struct { __uint32_t error_count; } state_data_t; typedef struct { __uint16_t foo_sample_size; __uint16_t foo_means[4]; __uint16_t foo_sds[4]; __uint16_t bar_sample_size; __uint16_t bar_means[32]; __uint16_t bar_sds[32]; } sample_data_t; typedef struct { __uint32_t alt_pressure; __int8_t alt_foo; __uint8_t hum_relative_humidity; __int8_t hum_foo; } stuff_data_t; typedef enum { ERR_NO_ERROR = 0, ERR_COUNT } err_t; typedef struct { state_data_t state; sample_data_t sample; stuff_data_t stuff; } response_packet_t; typedef enum { SELECT_NONE = 0, SELECT_1, SELECT_2, SELECT_3, } command_t; static const command_t EXPERIMENT[3U] = {SELECT_2, SELECT_3, SELECT_1}; // BEGIN MODIFICATION extern __uint8_t NONDET(); // I replaced the given get_index function because when it is called // below its formal parameter is always uninitialized so a warning // must be raised. The version I have is one that only assumes that // the return value must be between 0 and 2 because it is used as index // in EXPERIMENT whose size is 3. static inline __uint32_t get_index(const __uint32_t thing_index) { __uint32_t number = NONDET(); if (number <= 2) return number; else exit(0); } /* static inline __uint32_t get_index(const __uint32_t thing_index) */ /* { */ /* const __uint32_t result = thing_index / 19U; */ /* return result; */ /* } */ // END MODIFICATION err_t send(const command_t command, response_packet_t* const p_response_packet); void start(const __uint32_t thing_index, __uint32_t* const p_bar_experiment_time, __uint32_t* const p_start_time, const __uint32_t current_time) { response_packet_t response; const uint32_t index = get_index(thing_index); const command_t select_command = EXPERIMENT[index]; const err_t err = send(select_command, &response); } int main(void) { const __uint32_t foo = 0; start(foo, &foo, &foo, foo); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-41.c000066400000000000000000000014521473507761200237120ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); typedef struct { int* sampleHits; int y[5]; } foo; struct FOO_BAR { int a; int b; int c; foo d[5]; struct { int clockTick; struct { char TID0_2; char TID1_2; } RateInteraction; int* sampleHits; } Timing; }; #ifndef bar1 #define bar1(bar) ((bar)->Timing.sampleHits) #endif struct FOO_BAR foo_M_; struct FOO_BAR* foo_M = &foo_M_; int sampleHit = 20; static struct FOO_BAR* init() { struct FOO_BAR* tmp = foo_M; bar1(tmp) = &sampleHit; return tmp; } static void oneStep(struct FOO_BAR* M) { int* p = bar1(M); M->d[2].y[0] = 3; M->d[3].y[0] = 4; M->d[4].y[0] = M->d[2].y[0] + M->d[3].y[0] + *p; // __ikos_assert (M->d[4].y[0] == 27); } int main() { struct FOO_BAR* M = init(); oneStep(M); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-42.c000066400000000000000000000007531473507761200237160ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); static struct { int stopExecutionFlag; int isrOverrun; int overrunFlags[10]; const char* errmsg; } GBLbuf; typedef struct { int x; int y; } foo; typedef struct { int a; int b; int c; int d[5]; } FOO_BAR; FOO_BAR foo_M_; FOO_BAR* foo_M = &foo_M_; FOO_BAR* init() { return foo_M; } int main() { FOO_BAR* M = init(); M->d[2] = 3; M->d[3] = 4; M->d[4] = M->d[2] + M->d[3]; __ikos_assert(M->d[4] == 7); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-43.c000066400000000000000000000003601473507761200237110ustar00rootroot00000000000000#include void fun_exit() { int i = 0; while (1) { if (i == 42) exit(1); i++; } } int main() { int tab[10]; int i; fun_exit(); for (i = 0; i <= 10; i++) { tab[i] = i * i; } return tab[0]; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-44-unsafe.c000066400000000000000000000006701473507761200251750ustar00rootroot00000000000000#include #include #include typedef void* (*fun_ptr_t)(size_t); uint64_t buffer[6]; void* my_malloc(size_t s) { return &buffer; } extern int __ikos_nondet_int(void); int main() { fun_ptr_t f; if (__ikos_nondet_int()) { f = &malloc; } else { f = &my_malloc; } int* p = (int*)f(2 * sizeof(int)); if (!p) return 1; *p = 1; p++; *p = 2; printf("%d\n", *p); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-44.c000066400000000000000000000004761473507761200237220ustar00rootroot00000000000000#include #include #include typedef void* (*fun_ptr_t)(size_t); fun_ptr_t allocator() { return &malloc; } int main() { int tab[10]; int i = 0; int* p; fun_ptr_t f = allocator(); p = (int*)f(42); if (!p) return 1; *p = 42; printf("%d\n", tab[i]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-45-unsafe.c000066400000000000000000000004031473507761200251700ustar00rootroot00000000000000// UNSAFE #include int* init() { int tab[10]; for (int i = 0; i < 10; i++) { tab[i] = 0; } return tab; // unsafe: return a local variable } int main() { int* p = init(); printf("%d\n", p[0]); printf("%d\n", p[9]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-45.c000066400000000000000000000003631473507761200237160ustar00rootroot00000000000000// SAFE #include int* init(int* tab, int n) { for (int i = 0; i < n; i++) { tab[i] = 0; } return tab; } int main() { int tab[10]; int* p = init(tab, 10); printf("%d\n", p[0]); printf("%d\n", p[9]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-46-unsafe.c000066400000000000000000000003401473507761200251710ustar00rootroot00000000000000// UNSAFE #include #include int main() { int* p = (int*)malloc(sizeof(int)); if (!p) return 1; *p = 0x41424344; short* q = (short*)((char*)p + 3); *q = 0; // buffer overflow return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-46.c000066400000000000000000000003131473507761200237120ustar00rootroot00000000000000// SAFE #include #include int main() { int* p = (int*)malloc(sizeof(int)); if (!p) return 1; *p = 0x41424344; short* q = (short*)((char*)p + 2); *q = 0; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-47-unsafe.cpp000066400000000000000000000004211473507761200255320ustar00rootroot00000000000000#include extern "C" { extern int __ikos_nondet_int(void) noexcept; } int x; void f() { x = 10; if (__ikos_nondet_int()) { throw 0x42; } x = 0; } int main() { int tab[10] = {0}; try { f(); } catch (int) { } printf("%d\n", tab[x]); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-47.cpp000066400000000000000000000004201473507761200242520ustar00rootroot00000000000000#include extern "C" { extern int __ikos_nondet_int(void) noexcept; } int x; void f() { x = 9; if (__ikos_nondet_int()) { throw 0x42; } x = 0; } int main() { int tab[10] = {0}; try { f(); } catch (int) { } printf("%d\n", tab[x]); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-48-unsafe-1.c000066400000000000000000000002241473507761200253320ustar00rootroot00000000000000#include #include int main() { const char* s = "AAAAA"; int i = strlen(s); printf("%d\n", (int)s[i + 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-48-unsafe-2.c000066400000000000000000000002241473507761200253330ustar00rootroot00000000000000#include #include int main() { const char* s = "AAAAA"; int i = strlen(&s[6]); printf("%d\n", (int)s[i]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-48.c000066400000000000000000000002201473507761200237110ustar00rootroot00000000000000#include #include int main() { const char* s = "AAAAA"; int i = strlen(s); printf("%d\n", (int)s[i]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-49-unsafe-1.c000066400000000000000000000002031473507761200253300ustar00rootroot00000000000000#include #include int main() { char s1[10]; const char* s2 = "AAAA"; strcpy(s1, &s2[5]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-49-unsafe-2.c000066400000000000000000000001761473507761200253420ustar00rootroot00000000000000#include #include int main() { char s1[4]; const char* s2 = "AAAA"; strcpy(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-49.c000066400000000000000000000001771473507761200237250ustar00rootroot00000000000000#include #include int main() { char s1[10]; const char* s2 = "AAAA"; strcpy(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-5-unsafe-1.c000066400000000000000000000005741473507761200252530ustar00rootroot00000000000000// DEFINITE UNSAFE (overflow) #include #define MAX_ARRAY 10 // To test loops int main(int argc, char** argv) { int i, j; int a[MAX_ARRAY][MAX_ARRAY]; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) a[i + 1][j] = argc; // some unknown value here } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", a[i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-5-unsafe-2.c000066400000000000000000000005741473507761200252540ustar00rootroot00000000000000// DEFINITE UNSAFE (overflow) #include #define MAX_ARRAY 10 // To test loops int main(int argc, char** argv) { int i, j; int a[MAX_ARRAY][MAX_ARRAY]; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) a[i][j + 1] = argc; // some unknown value here } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", a[i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-5-unsafe-3.c000066400000000000000000000005751473507761200252560ustar00rootroot00000000000000// DEFINITE UNSAFE (underflow) #include #define MAX_ARRAY 10 // To test loops int main(int argc, char** argv) { int i, j; int a[MAX_ARRAY][MAX_ARRAY]; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) a[i][j - 1] = argc; // some unknown value here } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", a[i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-5-unsafe-4.c000066400000000000000000000005751473507761200252570ustar00rootroot00000000000000// DEFINITE UNSAFE (underflow) #include #define MAX_ARRAY 10 // To test loops int main(int argc, char** argv) { int i, j; int a[MAX_ARRAY][MAX_ARRAY]; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) a[i - 1][j] = argc; // some unknown value here } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", a[i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-5.c000066400000000000000000000005421473507761200236310ustar00rootroot00000000000000// SAFE #include #define MAX_ARRAY 10 // To test loops int main(int argc, char** argv) { int i, j; int a[MAX_ARRAY][MAX_ARRAY]; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) a[i][j] = argc; // some unknown value here } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", a[i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-50-unsafe.c000066400000000000000000000002111473507761200251610ustar00rootroot00000000000000#include #include int main() { char s1[10] = "A"; const char* s2 = "BBBB"; strcat(s1, &s2[5]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-50.c000066400000000000000000000002051473507761200237050ustar00rootroot00000000000000#include #include int main() { char s1[10] = "A"; const char* s2 = "BBBB"; strcat(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-51-unsafe.c000066400000000000000000000015551473507761200251760ustar00rootroot00000000000000#include #include void foo(const char* fmt, ...) { va_list ap; int d; char c, *s; double f; va_start(ap, fmt); while (*fmt) { switch (*fmt++) { case 's': /* string */ s = va_arg(ap, char*); printf("string %s\n", s); break; case 'd': /* int */ d = va_arg(ap, int); printf("int %d\n", d); break; case 'c': /* char */ /* need a cast here since va_arg only takes fully promoted types */ c = (char)va_arg(ap, int); printf("char %c\n", c); break; case 'f': /* float */ f = va_arg(ap, double); printf("double %f\n", f); break; default: break; } } va_end(ap); } int main(int argc, char** argv) { if (argc >= 2) { foo(argv[1]); // similar to a format string vulnerability } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-51.c000066400000000000000000000014611473507761200237130ustar00rootroot00000000000000#include #include void foo(const char* fmt, ...) { va_list ap; int d; char c, *s; double f; va_start(ap, fmt); while (*fmt) { switch (*fmt++) { case 's': /* string */ s = va_arg(ap, char*); printf("string %s\n", s); break; case 'd': /* int */ d = va_arg(ap, int); printf("int %d\n", d); break; case 'c': /* char */ /* need a cast here since va_arg only takes fully promoted types */ c = (char)va_arg(ap, int); printf("char %c\n", c); break; case 'f': /* float */ f = va_arg(ap, double); printf("double %f\n", f); break; default: break; } } va_end(ap); } int main() { foo("sdcd", "my string", 1, 'a', 3, 1.123); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-52.c000066400000000000000000000002021473507761200237040ustar00rootroot00000000000000// DEFINITE UNSAFE void foo(int** x) { x[3][2] = 5; } int main(int arg, char** argv) { int b[4][4]; foo(b); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-53.c000066400000000000000000000001771473507761200237200ustar00rootroot00000000000000static int* p; int main() { int A[10]; p = &A[0]; for (int i = 0; i < 10; i++) { *p = 0; p++; } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-54.c000066400000000000000000000002361473507761200237150ustar00rootroot00000000000000static int count = 10; int main() { int tab[10] = {0}; int i; for (i = 0; i < 10; i++) { count = count >> 1; tab[count] = 1; } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-55.cpp000066400000000000000000000002051473507761200242520ustar00rootroot00000000000000struct MyStruct { bool is_down[3] = {}; }; int main(int argc, char* argv[]) { MyStruct s; s.is_down[2] = false; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-56.cpp000066400000000000000000000001121473507761200242500ustar00rootroot00000000000000class a { long b; }; class c : virtual a {}; int main() { c d(d); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-57-unsafe.c000066400000000000000000000003221473507761200251730ustar00rootroot00000000000000#include int main() { char buffer[32]; FILE* f = fopen("passwd", "r"); if (f == NULL) { puts("error"); return -1; } fgets(buffer, 33, f); puts(buffer); fclose(f); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-57.c000066400000000000000000000003221473507761200237140ustar00rootroot00000000000000#include int main() { char buffer[32]; FILE* f = fopen("passwd", "r"); if (f == NULL) { puts("error"); return -1; } fgets(buffer, 32, f); puts(buffer); fclose(f); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-58.c000066400000000000000000000002221473507761200237140ustar00rootroot00000000000000#include #include int main() { char buffer[32]; strncpy(buffer, "hello", sizeof(buffer)); puts(buffer); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-59-unsafe.c000066400000000000000000000002561473507761200252030ustar00rootroot00000000000000#include extern void __ikos_check_mem_access(const void* ptr, size_t size); int main() { char buffer[32]; __ikos_check_mem_access(buffer, 33); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-59.c000066400000000000000000000002561473507761200237240ustar00rootroot00000000000000#include extern void __ikos_check_mem_access(const void* ptr, size_t size); int main() { char buffer[32]; __ikos_check_mem_access(buffer, 32); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-6-unsafe.c000066400000000000000000000006341473507761200251130ustar00rootroot00000000000000// DEFINITE SAFE #include #define MAX_ARRAY 10 struct foo { int x; int a[MAX_ARRAY][MAX_ARRAY]; }; // To test loops int main(int argc, char** argv) { int i, j; struct foo x; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) x.a[i][j] = argc; // some unknown value here } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", x.a[i][i + 1]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-6.c000066400000000000000000000006171473507761200236350ustar00rootroot00000000000000// SAFE #include #define MAX_ARRAY 10 struct foo { int x; int a[MAX_ARRAY][MAX_ARRAY]; }; // To test loops int main(int argc, char** argv) { int i, j; struct foo x; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) x.a[i][j] = argc; // some unknown value here } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", x.a[i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-60.c000066400000000000000000000001761473507761200237150ustar00rootroot00000000000000#include #include int main() { printf("hello world\n"); printf("errno = %d\n", errno); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-61.c000066400000000000000000000011611473507761200237110ustar00rootroot00000000000000#include extern void __ikos_check_string_access(const char* str); extern void __ikos_abstract_mem(void* ptr, size_t size); int main() { __ikos_check_string_access("hello world"); // safe char buffer[4] = {0}; __ikos_check_string_access(buffer); // safe __ikos_abstract_mem(buffer, sizeof(buffer)); __ikos_check_string_access(buffer); // unsafe, but analyzer says safe strcpy(buffer, "AAA"); __ikos_check_string_access(buffer); // safe buffer[3] = 'A'; __ikos_check_string_access(buffer); // unsafe, but analyzer says safe __ikos_check_string_access(&buffer[4]); // unsafe return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-62.c000066400000000000000000000005721473507761200237170ustar00rootroot00000000000000#include extern unsigned __ikos_nondet_uint(void); extern void __ikos_assume_mem_size(const void* ptr, size_t size); int main() { int* p = (int*)malloc(__ikos_nondet_uint()); if (!p) { return -1; } *p = 1; // warning __ikos_assume_mem_size(p, sizeof(int)); *p = 2; // safe __ikos_assume_mem_size(p, sizeof(char)); *p = 3; // error return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-63.c000066400000000000000000000001601473507761200237110ustar00rootroot00000000000000#include struct S { char* p; char c; }; int main() { struct S s = {NULL, 'a'}; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-64.c000066400000000000000000000003331473507761200237140ustar00rootroot00000000000000#include #include #include extern ssize_t read(int fd, void* buffer, size_t nbytes); int main() { char buffer[32]; read(0, buffer, 32); return strncmp(buffer, "hello", 32); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-65.c000066400000000000000000000002451473507761200237170ustar00rootroot00000000000000extern int __ikos_nondet_uint(void); static unsigned char i; int main() { int A[10]; i = __ikos_nondet_uint(); if (i < 10) { A[i] = 0; } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-66.c000066400000000000000000000001561473507761200237210ustar00rootroot00000000000000int main() { unsigned int A[10]; unsigned int B[3]; if (B[2] < 10) { A[B[2]] = 1; } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-67.c000066400000000000000000000004121473507761200237150ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); static uint8_t x = 0; int main() { int A[10]; while (__ikos_nondet_int()) { x++; if (x >= 10) { x = 0; } A[x] = __ikos_nondet_int(); } A[x] = __ikos_nondet_int(); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-68.c000066400000000000000000000004231473507761200237200ustar00rootroot00000000000000void f1(void) { int tab[10]; int* p = &tab[0]; int* q = &tab[10]; for (; p != q; p++) { *p = 0; } } void f2(void) { int tab[100]; int* p = &tab[0]; int* q = &tab[100]; for (; p != q; p++) { *p = 0; } } int main() { f1(); f2(); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-69.c000066400000000000000000000007671473507761200237340ustar00rootroot00000000000000#include #include static FILE* log = NULL; static int* array = NULL; int init() { // Open a file FILE* f = fopen("log", "w"); if (f == NULL) { return EXIT_FAILURE; } log = f; // Allocate the array void* p = malloc(100 * sizeof(100)); if (p == NULL) { return EXIT_FAILURE; } array = (int*)p; return EXIT_SUCCESS; } int main() { int status = init(); if (status != EXIT_SUCCESS) { return status; } array[0] = 0; return EXIT_SUCCESS; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-7-unsafe.c000066400000000000000000000011161473507761200251100ustar00rootroot00000000000000// DEFINITE UNSAFE (overflow) #include #define MAX_ARRAY 10 struct bar { int x; float y; }; struct foo { int x; struct bar y; int a[MAX_ARRAY][MAX_ARRAY][MAX_ARRAY - 1]; }; // To test loops int main(int argc, char** argv) { int i, j, k; struct foo x; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) { for (k = 0; k < MAX_ARRAY - 1; k++) { x.a[i][j][k] = argc; // some unknown value here x.y.x = x.a[i][j][k]; } } } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", x.a[i][i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-7.c000066400000000000000000000010741473507761200236340ustar00rootroot00000000000000// SAFE #include #define MAX_ARRAY 10 struct bar { int x; float y; }; struct foo { int x; struct bar y; int a[MAX_ARRAY][MAX_ARRAY][MAX_ARRAY - 1]; }; // To test loops int main(int argc, char** argv) { int i, j, k; struct foo x; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) { for (k = 0; k < MAX_ARRAY - 1; k++) { x.a[i][j][k] = argc; // some unknown value here x.y.x = x.a[i][j][k]; } } } for (i = 0; i < MAX_ARRAY - 1; i++) { printf("%d\n", x.a[i][i][i]); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-70.c000066400000000000000000000005431473507761200237140ustar00rootroot00000000000000#include extern void __ikos_abstract_mem(void* ptr, size_t size); static int tab[10]; static int* f(int value) { for (int i = 0; i < 10; i++) { if (tab[i] == value) { return &tab[i]; } } return NULL; } int main() { __ikos_abstract_mem(&tab[0], 10 * sizeof(int)); int* p = f(42); if (p != NULL) { *p = 0; } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-8-unsafe.c000066400000000000000000000007311473507761200251130ustar00rootroot00000000000000// DEFINITE UNSAFE #include #include // We just use a pointer as an array #define MAX_ARRAY 10 // To test loops that decrements a counter int main(int argc, char** argv) { int n = MAX_ARRAY - 1; int* p = (int*)malloc(sizeof(int) * n); int i; if (!p) return 1; for (i = n - 1; i >= 0; i--) { p[i] = i; } // for underflow check // printf("%d\n", p[i+1]); // for overflow check printf("%d\n", p[MAX_ARRAY - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-8.c000066400000000000000000000007051473507761200236350ustar00rootroot00000000000000// SAFE #include #include // We just use a pointer as an array #define MAX_ARRAY 10 // To test loops that decrements a counter int main(int argc, char** argv) { int* p = (int*)malloc(sizeof(int) * MAX_ARRAY); int i; if (!p) return 1; for (i = MAX_ARRAY - 1; i >= 0; i--) { p[i] = i; } // for underflow check // printf("%d\n", p[i+1]); // for overflow check printf("%d\n", p[MAX_ARRAY - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-9a-unsafe.c000066400000000000000000000006311473507761200252540ustar00rootroot00000000000000// DEFINITE UNSAFE // // If the multidimensional array is global then LLVM generates a // single GetElementPtr instruction int p[2][2][2]; int kalman_global(void) { p[0][0][0] = 1; p[0][0][1] = 1; p[0][1][0] = 1; p[0][1][1] = 1; p[2][0][0] = 1; p[1][0][1] = 1; p[1][1][0] = 1; p[1][1][1] = 1; return p[0][1][0] + p[0][1][1]; } int main(int arg, char** argv) { return kalman_global(); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-9a.c000066400000000000000000000005611473507761200237770ustar00rootroot00000000000000// SAFE // // If the multidimensional array is global then LLVM generates a // single GetElementPtr instruction int p[2][2][2]; void kalman_global(void) { p[0][0][0] = 1; p[0][0][1] = 1; p[0][1][0] = 1; p[0][1][1] = 1; p[1][0][0] = 1; p[1][0][1] = 1; p[1][1][0] = 1; p[1][1][1] = 1; } int main(int arg, char** argv) { kalman_global(); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-9b-unsafe.c000066400000000000000000000006311473507761200252550ustar00rootroot00000000000000// DEFINITE UNSAFE // // If the multidimensional array is local then LLVM generates multiple // GetElementPtr instructions int kalman_local(void) { int p[2][2][2]; p[0][0][2] = 1; p[0][0][1] = 1; p[0][1][0] = 1; p[0][1][1] = 1; p[1][0][0] = 1; p[2][0][1] = 1; p[1][1][0] = 1; p[1][1][1] = 1; return p[0][1][0] + p[0][1][1]; } int main(int arg, char** argv) { return kalman_local(); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/boa/test-9b.c000066400000000000000000000005611473507761200240000ustar00rootroot00000000000000// SAFE // // If the multidimensional array is local then LLVM generates multiple // GetElementPtr instructions void kalman_local(void) { int p[2][2][2]; p[0][0][0] = 1; p[0][0][1] = 1; p[0][1][0] = 1; p[0][1][1] = 1; p[1][0][0] = 1; p[1][0][1] = 1; p[1][1][0] = 1; p[1][1][1] = 1; } int main(int arg, char** argv) { kalman_local(); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dbz/000077500000000000000000000000001473507761200223615ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dbz/runtest000077500000000000000000000056461473507761200240260ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the division by zero analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the division by zero analysis') t = TestManager(root=current_dir) t.add(Test('test-1-unsafe.c', 'test-1-unsafe.c', 'dbz', 'unsafe', line_checks=[(13, 'warning')])) t.add(Test('test-2-safe.c', 'test-2-safe.c', 'dbz', 'safe', line_checks=[(13, 'ok')])) t.add(Test('test-3-unsafe.c', 'test-3-unsafe.c', 'dbz', 'error', line_checks=[(16, 'error')])) t.add(Test('test-4-unsafe.c', 'test-4-unsafe.c', 'dbz', 'error', line_checks=[(6, 'error')])) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dbz/test-1-unsafe.c000066400000000000000000000002511473507761200251170ustar00rootroot00000000000000// UNSAFE extern int __ikos_nondet_int(void); int main() { int x, y; if (__ikos_nondet_int()) { y = 0; } else { y = 10; } x = 10 / y; return x; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dbz/test-2-safe.c000066400000000000000000000002471473507761200245620ustar00rootroot00000000000000// SAFE extern int __ikos_nondet_int(void); int main() { int x, y; if (__ikos_nondet_int()) { y = 3; } else { y = 10; } x = 10 / y; return x; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dbz/test-3-unsafe.c000066400000000000000000000004101473507761200251160ustar00rootroot00000000000000// DEFINITE UNSAFE extern int __ikos_nondet_int(void); int main() { int x, y, z, w; z = 7; if (__ikos_nondet_int()) { y = 0; } else { y = z - 7; } // if (__ikos_nondet_int()) // { x = 10 / y; //} w = 10 / (y + 1); return x + w; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dbz/test-4-unsafe.c000066400000000000000000000003071473507761200251240ustar00rootroot00000000000000struct my_method { int (*div)(int x); }; static int div(int x) { return 100 / x; } int main(int argc, char* argv[]) { static const struct my_method meth = {div}; meth.div(0); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dfa/000077500000000000000000000000001473507761200223345ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dfa/runtest000077500000000000000000000055131473507761200237720ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the double free analysis # # Author: Thomas Bailleux # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the double free analysis') t = TestManager(root=current_dir) t.add(Test('test-1-error.c', 'test-1-error.c', 'dfa', 'error')) t.add(Test('test-2-warnings.c', 'test-2-warnings.c', 'dfa', 'unsafe')) t.add(Test('test-3-delete.cpp', 'test-3-delete.cpp', 'dfa', 'error')) t.add(Test('test-4-safe.c', 'test-4-safe.c', 'dfa', 'safe')) t.add(Test('test-5-delete-array.cpp', 'test-5-delete-array.cpp', 'dfa', 'error')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dfa/test-1-error.c000066400000000000000000000003061473507761200247430ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main() { int* p; p = (int*)calloc(1, sizeof(int)); if (p != NULL) { *p = __ikos_nondet_int(); free(p); free(p); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dfa/test-2-warnings.c000066400000000000000000000003551473507761200254470ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main() { int* p; p = (int*)calloc(1, sizeof(int)); if (p != NULL) { *p = __ikos_nondet_int(); if (__ikos_nondet_int()) { free(p); } free(p); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dfa/test-3-delete.cpp000066400000000000000000000001321473507761200254130ustar00rootroot00000000000000class Foo {}; int main() { Foo* a = new Foo(); Foo* b = a; delete a; delete b; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dfa/test-4-safe.c000066400000000000000000000003221473507761200245310ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main() { int* p; p = (int*)calloc(1, sizeof(int)); if (p != NULL) { *p = __ikos_nondet_int(); free(p); p = NULL; } free(p); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/dfa/test-5-delete-array.cpp000066400000000000000000000001551473507761200265360ustar00rootroot00000000000000class Foo {}; int main() { class Foo* a = new Foo[42]; class Foo* b = a; delete[] a; delete[] b; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/fca/000077500000000000000000000000001473507761200223335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/fca/runtest000077500000000000000000000051531473507761200237710ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the function call analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the function call analysis') t = TestManager(root=current_dir) t.add(Test('test-1-warning.c', 'test-1-warning.c', 'fca', 'unsafe')) t.add(Test('test-2-error.c', 'test-2-error.c', 'fca', 'error')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/fca/test-1-warning.c000066400000000000000000000010651473507761200252610ustar00rootroot00000000000000#include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); // void(int) static void a(int x) {} // void(double) static void b(double x) {} // void(int*) static void c(int* x) {} // void(int*) typedef void (*fun_ptr_t)(int*); int main() { void* vtable[3]; vtable[0] = (void*)a; vtable[1] = (void*)b; vtable[2] = (void*)c; int nd = __ikos_nondet_int(); if (nd >= 0 && nd <= 2) { fun_ptr_t f = (fun_ptr_t)vtable[nd]; f(NULL); // can only call c() because other functions have a wrong signature } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/fca/test-2-error.c000066400000000000000000000007721473507761200247520ustar00rootroot00000000000000#include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); // void(int) static void a(int x) {} // void(long) static void b(long x) {} // void(double) static void c(double x) {} // void(int*) typedef void (*fun_ptr_t)(int*); int main() { void* vtable[3]; vtable[0] = (void*)a; vtable[1] = (void*)b; vtable[2] = (void*)c; int nd = __ikos_nondet_int(); if (nd >= 0 && nd <= 2) { fun_ptr_t f = (fun_ptr_t)vtable[nd]; f(NULL); // error } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/libruntest.py000066400000000000000000000401021473507761200243440ustar00rootroot00000000000000############################################################################### # # Library for ikos regression tests # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import atexit import os import shutil import sqlite3 import subprocess import sys import tempfile USE_COLORS = True INTERACTIVE = True VERBOSE = False CLANG = 'clang' IKOS_PP = 'ikos-pp' IKOS_ANALYZER = 'ikos-analyzer' # available ikos analyses ANALYSES = ( 'boa', 'dbz', 'nullity', 'prover', 'upa', 'uva', 'sio', 'uio', 'shc', 'poa', 'pcmp', 'sound', 'fca', 'dca', 'dfa', 'dbg', 'watch', ) # available colors COLORS = { 'grey': 0, 'red': 1, 'green': 2, 'yellow': 3, 'blue': 4, 'magenta': 5, 'cyan': 6, 'white': 7 } # available attributes ATTRIBUTES = { 'bold': 1, 'dark': 2, 'underline': 4, 'blink': 5, 'reverse': 7, 'concealed': 8 } def printf(fmt, *args, **kwargs): file = kwargs.pop('file', sys.stdout) file.write(fmt % args if args else fmt) file.flush() def colorize(text, color=None, on_color=None, attrs=None): ''' Colorize text. >>> colorize('Hello, World!', 'red', 'grey', ['bold', 'blink']) '\x1b[5m\x1b[1m\x1b[40m\x1b[31mHello, World!\x1b[0m' >>> colorize('Hello, World!', 'green') '\x1b[32mHello, World!\x1b[0m' ''' if USE_COLORS: if color: text = '\033[%dm%s' % (30 + COLORS[color], text) if on_color: text = '\033[%dm%s' % (40 + COLORS[on_color], text) if attrs: for attr in attrs: text = '\033[%dm%s' % (ATTRIBUTES[attr], text) text += '\033[0m' return text def bold(s): return colorize(s, attrs=['bold']) def red(s): return colorize(s, 'red', attrs=['bold']) def green(s): return colorize(s, 'green', attrs=['bold']) def yellow(s): return colorize(s, 'yellow', attrs=['bold']) def is_executable(fpath): return fpath and os.path.isfile(fpath) and os.access(fpath, os.X_OK) def which(program): ''' Try to find program in the PATH, otherwise return None. >>> which('cat') '/bin/cat' ''' fpath, fname = os.path.split(program) if fpath: if is_executable(program): return program else: for path in os.environ['PATH'].split(os.pathsep): exe_file = os.path.join(path, program) if is_executable(exe_file): return exe_file return None def find_clang(): path = which(CLANG) assert is_executable(path), 'could not find clang' return path def find_ikos_pp(): path = which(IKOS_PP) assert is_executable(path), 'could not find ikos-pp' return path def find_ikos_analyzer(): path = which(IKOS_ANALYZER) assert is_executable(path), 'could not find ikos-analyzer' return path def clang_emit_llvm_flags(): ''' Clang flags to emit llvm bitcode ''' # see analyzer.clang_emit_llvm_flags() return ['-c', '-emit-llvm'] def clang_ikos_flags(): ''' Clang flags for ikos ''' # see analyzer.clang_ikos_flags() return [ # enable clang warnings '-Wall', # disable source code fortification '-U_FORTIFY_SOURCE', '-D_FORTIFY_SOURCE=0', # flag for intrinsic.h '-D__IKOS__', # compile in debug mode '-g', # disable optimizations '-O0', # disable the 'optnone' attribute # see https://bugs.llvm.org/show_bug.cgi?id=35950#c10 '-Xclang', '-disable-O0-optnone', ] class Result: OK = 0 WARNING = 1 ERROR = 2 UNREACHABLE = 3 class Database: def __init__(self, path): self.db = sqlite3.connect(path) self.cursor = self.db.cursor() def __enter__(self): return self def __exit__(self, *args): self.db.close() def get_num_checks(self, result=None): where = ('WHERE status=%d' % result) if result else '' self.cursor.execute('SELECT COUNT(*) FROM checks %s' % where) return self.cursor.fetchone()[0] def get_line_status(self, line): self.cursor.execute('SELECT checks.status FROM checks INNER JOIN statements ON checks.statement_id = statements.id WHERE statements.line=%d' % line) return [row[0] for row in self.cursor.fetchall()] class TestResult: def __init__(self, code, comments=None): assert code in ('PASS', 'PASS_IMPROVE', 'FAIL') self.code = code self.comments = comments or [] def add_comment(self, comment): self.comments.append(comment) class Test: def __init__(self, filename, description, analyses, result, expected=None, domain=None, opt_level=None, entry_points=None, procedural=None, options=None, line_checks=None): if not isinstance(analyses, list): analyses = [analyses] assert all(a in ANALYSES for a in analyses) assert result in ('safe', 'unsafe', 'error') assert expected in (None, 'safe', 'unsafe', 'error') self.filename = filename self.description = description self.result = result self.expected = expected or result self.analyses = analyses self.domain = domain or 'interval' self.opt_level = opt_level or 'basic' self.entry_points = entry_points or ('main',) self.procedural = procedural or 'inter' self.options = options or [] self.line_checks = line_checks or [] def run(self, root, output_db): fullpath = os.path.join(root, self.filename) assert os.path.exists(fullpath) # create working directory wd = tempfile.mkdtemp(prefix='ikos-%s' % self.filename) atexit.register(shutil.rmtree, path=wd) # run clang bc_path = os.path.join(wd, '%s.bc' % self.filename) cmd = [find_clang()] cmd += clang_emit_llvm_flags() cmd += clang_ikos_flags() cmd += [fullpath, '-o', bc_path] if self.filename.endswith('.cpp'): cmd.append('-std=c++17') subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # run ikos preprocessor pp_path = os.path.join(wd, '%s.pp.bc' % self.filename) cmd = [find_ikos_pp(), '-opt=%s' % self.opt_level, '-entry-points=%s' % ','.join(self.entry_points), bc_path, '-o', pp_path] subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # run ikos analyzer cmd = [find_ikos_analyzer(), '-a=%s' % ','.join(self.analyses), '-d=%s' % self.domain, '-entry-points=%s' % ','.join(self.entry_points), '-proc=%s' % self.procedural] cmd.extend(self.options) if self.opt_level == 'aggressive': cmd.append('-allow-dbg-mismatch') if 'gauge' in self.domain: cmd.append('-add-loop-counters') cmd += [pp_path, '-o', output_db] subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) with Database(output_db) as db: # Get the global result errors = db.get_num_checks(Result.ERROR) warnings = db.get_num_checks(Result.WARNING) if errors == 0 and warnings == 0: result = 'safe' elif errors != 0: result = 'error' else: result = 'unsafe' # Set the test result (passed or failed) ret = TestResult('PASS') if result not in (self.result, self.expected): ret.code = 'FAIL' ret.add_comment('Got %d errors and %d warnings, was expecting "%s".' % (errors, warnings, self.expected)) elif result == self.result and result != self.expected: ret.code = 'PASS_IMPROVE' ret.add_comment('improvement: IKOS returned the right result ' '(%s) and not the expected one (%s).' % (self.result, self.expected)) # Line by line check for line_check in self.line_checks: if len(line_check) == 3: line_num, line_result, line_expected = line_check elif len(line_check) == 2: line_num, line_result = line_check line_expected = line_result else: assert False, 'Unexpected line_checks' assert line_result in ('ok', 'warning', 'error', 'unreachable') assert line_expected in ('ok', 'warning', 'error', 'unreachable') result = db.get_line_status(line_num) if Result.ERROR in result: result = 'error' elif Result.WARNING in result: result = 'warning' elif Result.OK in result and all(s in (Result.OK, Result.UNREACHABLE) for s in result): result = 'ok' elif result and all(s == Result.UNREACHABLE for s in result): result = 'unreachable' else: result = 'unknown' if result not in (line_result, line_expected): ret.code = 'FAIL' ret.add_comment('Got status "%s" for line %d, was expecting "%s".' % (result, line_num, line_expected)) elif result == line_result and line_result != line_expected: if ret.code == 'PASS': ret.code = 'PASS_IMPROVE' ret.add_comment('improvement: IKOS returned the right result ' '(%s) for line %d and not the expected one (%s).' % (line_result, line_num, line_expected)) if ret.code == 'FAIL': ret.comments.insert(0, 'Running %r' % cmd) return ret class TestManager: def __init__(self, root): self.root = root self.tests = [] self.results = {'PASS': 0, 'PASS_IMPROVE': 0, 'FAIL': 0} def add(self, test): self.tests.append(test) def run(self): printf(bold('Running tests...\n')) # output database _, output_db = tempfile.mkstemp(suffix='.db', prefix='ikos-output-') atexit.register(lambda: os.unlink(output_db)) for t in self.tests: printf(' %s ... ', t.description) if INTERACTIVE: printf('\n') self.print_progress() # Move the cursor right after the '...' printf('\r\033[A\033[%dC' % len(' %s ... ' % t.description)) result = t.run(self.root, output_db) self.results[result.code] += 1 if result.code == 'FAIL': printf(red(('Failed\n'))) elif result.code == 'PASS': printf(green('Passed\n')) elif result.code == 'PASS_IMPROVE': printf(yellow('Passed with improvements!\n')) else: assert False, 'unknown result' if INTERACTIVE: # Clear everything down the cursor printf('\033[J') if VERBOSE: for line in result.comments: printf(' %s\n' % line) self.print_result() exit(self.results['FAIL']) def get_num_tests(self): return len(self.tests) def get_num_done(self): return self.results['PASS'] + self.results['PASS_IMPROVE'] + self.results['FAIL'] def print_result(self): printf(bold('Results:\n')) if self.results['FAIL'] == 0: if self.results['PASS_IMPROVE'] > 0: printf(green(' %d tests passed successfully (with %d improvement(s)).\n' % (self.results['PASS'] + self.results['PASS_IMPROVE'], self.results['PASS_IMPROVE']))) else: printf(green(' %d tests passed successfully.\n' % self.results['PASS'])) else: printf(red(' %d/%d tests failed.\n' % (self.results['FAIL'], self.get_num_tests()))) def print_progress(self): percent = 100.0 * self.get_num_done() / self.get_num_tests() full_width = 50 width = int(full_width * percent / 100.0) progressbar = '[' + '#' * width + ' ' * (full_width - width) + '] %d%%' % int(percent) printf(progressbar) def parse_args(description=None): parser = argparse.ArgumentParser(description=description) parser.add_argument('--verbose', '-v', dest='verbose', help='Verbose mode', action='store_true', default=False) parser.add_argument('--no-colors', dest='no_colors', help='Disable colors', action='store_true', default=False) parser.add_argument('--no-interactive', dest='no_interactive', help='Disable interactive mode', action='store_true', default=False) parser.add_argument('--clang', dest='clang', help='Path to the clang binary', default='clang') parser.add_argument('--ikos-pp', dest='ikos_pp', help='Path to the ikos-pp binary', default='ikos-pp') parser.add_argument('--ikos-analyzer', dest='ikos_analyzer', help='Path to the ikos-analyzer binary', default='ikos-analyzer') args = parser.parse_args() global VERBOSE, USE_COLORS, INTERACTIVE, CLANG, IKOS_PP, IKOS_ANALYZER VERBOSE = args.verbose USE_COLORS = False if args.no_colors else os.isatty(sys.stdout.fileno()) INTERACTIVE = False if args.no_interactive else os.isatty(sys.stdout.fileno()) CLANG = args.clang IKOS_PP = args.ikos_pp IKOS_ANALYZER = args.ikos_analyzer NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/000077500000000000000000000000001473507761200223605ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/astree.c000066400000000000000000000005501473507761200240070ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); typedef union _u { int a; char b[4]; } my_union; my_union U; typedef struct _x { unsigned int a : 1; unsigned int b : 1; } bit; int main() { bit z; z.b = 0; z.a = 1; __ikos_assert((z.a == 1)); U.b[0] = 1; U.b[1] = 1; U.b[2] = 1; U.b[3] = 1; __ikos_assert((U.a == 0x1010101)); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/mine-lctes06.c000066400000000000000000000010301473507761200247240ustar00rootroot00000000000000// SAFE typedef unsigned char uint8; typedef unsigned short uint16; // LCTES'06 example static union { struct { uint8 al; uint8 ah; uint8 bl; uint8 bh; } b; struct { uint16 ax; uint16 bx; } w; } regs; extern void __ikos_assert(int); int main() { regs.w.ax = 5; //(1) if (!regs.b.ah) /*(2)*/ regs.b.bl = regs.b.al; /*(3)*/ else /*(4)*/ regs.b.bh = regs.b.al; /*(5)*/ __ikos_assert(regs.w.ax == 5); __ikos_assert(regs.w.bx == 5); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/runtest000077500000000000000000000176331473507761200240240ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing analyses with memory level of precision. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for analyses with memory level of precision') t = TestManager(root=current_dir) t.add(Test('test-0-safe.c', 'test-0-safe.c', 'prover', 'safe')) t.add(Test('test-0-unsafe.c', 'test-0-unsafe.c', 'prover', 'error')) t.add(Test('test-1-safe.c', 'test-1-safe.c', 'prover', 'safe', expected='unsafe')) t.add(Test('test-1-unsafe.c', 'test-1-unsafe.c', 'prover', 'error', expected='unsafe')) t.add(Test('test-2-safe.c', 'test-2-safe.c', 'boa', 'safe')) t.add(Test('test-2-unsafe.c', 'test-2-unsafe.c', 'boa', 'error', line_checks=[(28, 'error')])) t.add(Test('test-3-safe.c', 'test-3-safe.c', 'boa', 'safe')) t.add(Test('test-3-unsafe.c', 'test-3-unsafe.c', 'boa', 'error', line_checks=[(15, 'error')])) t.add(Test('test-4-safe.c', 'test-4-safe.c', 'prover', 'safe')) t.add(Test('test-5-safe.c', 'test-5-safe.c', 'prover', 'safe')) t.add(Test('test-5-unsafe.c', 'test-5-unsafe.c', 'prover', 'error')) t.add(Test('test-6-safe.c', 'test-6-safe.c', 'prover', 'safe')) t.add(Test('test-7-safe.c', 'test-7-safe.c', 'prover', 'safe')) t.add(Test('test-7-unsafe.c', 'test-7-unsafe.c', 'prover', 'error', line_checks=[(16, 'ok'), (17, 'ok'), (40, 'ok'), (41, 'error')])) t.add(Test('test-8-safe.c', 'test-8-safe.c', 'prover', 'safe')) t.add(Test('test-9-safe.c', 'test-9-safe.c', 'prover', 'safe')) t.add(Test('test-9-unsafe.c', 'test-9-unsafe.c', 'prover', 'error', line_checks=[(22, 'error'), (24, 'error'), (30, 'ok')])) t.add(Test('test-10-safe.c', 'test-10-safe.c', 'prover', 'safe')) t.add(Test('test-10-unsafe.c', 'test-10-unsafe.c', 'prover', 'error')) t.add(Test('test-11.c', 'test-11.c', 'prover', 'safe')) t.add(Test('test-12.c', 'test-12.c', 'prover', 'safe')) t.add(Test('test-14a.c', 'test-14a.c', 'prover', 'safe')) t.add(Test('test-14b.c', 'test-14b.c', 'prover', 'safe')) t.add(Test('test-14c.c', 'test-14c.c', 'prover', 'safe', expected='unsafe')) t.add(Test('test-15-safe.c', 'test-15-safe.c', 'prover', 'safe')) t.add(Test('test-15-unsafe.c', 'test-15-unsafe.c', 'prover', 'unsafe')) t.add(Test('test-16.c', 'test-16.c', 'prover', 'safe')) t.add(Test('test-17.c', 'test-17.c', 'prover', 'safe')) t.add(Test('test-20.c', 'test-20.c', 'prover', 'safe')) t.add(Test('test-21.c', 'test-21.c', 'boa', 'safe', expected='unsafe', line_checks=[(15, 'ok'), (16, 'ok'), (19, 'ok'), (20, 'ok', 'warning')])) t.add(Test('test-22.c', 'test-22.c', 'prover', 'safe')) t.add(Test('test-23.c', 'test-23.c', 'prover', 'safe')) t.add(Test('test-24.c', 'test-24.c', 'prover', 'safe')) t.add(Test('test-25.c', 'test-25.c', 'prover', 'safe')) t.add(Test('test-26a-safe.c', 'test-26a-safe.c', 'prover', 'safe')) t.add(Test('test-26a-unsafe.c', 'test-26a-unsafe.c', 'prover', 'unsafe', line_checks=[(28, 'warning'), (29, 'warning')])) t.add(Test('test-26b-safe.c', 'test-26b-safe.c', 'prover', 'safe')) t.add(Test('test-26b-unsafe.c', 'test-26b-unsafe.c', 'prover', 'unsafe', line_checks=[(34, 'warning'), (35, 'warning')])) t.add(Test('test-26c.c', 'test-26c.c', 'prover', 'safe')) t.add(Test('test-28-safe.c', 'test-28-safe.c', 'prover', 'safe', expected='unsafe', line_checks=[(43, 'ok', 'warning'), (48, 'ok'), (50, 'ok'), (52, 'ok'), (53, 'ok'), (54, 'ok'), (67, 'ok')])) t.add(Test('test-28-unsafe.c', 'test-28-unsafe.c', 'prover', 'error', line_checks=[(28, 'ok'), (30, 'ok'), (32, 'ok'), (33, 'ok'), (34, 'error')])) t.add(Test('test-29-safe.c', 'test-29-safe.c', 'prover', 'safe')) t.add(Test('test-29-unsafe-1.c', 'test-29-unsafe-1.c', 'prover', 'error', expected='unsafe')) t.add(Test('test-29-unsafe-2.c', 'test-29-unsafe-2.c', 'prover', 'error', expected='unsafe')) t.add(Test('test-30-safe.c', 'test-30-safe.c (interval)', 'prover', 'safe', expected='unsafe', line_checks=[(12, 'ok', 'warning'), (13, 'ok', 'warning')], domain='interval')) t.add(Test('test-30-safe.c', 'test-30-safe.c (gauge-interval-congruence)', 'prover', 'safe', line_checks=[(12, 'ok'), (13, 'ok')], domain='gauge-interval-congruence')) t.add(Test('test-30-unsafe.c', 'test-30-unsafe.c (interval)', 'prover', 'unsafe', line_checks=[(14, 'ok', 'warning'), (15, 'ok', 'warning'), (16, 'warning')], domain='interval')) t.add(Test('test-30-unsafe.c', 'test-30-unsafe.c (gauge-interval-congruence)', 'prover', 'unsafe', line_checks=[(14, 'ok'), (15, 'ok'), (16, 'warning')], domain='gauge-interval-congruence')) t.add(Test('test-31-safe.c', 'test-31-safe.c', 'prover', 'safe')) t.add(Test('test-32-safe.c', 'test-32-safe.c', 'prover', 'safe')) t.add(Test('mine-lctes06.c', 'mine-lctes06.c', 'prover', 'safe', expected='unsafe', line_checks=[(29, 'ok'), (30, 'ok', 'warning')])) t.add(Test('astree.c', 'astree.c', 'prover', 'safe', expected='unsafe', line_checks=[(19, 'ok', 'warning'), (24, 'ok', 'warning')])) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-0-safe.c000066400000000000000000000006001473507761200245500ustar00rootroot00000000000000// SAFE #include #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int* p = (int*)malloc(sizeof(int)); if (p == NULL) exit(0); *p = 0; while (__ikos_nondet_int()) { if (__ikos_nondet_int()) *p = 1; if (__ikos_nondet_int()) *p = 5; } __ikos_assert(*p >= 0 && *p <= 5); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-0-unsafe.c000066400000000000000000000005521473507761200251210ustar00rootroot00000000000000// DEFINITE UNSAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int* p = (int*)malloc(sizeof(int)); if (p == 0) exit(0); *p = 0; while (__ikos_nondet_int()) { if (__ikos_nondet_int()) *p = 1; if (__ikos_nondet_int()) *p = 3; } __ikos_assert(*p == 4); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-1-safe.c000066400000000000000000000003111473507761200245500ustar00rootroot00000000000000// SAFE #include // all zeros extern void __ikos_assert(int); int main() { int a[10]; int64_t i; for (i = 0; i < 10; i++) a[i] = 0; __ikos_assert(a[9] == 0); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-1-unsafe.c000066400000000000000000000003241473507761200251170ustar00rootroot00000000000000// DEFINITE UNSAFE #include // all zeros extern void __ikos_assert(int); int main() { int a[10]; int64_t i; for (i = 0; i < 10; i++) a[i] = 0; __ikos_assert(a[9] == 5); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-10-safe.c000066400000000000000000000007041473507761200246360ustar00rootroot00000000000000// SAFE #include #include extern void __ikos_assert(int); struct foo { int a; int b; }; struct foo* x; int main(int argc, char** argv) { x = (struct foo*)malloc(sizeof(struct foo)); if (!x) return 0; x->a = 5; x->b = x->a + 7; x->a++; // printf("%d %d\n",x->a, x->b); __ikos_assert(x->a == 6 && x->b == 12); /* x->a = 5; x->b = 10; __ikos_assert (x->a == 5 && x->b == 10); */ return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-10-unsafe.c000066400000000000000000000005511473507761200252010ustar00rootroot00000000000000// DEFINITE UNSAFE #include #include extern void __ikos_assert(int); struct foo { int a; int b; }; struct foo* x; int main(int argc, char** argv) { x = (struct foo*)malloc(sizeof(struct foo)); if (x == 0) exit(0); x->a = 5; x->b = x->a + 7; x->a = x->a + 2; __ikos_assert(x->a == 6 && x->b == 12); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-11.c000066400000000000000000000003601473507761200237210ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); int main() { int a[10]; int b[10]; int* x = &a[0]; int* y = &b[0]; x = x + 2; *x = 3; x++; x--; y = y + 4; *y = 19; y = x; *y = 5; __ikos_assert(*x == 5); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-12.c000066400000000000000000000011361473507761200237240ustar00rootroot00000000000000// SAFE #include #include extern void __ikos_assert(int); struct foo { int a[5]; int k; int b[10]; }; struct foo* x; int main(int argc, char** argv) { x = (struct foo*)malloc(sizeof(struct foo)); if (!x) return 0; x->a[2] = 5; x->a[3] = 15; x->a[4] = 25; int* y = &(x->a[0]); y = y + 4; x->b[0] = 333; x->b[5] = 555; int* z = &(x->b[0]); __ikos_assert(*y == 25 && *z == 333); z = z + 5; __ikos_assert(*z == 555 && *z == x->b[5]); z = y; z++; *z = 888; __ikos_assert(x->a[5] == 888); __ikos_assert(*z == x->a[5]); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-14a.c000066400000000000000000000006011473507761200240630ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int a[10]; int b[10]; int* x; a[0] = 5; b[0] = 10; if (__ikos_nondet_int()) x = &a[0]; else x = &b[0]; //__ikos_assert ( *x == 5); // warning //__ikos_assert ( *x == 10); // warning __ikos_assert(*x >= 5 && *x <= 10); // safe return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-14b.c000066400000000000000000000010321473507761200240630ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int a[10]; int b[10]; int c[10]; int *x, *z; a[0] = 5; b[0] = 10; c[0] = 30; if (__ikos_nondet_int()) { x = &a[0]; z = &c[0]; } else { x = &b[0]; z = &c[0]; } *x = 20; *z = 50; __ikos_assert(a[0] >= 5 && a[0] <= 20); // safe __ikos_assert(b[0] >= 10 && b[0] <= 20); // safe __ikos_assert(c[0] == 50); // safe // __ikos_assert ( *x == 20); // warning *x = [5,20] return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-14c.c000066400000000000000000000004131473507761200240660ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int a[10]; int* x; a[0] = 5; a[1] = 10; if (__ikos_nondet_int()) x = &a[0]; else x = &a[1]; __ikos_assert(*x >= 5 && *x <= 10); // safe return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-15-safe.c000066400000000000000000000007151473507761200246450ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int addOne(int x) { return x + 1; } int addTwo(int x) { return x + 2; } int addThree(int x) { return x + 3; } int main() { int (*fPtr)(int); int x = 8; if (__ikos_nondet_int()) { fPtr = &addOne; } else if (__ikos_nondet_int()) { fPtr = &addTwo; } else { fPtr = &addThree; } int res = fPtr(x); __ikos_assert(res >= 9 && res <= 11); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-15-unsafe.c000066400000000000000000000007311473507761200252060ustar00rootroot00000000000000// DEFINITE UNSAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int addOne(int x) { return x + 1; } int addTwo(int x) { return x + 2; } int addThree(int x) { return x + 3; } int main() { int (*fPtr)(int); int x = 8; if (__ikos_nondet_int()) { fPtr = &addOne; } else if (__ikos_nondet_int()) { fPtr = &addTwo; } else { fPtr = &addThree; } int res = fPtr(x); __ikos_assert(res >= 10 && res <= 11); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-16.c000066400000000000000000000011471473507761200237320ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int addOne(int x) { return x + 1; } int addTwo(int x) { return x + 2; } int addThree(int x) { return x + 3; } int main() { int (*fPtr_array[2])(int); int x = 8; fPtr_array[0] = &addOne; if (__ikos_nondet_int()) { fPtr_array[1] = &addTwo; } else { fPtr_array[1] = &addThree; } int res1 = fPtr_array[0](x); int res2 = fPtr_array[1](x); __ikos_assert(res1 == 9); __ikos_assert(res1 >= 9 && res1 <= 11); __ikos_assert(res2 >= 10 && res2 <= 11); __ikos_assert(res2 >= 9 && res2 <= 11); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-17.c000066400000000000000000000012051473507761200237260ustar00rootroot00000000000000// SAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int* array[2]; int* p1 = (int*)malloc(sizeof(int)); int* p2 = (int*)malloc(sizeof(int)); int* p3 = (int*)malloc(sizeof(int)); if (!p1 || !p2 || !p3) return 0; *p1 = 9; *p2 = 10; *p3 = 11; array[0] = p1; if (__ikos_nondet_int()) { array[1] = p2; } else { array[1] = p3; } int res1 = *(array[0]); int res2 = *(array[1]); __ikos_assert(res1 == 9); __ikos_assert(res1 >= 9 && res1 <= 11); __ikos_assert(res2 >= 10 && res2 <= 11); __ikos_assert(res2 >= 9 && res2 <= 11); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-2-safe.c000066400000000000000000000004641473507761200245620ustar00rootroot00000000000000// SAFE int main(int argc, char** argv) { int a[2]; int b[3]; int c[10] = {0}; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 7; b[2] = 7; b[1] = 5; int* p = &a[0]; int* q = &b[0]; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } return c[*p + *(q - 1)]; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-2-unsafe.c000066400000000000000000000005001473507761200251140ustar00rootroot00000000000000// DEFINITE UNSAFE int main(int argc, char** argv) { int a[2]; int b[3]; int c[10] = {0}; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 7; b[2] = 7; // b[1]=5; int* p = &a[0]; int* q = &b[0]; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } return c[*p + *(q - 1)]; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-20.c000066400000000000000000000006151473507761200237240ustar00rootroot00000000000000// SAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int *p, *q, *r; p = (int*)malloc(sizeof(int)); q = (int*)malloc(sizeof(int)); r = (int*)malloc(sizeof(int)); if (!p || !q || !r) return 0; *q = 3; *r = 5; if (__ikos_nondet_int()) p = q; else p = r; __ikos_assert(*p >= 3 && *p <= 5); return *p; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-21.c000066400000000000000000000004031473507761200237200ustar00rootroot00000000000000// SAFE #include int main() { int n; int **p, *r; int* a[10]; for (n = 0; n < 10; n++) { p = &a[n]; r = (int*)malloc(sizeof(int)); if (r == NULL) { return 0; } *r = n; *p = r; } r = a[9]; return *r; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-22.c000066400000000000000000000013051473507761200237230ustar00rootroot00000000000000// SAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int* foo(int* a, int* b) { int* res; if (__ikos_nondet_int()) res = a; else res = b; return res; } int main() { int *p, *q, *r; int *a, *b, *c; p = (int*)malloc(sizeof(int)); q = (int*)malloc(sizeof(int)); r = (int*)malloc(sizeof(int)); if (!p || !q || !r) return 0; a = (int*)malloc(sizeof(int)); b = (int*)malloc(sizeof(int)); c = (int*)malloc(sizeof(int)); if (!a || !b || !c) return 0; *q = 3; *r = 5; *b = 10; *c = 15; p = foo(q, r); a = foo(b, c); __ikos_assert(*p >= 3 && *p <= 5); __ikos_assert(*a >= 10 && *a <= 15); return *p; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-23.c000066400000000000000000000006661473507761200237350ustar00rootroot00000000000000// SAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); struct foo { int p; int q; }; int main() { struct foo* x = (struct foo*)malloc(sizeof(struct foo)); if (x == 0) exit(0); x->p = 9; x->q = 20; int p1, p2; if (__ikos_nondet_int()) p1 = x->p; else p1 = x->q; p2 = x->q; __ikos_assert(p1 >= 9 && p1 <= 20); __ikos_assert(p2 == 20); return p1 + p2; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-24.c000066400000000000000000000010641473507761200237270ustar00rootroot00000000000000// SAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); struct foo { int* p; int* q; }; int main() { struct foo* x = (struct foo*)malloc(sizeof(struct foo)); if (!x) return 0; x->p = (int*)malloc(sizeof(int)); x->q = (int*)malloc(sizeof(int)); if (!(x->p) || !(x->q)) return 0; *(x->p) = 9; *(x->q) = 20; int *p1, *p2; if (__ikos_nondet_int()) p1 = x->p; else p1 = x->q; p2 = x->q; __ikos_assert(*p1 >= 9 && *p1 <= 20); __ikos_assert(*p2 == 20); return *p1 + *p2; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-25.c000066400000000000000000000005231473507761200237270ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); struct foo { int p; int q; }; struct foo x; int main() { x.p = 9; x.q = 20; int p1, p2; if (__ikos_nondet_int()) p1 = x.p; else p1 = x.q; p2 = x.q; __ikos_assert(p1 >= 9 && p1 <= 20); __ikos_assert(p2 == 20); return p1 + p2; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-26a-safe.c000066400000000000000000000006711473507761200250110ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int* fst(int* a, int* b) { return a; } int* snd(int* a, int* b) { return b; } int main() { int x = 5; int y = 7; int *p, *q; if (__ikos_nondet_int()) p = &x; else p = &y; if (__ikos_nondet_int()) q = fst(&x, &y); else q = snd(&x, &y); __ikos_assert(*p >= 5 && *p <= 7); __ikos_assert(*q >= 5 && *q <= 7); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-26a-unsafe.c000066400000000000000000000006451473507761200253550ustar00rootroot00000000000000// UNSAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int* fst(int* a, int* b) { return a; } int* snd(int* a, int* b) { return b; } int main() { int x = 5; int y = 7; int *p, *q; if (__ikos_nondet_int()) p = &x; else p = &y; if (__ikos_nondet_int()) q = fst(&x, &y); else q = snd(&x, &y); __ikos_assert(*p == 5); __ikos_assert(*q == 7); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-26b-safe.c000066400000000000000000000010551473507761200250070ustar00rootroot00000000000000// SAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int fst(int* a, int* b) { return *a; } int snd(int* a, int* b) { return *b; } int main() { int x = 5; int y = 7; int* p = (int*)malloc(sizeof(int)); int* q = (int*)malloc(sizeof(int)); if (!p || !q) return 0; if (__ikos_nondet_int()) *p = x; else *p = y; if (__ikos_nondet_int()) *q = fst(&x, &y); else *q = snd(&x, &y); __ikos_assert(*p >= 5 && *p <= 7); __ikos_assert(*q >= 5 && *q <= 7); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-26b-unsafe.c000066400000000000000000000010311473507761200253440ustar00rootroot00000000000000// UNSAFE #include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int fst(int* a, int* b) { return *a; } int snd(int* a, int* b) { return *b; } int main() { int x = 5; int y = 7; int* p = (int*)malloc(sizeof(int)); int* q = (int*)malloc(sizeof(int)); if (!p || !q) return 0; if (__ikos_nondet_int()) *p = x; else *p = y; if (__ikos_nondet_int()) *q = fst(&x, &y); else *q = snd(&x, &y); __ikos_assert(*p == 7); __ikos_assert(*q == 7); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-26c.c000066400000000000000000000007041473507761200240740ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int* id(int* p) { return p; } int main() { int x = 5; int y = 7; int* a[1]; int *p, *q; if (__ikos_nondet_int()) p = id(&x); else p = id(&y); if (__ikos_nondet_int()) q = id(&x); else q = id(&y); if (__ikos_nondet_int()) a[0] = p; // &x; else a[0] = q; // &y; __ikos_assert(*(a[0]) >= 5 && *(a[0]) <= 7); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-28-safe.c000066400000000000000000000024101473507761200246430ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); extern int __ikos_nondet_int(void); static struct { int stopExecutionFlag; int isrOverrun; int overrunFlags[10]; const char* errmsg; } buf; typedef struct { int x; int y; } foo; typedef struct { int a; int b; int c; int d[5]; } FOO_BAR; FOO_BAR foo_M_; FOO_BAR* foo_M = &foo_M_; void test1() { buf.isrOverrun++; if (buf.isrOverrun > 0 /*buf.isrOverrun++*/) { if (__ikos_nondet_int()) buf.stopExecutionFlag = 0; else buf.stopExecutionFlag = 1; } while (!buf.stopExecutionFlag) { if (__ikos_nondet_int()) buf.stopExecutionFlag = 0; else buf.stopExecutionFlag = 1; } __ikos_assert(buf.stopExecutionFlag >= 0 && buf.stopExecutionFlag <= 1); } void test2() { foo_M->a = 5; __ikos_assert(foo_M->a == 5); foo_M->b = 7; __ikos_assert(foo_M->b == 7); foo_M->c = foo_M->a + foo_M->b; __ikos_assert(foo_M->a == 5); __ikos_assert(foo_M->b == 7); __ikos_assert(foo_M->c == 12); // __ikos_assert (foo_M->c > 12); } FOO_BAR* init() { return foo_M; } void test3() { FOO_BAR* M = init(); M->d[2] = 3; M->d[3] = 4; M->d[4] = M->d[2] + M->d[3]; __ikos_assert(M->d[4] == 7); } int main() { test1(); // SAFE test2(); test3(); // SAFE return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-28-unsafe.c000066400000000000000000000011321473507761200252060ustar00rootroot00000000000000// DEFINITE UNSAFE extern void __ikos_assert(int); static struct { int stopExecutionFlag; int isrOverrun; int overrunFlags[10]; const char* errmsg; } buf; typedef struct { int x; int y; } foo; typedef struct { int a; int b; int c; int d[5]; } FOO_BAR; FOO_BAR foo_M_; FOO_BAR* foo_M = &foo_M_; void test2() { foo_M->a = 5; __ikos_assert(foo_M->a == 5); foo_M->b = 7; __ikos_assert(foo_M->b == 7); foo_M->c = foo_M->a + foo_M->b; __ikos_assert(foo_M->a == 5); __ikos_assert(foo_M->b == 7); __ikos_assert(foo_M->c > 12); } int main() { test2(); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-29-safe.c000066400000000000000000000004201473507761200246430ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); struct point { int x; int y; int z; }; int main(int argc, char** argv) { struct point p; p.x = 1; p.y = 2; p.z = 8; int* q = (int*)(((char*)&p.x) + 2); *q = 3; __ikos_assert(p.z == 8); // SAFE return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-29-unsafe-1.c000066400000000000000000000004361473507761200253530ustar00rootroot00000000000000// DEFINITE UNSAFE extern void __ikos_assert(int); struct point { int x; int y; int z; }; int main(int argc, char** argv) { struct point p; p.x = 1; p.y = 2; p.z = 8; int* q = (int*)(((char*)&p.x) + 2); *q = 3; __ikos_assert(p.x == 1); // WARNING return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-29-unsafe-2.c000066400000000000000000000004361473507761200253540ustar00rootroot00000000000000// DEFINITE UNSAFE extern void __ikos_assert(int); struct point { int x; int y; int z; }; int main(int argc, char** argv) { struct point p; p.x = 1; p.y = 2; p.z = 8; int* q = (int*)(((char*)&p.x) + 2); *q = 3; __ikos_assert(p.y == 2); // WARNING return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-3-safe.c000066400000000000000000000005151473507761200245600ustar00rootroot00000000000000// SAFE int foo(int* a, int* b, int* c) { int* p; int* q; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } return c[*p + *q]; } int main(int argc, char** argv) { int a[2]; int b[3]; int c[10] = {0}; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 5; b[2] = 6; return foo(a, b, c); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-3-unsafe.c000066400000000000000000000005301473507761200251200ustar00rootroot00000000000000// DEFINITE UNSAFE int foo(int* a, int* b, int* c) { int* p; int* q; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } return c[*p + *q]; } int main(int argc, char** argv) { int a[2]; int b[3]; int c[10] = {0}; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 5; b[2] = 7; return foo(a, b, c); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-30-safe.c000066400000000000000000000004771473507761200246470ustar00rootroot00000000000000// SAFE if --domain=interval-congruence extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int a[3]; a[0] = 5; a[1] = 10; int x = __ikos_nondet_int(); a[x] = 7; __ikos_assert(a[0] >= 5 && a[0] <= 7); // safe __ikos_assert(a[1] >= 7 && a[1] <= 10); // safe return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-30-unsafe.c000066400000000000000000000006651473507761200252110ustar00rootroot00000000000000// UNSAFE if --domain=interval-congruence extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int a[3]; a[0] = 5; a[1] = 10; // a = [ 5 | 10 | T ] int x = __ikos_nondet_int(); a[x] = 7; // a = [ [5,7] | [7,10] | [-oo,+oo] ] __ikos_assert(a[0] >= 5 && a[0] <= 7); // safe __ikos_assert(a[1] >= 7 && a[1] <= 10); // safe __ikos_assert(a[x] >= 5 && a[x] <= 10); // unsafe return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-31-safe.c000066400000000000000000000005241473507761200246410ustar00rootroot00000000000000#include #include extern void __ikos_assert(int); int main() { int** a = malloc(sizeof(int*)); if (a == NULL) return 1; *a = NULL; __ikos_assert(*((int64_t*)a) == 0); int64_t* b = malloc(sizeof(int64_t)); if (b == NULL) return 1; *b = 0; __ikos_assert(*(int**)(b) == NULL); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-32-safe.c000066400000000000000000000003751473507761200246460ustar00rootroot00000000000000#include extern void __ikos_assert(int); typedef struct { char message[255]; int id; } Struct; int main() { Struct s = {.message = "", .id = 1}; strncpy(&s.message[0], "hello world", 255); __ikos_assert(s.id == 1); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-4-safe.c000066400000000000000000000005261473507761200245630ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); struct bar { int y; unsigned char z; }; struct foo { unsigned char a; long b; unsigned char c; struct bar d; }; struct foo x = {5, 2000, 10, {32, 5}}; int h; int main() { if (x.d.y > 0) { x.d.y++; h = 8; h++; __ikos_assert(x.d.y + x.c + h == 52); } return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-5-safe.c000066400000000000000000000005221473507761200245600ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); struct bar { int y; unsigned char z; }; struct foo { unsigned char a; long b; unsigned char c; struct bar d; }; int main() { struct foo x; x.a = 5; x.b = 2000; x.c = 10; x.d.y = 32; x.d.z = 5; if (x.d.y > 0) { __ikos_assert(x.d.y + x.c == 42); } return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-5-unsafe.c000066400000000000000000000005351473507761200251270ustar00rootroot00000000000000// DEFINITE UNSAFE extern void __ikos_assert(int); struct bar { int y; unsigned char z; }; struct foo { unsigned char a; long b; unsigned char c; struct bar d; }; int main() { struct foo x; x.a = 5; x.b = 2000; x.c = 10; x.d.y = 32; x.d.z = 5; if (x.d.y > 0) { __ikos_assert(x.d.y + x.c == 43); } return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-6-safe.c000066400000000000000000000005211473507761200245600ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); struct bar { int y; unsigned char z; }; struct foo { unsigned char a; long b; unsigned char c; struct bar d; }; struct foo x; int main() { x.a = 5; x.b = 2000; x.c = 10; x.d.y = 32; x.d.z = 5; if (x.d.y > 0) { __ikos_assert(x.d.y + x.c == 42); } return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-7-safe.c000066400000000000000000000010271473507761200245630ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); int foo(int* a, int* b, int* c) { int* p; int* q; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } __ikos_assert(*p == 3); __ikos_assert(*q == 6); int res = c[*p + *q]; c[*p + *q] = 555; return res; } int main(int argc, char** argv) { int a[2]; int b[3]; int c[10]; c[9] = 666; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 5; b[2] = 6; int x = foo(a, b, c); __ikos_assert(x == 666); __ikos_assert(c[9] == 555); return x; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-7-unsafe.c000066400000000000000000000010421473507761200251230ustar00rootroot00000000000000// DEFINITE UNSAFE extern void __ikos_assert(int); int foo(int* a, int* b, int* c) { int* p; int* q; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } __ikos_assert(*p == 3); __ikos_assert(*q == 6); int res = c[*p + *q]; c[*p + *q] = 555; return res; } int main(int argc, char** argv) { int a[2]; int b[3]; int c[10]; c[9] = 666; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 5; b[2] = 6; int x = foo(a, b, c); __ikos_assert(x == 666); __ikos_assert(c[9] == 666); return x; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-8-safe.c000066400000000000000000000005371473507761200245710ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); int foo(int* a, int* c) { int* p; p = a + 1; __ikos_assert(*p == 3); int res = c[*p]; c[*p] = 555; return res; } int main(int argc, char** argv) { int a[2]; int c[10]; a[1] = 3; c[3] = 666; int x = foo(a, c); __ikos_assert(x == 666); __ikos_assert(c[3] == 555); return x; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-9-safe.c000066400000000000000000000005241473507761200245660ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); int x = 6; int y = 4; void f4() { x++; y++; } void f3() { f4(); } void f2() { f3(); } void f1() { f2(); __ikos_assert(x == 7 && y == 5); f3(); __ikos_assert(x == 8 && y == 6); x++; } int main(int argc, char** argv) { f1(); __ikos_assert(x == 9 && y == 6); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/mem/test-9-unsafe.c000066400000000000000000000005131473507761200251270ustar00rootroot00000000000000// DEFINITE UNSAFE extern void __ikos_assert(int); int x = 6; void f4() { x++; x++; } void f3() { f4(); } void f2() { f3(); } void f1() { f2(); __ikos_assert(x == 7); // x == 8 f3(); __ikos_assert(x == 8); // x== 10 x++; } int main(int argc, char** argv) { f1(); __ikos_assert(x == 11); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/000077500000000000000000000000001473507761200225545ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/runtest000077500000000000000000000075641473507761200242220ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the null pointer dereference analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the nullity analysis') t = TestManager(root=current_dir) t.add(Test('test-1.c', 'test-1.c', 'nullity', 'safe')) t.add(Test('test-2.c', 'test-2.c', 'nullity', 'error', line_checks=[(10, 'error')])) t.add(Test('test-3.c', 'test-3.c', 'nullity', 'safe')) t.add(Test('test-3-unsafe.c', 'test-3-unsafe.c', 'nullity', 'error', line_checks=[(6, 'error')])) t.add(Test('test-4.c', 'test-4.c', 'nullity', 'safe')) t.add(Test('test-4-unsafe-1.c', 'test-4-unsafe-1.c', 'nullity', 'unsafe', line_checks=[(17, 'warning')])) t.add(Test('test-4-unsafe-2.c', 'test-4-unsafe-2.c', 'nullity', 'unsafe', line_checks=[(19, 'warning')])) t.add(Test('test-5.c', 'test-5.c', 'nullity', 'safe')) t.add(Test('test-5-unsafe-1.c', 'test-5-unsafe-1.c', 'nullity', 'unsafe', line_checks=[(17, 'warning')])) t.add(Test('test-5-unsafe-2.c', 'test-5-unsafe-2.c', 'nullity', 'unsafe', line_checks=[(19, 'warning')])) t.add(Test('test-6-unsafe.c', 'test-6-unsafe.c', 'nullity', 'error', line_checks=[(4, 'error')])) t.add(Test('test-7-unsafe.c', 'test-7-unsafe.c', 'nullity', 'error', line_checks=[(7, 'error')])) t.add(Test('test-8-unsafe.c', 'test-8-unsafe.c', 'nullity', 'error', line_checks=[(7, 'error')])) t.add(Test('test-9-unsafe.c', 'test-9-unsafe.c', 'nullity', 'error', line_checks=[(6, 'error')])) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-1.c000066400000000000000000000002171473507761200240350ustar00rootroot00000000000000// SAFE int* foo(int* x, int* y) { return x + *y; } int main() { int a[10] = {0}; int b = 5; int* z = foo(&a[0], &b); return *z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-2.c000066400000000000000000000002461473507761200240400ustar00rootroot00000000000000// DEFINITE UNSAFE int* foo(int* x, int* y) { return x + *y; } int* p; // NULL int main() { int a[10]; int b = *p; int* z = foo(&a[0], &b); return *z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-3-unsafe.c000066400000000000000000000001351473507761200253150ustar00rootroot00000000000000#include #include int main() { char* s = NULL; return strlen(s); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-3.c000066400000000000000000000001451473507761200240370ustar00rootroot00000000000000#include #include int main() { const char* s = "AAAA"; return strlen(s); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-4-unsafe-1.c000066400000000000000000000004061473507761200254550ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); const char* f() { if (__ikos_nondet_int()) { return "AAAA"; } else { return NULL; } } int main() { char s1[10]; const char* s2 = f(); strcpy(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-4-unsafe-2.c000066400000000000000000000004221473507761200254540ustar00rootroot00000000000000#include #include char buf[10]; extern int __ikos_nondet_int(void); char* f() { if (__ikos_nondet_int()) { return buf; } else { return NULL; } } int main() { char* s1 = f(); const char* s2 = "AAAA"; strcpy(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-4.c000066400000000000000000000001771473507761200240450ustar00rootroot00000000000000#include #include int main() { char s1[10]; const char* s2 = "AAAA"; strcpy(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-5-unsafe-1.c000066400000000000000000000004161473507761200254570ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); const char* f() { if (__ikos_nondet_int()) { return "BBBB"; } else { return NULL; } } int main() { char s1[9] = "AAAA"; const char* s2 = f(); strcat(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-5-unsafe-2.c000066400000000000000000000004331473507761200254570ustar00rootroot00000000000000#include #include char buf[10] = "AAAA"; extern int __ikos_nondet_int(void); char* f() { if (__ikos_nondet_int()) { return buf; } else { return NULL; } } int main() { char* s1 = f(); const char* s2 = "BBBB"; strcat(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-5.c000066400000000000000000000002071473507761200240400ustar00rootroot00000000000000#include #include int main() { char s1[9] = "AAAA"; const char* s2 = "BBBB"; strcat(s1, s2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-6-unsafe.c000066400000000000000000000000711473507761200253170ustar00rootroot00000000000000int* p; // NULL int main() { *p = 0x42; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-7-unsafe.c000066400000000000000000000001501473507761200253160ustar00rootroot00000000000000#include char* p; // NULL int main() { char tab[10]; memcpy(p, tab, 10); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-8-unsafe.c000066400000000000000000000001501473507761200253170ustar00rootroot00000000000000#include char* p; // NULL int main() { char tab[10]; memcpy(tab, p, 10); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/null/test-9-unsafe.c000066400000000000000000000001261473507761200253230ustar00rootroot00000000000000#include char* p; // NULL int main() { memset(p, 0, 10); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/pcmp/000077500000000000000000000000001473507761200225415ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/pcmp/runtest000077500000000000000000000052761473507761200242050ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the pointer comparison analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the pointer comparison analysis') t = TestManager(root=current_dir) t.add(Test('test-1-unsafe.c', 'test-1-unsafe.c', 'pcmp', 'error')) t.add(Test('test-2-warnings.c', 'test-2-warnings.c', 'pcmp', 'unsafe')) t.add(Test('test-3-null.c', 'test-3-null.c', 'pcmp', 'error')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/pcmp/test-1-unsafe.c000066400000000000000000000002331473507761200252770ustar00rootroot00000000000000#include int main(void) { char* p = malloc(42); char* q = malloc(42); int tmp = p < q; // Error free(p); free(q); return tmp; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/pcmp/test-2-warnings.c000066400000000000000000000012141473507761200256470ustar00rootroot00000000000000#include #include #include extern int __ikos_nondet_int(void); extern unsigned int __ikos_nondet_uint(void); bool f(int* array_a, int* array_b, int pos_a, int pos_b) { return &array_a[pos_a] < &array_b[pos_b]; } int main() { int* array_a = calloc(10, sizeof(int)); int* array_b = calloc(10, sizeof(int)); int* final_array; int pos_a = __ikos_nondet_uint() % 10; int pos_b = __ikos_nondet_uint() % 10; bool b; if (__ikos_nondet_int()) { final_array = array_a; } else { final_array = array_b; } b = f(final_array, array_b, pos_a, pos_b); free(array_a); free(array_b); return b; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/pcmp/test-3-null.c000066400000000000000000000010611473507761200247720ustar00rootroot00000000000000#include #include #include extern int __ikos_nondet_int(void); extern unsigned int __ikos_nondet_uint(void); bool f(int* array_a, int* array_b, int pos_a, int pos_b) { return &array_a[pos_a] < &array_b[pos_b]; } int main() { int* array_a = calloc(10, sizeof(int)); int* array_b = calloc(10, sizeof(int)); int* final_array = NULL; int pos_a = __ikos_nondet_uint() % 10; int pos_b = __ikos_nondet_uint() % 10; bool b; b = f(final_array, array_b, pos_a, pos_b); free(array_a); free(array_b); return b; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/poa/000077500000000000000000000000001473507761200223615ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/poa/runtest000077500000000000000000000053011473507761200240120ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the pointer overflow analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the pointer overflow analysis') t = TestManager(root=current_dir) t.add(Test('test-1-unsafe.c', 'test-1-unsafe.c', 'poa', 'error')) t.add(Test('test-2-warnings.c', 'test-2-warnings.c', 'poa', 'unsafe')) t.add(Test('test-3-undefined.c', 'test-3-undefined.c', 'poa', 'error')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/poa/test-1-unsafe.c000066400000000000000000000003141473507761200251170ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); extern unsigned int __ikos_nondet_uint(void); extern uint64_t f(void); int main() { int c[40]; uint64_t a = UINT64_MAX / 4 + 1; c[a] = 5; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/poa/test-2-warnings.c000066400000000000000000000003361473507761200254730ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); extern unsigned int __ikos_nondet_uint(void); extern uint64_t f(void); int main() { int c[40]; uint64_t a = UINT64_MAX / 4 + __ikos_nondet_int(); c[a] = 5; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/poa/test-3-undefined.c000066400000000000000000000002471473507761200256060ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); extern unsigned int __ikos_nondet_uint(void); extern uint64_t f(void); int main() { int* c; c[4] = 5; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/000077500000000000000000000000001473507761200231175ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/01.c000066400000000000000000000004211473507761200235000ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * IC3 motivating example */ int main() { int x = 1; int y = 1; while (__ikos_nondet_int()) { int t1 = x; int t2 = y; x = t1 + t2; y = t1 + t2; } __ikos_assert(y >= 1); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/02.c000066400000000000000000000004551473507761200235100ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int i = 1; int j = 0; int z = i - j; int x = 0; int y = 0; int w = 0; while (__ikos_nondet_int()) { z += x + y + w; y++; if (z % 2 == 1) x++; w += 2; } __ikos_assert(x == y); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/03.c000066400000000000000000000006071473507761200235100ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * "nested4.c" from InvGen benchmark suite */ int main() { int i, k, n, l; n = __ikos_nondet_int(); l = __ikos_nondet_int(); // assume(l>0); if (l > 0) { for (k = 1; k < n; k++) { for (i = l; i < n; i++) { } for (i = l; i < n; i++) { __ikos_assert(1 <= i); } } } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/04.c000066400000000000000000000004361473507761200235110ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Taken from Gulwani PLDI'08: * Program Analysis as Constraint Solving */ int main() { int x, y; x = -50; y = __ikos_nondet_int(); while (x < 0) { x = x + y; y++; } __ikos_assert(y > 0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/05.c000066400000000000000000000004421473507761200235070ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int flag, char** argv) { int x = 0; int y = 0; int j = 0; int i = 0; while (__ikos_nondet_int()) { x++; y++; i += x; j += y; if (flag) j += 1; } __ikos_assert(j >= i); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/06.c000066400000000000000000000005231473507761200235100ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int w = 1; int z = 0; int x = 0; int y = 0; while (__ikos_nondet_int()) { while (__ikos_nondet_int()) { if (w % 2 == 1) x++; if (z % 2 == 0) y++; } z = x + y; w = z + 1; } __ikos_assert(x == y); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/07.c000066400000000000000000000007271473507761200235170ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * From "Path Invariants" PLDI 07 by Beyer et al. */ int main() { int i, n, a, b; n = __ikos_nondet_int(); if (n >= 0) { // assume( n >= 0 ); i = 0; a = 0; b = 0; while (i < n) { if (__ikos_nondet_int()) { a = a + 1; b = b + 2; } else { a = a + 2; b = b + 1; } i = i + 1; } __ikos_assert(a + b == 3 * n); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/08.c000066400000000000000000000006761473507761200235230ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Based on "Automatically refining abstract interpretations" fig.1 */ int main() { int x = 0, y = 0; while (__ikos_nondet_int()) { if (__ikos_nondet_int()) { x++; y += 100; } else if (__ikos_nondet_int()) { if (x >= 4) { x++; y++; } if (x < 0) { y--; } } } __ikos_assert(x < 4 || y > 2); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/09.c000066400000000000000000000012111473507761200235060ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * "fragtest_simple" from InvGen benchmark suite */ int main() { int i, pvlen; int t; int k = 0; int n; i = 0; pvlen = __ikos_nondet_int(); // pkt = pktq->tqh_first; while (__ikos_nondet_int()) i = i + 1; if (i > pvlen) { pvlen = i; } else { } i = 0; while (__ikos_nondet_int()) { t = i; i = i + 1; k = k + 1; } while (__ikos_nondet_int()) ; int j = 0; n = i; while (1) { __ikos_assert(k >= 0); k = k - 1; i = i - 1; j = j + 1; if (j < n) { } else { break; } } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/10.c000066400000000000000000000004411473507761200235020ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int w = 1; int z = 0; int x = 0; int y = 0; while (__ikos_nondet_int()) { if (w) { x++; w = !w; }; if (!z) { y++; z = !z; }; } __ikos_assert(x == y); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/11.c000066400000000000000000000003411473507761200235020ustar00rootroot00000000000000extern void __ikos_assert(int); /* * Based on ex3 from NECLA Static Analysis Benchmarks */ int main() { int j = 0; int i; int x = 100; for (i = 0; i < x; i++) { j = j + 2; } __ikos_assert(j == 2 * x); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/12.c000066400000000000000000000007331473507761200235100ustar00rootroot00000000000000 extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int flag, char** argv) { int t = 0; int s = 0; int a = 0; int b = 0; while (__ikos_nondet_int()) { a++; b++; s += a; t += b; if (flag) { t += a; } } // 2s >= t int x = 1; if (flag) { x = t - 2 * s + 2; } // x <= 2 int y = 0; while (y <= x) { if (__ikos_nondet_int()) y++; else y += 2; } __ikos_assert(y <= 4); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/13.c000066400000000000000000000006171473507761200235120ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Based on "Property-Directed Incremental Invariant Generation" by Bradley et * al. */ int main(int flag, char** argv) { int j = 2; int k = 0; while (__ikos_nondet_int()) { if (flag) j = j + 4; else { j = j + 2; k = k + 1; } } if (k != 0) { __ikos_assert(j == 2 * k + 2); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/14.c000066400000000000000000000005731473507761200235140ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * From "The Octagon Abstract Domain" HOSC 2006 by Mine. */ int main() { int a = 0; int j; int m; m = __ikos_nondet_int(); if (m <= 0) return 0; for (j = 1; j <= m; j++) { if (__ikos_nondet_int()) a++; else a--; } __ikos_assert(a >= -m); __ikos_assert(a <= m); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/15.c000066400000000000000000000006211473507761200235070ustar00rootroot00000000000000 extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * from Invgen test suite */ int main(int argc, char** argv) { int n; int k, j; n = __ikos_nondet_int(); k = __ikos_nondet_int(); if (n > 0) { // assume(n>0); if (k > n) { // assume(k>n); j = 0; while (j < n) { j++; k--; } __ikos_assert(k >= 0); } } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/16.c000066400000000000000000000006001473507761200235050ustar00rootroot00000000000000 extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * From "A Practical and Complete Approach to Predicate Refinement" by McMillan * TACAS'06 */ int main(int argc, char** argv) { int i = __ikos_nondet_int(); int j = __ikos_nondet_int(); int x = i; int y = j; while (x != 0) { x--; y--; } if (i == j) { __ikos_assert(y == 0); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/17.c000066400000000000000000000005061473507761200235130ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int argc, char** argv) { int n = __ikos_nondet_int(); int k = 1; int i = 1; int j = 0; if (n < 0) return 0; while (i < n) { j = 0; while (j < i) { k += (i - j); j++; } i++; } __ikos_assert(k >= n); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/18.c000066400000000000000000000005211473507761200235110ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Adapted from ex17.c in NECLA test suite */ int main() { int flag = __ikos_nondet_int(); int a = __ikos_nondet_int(); int b; int j = 0; for (b = 0; b < 100; ++b) { if (flag) j = j + 1; } if (flag) { __ikos_assert(j == 100); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/19.c000066400000000000000000000010271473507761200235140ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * From "Simplifying Loop Invariant Generation using Splitter Predicates", * Sharma et al. CAV'11 */ int main() { int n = __ikos_nondet_int(); int m = __ikos_nondet_int(); if (n >= 0) { // assume(n>=0); if (m >= 0) { // assume(m>=0); if (m < n) { // assume(m m) y++; } __ikos_assert(y == n); } } } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/20.c000066400000000000000000000011741473507761200235070ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int x = __ikos_nondet_int(); int y = __ikos_nondet_int(); int k = __ikos_nondet_int(); int j = __ikos_nondet_int(); int i = __ikos_nondet_int(); int n = __ikos_nondet_int(); if ((x + y) == k) { // assume((x+y)== k); int m = 0; j = 0; while (j < n) { if (j == i) { x++; y--; } else { y++; x--; } if (__ikos_nondet_int()) m = j; j++; } __ikos_assert((x + y) == k); if (n > 0) { __ikos_assert(0 <= m); __ikos_assert(m < n); } } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/21.c000066400000000000000000000010101473507761200234750ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Based on "larg_const.c" from InvGen test suite */ int main(int argc, char** argv) { int c1 = 4000; int c2 = 2000; int n, v; int i, k; n = __ikos_nondet_int(); if (n > 0 && n < 10) { k = 0; i = 0; while (i < n) { i++; if (__ikos_nondet_int() % 2 == 0) v = 0; else v = 1; if (v == 0) k += c1; else k += c2; } __ikos_assert(k > n); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/22.c000066400000000000000000000004441473507761200235100ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int x = 0; int y = 0; int z = 0; int k = 0; while (__ikos_nondet_int()) { if (k % 3 == 0) x++; y++; z++; k = x + y + z; } __ikos_assert(x == y); __ikos_assert(y == z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/23.c000066400000000000000000000005411473507761200235070ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * ex49 from NECLA Static Analysis Benchmarks */ int main(int argc, char** argv) { int n = __ikos_nondet_int(); int i, sum = 0; if (n < 0) return 0; if (n >= 0) { for (i = 0; i < n; ++i) { sum = sum + i; } __ikos_assert(sum >= 0); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/24.c000066400000000000000000000004431473507761200235110ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * "nested5.c" from InvGen test suite */ int main() { int i, j, k, n; n = __ikos_nondet_int(); for (i = 0; i < n; i++) for (j = i; j < n; j++) for (k = j; k < n; k++) __ikos_assert(k >= i); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/25.c000066400000000000000000000005441473507761200235140ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int x = 0; int y = 0; int i = 0; int j = 0; while (__ikos_nondet_int()) { while (__ikos_nondet_int()) { if (x == y) i++; else j++; } if (i >= j) { x++; y++; } else y++; } __ikos_assert(i >= j); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/26.c000066400000000000000000000005531473507761200235150ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int w = 1, z = 0, x = 0, y = 0; while (__ikos_nondet_int()) { while (__ikos_nondet_int()) { if (w % 2 == 1) x++; if (z % 2 == 0) y++; } while (__ikos_nondet_int()) { z = x + y; w = z + 1; } } __ikos_assert(x == y); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/27.c000066400000000000000000000006071473507761200235160ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * "nested2.c" from InvGen benchmark suite */ int main() { int i, k, n, l; // assume(l>0); l = __ikos_nondet_int(); n = __ikos_nondet_int(); if (l > 0) { for (k = 1; k < n; k++) { for (i = l; i < n; i++) { } for (i = l; i < n; i++) { __ikos_assert(1 <= k); } } } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/28.c000066400000000000000000000004331473507761200235140ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * From CAV'12 by Sharma et al. */ int main() { int x = 0; int y = 0; int n = 0; while (__ikos_nondet_int()) { x++; y++; } while (x != n) { x--; y--; } __ikos_assert(y == n); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/29.c000066400000000000000000000006231473507761200235160ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int a = 1; int b = 1; int c = 2; int d = 2; int x = 3; int y = 3; while (__ikos_nondet_int()) { x = a + c; y = b + d; if ((x + y) % 2 == 0) { a++; d++; } else { a--; } while (__ikos_nondet_int()) { c--; b--; } } __ikos_assert(a + c == b + d); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/30.c000066400000000000000000000003671473507761200235130ustar00rootroot00000000000000extern void __ikos_assert(int); /* * Based on "SYNERGY: A New Algorithm for Property Checking" by Gulavani et al. */ int main() { int i, c; i = 0; c = 0; while (i < 1000) { c = c + i; i = i + 1; } __ikos_assert(c >= 0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/31.c000066400000000000000000000010461473507761200235070ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * "nest-if8" from InvGen benchmark suite */ int main() { int i, j, k, n, m; n = __ikos_nondet_int(); m = __ikos_nondet_int(); if (m + 1 < n) ; else return 0; for (i = 0; i < n; i += 4) { for (j = i; j < m;) { if (__ikos_nondet_int()) { __ikos_assert(j >= 0); j++; k = 0; while (k < j) { k++; } } else { __ikos_assert(n + j + 5 > i); j += 2; } } } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/32.c000066400000000000000000000005471473507761200235150ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * "split.c" from InvGen benchmark suite */ int main() { int k = 100; int b = __ikos_nondet_int(); int j = __ikos_nondet_int(); int n; int i = j; for (n = 0; n < 2 * k; n++) { if (b) { i++; } else { j++; } b = !b; } __ikos_assert(i == j); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/33.c000066400000000000000000000010151473507761200235050ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int argc, char** argv) { int k = __ikos_nondet_int(); if (k < 0) return 0; int z = k; int x = 0; int y = 0; while (__ikos_nondet_int()) { int c = 0; while (__ikos_nondet_int()) { if (z == k + y - c) { x++; y++; c++; } else { x++; y--; c++; } } while (__ikos_nondet_int()) { x--; y--; } z = k + y; } __ikos_assert(x == y); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/34.c000066400000000000000000000005241473507761200235120ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int argc, char** argv) { int n = __ikos_nondet_int(); int x = 0; int y = 0; int i = 0; int m = 10; if (n < 0) return 0; while (i < n) { i++; x++; if (i % 2 == 0) y++; } if (i == m) { __ikos_assert(x == 2 * y); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/35.c000066400000000000000000000004441473507761200235140ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * InvGen, CAV'09 paper, fig 2 */ int main(int argc, char** argv) { int n = __ikos_nondet_int(); int x = 0; if (n < 0) return 0; while (x < n) { x++; } if (n > 0) { __ikos_assert(x == n); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/36.c000066400000000000000000000014131473507761200235120ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int flag, char** argv) { int a = 0; int b = 0; int x = 0; int y = 0; int z = 0; int j = 0; int w = 0; while (__ikos_nondet_int()) { int i = z; int j = w; int k = 0; while (i < j) { k++; i++; } x = z; y = k; if (x % 2 == 1) { x++; y--; } while (__ikos_nondet_int()) { if (x % 2 == 0) { x += 2; y -= 2; } else { x--; y--; } } z++; w = x + y + 1; } int c = 0; int d = 0; while (__ikos_nondet_int()) { c++; d++; if (flag) { a++; b++; } else { a += c; b += d; } } __ikos_assert(w >= z && a - b == 0); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/37.c000066400000000000000000000006721473507761200235210ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Taken from "Counterexample Driven Refinement for Abstract Interpretation" * (TACAS'06) by Gulavani */ int main(int argc, char** argv) { int n = __ikos_nondet_int(); int x = 0; int m = 0; if (n < 0) return 0; while (x < n) { if (__ikos_nondet_int()) { m = x; } x = x + 1; } if (n > 0) { __ikos_assert(0 <= m && m < n); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/38.c000066400000000000000000000005121473507761200235130ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int argc, char** argv) { int n = __ikos_nondet_int(); int x = 0; int y = 0; int i = 0; if (n < 0) return 0; while (i < n) { i++; x++; if (i % 2 == 0) y++; } if (i % 2 == 0) { __ikos_assert(x == 2 * y); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/39.c000066400000000000000000000022311473507761200235140ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); // int MAXPATHLEN; /* * "NetBSD_loop_int" from InvGen benchmark suite */ int main() { /* Char *buf; Char *pattern; Char *bound; */ int MAXPATHLEN = __ikos_nondet_int(); int buf_off; int pattern_off; int bound_off; // int A [MAXPATHLEN+1]; // int B [PATTERNLEN]; /* glob3's local vars */ int glob3_pathbuf_off; int glob3_pathend_off; int glob3_pathlim_off; int glob3_pattern_off; int glob3_dc; if (MAXPATHLEN > 0) ; else goto END; /* buf = A; pattern = B; */ buf_off = 0; pattern_off = 0; /* bound = A + sizeof(A)/sizeof(*A) - 1; */ bound_off = 0 + (MAXPATHLEN + 1) - 1; glob3_pathbuf_off = buf_off; glob3_pathend_off = buf_off; glob3_pathlim_off = bound_off; glob3_pattern_off = pattern_off; glob3_dc = 0; for (;;) if (glob3_pathend_off + glob3_dc >= glob3_pathlim_off) break; else { // A[glob3_dc] = 1; glob3_dc++; /* OK */ __ikos_assert(0 <= glob3_dc); __ikos_assert(glob3_dc < MAXPATHLEN + 1); if (__ikos_nondet_int()) goto END; } END: return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/40.c000066400000000000000000000006441473507761200235120ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int flag, char** argv) { int i, j; j = 1; if (flag) { i = 0; } else { i = 1; } while (__ikos_nondet_int()) { i += 2; if (i % 2 == 0) { j += 2; } else j++; } int a = 0; int b = 0; while (__ikos_nondet_int()) { a++; b += (j - i); } if (flag) { __ikos_assert(a == b); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/41.c000066400000000000000000000010201473507761200235000ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Adapted from "Automated Error Diagnosis Using Abductive Inference" by Dillig * et al. */ int main() { int n = __ikos_nondet_int(); int flag = __ikos_nondet_int(); if (n >= 0) { // assume(n>=0); int k = 1; if (flag) { k = __ikos_nondet_int(); // assume(k>=0); // ?? } int i = 0, j = 0; while (i <= n) { i++; j += i; } int z = k + i + j; __ikos_assert(z > 2 * n); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/42.c000066400000000000000000000006521473507761200235130ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int flag, char** argv) { int x = 1; int y = 1; int a; if (flag) a = 0; else a = 1; while (__ikos_nondet_int()) { if (flag) { a = x + y; x++; } else { a = x + y + 1; y++; } if (a % 2 == 1) y++; else x++; } // x==y if (flag) a++; __ikos_assert(a % 2 == 1); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/43.c000066400000000000000000000005321473507761200235110ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Based on ex16 from NECLA Static Analysis Benchmarks */ int main() { int x = __ikos_nondet_int(); int y = __ikos_nondet_int(); int t = y; if (x == y) return x; while (__ikos_nondet_int()) { if (x > 0) y = y + x; } __ikos_assert(y >= t); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/44.c000066400000000000000000000006411473507761200235130ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); /* * Adapted from ex20 from NECLA Static Analysis Benchmarks */ int main() { int k = __ikos_nondet_int(); int flag = __ikos_nondet_int(); int i = 0; int j = 0; int n; if (flag == 1) { n = 1; } else { n = 2; } i = 0; while (i <= k) { i++; j = j + n; } if (flag == 1) { __ikos_assert(j == i); } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/45.c000066400000000000000000000010421473507761200235100ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main(int flag, char** argv) { int x = 0; int y = 0; int j = 0; int i = 0; while (__ikos_nondet_int()) { x++; y++; i += x; j += y; if (flag) { j += 1; } } if (j >= i) x = y; else x = y + 1; int w = 1; int z = 0; while (__ikos_nondet_int()) { while (__ikos_nondet_int()) { if (w % 2 == 1) x++; if (z % 2 == 0) y++; } z = x + y; w = z + 1; } __ikos_assert(x == y); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/46.c000066400000000000000000000004551473507761200235200ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int w = 1; int z = 0; int x = 0; int y = 0; while (__ikos_nondet_int()) { if (w % 2 == 1) { x++; w++; }; if (z % 2 == 0) { y++; z++; }; } __ikos_assert(x <= 1); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/47.c000066400000000000000000000030051473507761200235130ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); // This example is extracted from "Symbolic Methods to Enhance the // Precision of Numerical Abstract Domains" by A. Mine, (VMCAI'06). // // However, the technique of symbolic constant propagation 'a la' Mine // does not help here because the copy propagation done by LLVM is // enough. int id(int x) { return x; } void _abs() { int x, y, z; // int a[21]; if (__ikos_nondet_int()) x = -10; else x = 20; // z=id(x); // y = z; y = x; if (y <= 0) { // y = -z; y = -x; } /* the code: y= x; if (y <= 0){ y = -x; } is already translated by LLVM+ARBOS as if (x <= 0) y = -x; else y = x; */ // return a[y]; // SAFE __ikos_assert(y >= 0 && y <= 20); } // Another example from Mine's paper. // Again, it turns out that LLVM optimizations is enough so no need of // "linearization" here. void lin_1() { int x, y, z; if (__ikos_nondet_int()) x = 5; else x = 10; y = 3 * x - x; // LLVM ==> y = 2*x; __ikos_assert(y >= 10 && y <= 20); } // Another example from Mine's paper. void lin_2() { int t, x, y, z; if (__ikos_nondet_int()) x = 5; else x = 10; if (__ikos_nondet_int()) y = 2; else y = 4; if (__ikos_nondet_int()) z = 6; else z = 9; t = (x * y) - (x * z) + z; // t = [-74,19] // LLVM ==> (y-z)*x +z ==> t = [-64,-1] __ikos_assert(t >= -74 && t <= 19); } int main() { lin_1(); lin_2(); _abs(); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/48-volatile-safe.c000066400000000000000000000003261473507761200262500ustar00rootroot00000000000000#include extern void __ikos_assert(int); int main() { int src[11] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; int dest[11] = {0}; memcpy(dest, src, sizeof(int) * 11); __ikos_assert(dest[0] == 3); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/48-volatile-unsafe.c000066400000000000000000000003371473507761200266150ustar00rootroot00000000000000#include extern void __ikos_assert(int); int main() { volatile int src[11] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; int dest[11] = {0}; memcpy(dest, src, sizeof(int) * 11); __ikos_assert(dest[0] == 3); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/asian06-ex2.c000066400000000000000000000002551473507761200252220ustar00rootroot00000000000000extern void __ikos_assert(int); int main(int argc, char** argv) { int i, x; x = 10; for (i = 0; i <= 10; i++) { x++; } __ikos_assert(x <= 21); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/astree-1.c000066400000000000000000000002741473507761200247070ustar00rootroot00000000000000extern void __ikos_assert(int); // need of relational domain int main() { int X = 100000, Y = 1000000; while (X >= 0) { X--; Y--; } __ikos_assert(X <= Y); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/astree-2a.c000066400000000000000000000004521473507761200250470ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); // Need of the clock domain or fully relational int main() { int i = 0; int x = 0; int b = __ikos_nondet_int(); while (i < 1000) { x++; if (b) x = 0; i++; } __ikos_assert(x <= 1000); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/astree-2b.c000066400000000000000000000004661473507761200250550ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); // Need of the clock domain or fully relational int main() { int i = 5; int x = 5; int b = __ikos_nondet_int(); while (i < 1000) { x = x + 2; if (b) x = 0; i = i + 2; } __ikos_assert(x <= 1001); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/astree-2c.c000066400000000000000000000004641473507761200250540ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); // Need of the clock domain or fully relational int main() { int i = 1000; int x = 1000; int b = __ikos_nondet_int(); while (i >= -200) { x--; if (b) x = 1000; i--; } __ikos_assert(x <= 1000); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/loop-1.c000066400000000000000000000004211473507761200243670ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); #define TRUE 1 int main() { int s = 0; while (TRUE) { if (__ikos_nondet_int()) break; if (s < 5) s++; else s = 0; } __ikos_assert(s >= 0 && s <= 5); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/loop-10.c000066400000000000000000000004551473507761200244560ustar00rootroot00000000000000extern void __ikos_assert(int); // provable by using a fully relational or gauge domain but as well // by using simply intervals after induction variable optimization. int main() { int i, s, n; n = 100; s = 0; for (i = 0; i < n; i++) { s++; } __ikos_assert(s == i); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/loop-2.c000066400000000000000000000004271473507761200243760ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); #define TRUE 1 int main() { int n = 0; while (TRUE) { if (__ikos_nondet_int()) continue; if (n < 60) n++; else n = 0; __ikos_assert(n >= 0 && n <= 60); } return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/loop-3.c000066400000000000000000000004141473507761200243730ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int x = 0; int y = 0; while (x < 100) { if (__ikos_nondet_int()) y = 1; x = x + 4; } __ikos_assert(y >= 0 && y <= 1); __ikos_assert(x <= 103); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/loop-4.c000066400000000000000000000005041473507761200243740ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int foo(int x, int y) { while (x < 100) { if (__ikos_nondet_int()) y = 1; x = x + 4; } __ikos_assert(y >= 0 && y <= 1); __ikos_assert(x <= 103); return x + y; } int main() { int res = foo(0, 0); __ikos_assert(res <= 104); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/loop-9.c000066400000000000000000000003311473507761200243770ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int i, s, n; n = __ikos_nondet_int(); s = 0; for (i = 0; i < n; i++) { s++; } __ikos_assert(s == i); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/runtest000077500000000000000000000305111473507761200245510ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the prover. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the prover') t = TestManager(root=current_dir) t.add(Test('01.c', '01.c', 'prover', 'safe')) t.add(Test('02.c', '02.c', 'prover', 'safe', expected='unsafe')) t.add(Test('03.c', '03.c', 'prover', 'safe')) t.add(Test('04.c', '04.c', 'prover', 'safe', expected='unsafe')) t.add(Test('05.c', '05.c', 'prover', 'safe', expected='unsafe')) t.add(Test('06.c', '06.c', 'prover', 'safe', expected='unsafe')) t.add(Test('07.c', '07.c', 'prover', 'safe', expected='unsafe')) t.add(Test('08.c', '08.c (interval)', 'prover', 'safe', expected='unsafe', domain='interval')) t.add(Test('08.c', '08.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('09.c', '09.c', 'prover', 'safe', expected='unsafe')) t.add(Test('10.c', '10.c', 'prover', 'safe', expected='unsafe')) t.add(Test('11.c', '11.c (interval)', 'prover', 'safe', expected='unsafe', domain='interval')) t.add(Test('11.c', '11.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('12.c', '12.c', 'prover', 'safe', expected='unsafe')) t.add(Test('13.c', '13.c', 'prover', 'safe', expected='unsafe')) t.add(Test('14.c', '14.c', 'prover', 'safe', expected='unsafe')) t.add(Test('15.c', '15.c', 'prover', 'safe', expected='unsafe')) t.add(Test('16.c', '16.c', 'prover', 'safe', expected='unsafe')) t.add(Test('17.c', '17.c', 'prover', 'safe', expected='unsafe')) t.add(Test('18.c', '18.c', 'prover', 'safe', expected='unsafe')) t.add(Test('19.c', '19.c', 'prover', 'safe', expected='unsafe')) t.add(Test('20.c', '20.c', 'prover', 'safe', expected='unsafe', line_checks=[(27, 'ok', 'warning'), (29, 'ok'), (30, 'warning')])) t.add(Test('21.c', '21.c', 'prover', 'safe', expected='unsafe')) t.add(Test('22.c', '22.c', 'prover', 'safe', expected='unsafe')) t.add(Test('23.c', '23.c', 'prover', 'safe')) t.add(Test('24.c', '24.c (interval)', 'prover', 'safe', expected='unsafe', domain='interval')) t.add(Test('24.c', '24.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('24.c', '24.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('25.c', '25.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('25.c', '25.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('26.c', '26.c', 'prover', 'safe', expected='unsafe')) t.add(Test('27.c', '27.c', 'prover', 'safe')) t.add(Test('28.c', '28.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('28.c', '28.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('29.c', '29.c', 'prover', 'safe', expected='unsafe')) t.add(Test('30.c', '30.c', 'prover', 'safe')) t.add(Test('31.c', '31.c', 'prover', 'safe', expected='unsafe', line_checks=[(19, 'ok'), (26, 'ok', 'warning')])) t.add(Test('32.c', '32.c', 'prover', 'safe', expected='unsafe')) t.add(Test('33.c', '33.c', 'prover', 'safe', expected='unsafe')) t.add(Test('34.c', '34.c', 'prover', 'safe', expected='unsafe')) t.add(Test('35.c', '35.c', 'prover', 'safe', expected='unsafe')) t.add(Test('36.c', '36.c', 'prover', 'safe', expected='unsafe')) t.add(Test('37.c', '37.c', 'prover', 'safe', expected='unsafe')) t.add(Test('38.c', '38.c', 'prover', 'safe', expected='unsafe')) t.add(Test('39.c', '39.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('39.c', '39.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('40.c', '40.c', 'prover', 'safe', expected='unsafe')) t.add(Test('41.c', '41.c', 'prover', 'safe', expected='unsafe')) t.add(Test('42.c', '42.c', 'prover', 'safe', expected='unsafe')) t.add(Test('43.c', '43.c', 'prover', 'safe', expected='unsafe')) t.add(Test('44.c', '44.c', 'prover', 'safe', expected='unsafe')) t.add(Test('45.c', '45.c', 'prover', 'safe', expected='unsafe')) t.add(Test('46.c', '46.c', 'prover', 'safe', expected='unsafe')) t.add(Test('47.c', '47.c', 'prover', 'safe', opt_level='aggressive')) t.add(Test('48-volatile-safe.c', '48-volatile-safe.c', 'prover', 'safe')) t.add(Test('48-volatile-unsafe.c', '48-volatile-unsafe.c', 'prover', 'unsafe')) t.add(Test('asian06-ex2.c', 'asian06-ex2.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('asian06-ex2.c', 'asian06-ex2.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('asian06-ex2.c', 'asian06-ex2.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('astree-1.c', 'astree-1.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('astree-1.c', 'astree-1.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('astree-1.c', 'astree-1.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('astree-2a.c', 'astree-2a.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('astree-2a.c', 'astree-2a.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('astree-2a.c', 'astree-2a.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('astree-2b.c', 'astree-2b.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('astree-2b.c', 'astree-2b.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('astree-2c.c', 'astree-2c.c', 'prover', 'safe')) t.add(Test('loop-1.c', 'loop-1.c', 'prover', 'safe')) t.add(Test('loop-2.c', 'loop-2.c', 'prover', 'safe')) t.add(Test('loop-3.c', 'loop-3.c', 'prover', 'safe')) t.add(Test('loop-4.c', 'loop-4.c', 'prover', 'safe')) t.add(Test('loop-9.c', 'loop-9.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('loop-9.c', 'loop-9.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('loop-10.c', 'loop-10.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('loop-10.c', 'loop-10.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('loop-10.c', 'loop-10.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('test-1.c', 'test-1.c', 'prover', 'safe')) t.add(Test('test-2.c', 'test-2.c', 'prover', 'safe', expected='unsafe')) t.add(Test('test-3.c', 'test-3.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('test-3.c', 'test-3.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('test-4.cpp', 'test-4.cpp', 'prover', 'safe', expected='unsafe', line_checks=[(22, 'ok'), (37, 'ok'), (38, 'ok'), (39, 'ok'), (41, 'ok'), (42, 'ok', 'warning')])) t.add(Test('test-5.cpp', 'test-5.cpp', 'prover', 'safe')) t.add(Test('test-6.cpp', 'test-6.cpp', 'prover', 'safe')) t.add(Test('test-7.cpp', 'test-7.cpp', 'prover', 'safe')) t.add(Test('test-8.cpp', 'test-8.cpp', 'prover', 'safe')) t.add(Test('test-9.c', 'test-9.c', 'prover', 'safe', expected='unsafe')) t.add(Test('test-10.c', 'test-10.c', 'prover', 'safe', expected='unsafe')) t.add(Test('test-11.c', 'test-11.c', 'prover', 'safe', expected='unsafe', line_checks=[(21, 'ok', 'warning'), (22, 'ok', 'warning')])) t.add(Test('test-12.c', 'test-12.c', 'prover', 'safe', line_checks=[(5, 'unreachable'), (7, 'ok')])) t.add(Test('test-13.c', 'test-13.c', 'prover', 'safe')) t.add(Test('test-14.c', 'test-14.c', 'prover', 'safe')) t.add(Test('test-15.cpp', 'test-15.cpp', 'prover', 'safe')) t.add(Test('test-16.c', 'test-16.c', 'prover', 'safe')) t.add(Test('test-17.c', 'test-17.c', 'prover', 'safe', line_checks=[(19, 'ok'), (21, 'ok')])) t.add(Test('test-18.c', 'test-18.c (interval)', 'prover', 'safe')) t.add(Test('test-18.c', 'test-18.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('test-19.c', 'test-19.c (interval)', 'prover', 'safe', expected='unsafe')) t.add(Test('test-19.c', 'test-19.c (dbm)', 'prover', 'safe', domain='dbm')) t.add(Test('test-19.c', 'test-19.c (gauge-interval-congruence)', 'prover', 'safe', domain='gauge-interval-congruence')) t.add(Test('test-20.c', 'test-20.c', 'prover', 'safe')) t.add(Test('test-21-exceptions.cpp', 'test-21-exceptions.cpp', 'prover', 'safe')) t.add(Test('test-22-exceptions.cpp', 'test-22-exceptions.cpp', 'prover', 'safe')) t.add(Test('test-23.c', 'test-23.c', 'prover', 'safe')) t.add(Test('test-24.c', 'test-24.c', 'prover', 'safe')) t.add(Test('test-25.c', 'test-25.c', 'prover', 'unsafe')) t.add(Test('test-26.c', 'test-26.c', 'prover', 'unsafe', line_checks=[(17, 'ok'), (18, 'ok'), (19, 'ok'), (22, 'warning'), (23, 'warning'), (24, 'ok'), (27, 'warning'), (28, 'warning'), (29, 'ok', 'warning')])) t.add(Test('test-27.c', 'test-27.c', 'prover', 'safe', expected='unsafe')) t.add(Test('test-27.c', 'test-27.c (partitioning=return)', 'prover', 'safe', options=['-add-partitioning-variables', '-enable-partitioning-domain'])) t.add(Test('test-28.c', 'test-28.c', 'prover', 'safe', expected='unsafe')) t.add(Test('test-28.c', 'test-28.c (partitioning=return)', 'prover', 'safe', options=['-add-partitioning-variables', '-enable-partitioning-domain'])) t.add(Test('test-29.cpp', 'test-29.cpp', 'prover', 'safe', expected='unsafe')) t.add(Test('test-29.cpp', 'test-29.cpp (partitioning=return)', 'prover', 'safe', options=['-add-partitioning-variables', '-enable-partitioning-domain'])) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-1.c000066400000000000000000000006771473507761200244120ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int i = 0; int x = 2; while (__ikos_nondet_int()) { x = 3; i++; } __ikos_assert(i >= 0); // any numerical domain >= intervals will do it __ikos_assert(x == 2 || x == 3); // a numerical domain with some // reasoning for disequalities (currently // only intervals if the interval is a singleton) return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-10.c000066400000000000000000000005011473507761200244540ustar00rootroot00000000000000#include #include extern void __ikos_assert(int); long foo(long n, ...) { long r = 0; va_list ap; va_start(ap, n); for (long i = 0; i < n; i++) { r += va_arg(ap, long); } va_end(ap); return r; } int main() { long r = foo(4, 1, 2, 3, 4); __ikos_assert(r == 10); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-11.c000066400000000000000000000005621473507761200244640ustar00rootroot00000000000000#include extern void __ikos_assert(int); int foo(int n, ...) { int* p; int r = 0; va_list ap; va_start(ap, n); for (int i = 0; i < n; i++) { p = va_arg(ap, int*); r += *p; } va_end(ap); return r; } int main() { int x = 1, y = 2, z = 3; int r = foo(2, &x, &y, &z); __ikos_assert(r >= 0); __ikos_assert(r == 3); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-12.c000066400000000000000000000003211473507761200244560ustar00rootroot00000000000000extern void __ikos_assert(int); void f(int* p, int* q) { if (p == q) { __ikos_assert(0); } else { __ikos_assert(1); } } int main() { int a[10]; int b[10]; f(&a[0], &b[0]); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-13.c000066400000000000000000000011451473507761200244640ustar00rootroot00000000000000#include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int g = 0; // void(int) void a(int x) { g = 1; } // void(double) void b(double x) { g = 2; } // void(int*) void c(int* x) { g = 3; } // void(int*) typedef void (*fun_ptr_t)(int*); int main() { void* vtable[3]; vtable[0] = (void*)a; vtable[1] = (void*)b; vtable[2] = (void*)c; int nd = __ikos_nondet_int(); if (nd >= 0 && nd <= 2) { fun_ptr_t f = (fun_ptr_t)vtable[nd]; f(NULL); // can only call c() because other functions have a wrong signature __ikos_assert(g == 3); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-14.c000066400000000000000000000002441473507761200244640ustar00rootroot00000000000000#include extern void __ikos_assert(int); int main() { uint64_t x = 0x200000001; uint32_t y = (uint32_t)(x); __ikos_assert(y == 1); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-15.cpp000066400000000000000000000002711473507761200250250ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int) noexcept; } class X { public: int v; X() : v(0) { v++; // constructor body } }; X x; int main() { __ikos_assert(x.v == 1); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-16.c000066400000000000000000000006271473507761200244730ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int x = 0; void f(void) { x++; __ikos_assert(x == 1); } void g(void) { f(); __ikos_assert(x == 1); } typedef void (*fun_ptr_t)(void); int main(int argc, char** argv) { fun_ptr_t tab[2]; tab[0] = &f; tab[1] = &g; int i = __ikos_nondet_int(); if (i < 0 || i > 1) { return 0; } fun_ptr_t h = tab[i]; h(); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-17.c000066400000000000000000000004601473507761200244670ustar00rootroot00000000000000#include extern void __ikos_assert(int); extern int __ikos_nondet_int(void); int main() { int x = 0; int* p; if (__ikos_nondet_int()) { p = &x; } else { p = NULL; } int* q = &x; if (p != q) { __ikos_assert(1); } else { __ikos_assert(1); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-18.c000066400000000000000000000003171473507761200244710ustar00rootroot00000000000000#include extern void __ikos_assert(int); int main() { uint16_t k; for (k = 0; k < 60000; k++) { asm volatile("nop"); } __ikos_assert(1); __ikos_assert(k == 60000); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-19.c000066400000000000000000000003561473507761200244750ustar00rootroot00000000000000extern int __ikos_nondet_int(void); extern void __ikos_assert(int); int main() { int i, j; j = 0; for (i = 0; i < 10; ++i) { if (__ikos_nondet_int()) { j++; } __ikos_assert(j >= 0 && j <= 10); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-2.c000066400000000000000000000002661473507761200244050ustar00rootroot00000000000000extern void __ikos_assert(int); int x = 4; int y = 5; float z = 8; int main() { while (x < 10) { x++; } y--; z = z + y; __ikos_assert(x + y + z == 26); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-20.c000066400000000000000000000003441473507761200244620ustar00rootroot00000000000000extern void __ikos_assert(int); int f() { return 1; } unsigned g() { return 1; } int main() { int* p = (int*)f(); int* q = (int*)g(); int* r = (int*)1; __ikos_assert(p == q); __ikos_assert(p == r); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-21-exceptions.cpp000066400000000000000000000005671473507761200272110ustar00rootroot00000000000000extern "C" { extern int __ikos_nondet_int(void) noexcept; extern void __ikos_assert(int) noexcept; } int x = 0; void may_throw() { x = 1; if (__ikos_nondet_int()) { throw nullptr; } } extern int f(); int main() { may_throw(); try { __ikos_assert(x == 1); x = 2; f(); } catch (void*) { __ikos_assert(x == 2); } __ikos_assert(x == 2); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-22-exceptions.cpp000066400000000000000000000005121473507761200272000ustar00rootroot00000000000000extern "C" { extern int __ikos_nondet_int(void) noexcept; extern void __ikos_assert(int) noexcept; } int x; void f() { if (__ikos_nondet_int() == 47) { throw 42; } } int main() { x = 0; f(); x = 1; try { f(); x = 2; } catch (int) { __ikos_assert(x == 1); } __ikos_assert(x >= 1 && x <= 2); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-23.c000066400000000000000000000005031473507761200244620ustar00rootroot00000000000000#include #include extern void __ikos_assert(int); int* f() { int* p = (int*)malloc(sizeof(int)); if (p == NULL) { exit(0); } return p; } int main() { int* p = f(); *p = 0; int* q = f(); *q = 42; __ikos_assert(p != q); __ikos_assert(*p == 0); __ikos_assert(*q == 42); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-24.c000066400000000000000000000002271473507761200244660ustar00rootroot00000000000000extern void __ikos_assert(int); struct { struct { int a; }; double b[]; } c = {{9}}; int main() { __ikos_assert(c.a == 9); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-25.c000066400000000000000000000003231473507761200244640ustar00rootroot00000000000000#include #include extern void __ikos_assert(int); int main() { errno = 0; printf("hello world\n"); __ikos_assert(errno == 0); // errno could be != 0, assertion is wrong return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-26.c000066400000000000000000000020511473507761200244650ustar00rootroot00000000000000#include extern void __ikos_assert(int); extern unsigned __ikos_nondet_uint(void); extern void __ikos_forget_mem(void* ptr, size_t size); extern void __ikos_abstract_mem(void* ptr, size_t size); typedef struct { int integers[2]; int* pointers[2]; } Struct; int main() { int x = 3, y = 3; Struct s = {{1, 2}, {&x, &y}}; __ikos_assert(s.integers[0] == 1); // OK __ikos_assert(s.integers[1] == 2); // OK __ikos_assert(*s.pointers[__ikos_nondet_uint() % 2] == 3); // OK __ikos_abstract_mem(&s.integers[0], sizeof(s.integers)); __ikos_assert(s.integers[0] == 1); // NO __ikos_assert(s.integers[1] == 2); // NO __ikos_assert(*s.pointers[__ikos_nondet_uint() % 2] == 3); // OK __ikos_forget_mem(&s.integers[0], sizeof(s.integers)); __ikos_assert(s.integers[0] == 1); // NO __ikos_assert(s.integers[1] == 2); // NO __ikos_assert(*s.pointers[__ikos_nondet_uint() % 2] == 3); // NO } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-27.c000066400000000000000000000010241473507761200244650ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); static int x = 0; static int y = 0; static int f() { int status = __ikos_nondet_int(); if (status < 0) { return -1; } x++; status = __ikos_nondet_int(); if (status < 0) { return -2; } x++; y++; return 0; } int main() { int status = f(); if (status == -1) { __ikos_assert(x == 0 && y == 0); } else if (status == -2) { __ikos_assert(x == 1 && y == 0); } else { __ikos_assert(x == 2 && y == 1); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-28.c000066400000000000000000000012601473507761200244700ustar00rootroot00000000000000extern void __ikos_assert(int); extern int __ikos_nondet_int(void); static int x = 0; static int y = 0; static int z = 0; static int f() { int status = __ikos_nondet_int(); if (status < 0) { __builtin_unreachable(); } x++; status = __ikos_nondet_int(); if (status < 0) { return -1; } x++; y++; status = __ikos_nondet_int(); if (status < 0) { return -2; } x++; y++; z++; return 0; } int main() { int status = f(); if (status == -1) { __ikos_assert(x == 1 && y == 0 && z == 0); } else if (status == -2) { __ikos_assert(x == 2 && y == 1 && z == 0); } else { __ikos_assert(x == 3 && y == 2 && z == 1); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-29.cpp000066400000000000000000000014451473507761200250360ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int) noexcept; extern int __ikos_nondet_int(void) noexcept; } static int x = 0; static int y = 0; static int z = 0; static int f() { int status = __ikos_nondet_int(); if (status < 0) { throw nullptr; } x++; status = __ikos_nondet_int(); if (status < 0) { return -1; } x++; y++; status = __ikos_nondet_int(); if (status < 0) { return -2; } x++; y++; z++; return 0; } int main() { try { int status = f(); if (status == -1) { __ikos_assert(x == 1 && y == 0 && z == 0); } else if (status == -2) { __ikos_assert(x == 2 && y == 1 && z == 0); } else { __ikos_assert(x == 3 && y == 2 && z == 1); } } catch (...) { __ikos_assert(x == 0 && y == 0 && z == 0); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-3.c000066400000000000000000000002711473507761200244020ustar00rootroot00000000000000// for relational domains extern void __ikos_assert(int); int main() { int i = 0; int x = 0; while (i < 10) { i++; x += 32; } __ikos_assert(x == 320); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-4.cpp000066400000000000000000000016231473507761200247450ustar00rootroot00000000000000// test exception handling extern "C" { extern void __ikos_assert(int) noexcept; extern int __ikos_nondet_int(void) noexcept; } int x; int y; int f() { x = 0; y = 0; try { if (__ikos_nondet_int()) { x = 1; throw 0x42; } else if (__ikos_nondet_int()) { return 0; } } catch (int) { __ikos_assert(x == 1); if (__ikos_nondet_int()) { y = 1; throw 0x42; } else { return 1; } } return 2; } int main() { try { int r = f(); __ikos_assert(r >= 0 && r <= 2); // ok __ikos_assert(x >= 0 && x <= 1); // ok __ikos_assert(y == 0); // ok } catch (int) { __ikos_assert(x == 1); // ok __ikos_assert(y == 1); // warning because ikos is imprecise on the type of // exception. The first catch() {...} catches all exceptions and rethrow // the exception if it does not have the type void*. } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-5.cpp000066400000000000000000000005721473507761200247500ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int) noexcept; extern int __ikos_nondet_int(void) noexcept; } int x; void no_exit() { while (true) { } } void throw_exc() { throw 0x42; } void f() { if (__ikos_nondet_int()) { x = 1; throw_exc(); } no_exit(); } int main() { x = 0; try { f(); } catch (int) { __ikos_assert(x == 1); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-6.cpp000066400000000000000000000007751473507761200247560ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int) noexcept; } class A { public: A() noexcept {} virtual void f() { __ikos_assert(false); } virtual void g() { __ikos_assert(false); } virtual ~A() {} }; class B : public A { public: B() noexcept {} void f() { __ikos_assert(true); } void g() { __ikos_assert(false); } }; class C : public A { public: C() noexcept {} void f() { __ikos_assert(false); } void g() { __ikos_assert(false); } }; int main() { A* a = new B(); a->f(); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-7.cpp000066400000000000000000000006351473507761200247520ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int) noexcept; } class Vector { public: int _x; int _y; int _z; Vector(int x, int y, int z) noexcept : _x(x), _y(y), _z(z) {} }; int f(Vector* v) { return v->_y; } class Master { public: Vector* _v; int* _p; Master() { _v = new Vector(1, 2, 3); _p = new int(4); __ikos_assert(f(_v) == 2); } }; int main() { Master master; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-8.cpp000066400000000000000000000006201473507761200247450ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int) noexcept; extern int __ikos_nondet_int(void) noexcept; } int x = 0; void may_throw() { x = 1; if (__ikos_nondet_int()) { throw 0x42; } } void does_not_throw() { x = 2; } void does_not_catch() { try { does_not_throw(); } catch (int) { __ikos_assert(false); // unreachable } } int main() { may_throw(); does_not_catch(); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/prover/test-9.c000066400000000000000000000005111473507761200244050ustar00rootroot00000000000000#include #include extern void __ikos_assert(int); long foo(long a, ...) { long r = a; va_list ap; va_start(ap, a); r += va_arg(ap, long); r += va_arg(ap, long); r += va_arg(ap, long); va_end(ap); return r; } int main() { long r = foo(1, 2, 3, 4); __ikos_assert(r == 10); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/runalltests000077500000000000000000000002111473507761200241020ustar00rootroot00000000000000#!/usr/bin/sh for d in `find -type d` do if test -x "$d/runtest" then echo "++++++++++++" echo $d $d/runtest fi echo "" done NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/shc/000077500000000000000000000000001473507761200223575ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/shc/runtest000077500000000000000000000055061473507761200240170ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the shift count analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the shift count analysis') t = TestManager(root=current_dir) t.add(Test('test-1-negative.c', 'test-1-negative.c', 'shc', 'error')) t.add(Test('test-2-warnings.c', 'test-2-warnings.c', 'shc', 'unsafe')) t.add(Test('test-3-oversized.c', 'test-3-oversized.c', 'shc', 'error')) t.add(Test('test-4-unsigned.c', 'test-4-unsigned.c', 'shc', 'error')) t.add(Test('test-5-safe.c', 'test-5-safe.c', 'shc', 'safe')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/shc/test-1-negative.c000066400000000000000000000003471473507761200254440ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main() { int a = __ikos_nondet_int(); int b = __ikos_nondet_int(); if (b > 0) { b = -b; } else if (b == 0) { b = -1; } int c = a << b; return c; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/shc/test-2-warnings.c000066400000000000000000000003051473507761200254650ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main() { int a = __ikos_nondet_int(); int b = __ikos_nondet_int(); if (b > 0) { b = -b; } int c = a >> b; return c; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/shc/test-3-oversized.c000066400000000000000000000003611473507761200256520ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main() { int a = __ikos_nondet_int(); int b = __ikos_nondet_int(); if (b < 0) { b = -b; } else if (b == 0) { b = 2; } b *= 32; int c = a << b; return c; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/shc/test-4-unsigned.c000066400000000000000000000003261473507761200254560ustar00rootroot00000000000000#include extern unsigned __ikos_nondet_uint(void); int main() { unsigned a = __ikos_nondet_uint(); if (a > 1000) { return 0; } unsigned b = a * 8 + 42; unsigned c = a << b; return c; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/shc/test-5-safe.c000066400000000000000000000003031473507761200245540ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main() { int a = __ikos_nondet_int(); int b = __ikos_nondet_int(); if (b < 0 || b >= 32) { return 0; } return a << b; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/000077500000000000000000000000001473507761200223745ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/runtest000077500000000000000000000060031473507761200240250ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing signed integer overflow analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the signed integer overflow analysis') t = TestManager(root=current_dir) t.add(Test('test-1-overflow-unsafe.c', 'test-1-overflow-unsafe.c', 'sio', 'error')) t.add(Test('test-2-underflow-unsafe.c', 'test-2-underflow-unsafe.c', 'sio', 'error')) t.add(Test('test-3-warnings.c', 'test-3-warnings.c', 'sio', 'unsafe')) t.add(Test('test-4-safe.c', 'test-4-safe.c', 'sio', 'safe')) t.add(Test('test-5-div-unsafe.c', 'test-5-div-unsafe.c', 'sio', 'error')) t.add(Test('test-6-warning.c', 'test-6-warning.c', 'sio', 'unsafe')) t.add(Test('test-7-rem.c', 'test-7-rem.c', 'sio', 'error')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/test-1-overflow-unsafe.c000066400000000000000000000004041473507761200267730ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int x = __ikos_nondet_int(); int y = __ikos_nondet_int(); int z; if (x >= INT_MAX - 1 && y >= 2) { z = x + y; } else { z = 42; } printf("%d", z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/test-2-underflow-unsafe.c000066400000000000000000000004041473507761200271360ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int x = __ikos_nondet_int(); int y = __ikos_nondet_int(); int z; if (x <= INT_MIN + 1 && y >= 2) { z = x - y; } else { z = 42; } printf("%d", z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/test-3-warnings.c000066400000000000000000000003011473507761200254770ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int x, y, z; x = __ikos_nondet_int(); y = __ikos_nondet_int(); z = x + y; printf("%d", z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/test-4-safe.c000066400000000000000000000004721473507761200245770ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int x = __ikos_nondet_int(); int y = __ikos_nondet_int(); int lim = INT_MAX / 2; if (x > lim || x < 0) { x = lim - 1; } if (y > lim || y < 0) { y = lim - 1; } int z; z = x + y; printf("%d", z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/test-5-div-unsafe.c000066400000000000000000000002441473507761200257200ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int x, y, z; x = INT_MIN; y = -1; z = x / y; printf("%d", z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/test-6-warning.c000066400000000000000000000002161473507761200253240ustar00rootroot00000000000000extern int __ikos_nondet_int(void); int main() { int x = __ikos_nondet_int(); if (x < 0) { return -x; } else { return 0; } } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sio/test-7-rem.c000066400000000000000000000002571473507761200244500ustar00rootroot00000000000000#include #include extern int __ikos_nondet_int(void); int main() { int x = INT_MIN; int y = -1; int z = x % y; printf("%d", z); return z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/000077500000000000000000000000001473507761200227325ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/runtest000077500000000000000000000057171473507761200243760ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the soundness analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the soundness analysis') t = TestManager(root=current_dir) t.add(Test('test-store.c', 'test-store.c', 'sound', 'unsafe')) t.add(Test('test-memcpy.c', 'test-memcpy.c', 'sound', 'unsafe')) t.add(Test('test-memmove.c', 'test-memmove.c', 'sound', 'unsafe')) t.add(Test('test-memset.c', 'test-memset.c', 'sound', 'unsafe')) t.add(Test('test-free.c', 'test-free.c', 'sound', 'unsafe')) t.add(Test('test-call-side-effect.c', 'test-call-side-effect.c', 'sound', 'unsafe')) t.add(Test('test-recursive.c', 'test-recursive.c', 'sound', 'unsafe')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/test-call-side-effect.c000066400000000000000000000001671473507761200271460ustar00rootroot00000000000000extern char* os_name(void); extern int os_strlen(char*); int main() { char* p = os_name(); return os_strlen(p); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/test-free.c000066400000000000000000000001571473507761200247770ustar00rootroot00000000000000#include extern char* os_name(void); int main() { char* p = os_name(); free(p); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/test-memcpy.c000066400000000000000000000001751473507761200253500ustar00rootroot00000000000000#include extern char* os_name(void); int main() { char* p = os_name(); memcpy(p, "Linux", 6); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/test-memmove.c000066400000000000000000000001761473507761200255240ustar00rootroot00000000000000#include extern char* os_name(void); int main() { char* p = os_name(); memmove(p, "Linux", 6); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/test-memset.c000066400000000000000000000001671473507761200253510ustar00rootroot00000000000000#include extern char* os_name(void); int main() { char* p = os_name(); memset(p, 0, 7); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/test-recursive.c000066400000000000000000000002671473507761200260670ustar00rootroot00000000000000extern void f1(void); extern void f2(void); extern void f3(void); void f1(void) { f2(); } void f2(void) { f3(); } void f3(void) { f1(); } int main() { f1(); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/sound/test-store.c000066400000000000000000000001331473507761200252040ustar00rootroot00000000000000extern char* os_name(void); int main() { char* p = os_name(); *p = 'a'; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uio/000077500000000000000000000000001473507761200223765ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uio/runtest000077500000000000000000000052131473507761200240310ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing unsigned integer overflow analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the unsigned integer overflow analysis') t = TestManager(root=current_dir) t.add(Test('test-1-overflow-unsafe.c', 'test-1-overflow-unsafe.c', 'uio', 'error')) t.add(Test('test-2-safe.c', 'test-2-safe.c', 'uio', 'safe')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uio/test-1-overflow-unsafe.c000066400000000000000000000004341473507761200270000ustar00rootroot00000000000000#include #include extern unsigned __ikos_nondet_uint(void); int main() { unsigned x = __ikos_nondet_uint(); unsigned y = __ikos_nondet_uint(); unsigned z; if (x >= UINT_MAX - 1 && y >= 2) { z = x + y; } else { z = 42; } printf("%d", z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uio/test-2-safe.c000066400000000000000000000005041473507761200245730ustar00rootroot00000000000000#include #include extern unsigned __ikos_nondet_uint(void); int main() { unsigned x = __ikos_nondet_uint(); unsigned y = __ikos_nondet_uint(); unsigned lim = INT_MAX / 2; if (x > lim) { x = lim - 1; } if (y > lim) { y = lim - 1; } unsigned z; z = x + y; printf("%d", z); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/000077500000000000000000000000001473507761200223645ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-10-safe.c000066400000000000000000000001631473507761200246410ustar00rootroot00000000000000int main() { double a[10]; int i; for (i = 0; i < 10; ++i) { a[i] = 1.0; } a[i] = 0.0; return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-11-safe.c000066400000000000000000000002721473507761200246430ustar00rootroot00000000000000struct Foo { int x; double a[10]; }; void f(struct Foo* p) { int i; for (i = 0; i < 10; ++i) { p->a[i] = 1.0; } } int main() { struct Foo foo; f(&foo); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-12-safe.c000066400000000000000000000003101473507761200246350ustar00rootroot00000000000000struct Foo { int x; double a[10]; }; void f(double* p, int n) { int i; for (i = 0; i < n; ++i) { p[i] = 1.0; } } int main() { struct Foo foo; f((double*)&foo.a, 10); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-13-error.c000066400000000000000000000002011473507761200250500ustar00rootroot00000000000000int* foo(int* x, int* y) { return x + *y; } int main() { int a[10]; int b = 5; int* z = foo(&a[0], &b); return *z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-13-safe.c000066400000000000000000000002371473507761200246460ustar00rootroot00000000000000int* foo(int* x, int* y) { int* z = x + *y; *z = 78; return x + *y; } int main() { int a[10]; int b = 5; int* z = foo(&a[0], &b); return *z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-20-safe.c000066400000000000000000000005651473507761200246500ustar00rootroot00000000000000// Test that generates extractelem, insertelem and range for a struct #include typedef struct { int x1; int x2; int x3; } vector_t; vector_t f() { vector_t v; v.x1 = 1; v.x2 = 2; v.x3 = 3; return v; } void print_vector(vector_t v) { printf("%d %d %d\n", v.x1, v.x2, v.x3); } int main() { vector_t v = f(); print_vector(v); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-3-error.c000066400000000000000000000002141473507761200247730ustar00rootroot00000000000000// From http://blog.regehr.org/archives/519 int main(void) { int a[6], i; for (i = 0; i < 5; i++) { a[i] = 1; } return a[5]; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-3-safe.c000066400000000000000000000002141473507761200245600ustar00rootroot00000000000000// From http://blog.regehr.org/archives/519 int main(void) { int a[6], i; for (i = 0; i < 6; i++) { a[i] = 1; } return a[5]; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-4-error-1.c000066400000000000000000000000751473507761200251370ustar00rootroot00000000000000int main(void) { int a[15]; return a[10]; // undefined } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-4-error-2.c000066400000000000000000000001251473507761200251340ustar00rootroot00000000000000void bar(int* p) {} int main(void) { int x; bar(&x); return x; // undefined } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uma/test-7-safe.c000066400000000000000000000004731473507761200245730ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); void foo(int vsupply, int LOW_BATTERY_DECIVOLT) { static int t = 0; if (vsupply < LOW_BATTERY_DECIVOLT) t++; else t = 0; printf("%d\n", t); } int main(int argc, char** argv) { foo(__ikos_nondet_int(), __ikos_nondet_int()); return 42; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/000077500000000000000000000000001473507761200223675ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/runtest000077500000000000000000000076451473507761200240350ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the unaligned pointer analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the unaligned pointer analysis') t = TestManager(root=current_dir) t.add(Test('test-1.c', 'test-1.c', 'upa', 'safe')) t.add(Test('test-1-unsafe.c', 'test-1-unsafe.c', 'upa', 'error', line_checks=[(24, 'error')])) t.add(Test('test-2.c', 'test-2.c', 'upa', 'safe')) t.add(Test('test-3.c', 'test-3.c', 'upa', 'safe')) t.add(Test('test-4.c', 'test-4.c (interval)', 'upa', 'safe', expected='unsafe')) t.add(Test('test-4.c', 'test-4.c (congruence)', 'upa', 'safe', domain='congruence')) t.add(Test('test-4-unsafe.c', 'test-4-unsafe.c (interval)', 'upa', 'error', expected='unsafe', line_checks=[(21, 'error', 'warning')])) t.add(Test('test-4-unsafe.c', 'test-4-unsafe.c (congruence)', 'upa', 'error', domain='congruence', line_checks=[(21, 'error')])) t.add(Test('test-5-unsafe.c', 'test-5-unsafe.c (interval)', 'upa', 'error', expected='unsafe', line_checks=[(15, 'error', 'warning')])) t.add(Test('test-5-unsafe.c', 'test-5-unsafe.c (congruence)', 'upa', 'error', domain='congruence', line_checks=[(15, 'error')])) t.add(Test('test-6.c', 'test-6.c', 'upa', 'safe')) t.add(Test('test-7-unsafe.c', 'test-7-unsafe.c', 'upa', 'error', line_checks=[(22, 'error')])) t.add(Test('test-8-unsafe.c', 'test-8-unsafe.c', 'upa', 'error', expected='unsafe', line_checks=[(21, 'error', 'warning'), (25, 'error', 'warning')])) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-1-unsafe.c000066400000000000000000000017421473507761200251330ustar00rootroot00000000000000// UNSAFE // This test performs a malloc and tries to access every byte independently // The access should be aligned on the first access, but not on the following // // The Misaligned access is caused by setting the an uint16_t pointer to the // second byte of a malloc. To remove the incompatible-pointer-type warning, // the malloc pointer is casted to a void* // // The undefined behaviour appears on the pointer cast operated: dynAlloc is of // type uint8_t (1 byte), while the secondByte pointer is of type uint16_t, thus // making an implicit cast from a 8b to a 16b pointer. See (6.3.2.3.7) of // ISO/IEC 9899:TC2 for more details. #include #include #include int main(int argc, char* argv[]) { // Request 3 bytes, the first is aligned, the second is aligned to 1 byte, // not to 2 bytes uint8_t* dynAlloc = malloc(3); uint16_t* secondByte = (void*)(dynAlloc + 1); printf("Access to %p, value: %x\n", secondByte, *secondByte); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-1.c000066400000000000000000000007431473507761200236540ustar00rootroot00000000000000// SAFE // This test performs a malloc and tries to access every byte independently // The access should be aligned on the two accesses // #include #include #include int main(int argc, char* argv[]) { // Request 3 bytes, the first is aligned, the second is aligned to 1 byte, // not to 2 bytes uint8_t* dynAlloc = malloc(3); uint8_t* secondByte = dynAlloc + 1; printf("Access to %p, value: %x\n", secondByte, *secondByte); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-2.c000066400000000000000000000015251473507761200236540ustar00rootroot00000000000000// SAFE // This test does an aligned alloc with specific alignment properties and then // does a realloc over it // // The over-alignment is not guaranteed anymore after a realloc have been done. // // WARNING: The non guaranteed alignment is the one specified by the // aligned_alloc, not by the one guaranted by the realloc (not an UB) #include #include #include // Only available since C11 extern void* aligned_alloc(size_t alignment, size_t size); int main(int argc, char* argv[]) { int* aligned_ptr = aligned_alloc(1 << 12, sizeof(int)); printf("Aligned pointer: %p, value %d\n", aligned_ptr, *aligned_ptr); int* possibly_non_aligned = realloc(aligned_ptr, 324000000 * sizeof(int)); printf("unkown pointer: %p, value %d", possibly_non_aligned, *possibly_non_aligned); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-3.c000066400000000000000000000014301473507761200236500ustar00rootroot00000000000000// This test performs an access in an unaligned struct, thus resulting in // undefined behaviour // // The access are not volatile to get UBSan check the alignment #include #include #include int main(int argc, char* argv[]) { // reg2 is uint32_t, thus it is not aligned because of the reg1, there // should be additionnal padding to use a struct like this typedef struct __attribute__((__packed__)) { uint8_t reg1; uint32_t reg2; } twoRegs_t; // Malloc to force the structure to be in memory and not optimized inside // the registers twoRegs_t* twoRegs = malloc(sizeof(twoRegs_t)); // Perform writing twoRegs->reg2 = 30000; // Perform a reading printf("%p\n", &twoRegs->reg2); printf("%i\n", twoRegs->reg2); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-4-unsafe.c000066400000000000000000000005641473507761200251370ustar00rootroot00000000000000// SAFE // Adds odd number to a uint16_t address, resulting in unsafe access #include extern int __ikos_nondet_int(void); uint16_t* foo(uint8_t* x, uint8_t* y) { return (uint16_t*)(x + *y); } int main() { uint16_t a = 0; uint8_t b = 3; if (__ikos_nondet_int()) b = 5 * b; else b = 7; uint16_t* z = foo((uint8_t*)&a, &b); return *z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-4.c000066400000000000000000000005451473507761200236570ustar00rootroot00000000000000// SAFE // Adds even number to a uint16_t address, still resulting in safe access #include extern int __ikos_nondet_int(void); uint16_t* foo(uint16_t* x, uint16_t* y) { return x + *y; } int main() { uint16_t a = 0; uint16_t b = 2; if (__ikos_nondet_int()) b = 4 * b; else b = 6; uint16_t* z = foo(&a, &b); return *z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-5-unsafe.c000066400000000000000000000004111473507761200251270ustar00rootroot00000000000000// UNSAFE // global variable is 2-aligned, add 1 so it's unaligned #include extern int __ikos_nondet_int(void); uint16_t x; int main() { int a = 1; if (__ikos_nondet_int()) a = 3; uint16_t* b = (uint16_t*)((uint8_t*)&x + a); return *b; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-6.c000066400000000000000000000004741473507761200236620ustar00rootroot00000000000000// SAFE // Runs some safe code with lots of special functions that are caught // differently in the analyzer #include #include #include int main() { const char* s = "AAAA"; int a = strlen(s); char* p = malloc(sizeof(*s)); memcpy(p, s, sizeof(*s)); printf(p); return a; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-7-unsafe.c000066400000000000000000000006061473507761200251370ustar00rootroot00000000000000// UNSAFE // Complex function that gives an offset #include #include uint8_t foo(uint8_t k, uint8_t N) { return k + N; } uint8_t bar(uint8_t p) { return p + foo(p, 10); } int main(int argc, char** argv) { uint8_t a[56]; uint8_t x = foo(5, 10); // x=15 uint8_t y = x + bar(x); // y=55 a[x] = y; uint16_t* test; test = a[x] + y + 1; return *test; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/upa/test-8-unsafe.c000066400000000000000000000013601473507761200251360ustar00rootroot00000000000000#include #include #include #include void foo(const char* fmt, ...) { va_list ap; uint8_t* a; uint16_t* b; uint32_t* c; va_start(ap, fmt); while (*fmt) { switch (*fmt++) { case '8': /* uint8_t */ a = va_arg(ap, uint8_t*); printf("int %d\n", *a); break; case '1': /* uint16_t */ b = va_arg(ap, uint16_t*); printf("int %d\n", *b); break; case '3': /* uint32_t */ c = va_arg(ap, uint32_t*); printf("int %d\n", *c); break; default: break; } } va_end(ap); } int main() { uint32_t a[10] = {0}; foo("813", ((char*)&a[0]) + 1, ((char*)&a[0]) + 1, ((char*)&a[0]) + 1); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/000077500000000000000000000000001473507761200223755ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/runtest000077500000000000000000000133501473507761200240310ustar00rootroot00000000000000#!/usr/bin/env python ################################################################################ # Script for testing the uninitialized variable analysis # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ import os.path import sys current_dir = os.path.dirname(os.path.abspath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.insert(0, parent_dir) sys.dont_write_bytecode = True from libruntest import TestManager, Test, parse_args if __name__ == '__main__': parse_args(description='Regression tests for the uninitialized variable analysis') t = TestManager(root=current_dir) t.add(Test('test-1-safe.c', 'test-1-safe.c', 'uva', 'safe')) t.add(Test('test-1-error.c', 'test-1-error.c', 'uva', 'error')) t.add(Test('test-2-safe.c', 'test-2-safe.c', 'uva', 'safe')) t.add(Test('test-2-error-1.c', 'test-2-error-1.c', 'uva', 'error')) t.add(Test('test-2-error-2.c', 'test-2-error-2.c', 'uva', 'error', expected='safe')) t.add(Test('test-8-safe.c', 'test-8-safe.c', 'uva', 'safe')) t.add(Test('test-8-warning.c', 'test-8-warning.c', 'uva', 'unsafe', expected='safe')) t.add(Test('test-8-warning.c', 'test-8-warning.c (opt_level=none)', 'uva', 'unsafe', opt_level='none')) t.add(Test('test-14-safe.c', 'test-14-safe.c', 'uva', 'safe')) t.add(Test('test-15-error.c', 'test-15-error.c', 'uva', 'error')) t.add(Test('test-16-error.c', 'test-16-error.c', 'uva', 'error')) t.add(Test('test-17-error.c', 'test-17-error.c', 'uva', 'error')) t.add(Test('test-18-error.c', 'test-18-error.c', 'uva', 'error')) t.add(Test('test-19-error.c', 'test-19-error.c', 'uva', 'error')) t.add(Test('test-20-safe.c', 'test-20-safe.c', 'uva', 'safe')) t.add(Test('test-20-safe.c', 'test-20-safe.c', 'uva', 'safe', opt_level='aggressive')) t.add(Test('test-21-safe.cpp', 'test-21-safe.cpp', 'uva', 'safe')) t.add(Test('test-21-safe.cpp', 'test-21-safe.cpp', 'uva', 'safe', opt_level='aggressive')) t.add(Test('test-22-error.c', 'test-22-error.c', 'uva', 'error')) t.add(Test('test-23-warning.c', 'test-23-warning.c', 'uva', 'unsafe')) t.add(Test('test-24-error.cpp', 'test-24-error.cpp', 'uva', 'error')) t.add(Test('test-25-warning.c', 'test-25-warning.c', 'uva', 'unsafe', expected='safe')) t.add(Test('test-25-warning.c', 'test-25-warning.c (opt_level=none)', 'uva', 'unsafe', opt_level='none')) t.add(Test('test-26-error.cpp', 'test-26-error.cpp', 'uva', 'error')) t.add(Test('test-27-error.c', 'test-27-error.c', 'uva', 'error')) t.add(Test('test-28-error.cpp', 'test-28-error.cpp', 'uva', 'error')) t.add(Test('test-29-safe.cpp', 'test-29-safe.cpp', 'uva', 'safe', expected='unsafe')) t.add(Test('test-30-safe.c', 'test-30-safe.c', 'uva', 'safe')) t.add(Test('test-31-error.cpp', 'test-31-error.cpp', 'uva', 'error')) t.add(Test('test-32-error.cpp', 'test-32-error.cpp', 'uva', 'error')) # The following test seems to have some debug information mismatch so ignore that. t.add(Test('test-33-error.cpp', 'test-33-error.cpp', 'uva', 'error', options=['-allow-dbg-mismatch'])) # In the following 2 test there are warnings coming from the standard library. # A future PR to IKOS may contain the ability to filter these out so that # the focus is on the user code. This test has no warnings in user code. t.add(Test('test-34-safe.cpp', 'test-34-safe.cpp', 'uva', 'safe', expected='unsafe')) t.add(Test('test-35-safe.cpp', 'test-35-safe.cpp', 'uva', 'safe', expected='unsafe')) # The following test is really an error but current analysis is only giving warning. t.add(Test('test-36-error.cpp', 'test-36-error.cpp', 'uva', 'error', expected='unsafe')) t.add(Test('test-37-error.cpp', 'test-37-error.cpp', 'uva', 'error')) t.add(Test('test-38-safe.cpp', 'test-38-safe.cpp', 'uva', 'safe')) t.add(Test('test-39-error.cpp', 'test-39-error.cpp', 'uva', 'error')) t.run() NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-1-error.c000066400000000000000000000003671473507761200250130ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main(int argc, char** argv) { argc = __ikos_nondet_int(); if (argc > 0) { int k, i; for (i = 0; i < 10; i++) { k = k + 1; } printf("%d", k); } return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-1-safe.c000066400000000000000000000002341473507761200245710ustar00rootroot00000000000000#include int main(int argc, char** argv) { int k, i; k = 0; for (i = 0; i < 10; i++) { k = k + 1; } printf("%d", k); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-14-safe.c000066400000000000000000000004501473507761200246550ustar00rootroot00000000000000int x = 5; float y = 5.7; extern int __ikos_nondet_int(void); void incr_x() { if (__ikos_nondet_int()) x++; } void incr_y() { if (__ikos_nondet_int()) y = y + 1.0; } int main() { int a; incr_x(); a = x; float b; incr_y(); b = y; int c = a + (int)b; return c; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-15-error.c000066400000000000000000000001161473507761200250700ustar00rootroot00000000000000void f(int* p) { *p = 0x42; } int main() { int* p; f(p); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-16-error.c000066400000000000000000000001101473507761200250630ustar00rootroot00000000000000int f(int* p) { return *p; } int main() { int* p; return f(p); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-17-error.c000066400000000000000000000001751473507761200250770ustar00rootroot00000000000000#include void f(int* p) { char tab[10]; memcpy(p, tab, 105); } int main() { int* p; f(p); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-18-error.c000066400000000000000000000001751473507761200251000ustar00rootroot00000000000000#include void f(int* p) { char tab[10]; memcpy(tab, p, 105); } int main() { int* p; f(p); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-19-error.c000066400000000000000000000001521473507761200250740ustar00rootroot00000000000000#include void f(int* p) { memset(p, 0, 10); } int main() { int* p; f(p); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-2-error-1.c000066400000000000000000000001731473507761200251450ustar00rootroot00000000000000// From http://blog.regehr.org/archives/519 int main(void) { int y, z; for (y = 0; y < 5; y++) z++; return z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-2-error-2.c000066400000000000000000000010561473507761200251470ustar00rootroot00000000000000// From http://blog.regehr.org/archives/519 // This is an example where the compiler can use undefinedness to make // a bit surprising transformation. Note that z may be // uninitialized. The compiler notices that and it initializes it. // This is a sound transformation since the program has an undefined // behavior so the compiler can do whatever it wants. extern int __ikos_nondet_int(void); int main(int argc, char** argv) { argc = __ikos_nondet_int(); int y, z; if (argc > 2) { z = 5; } for (y = 0; y < 5; y++) z++; return z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-2-safe.c000066400000000000000000000002041473507761200245670ustar00rootroot00000000000000// From http://blog.regehr.org/archives/519 int main(void) { int y, z; z = 0; for (y = 0; y < 5; y++) z++; return z; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-20-safe.c000066400000000000000000000005651473507761200246610ustar00rootroot00000000000000// Test that generates extractelem, insertelem and range for a struct #include typedef struct { int x1; int x2; int x3; } vector_t; vector_t f() { vector_t v; v.x1 = 1; v.x2 = 2; v.x3 = 3; return v; } void print_vector(vector_t v) { printf("%d %d %d\n", v.x1, v.x2, v.x3); } int main() { vector_t v = f(); print_vector(v); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-21-safe.cpp000066400000000000000000000004341473507761200252150ustar00rootroot00000000000000// Test that generates array inside structs #include typedef struct { float x; float y; } pos_t; typedef struct { pos_t begin; pos_t end; } line_t; line_t f(float y) { return {{0.0, y}, {2.0, 0}}; } int main() { printf("%f\n", f(2.0).begin.y); return 0; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-22-error.c000066400000000000000000000001701473507761200250660ustar00rootroot00000000000000#include int main() { int* p = (int*)malloc(sizeof(int)); if (!p) { return 0; } return *p + 5; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-23-warning.c000066400000000000000000000004251473507761200254060ustar00rootroot00000000000000#include int main(int argc, char** argv) { int* p = NULL; int x = 0; p = malloc(sizeof(int)); // uninitialized if (!p) { return 0; } if (argc) { p = &x; } int y = *p; // initialized if p = &x but uninitialized if p = malloc(..) return y; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-24-error.cpp000066400000000000000000000001301473507761200254240ustar00rootroot00000000000000int main(int argc, char *argv[]) { int myray[2]; myray[1] = 5; return myray[0]; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-25-warning.c000066400000000000000000000001421473507761200254040ustar00rootroot00000000000000int main(int argc, char** argv) { int ivar; if(argc > 1) { ivar = 5; } return ivar; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-26-error.cpp000066400000000000000000000001031473507761200254260ustar00rootroot00000000000000#include int main() { int* p = new int; return *p; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-27-error.c000066400000000000000000000000541473507761200250740ustar00rootroot00000000000000int main() { int* ivar; return *ivar; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-28-error.cpp000066400000000000000000000004531473507761200254400ustar00rootroot00000000000000#include struct MyStruct { int _aa; int _bb; MyStruct() noexcept { //_aa = 5; _bb = 7; } }; int main(int argc, char *argv[]) { MyStruct* test1 = nullptr; int i = 0; do { test1 = new MyStruct; i++; }while (i < 2); return test1->_aa; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-29-safe.cpp000066400000000000000000000006451473507761200252310ustar00rootroot00000000000000#include struct MyStruct { int _aa; int _bb; MyStruct() noexcept { _aa = 5; _bb = 7; } }; int main(int argc, char *argv[]) { // This test gives a false positive because the ikos AR // does not assure that the body is executed at least once. // That could probably be fixed. MyStruct* test1 = nullptr; for(int i = 0; i < 2;i++) { test1 = new MyStruct; } return test1->_aa; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-30-safe.c000066400000000000000000000001771473507761200246610ustar00rootroot00000000000000#include int main() { char* p = malloc(sizeof(char)); if (!p) { return 5; } *p = 3; return (int)*p; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-31-error.cpp000066400000000000000000000001471473507761200254320ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { bool* test1 = new bool; return (int)*test1; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-32-error.cpp000066400000000000000000000002671473507761200254360ustar00rootroot00000000000000#include bool* getBool() { return new bool; } int main(int argc, char *argv[]) { bool* test1 = new bool; bool* test2 = getBool(); return (int)(*test1 && *test2); } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-33-error.cpp000066400000000000000000000001671473507761200254360ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { std::shared_ptr test1 (new bool); return (int)*test1; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-34-safe.cpp000066400000000000000000000002741473507761200252230ustar00rootroot00000000000000#include using namespace std; int main(int argc, char *argv[]) { auto test1 = make_shared(); //dereference pointer that is properly initialized. return (int)*test1; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-35-safe.cpp000066400000000000000000000003611473507761200252210ustar00rootroot00000000000000#include using namespace std; struct MyStruct { int _aa; int _bb; MyStruct() noexcept { _aa = 5; _bb = 7; } }; int main(int argc, char *argv[]) { auto test1 = make_shared(); return test1->_aa; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-36-error.cpp000066400000000000000000000003601473507761200254340ustar00rootroot00000000000000#include using namespace std; struct MyStruct { int _aa; int _bb; MyStruct() noexcept { //_aa = 5; _bb = 7; } }; int main(int argc, char *argv[]) { auto test1 = make_shared(); return test1->_aa; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-37-error.cpp000066400000000000000000000001671473507761200254420ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { std::unique_ptr test1 (new bool); return (int)*test1; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-38-safe.cpp000066400000000000000000000002061473507761200252220ustar00rootroot00000000000000#include using namespace std; int main(int argc, char *argv[]) { auto test1 = make_unique(); return (int)*test1; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-39-error.cpp000066400000000000000000000002561473507761200254430ustar00rootroot00000000000000struct MyStruct { int _aa; int _bb; MyStruct() noexcept { //_aa = 5; _bb = 7; } }; int main(int argc, char *argv[]) { MyStruct ss{}; return ss._aa; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-8-safe.c000066400000000000000000000004171473507761200246030ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); int main(int argc, char** argv) { argc = __ikos_nondet_int(); if (argc < 0) return 42; int x; if (argc == 0) x = 0; else if (argc == 1) x = 1; else if (argc > 1) x = 2; return x; } NASA-SW-VnV-ikos-1d98c65/analyzer/test/regression/uva/test-8-warning.c000066400000000000000000000007741473507761200253400ustar00rootroot00000000000000#include extern int __ikos_nondet_int(void); // gcc test-8.c -Wuninitialized -o test-8 // gcc does not report any warning. // uno test-8.c: uno: in fct main, possibly uninitialized variable 'x' // this test is biased by the compiler. It should be unsafe but ikos reports // safe. int main(int argc, char** argv) { argc = __ikos_nondet_int(); if (argc < 0) return 42; int x; if (argc == 0) x = 0; else if (argc == 1) x = 1; else if (argc > 2) x = 2; return x; } NASA-SW-VnV-ikos-1d98c65/ar/000077500000000000000000000000001473507761200152205ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/CMakeLists.txt000066400000000000000000000134011473507761200177570ustar00rootroot00000000000000#******************************************************************************* # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2017-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR) if (POLICY CMP0074) cmake_policy(SET CMP0074 NEW) endif() project(ikos-abstract-representation) # # Build settings # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "In-source builds are not allowed. Please clean your source tree and try again.") endif() if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE) endif() if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "Install directory" FORCE) endif() if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "CMake generator: ${CMAKE_GENERATOR}") endif() # # Dependency checks # # Add path for custom modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") set(CUSTOM_BOOST_ROOT "" CACHE PATH "Path to custom boost installation") if (CUSTOM_BOOST_ROOT) set(BOOST_ROOT "${CUSTOM_BOOST_ROOT}") set(Boost_NO_SYSTEM_PATHS TRUE) endif() find_package(Boost 1.55.0 REQUIRED) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) find_package(GMP REQUIRED) include_directories(SYSTEM ${GMP_INCLUDE_DIR}) include_directories(SYSTEM ${GMPXX_INCLUDE_DIR}) find_package(Core REQUIRED) include_directories(${CORE_INCLUDE_DIR}) # # Compiler flags # include(AddFlagUtils) add_compiler_flag(REQUIRED "CXX14" "-std=c++1y") add_compiler_flag(REQUIRED "FVISIBILITY_INLINES_HIDDEN" "-fvisibility-inlines-hidden") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compiler_flag(REQUIRED "WEVERYTHING" "-Weverything") add_compiler_flag(OPTIONAL "WNO_SWITCH_ENUM" "-Wno-switch-enum") add_compiler_flag(OPTIONAL "WNO_PADDED" "-Wno-padded") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT" "-Wno-c++98-compat") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT_PEDANTIC" "-Wno-c++98-compat-pedantic") add_compiler_flag(OPTIONAL "WNO_COVERED_SWITCH_DEFAULT" "-Wno-covered-switch-default") add_compiler_flag(OPTIONAL "WNO_WEAK_VTABLES" "-Wno-weak-vtables") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") add_compiler_flag(REQUIRED "WALL" "-Wall") add_compiler_flag(REQUIRED "WEXTRA" "-Wextra") endif() # # Targets # include_directories(include) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.hpp" ) add_library(ikos-ar src/format/dot.cpp src/format/namer.cpp src/format/text.cpp src/pass/add_loop_counters.cpp src/pass/add_partitioning_variables.cpp src/pass/name_values.cpp src/pass/pass.cpp src/pass/simplify_cfg.cpp src/pass/simplify_upcast_comparison.cpp src/semantic/bundle.cpp src/semantic/code.cpp src/semantic/context.cpp src/semantic/context_impl.cpp src/semantic/data_layout.cpp src/semantic/function.cpp src/semantic/intrinsic.cpp src/semantic/statement.cpp src/semantic/type.cpp src/semantic/value.cpp src/verify/frontend.cpp src/verify/type.cpp ) target_link_libraries(ikos-ar ${GMP_LIB} ${GMPXX_LIB} ) install(TARGETS ikos-ar ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) # # Doxygen # find_package(Doxygen) if (DOXYGEN_FOUND) configure_file(doc/doxygen/Doxyfile.in doc/Doxyfile @ONLY) add_custom_target(doxygen-ar ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMENT "Generating AR API documentation with Doxygen" VERBATIM ) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doc/html" DESTINATION doc/ar OPTIONAL) endif() # # If it's the top level CMakeLists.txt, Add some aliases # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) add_custom_target(doc DEPENDS doxygen-ar) endif() NASA-SW-VnV-ikos-1d98c65/ar/README.md000066400000000000000000000043251473507761200165030ustar00rootroot00000000000000IKOS Abstract Representation ============================ This folder contains the implementation of the Abstract Representation. Introduction ------------ The Abstract Representation is an assembly language used internally in IKOS. Installation ------------ IKOS Abstract Representation is a C++ library. It can be installed independently from the other components. ### Dependencies To build IKOS AR, you will need the following dependencies: * A C++ compiler that supports C++14 (gcc >= 4.9.2 or clang >= 3.4) * CMake >= 2.8.12.2 * GMP >= 4.3.1 * Boost >= 1.55 * IKOS Core ### Build and Install To build and install IKOS AR, run the following commands in the `ar` directory: ``` $ mkdir build $ cd build $ cmake \ -DCMAKE_INSTALL_PREFIX=/path/to/ar-install-directory \ -DCORE_ROOT=/path/to/core-install-directory \ .. $ make $ make install ``` ### Documentation To build the documentation, you will need [Doxygen](http://www.doxygen.org). Then, simply type: ``` $ make doc $ open doc/html/index.html ``` Overview of the source code --------------------------- The following illustrates the directory structure of this folder: ``` . ├── doc │ └── doxygen ├── include │ └── ikos │ └── ar │ ├── format │ ├── pass │ ├── semantic │ ├── support │ └── verify └── src ├── format ├── pass ├── semantic └── verify ``` #### doc/ Contains Doxygen files. #### include/ * [include/ikos/ar/format](include/ikos/ar/format) contains definition of formatters for the AR, e.g, a text formatter, a dot formatter, etc. * [include/ikos/ar/pass](include/ikos/ar/pass) contains definition of passes on the AR. * [include/ikos/ar/semantic](include/ikos/ar/semantic) contains definition of the AR assembly language, e.g, functions, basic blocks, statements, etc. * [include/ikos/ar/support](include/ikos/ar/support) contains various helpers, e.g, assertions. * [include/ikos/ar/verify](include/ikos/ar/verify) contains definition of verifiers for the AR, e.g, a type checker. #### src/ Contains implementation files, following the structure of `include/ikos/ar`. NASA-SW-VnV-ikos-1d98c65/ar/doc/000077500000000000000000000000001473507761200157655ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/doc/doxygen/000077500000000000000000000000001473507761200174425ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/doc/doxygen/Doxyfile.in000066400000000000000000002336661473507761200215750ustar00rootroot00000000000000#******************************************************************************* # Notices: # # Copyright (c) 2017-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "IKOS AR" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = "@PACKAGE_VERSION@" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@/doc" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = "@CMAKE_CURRENT_SOURCE_DIR@/include" # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = "@CMAKE_CURRENT_SOURCE_DIR@/include" # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 2 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = NO # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/include" \ "@CMAKE_CURRENT_SOURCE_DIR@/doc/doxygen/mainpage.dox" # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */.git* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = detail # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 4 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = ikos::ar:: #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = pdflatex \\nonstopmode\\input # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = YES # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. EXTERNAL_PAGES = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. DIA_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = NO # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of # processors available in the system. You can set it explicitly to a value # larger than 0 to get control over the balance between CPU load and processing # speed. # Minimum value: 0, maximum value: 32, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. DOT_NUM_THREADS = 0 # When you want a differently looking font n the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by # setting DOT_FONTPATH to the directory containing the font. # The default value is: Helvetica. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size (in points) of the font of # dot graphs. # Minimum value: 4, maximum value: 24, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the default font as specified with # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside the # class node. If there are many fields or methods and many nodes the graph may # become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the # number of items for each type to make the size more manageable. Set this to 0 # for no limit. Note that the threshold may be exceeded by 50% before the limit # is enforced. So when you set the threshold to 10, up to 15 fields may appear, # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # # Note that this requires a modern browser other than Internet Explorer. Tested # and working are Firefox, Chrome, Safari, and Opera. # Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make # the SVG files visible. Older versions of IE do not have SVG support. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). DIAFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = YES # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the reference definitions. This must be a list of .bib # files. The .bib extension is automatically appended if omitted. This # requires the bibtex tool to be installed. For LaTeX the style of the # bibliography can be controlled using LATEX_BIB_STYLE. See also \cite # for info how to create references. CITE_BIB_FILES = NASA-SW-VnV-ikos-1d98c65/ar/doc/doxygen/mainpage.dox000066400000000000000000000021321473507761200217350ustar00rootroot00000000000000/// \mainpage IKOS: Inference Kernel for Open Static Analyzers /// /// \section Introduction /// Welcome to IKOS. /// /// IKOS is a C++ library designed to facilitate the development of sound static /// analyzers based on Abstract Interpretation. Specialization of a static /// analyzer for an application or family of applications is critical for /// achieving both precision and scalability. Developing such an analyzer is /// arduous and requires significant expertise in Abstract Interpretation. /// /// This documentation describes the internal representation of a program, /// also called abstract representation. /// /// \section Contact /// Contact us by sending an email to ikos@lists.nasa.gov /// /// \section Contributors /// * Maxime Arthaud /// * Thomas Bailleux /// * Guillaume Brat /// * Clément Decoodt /// * Arnaud Hamon /// * Jorge Navas /// * Elodie-Jane Simms /// * Nija Shi /// * Sarah Thompson /// * Arnaud Venet /// * Alexandre Wimmers /// /// \section License /// This software is released under the terms and conditions of the NASA Open /// Source Agreement (NOSA) Version 1.3 or later. NASA-SW-VnV-ikos-1d98c65/ar/include/000077500000000000000000000000001473507761200166435ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/000077500000000000000000000000001473507761200176105ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/000077500000000000000000000000001473507761200202125ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/format/000077500000000000000000000000001473507761200215025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/format/dot.hpp000066400000000000000000000071121473507761200230020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Dot format for the abstract representation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace ar { /// \brief Dot formatter class DotFormatter : public Formatter { public: /// \brief Public constructor explicit DotFormatter(FormatOptions opts = DefaultFormat) : Formatter(opts) {} /// \brief Copy constructor DotFormatter(const DotFormatter&) noexcept = default; /// \brief Move constructor DotFormatter(DotFormatter&&) noexcept = default; /// \brief Copy assignment operator DotFormatter& operator=(const DotFormatter&) noexcept = default; /// \brief Move assignment operator DotFormatter& operator=(DotFormatter&&) noexcept = default; /// \brief Destructor ~DotFormatter() = default; /// \brief Format a function into a .dot void format(std::ostream&, Function*) const; /// \brief Format a global variable into a .dot void format(std::ostream&, GlobalVariable*) const; private: /// \brief Format a code into a .dot void format(std::ostream&, Code*) const; /// \brief Format a basic block into a .dot void format(std::ostream&, BasicBlock*, const Namer&) const; /// \brief Escape .dot forbidden characters (such as '{', '}') static std::string armor(StringRef); }; // end class DotFormatter } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/format/formatter.hpp000066400000000000000000000076171473507761200242310ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Base class for formatter of the abstract representation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Base class for formatters class Formatter { public: /// \brief Formatting options enum FormatOption { NoOption = 0x0, /// \brief When formatting a statement, show the result type ShowResultType = 0x1, /// \brief When formatting a statement, show the operand types ShowOperandTypes = 0x2, /// \brief Order global variables and functions by name /// /// This is useful to have a deterministic output, for testing purposes. OrderGlobals = 0x4, /// \brief Default format DefaultFormat = ShowResultType, }; /// \brief Formatting options using FormatOptions = Flags< FormatOption >; protected: FormatOptions _opts; public: /// \brief Public constructor explicit Formatter(FormatOptions opts = DefaultFormat) : _opts(opts) {} /// \brief Copy constructor Formatter(const Formatter&) noexcept = default; /// \brief Move constructor Formatter(Formatter&&) noexcept = default; /// \brief Copy assignment operator Formatter& operator=(const Formatter&) noexcept = default; /// \brief Move assignment operator Formatter& operator=(Formatter&&) noexcept = default; /// \brief Destructor ~Formatter() = default; /// \brief Show the result type of the statements bool show_result_type() const { return this->_opts.test(ShowResultType); } /// \brief Show the operand types of the statements bool show_operand_types() const { return this->_opts.test(ShowOperandTypes); } /// \brief Order global variables and functions bool order_globals() const { return this->_opts.test(OrderGlobals); } }; // end class Formatter IKOS_DECLARE_OPERATORS_FOR_FLAGS(Formatter::FormatOptions) } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/format/namer.hpp000066400000000000000000000060171473507761200233210ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Provide deterministic names to variables and basic blocks * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace ar { /// \brief Provide deterministic names to variables and basic blocks class Namer { private: // Map from variable to name std::unordered_map< Variable*, std::string > _variables; // Map from basic block to name std::unordered_map< BasicBlock*, std::string > _basic_blocks; public: /// \brief Public constructor Namer(); /// \brief Public constructor explicit Namer(Code*); /// \brief Initialize the namer with the given code void init(Code*); /// \brief Return the deterministic name of the given variable const std::string& name(Variable*) const; /// \brief Return the deterministic name of the given basic block const std::string& name(BasicBlock*) const; }; // end class Namer } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/format/text.hpp000066400000000000000000000107011473507761200231760ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Text format for the abstract representation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include namespace ikos { namespace ar { /// \brief Text formatter class TextFormatter : public Formatter { public: /// \brief Public constructor explicit TextFormatter(FormatOptions opts = DefaultFormat) : Formatter(opts) {} /// \brief Copy constructor TextFormatter(const TextFormatter&) noexcept = default; /// \brief Move constructor TextFormatter(TextFormatter&&) noexcept = default; /// \brief Copy assignment operator TextFormatter& operator=(const TextFormatter&) noexcept = default; /// \brief Move assignment operator TextFormatter& operator=(TextFormatter&&) noexcept = default; /// \brief Destructor ~TextFormatter() = default; /// \brief Format a bundle into text format void format(std::ostream&, Bundle*) const; /// \brief Format a global variable into text format void format(std::ostream&, GlobalVariable*) const; // \brief Format just the head part of a function. void format_header(std::ostream&, const Function*, Namer&) const; /// \brief Format a function into text format void format(std::ostream&, Function*) const; /// \brief Format a code into text format void format(std::ostream&, Code*) const; /// \brief Format a code into text format void format(std::ostream&, Code*, const Namer&) const; /// \brief Format a basic block into text format void format(std::ostream&, BasicBlock*) const; /// \brief Format a basic block into text format void format(std::ostream&, BasicBlock*, const Namer&) const; /// \brief Format a statement into text format void format(std::ostream&, Statement*) const; /// \brief Format a statement into text format void format(std::ostream&, Statement*, const Namer&) const; /// \brief Format a type into text format void format(std::ostream&, Type*) const; /// \brief Format a value into text format void format(std::ostream&, Value*, const Namer&, bool show_type = false) const; }; // end class TextFormatter } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/pass/000077500000000000000000000000001473507761200211605ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/pass/add_loop_counters.hpp000066400000000000000000000060711473507761200254000ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Add Loop Counters pass * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Add Loop Counters pass /// /// This pass adds a hidden loop counter variable within each loop, using the /// `ikos.counter.init` and `ikos.counter.incr` intrinsic functions. /// /// This can be used by the gauge abstract domain to infer loop invariants. class AddLoopCountersPass final : public CodePass { public: /// \brief Default constructor AddLoopCountersPass() = default; /// \brief Get the pass name const char* name() const override; /// \brief Get the pass description const char* description() const override; /// \brief Run the pass on the given Bundle /// /// Returns true if the bundle has been updated bool run(Bundle*) override; private: /// \brief Run the pass on the given Code /// /// Returns true if the code has been updated bool run_on_code(Code*) override; }; // end class AddLoopCountersPass } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/pass/add_partitioning_variables.hpp000066400000000000000000000061141473507761200272420ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Add Partitioning Variables pass * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Add Partitioning Variables pass /// /// This pass adds annotations to functions that return an error code. It /// detects integer variables containing the error code and adds calls to the /// `ikos.partitioning.var.*` intrinsic functions. class AddPartitioningVariablesPass final : public Pass { public: /// \brief Default constructor AddPartitioningVariablesPass() = default; /// \brief Get the pass name const char* name() const override; /// \brief Get the pass description const char* description() const override; /// \brief Run the pass on the given Bundle /// /// Returns true if the bundle has been updated bool run(Bundle*) override; private: /// \brief Run the pass on the given function /// /// Returns true if the function has been updated bool run_on_function(Function*); }; // end class AddPartitioningVariablesPass } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/pass/name_values.hpp000066400000000000000000000056461473507761200242030ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pass to give a name to all variables and basic blocks * * This is very useful for debugging. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Pass to give a name to all variables and basic blocks class NameValuesPass final : public CodePass { private: bool _prefix; public: /// \brief Default constructor /// /// \param prefix Prefix variable names with their function name explicit NameValuesPass(bool prefix) : _prefix(prefix) {} /// \brief Get the pass name const char* name() const override; /// \brief Get the pass description const char* description() const override; private: /// \brief Run the pass on the given Code /// /// Returns true if the code has been updated bool run_on_code(Code*) override; }; // end class NameValuesPass } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/pass/pass.hpp000066400000000000000000000070131473507761200226400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Define base classes for passes * * All passes should extend one of the classes below. * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace ar { /// \brief Base class for passes class Pass { public: /// \brief Default constructor Pass() = default; /// \brief Copy constructor Pass(const Pass&) noexcept = default; /// \brief Move constructor Pass(Pass&&) noexcept = default; /// \brief Copy assignment operator Pass& operator=(const Pass&) noexcept = default; /// \brief Move assignment operator Pass& operator=(Pass&&) noexcept = default; /// \brief Destructor virtual ~Pass() = default; /// \brief Run the pass on the given Bundle /// /// Returns true if the bundle has been updated virtual bool run(Bundle*) = 0; /// \brief Get the pass name virtual const char* name() const = 0; /// \brief Get the pass description virtual const char* description() const = 0; }; // end class Pass /// \brief Helper class for passes that work on Codes class CodePass : public Pass { public: /// \brief Default constructor CodePass() = default; /// \brief Run the pass on the given Bundle /// /// Returns true if the bundle has been updated bool run(Bundle*) override; private: /// \brief Run the pass on the given Code /// /// Returns true if the code has been updated virtual bool run_on_code(Code*) = 0; }; // end class CodePass } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/pass/simplify_cfg.hpp000066400000000000000000000055361473507761200243550ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pass to simplify control flow graphs * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Pass to simplify control flow graphs /// /// The main goal of this pass is to merge basic blocks with their only child, /// thus reducing the number of basic blocks. class SimplifyCFGPass final : public CodePass { public: /// \brief Default constructor SimplifyCFGPass() = default; /// \brief Get the pass name const char* name() const override; /// \brief Get the pass description const char* description() const override; private: /// \brief Run the pass on the given Code /// /// Returns true if the code has been updated bool run_on_code(Code*) override; }; // end class SimplifyCFGPass } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/pass/simplify_upcast_comparison.hpp000066400000000000000000000103321473507761200273350ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pass to simplify upcasts before a comparison. * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace ar { /// \brief Simplify upcasts that happen before a comparison /// /// This pass adds assertions after comparisons on upcasts. The goal is to /// help the numerical analysis in ikos. /// /// For instance: /// /// [ si32 %1 = sext %0 ] /// / \  /// [ %1 silt 10 ] [ %1 sige 10 ] /// /// Will become: /// /// [ si32 %1 = sext %0 ] /// / \  /// [ %1 silt 10 ] [ %1 sige 10 ] /// [ %0 silt 10 ] [ %0 sige 10 ] class SimplifyUpcastComparisonPass final : public CodePass { private: using IntInterval = core::machine_int::Interval; using ZInterval = core::numeric::Interval< ZNumber >; public: /// \brief Default constructor SimplifyUpcastComparisonPass() = default; /// \brief Get the pass name const char* name() const override; /// \brief Get the pass description const char* description() const override; private: /// \brief Run the pass on the given Code /// /// Return true if the code has been updated bool run_on_code(Code*) override; /// \brief Run the pass on the given statement /// /// Return true if we should backtrace that statement bool run_on_statement(Statement*); /// \brief Backtrace a comparison statement /// /// Return true if the code has been updated bool run_on_comparison(Comparison*, IntegerConstant*, Value*); /// \brief Run the pass on the upcast associated to a comparison /// /// Return true if this if the upcast we want boost::optional< IntegerConstant* > run_on_upcast(Context&, Value*, IntegerConstant*); /// \brief Insert an assert for simplifying an upcast comparison void insert_assert( Comparison*, Value*, IntegerConstant*, IntegerConstant*, bool); }; // end class SimplifyUpcastComparisonPass } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic.hpp000066400000000000000000000056341473507761200225360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Semantic definitions * * This header includes: * * ikos/ar/semantic/bundle.hpp * * ikos/ar/semantic/code.hpp * * ikos/ar/semantic/context.hpp * * ikos/ar/semantic/function.hpp * * ikos/ar/semantic/statement.hpp * * ikos/ar/semantic/statement_visitor.hpp * * ikos/ar/semantic/type.hpp * * ikos/ar/semantic/type_visitor.hpp * * ikos/ar/semantic/value.hpp * * ikos/ar/semantic/value_visitor.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/000077500000000000000000000000001473507761200220155ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/bundle.hpp000066400000000000000000000152531473507761200240050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Bundle definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace ar { // forward declaration class GlobalVariable; class Function; /// \brief AR bundle /// /// A bundle is the main container representing a whole program. /// /// It contains a list of global variables and functions. class Bundle : public Traceable { private: // AR Context Context& _context; // Data Layout std::unique_ptr< DataLayout > _data_layout; // Target triple std::string _target_triple; // List of global variables SymbolTable< GlobalVariable > _globals; // List of functions SymbolTable< Function > _functions; public: /// \brief Iterator over a list of global variables using GlobalVariableIterator = SymbolTable< GlobalVariable >::Iterator; /// \brief Iterator over a list of functions using FunctionIterator = SymbolTable< Function >::Iterator; private: /// \brief Private constructor Bundle(Context& ctx, std::unique_ptr< DataLayout > data_layout, std::string triple); public: /// \brief No copy constructor Bundle(const Bundle&) = delete; /// \brief No move constructor Bundle(Bundle&&) = delete; /// \brief No copy assignment operator Bundle& operator=(const Bundle&) = delete; /// \brief No move assignment operator Bundle& operator=(Bundle&&) = delete; /// \brief Destructor ~Bundle(); /// \brief Static constructor static Bundle* create(Context& ctx, std::unique_ptr< DataLayout > data_layout, std::string triple); /// \brief Get the parent context Context& context() const { return this->_context; } /// \brief Get the data layout DataLayout& data_layout() { return *this->_data_layout; } /// \brief Get the data layout const DataLayout& data_layout() const { return *this->_data_layout; } /// \brief Get the target triple const std::string& target_triple() const { return this->_target_triple; } /// \brief Begin iterator over the list of global variables GlobalVariableIterator global_begin() const { return this->_globals.begin(); } /// \brief End iterator over the list of global variables GlobalVariableIterator global_end() const { return this->_globals.end(); } /// \brief Return the number of global variables std::size_t num_globals() const { return this->_globals.size(); } /// \brief Get the global variable with the given name, or nullptr GlobalVariable* global_or_null(const std::string& name) const { return this->_globals.find(name); } /// \brief Begin iterator over the list of functions FunctionIterator function_begin() const { return this->_functions.begin(); } /// \brief End iterator over the list of functions FunctionIterator function_end() const { return this->_functions.end(); } /// \brief Return the number of functions std::size_t num_functions() const { return this->_functions.size(); } /// \brief Get or create the intrinsic function with the given id /// /// Function iterators are invalidated. Function* intrinsic_function(Intrinsic::ID id); /// \brief Get or create the intrinsic function with the given id and type /// parameter /// /// Function iterators are invalidated. Function* intrinsic_function(Intrinsic::ID id, Type* template_ty); /// \brief Get the function with the given name, or nullptr Function* function_or_null(const std::string& name) const { return this->_functions.find(name); } /// \brief Return true if the given name is available bool is_name_available(const std::string& name) const; /// \brief Find an available name with the given prefix std::string find_available_name(StringRef prefix) const; private: /// \brief Add a global variable in the bundle void add_global_variable(std::unique_ptr< GlobalVariable >); /// \brief Rename a global variable void rename_global_variable(GlobalVariable* gv, const std::string& prev_name, const std::string& new_name); /// \brief Add a function in the bundle void add_function(std::unique_ptr< Function >); /// \brief Rename a function void rename_function(Function* fun, const std::string& prev_name, const std::string& new_name); // friends friend class GlobalVariable; friend class Function; }; // end class Bundle } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/code.hpp000066400000000000000000000377131473507761200234530ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Control flow graph definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace ar { // forward declaration class Code; class Statement; /// \brief Basic block /// /// A basic block is a container of statements that execute sequentially. class BasicBlock : public Traceable { private: // List of statements std::vector< std::unique_ptr< Statement > > _statements; // List of successor basic blocks std::vector< BasicBlock* > _successors; // List of predecessor basic blocks std::vector< BasicBlock* > _predecessors; // Parent code Code* _parent; // Name (optional) std::string _name; public: /// \brief Iterator over an ordered list of statements using StatementIterator = boost::transform_iterator< SeqExposeRawPtr< Statement >, std::vector< std::unique_ptr< Statement > >::const_iterator >; /// \brief Reverse iterator over an ordered list of statements using StatementReverseIterator = boost::transform_iterator< SeqExposeRawPtr< Statement >, std::vector< std::unique_ptr< Statement > >::const_reverse_iterator >; /// \brief Iterator over a list of basic block using BasicBlockIterator = std::vector< BasicBlock* >::const_iterator; private: /// \brief Private constructor explicit BasicBlock(Code* code); public: /// \brief No copy constructor BasicBlock(const BasicBlock&) = delete; /// \brief No move constructor BasicBlock(BasicBlock&&) = delete; /// \brief No copy assignment operator BasicBlock& operator=(const BasicBlock&) = delete; /// \brief No move assignment operator BasicBlock& operator=(BasicBlock&&) = delete; /// \brief Destructor ~BasicBlock(); /// \brief Static constructor static BasicBlock* create(Code* code); /// \brief Get the parent context Context& context() const; /// \brief Get the parent bundle Bundle* bundle() const; /// \brief Get the parent code Code* code() const { return this->_parent; } /// \brief Get the first statement Statement* front() const { ikos_assert_msg(!this->_statements.empty(), "basic block is empty"); return this->_statements.front().get(); } /// \brief Get the last statement Statement* back() const { ikos_assert_msg(!this->_statements.empty(), "basic block is empty"); return this->_statements.back().get(); } /// \brief Begin iterator over the statements StatementIterator begin() const { return boost::make_transform_iterator(this->_statements.cbegin(), SeqExposeRawPtr< Statement >()); } /// \brief End iterator over the statements StatementIterator end() const { return boost::make_transform_iterator(this->_statements.cend(), SeqExposeRawPtr< Statement >()); } /// \brief Begin reverse iterator over the statements StatementReverseIterator rbegin() const { return boost::make_transform_iterator(this->_statements.crbegin(), SeqExposeRawPtr< Statement >()); } /// \brief End reverse iterator over the statements StatementReverseIterator rend() const { return boost::make_transform_iterator(this->_statements.crend(), SeqExposeRawPtr< Statement >()); } /// \brief Return the number of statements std::size_t num_statements() const { return this->_statements.size(); } /// \brief Return true if the basic block is empty bool empty() const { return this->_statements.empty(); } /// \brief Insert a statement to the beginning /// /// Statement iterators are invalidated. void push_front(std::unique_ptr< Statement > stmt); /// \brief Add a statement to the end /// /// Statement iterators are invalidated. void push_back(std::unique_ptr< Statement > stmt); /// \brief Insert a statement before `it` /// /// Statement iterators are invalidated. /// /// Returns an iterator on the inserted statement. StatementIterator insert_before(StatementIterator it, std::unique_ptr< Statement > stmt); /// \brief Insert a statement after `it` /// /// Statement iterators are invalidated. /// /// Returns an iterator on the inserted statement. StatementIterator insert_after(StatementIterator it, std::unique_ptr< Statement > stmt); /// \brief Replace the statement at `it` /// /// Returns the previous statement std::unique_ptr< Statement > replace(StatementIterator it, std::unique_ptr< Statement > stmt); /// \brief Remove the statement at `it` /// /// Statement iterators at or after `it` are invalidated. /// /// Returns an iterator on the statement following the removed statement. If /// `it` refers to the last element, it returns the end iterator. StatementIterator remove(StatementIterator it); /// \brief Remove the last statement and return it /// /// The end() statement iterator is invalidated. std::unique_ptr< Statement > pop_back(); /// \brief Remove all statements void clear_statements(); /// \brief Return the number of successors std::size_t num_successors() const { return this->_successors.size(); } /// \brief Begin iterator over the successors BasicBlockIterator successor_begin() const { return this->_successors.cbegin(); } /// \brief End iterator over the successors BasicBlockIterator successor_end() const { return this->_successors.cend(); } /// \brief Return the number of predecessors std::size_t num_predecessors() const { return this->_predecessors.size(); } /// \brief Begin iterator over the predecessors BasicBlockIterator predecessor_begin() const { return this->_predecessors.cbegin(); } /// \brief End iterator over the predecessors BasicBlockIterator predecessor_end() const { return this->_predecessors.cend(); } /// \brief Is the given basic block a successor? bool is_successor(BasicBlock* bb) const; /// \brief Is the given basic block a predecessor? bool is_predecessor(BasicBlock* bb) const; /// \brief Add the given basic block as a successor void add_successor(BasicBlock* bb); /// \brief Add the given basic block as a predecessor void add_predecessor(BasicBlock* bb); /// \brief Remove the given basic block from the list of successors void remove_successor(BasicBlock* bb); /// \brief Remove all successors void clear_successors(); /// \brief Remove the given basic block from the list of predecessors void remove_predecessor(BasicBlock* bb); /// \brief Remove all predecessors void clear_predecessors(); /// \brief Does the basic block have a name? bool has_name() const { return !this->_name.empty(); } /// \brief Get the name const std::string& name() const { ikos_assert_msg(!this->_name.empty(), "basic block has no name"); return this->_name; } /// \brief Get the name /// /// Returns an empty string if the basic block has no name. const std::string& name_or_empty() const { return this->_name; } /// \brief Set the name void set_name(std::string name); /// \brief Dump the basic block for debugging purpose void dump(std::ostream&) const; /// \brief Dump the basic block and its content, for debugging purpose void full_dump(std::ostream&) const; }; // end class BasicBlock /// \brief Code /// /// A code represents the control flow graph of a function or global variable /// initializer class Code : public Traceable { private: // List of basic blocks std::vector< std::unique_ptr< BasicBlock > > _blocks; // List of internal variables std::vector< std::unique_ptr< InternalVariable > > _internal_vars; // Entry block BasicBlock* _entry_block; // Exit block, or null BasicBlock* _exit_block; // Parent function, or null Function* _function; // Parent global variable, or null GlobalVariable* _global_var; // Parent bundle (non-null) Bundle* _bundle; public: /// \brief Iterator over a list of basic block using BasicBlockIterator = boost::transform_iterator< SeqExposeRawPtr< BasicBlock >, std::vector< std::unique_ptr< BasicBlock > >::const_iterator >; /// \brief Iterator over a list of internal variables using InternalVariableIterator = boost::transform_iterator< SeqExposeRawPtr< InternalVariable >, std::vector< std::unique_ptr< InternalVariable > >::const_iterator >; private: /// \brief Private constructor explicit Code(Function* function); /// \brief Private constructor explicit Code(GlobalVariable* gv); public: /// \brief No copy constructor Code(const Code&) = delete; /// \brief No move constructor Code(Code&&) = delete; /// \brief No copy assignment operator Code& operator=(const Code&) = delete; /// \brief No move assignment operator Code& operator=(Code&&) = delete; /// \brief Destructor ~Code(); /// \brief Begin iterator over the list of basic blocks BasicBlockIterator begin() const { return boost::make_transform_iterator(this->_blocks.cbegin(), SeqExposeRawPtr< BasicBlock >()); } /// \brief End iterator over the list of basic blocks BasicBlockIterator end() const { return boost::make_transform_iterator(this->_blocks.cend(), SeqExposeRawPtr< BasicBlock >()); } /// \brief Begin iterator over the list of internal variables InternalVariableIterator internal_variable_begin() const { return boost::make_transform_iterator(this->_internal_vars.cbegin(), SeqExposeRawPtr< InternalVariable >()); } /// \brief End iterator over the list of internal variables InternalVariableIterator internal_variable_end() const { return boost::make_transform_iterator(this->_internal_vars.cend(), SeqExposeRawPtr< InternalVariable >()); } /// \brief Does it have an entry block? /// /// This should always return true, except if we just created this code and /// didn't set the entry block yet. bool has_entry_block() const { return this->_entry_block != nullptr; } /// \brief Get the entry basic block BasicBlock* entry_block() const { ikos_assert_msg(this->_entry_block, "code has no entry block"); return this->_entry_block; } /// \brief Set the entry basic block void set_entry_block(BasicBlock* bb); /// \brief Does it have an exit block? bool has_exit_block() const { return this->_exit_block != nullptr; } /// \brief Get the exit basic block BasicBlock* exit_block() const { ikos_assert_msg(this->_exit_block, "code has no exit block"); return this->_exit_block; } /// \brief Get the exit basic block, or null if there is none BasicBlock* exit_block_or_null() const { return this->_exit_block; } /// \brief Set the exit basic block void set_exit_block(BasicBlock* bb); /// \brief Is it the body of a function? bool is_function_body() const { return this->_function != nullptr; } /// \brief Get the parent function Function* function() const { ikos_assert_msg(this->_function, "code is a global variable initializer"); return this->_function; } /// \brief Get the parent function if it is a body, or nullptr Function* function_or_null() const { return this->_function; } /// \brief Is it the code for a global variable initializer? bool is_global_var_initializer() const { return this->_global_var != nullptr; } /// \brief Get the parent global variable GlobalVariable* global_var() const { ikos_assert_msg(this->_global_var, "code is a function code"); return this->_global_var; } /// \brief Get the parent global variable if it is an initializer, or nullptr GlobalVariable* global_var_or_null() const { return this->_global_var; } /// \brief Get the parent context Context& context() const { return this->bundle()->context(); } /// \brief Get the parent bundle Bundle* bundle() const { return this->_bundle; } private: /// \brief Add a basic block in the code /// /// \returns a pointer on the basic block BasicBlock* add_basic_block(std::unique_ptr< BasicBlock >); public: /// \brief Remove the given basic block /// /// Using the basic block after calling erase_basic_block() is an undefined /// behaviour void erase_basic_block(BasicBlock*); private: /// \brief Add an internal variable in the code /// /// \returns a pointer on the interval variable InternalVariable* add_internal_variable(std::unique_ptr< InternalVariable >); // friends friend class Function; friend class BasicBlock; friend class GlobalVariable; friend class InternalVariable; }; // end class Code } // end namespace ar } // end namespace ikos namespace ikos { namespace core { /// \brief Implement GraphTraits for ar::Code* template <> struct GraphTraits< ar::Code* > { using NodeRef = ar::BasicBlock*; using SuccessorNodeIterator = ar::BasicBlock::BasicBlockIterator; using PredecessorNodeIterator = ar::BasicBlock::BasicBlockIterator; static ar::BasicBlock* entry(ar::Code* code) { return code->entry_block(); } static SuccessorNodeIterator successor_begin(ar::BasicBlock* bb) { return bb->successor_begin(); } static SuccessorNodeIterator successor_end(ar::BasicBlock* bb) { return bb->successor_end(); } static PredecessorNodeIterator predecessor_begin(ar::BasicBlock* bb) { return bb->predecessor_begin(); } static PredecessorNodeIterator predecessor_end(ar::BasicBlock* bb) { return bb->predecessor_end(); } }; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/context.hpp000066400000000000000000000057731473507761200242260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Context definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { // forward declaration class ContextImpl; class Bundle; class Type; class Value; /// \brief AR global context /// /// It owns global data of the Abstract Representation, /// such as bundles and types. class Context { private: // Private implementation std::unique_ptr< ContextImpl > _impl; public: /// \brief Default constructor Context(); /// \brief No copy constructor Context(const Context&) = delete; /// \brief Move constructor Context(Context&&) noexcept = default; /// \brief No copy assignment operator Context& operator=(const Context&) = delete; /// \brief Move assignment operator Context& operator=(Context&&) noexcept = default; /// \brief Destructor ~Context(); // friends friend class Bundle; friend class Type; friend class Value; }; // end class Context } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/data_layout.hpp000066400000000000000000000173601473507761200250430ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Data Layout definition * * Define size and alignment of AR data types. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2023 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace ar { /// \brief Endianness enum Endianness { LittleEndian, BigEndian }; // forward declaration class Type; /// \brief Return the next integer that is greater than or equal to \p value /// and is a multiple of \p align. /// /// \p align must be non-zero. /// /// Examples: /// \code /// align_to(5, 8) = 8 /// align_to(17, 8) = 24 /// align_to(321, 255) = 510 /// \endcode inline ZNumber align_to(const ZNumber& value, const ZNumber& align) { ikos_assert_msg(align != 0, "alignment cannot be 0"); return (value + align - 1) / align * align; } /// \brief Information about a data type struct DataLayoutInfo { /// \brief Bit width uint64_t bit_width; /// \brief ABI alignment, in bytes uint64_t abi_alignment; /// \brief Preferred alignment, in bytes uint64_t pref_alignment; /// \brief Default constructor DataLayoutInfo(uint64_t bit_width_, uint64_t abi_alignment_, uint64_t pref_alignment_) : bit_width(bit_width_), abi_alignment(abi_alignment_), pref_alignment(pref_alignment_) {} }; // end struct DataLayoutInfo /// \brief Target data layout /// /// This class holds information about data type sizes and alignments. class DataLayout { public: /// \brief Endianness (LittleEndian or BigEndian) Endianness endianness; /// \brief Information about pointers DataLayoutInfo pointers; /// \brief Information about integer types (ordered by bit-width) std::vector< DataLayoutInfo > integers; /// \brief Information about floating point types (ordered by bit-width) std::vector< DataLayoutInfo > floats; private: /// \brief Default constructor DataLayout(Endianness endianness, DataLayoutInfo pointers); public: /// \brief No copy constructor DataLayout(const DataLayout&) = delete; /// \brief No move constructor DataLayout(DataLayout&&) = delete; /// \brief No copy assignment operator DataLayout& operator=(const DataLayout&) = delete; /// \brief No move assignment operator DataLayout& operator=(DataLayout&&) = delete; /// \brief Destructor ~DataLayout(); /// \name Constructors /// @{ /// \brief Static constructor static std::unique_ptr< DataLayout > create(Endianness endianness, DataLayoutInfo pointers); /// @} /// \name Endianness /// @{ bool is_little_endian() const { return this->endianness == LittleEndian; } bool is_big_endian() const { return this->endianness == BigEndian; } /// @} /// \name Type alignments /// @{ /// \brief Set the ABI and preferred alignment for integers of the given /// bit-with. void set_integer_alignment(DataLayoutInfo info); /// \brief Set the ABI and preferred alignment for floats of the given /// bit-with. void set_float_alignment(DataLayoutInfo info); /// \brief Return the minimum ABI-required alignment for the given type, /// in bytes. ZNumber abi_alignment(Type*) const; /// \brief Return the preferred alignment for the given type, /// in bytes. ZNumber pref_alignment(Type*) const; /// @} /// \name Type sizes /// @{ /// \brief Return the number of bits necessary to hold the given type. /// /// For example, returns 36 for i36 and 80 for x86_fp80. /// /// Examples: /// /// Type size_in_bits store_size_in_bits alloc_size_in_bits /// ---- ------------ ------------------ ------------------ /// i1 1 8 8 /// i8 8 8 8 /// i19 19 24 32 /// i32 32 32 32 /// i100 100 104 128 /// i128 128 128 128 /// Float 32 32 32 /// Double 64 64 64 /// X86_FP80 80 80 96 ZNumber size_in_bits(Type*) const; /// \brief Return the maximum number of bytes that may be overwritten by /// storing the specified type. /// /// For example, returns 5 for i36 and 10 for x86_fp80. ZNumber store_size_in_bytes(Type* t) const { return (this->size_in_bits(t) + 7) / 8; } /// \brief Return the maximum number of bits that may be overwritten by /// storing the specified type // /// Always a multiple of 8. /// /// For example, returns 40 for i36 and 80 for x86_fp80. ZNumber store_size_in_bits(Type* t) const { return this->store_size_in_bytes(t) * 8; } /// \brief Return the offset in bytes between successive objects of the /// specified type, including alignment padding. /// /// This is the amount of space that Allocate reserves for this type. /// For example, returns 12 or 16 for x86_fp80, depending on alignment. ZNumber alloc_size_in_bytes(Type* t) const { return align_to(this->store_size_in_bytes(t), this->abi_alignment(t)); } /// \brief Return the offset in bits between successive objects of the /// specified type, including alignment padding. /// /// Always a multiple of 8. /// /// This is the amount of space that Allocate reserves for this type. /// For example, returns 96 or 128 for x86_fp80, depending on alignment. ZNumber alloc_size_in_bits(Type* t) const { return this->alloc_size_in_bytes(t) * 8; } /// @} }; // end class DataLayout } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/function.hpp000066400000000000000000000177161473507761200243670ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Function definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace ar { // forward declaration class Code; /// \brief Function class Function : public Traceable { private: // Parent bundle Bundle* _parent; // Name std::string _name; // Type FunctionType* _type; // Intrinsic ID Intrinsic::ID _intrinsic_id; // Body (if definition) std::unique_ptr< Code > _body; // List of local variables (if definition) std::vector< std::unique_ptr< LocalVariable > > _local_vars; // List of parameters (if definition) std::vector< InternalVariable* > _parameters; public: /// \brief Iterator over a list of local variables using LocalVariableIterator = boost::transform_iterator< SeqExposeRawPtr< LocalVariable >, std::vector< std::unique_ptr< LocalVariable > >::const_iterator >; /// \brief Iterator over a list of internal variables using InternalVariableIterator = std::vector< InternalVariable* >::const_iterator; private: /// \brief Private constructor Function(Bundle* bundle, FunctionType* type, std::string name, bool is_definition, Intrinsic::ID intrinsic_id); public: /// \brief No copy constructor Function(const Function&) = delete; /// \brief No move constructor Function(Function&&) = delete; /// \brief No copy assignment operator Function& operator=(const Function&) = delete; /// \brief No move assignment operator Function& operator=(Function&&) = delete; /// \brief Destructor ~Function(); /// \brief Static constructor static Function* create(Bundle* bundle, FunctionType* type, std::string name, bool is_definition, Intrinsic::ID intrinsic_id = Intrinsic::NotIntrinsic); /// \brief Get parent context Context& context() const { return this->bundle()->context(); } /// \brief Get parent bundle Bundle* bundle() const { return this->_parent; } /// \brief Get the name const std::string& name() const { return this->_name; } /// \brief Set the name void set_name(std::string new_name); /// \brief Get the function type FunctionType* type() const { return this->_type; } /// \brief Is this a declaration? bool is_declaration() const { return this->_body == nullptr; } /// \brief Is this a definition? bool is_definition() const { return this->_body != nullptr; } /// \brief Is it a variable argument (var-arg) function? bool is_var_arg() const { return this->_type->is_var_arg(); } /// \brief Is it an intrinsic function? bool is_intrinsic() const { return this->_intrinsic_id != Intrinsic::NotIntrinsic; } /// \brief Is it an ikos intrinsic function? bool is_ikos_intrinsic() const { return this->_intrinsic_id >= Intrinsic::_BeginIkosIntrinsic && this->_intrinsic_id <= Intrinsic::_EndIkosIntrinsic; } /// \brief Is it a libc intrinsic function? bool is_libc_intrinsic() const { return this->_intrinsic_id >= Intrinsic::_BeginLibcIntrinsic && this->_intrinsic_id <= Intrinsic::_EndLibcIntrinsic; } /// \brief Is it a libc++ intrinsic function bool is_libcpp_intrinsic() const { return this->_intrinsic_id >= Intrinsic::_BeginLibcppIntrinsic && this->_intrinsic_id <= Intrinsic::_EndLibcppIntrinsic; } /// \brief Get the intrinsic ID Intrinsic::ID intrinsic_id() const { return this->_intrinsic_id; } /// \brief Get the function body code Code* body() const { ikos_assert_msg(this->_body, "function is a declaration"); return this->_body.get(); } /// \brief Get the function body code, or null if it's a declaration Code* body_or_null() const { return this->_body.get(); } /// \brief Begin iterator over the list of local variables LocalVariableIterator local_variable_begin() const { ikos_assert_msg(this->_body, "function is a declaration"); return boost::make_transform_iterator(this->_local_vars.cbegin(), SeqExposeRawPtr< LocalVariable >()); } /// \brief End iterator over the list of local variables LocalVariableIterator local_variable_end() const { ikos_assert_msg(this->_body, "function is a declaration"); return boost::make_transform_iterator(this->_local_vars.cend(), SeqExposeRawPtr< LocalVariable >()); } /// \brief Get the i-th parameter variable InternalVariable* param(std::size_t i) const { ikos_assert_msg(i < this->_parameters.size(), "invalid index"); return this->_parameters[i]; } /// \brief Begin iterator over the list of parameter variables InternalVariableIterator param_begin() const { ikos_assert_msg(this->_body, "function is a declaration"); return this->_parameters.cbegin(); } /// \brief End iterator over the list of parameter variables InternalVariableIterator param_end() const { ikos_assert_msg(this->_body, "function is a declaration"); return this->_parameters.cend(); } /// \brief Get the number of parameters std::size_t num_parameters() const { return this->_type->num_parameters(); } /// \brief Get a function pointer on this function FunctionPointerConstant* pointer() { return FunctionPointerConstant::get(this->context(), this); } private: /// \brief Add a local variable in the function /// /// \returns a pointer on the local variable LocalVariable* add_local_variable(std::unique_ptr< LocalVariable >); // friends friend class LocalVariable; }; // end class Function } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/intrinsic.hpp000066400000000000000000000120741473507761200245340ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Intrinsic definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { // forward declaration class Bundle; class Type; class FunctionType; /// \brief Helper for intrinsics class Intrinsic { public: /// \brief Unique integer for each intrinsic enum ID { NotIntrinsic = 0, MemoryCopy, MemoryMove, MemorySet, VarArgStart, VarArgEnd, VarArgGet, VarArgCopy, StackSave, StackRestore, LifetimeStart, LifetimeEnd, EhTypeidFor, Trap, _BeginIkosIntrinsic, // IkosAssert, IkosAssume, IkosNonDet, IkosCounterInit, IkosCounterIncr, IkosCheckMemAccess, IkosCheckStringAccess, IkosAssumeMemSize, IkosForgetMemory, IkosAbstractMemory, IkosWatchMemory, IkosPartitioningVar, IkosPartitioningJoin, IkosPartitioningDisable, IkosPrintInvariant, IkosPrintValues, _EndIkosIntrinsic, _BeginLibcIntrinsic, // LibcMalloc, LibcCalloc, LibcValloc, LibcAlignedAlloc, LibcRealloc, LibcFree, LibcAbs, LibcRand, LibcSrand, LibcExit, LibcAbort, // LibcErrnoLocation, // LibcOpen, // LibcClose, LibcRead, LibcWrite, // LibcGets, LibcFgets, LibcGetc, LibcFgetc, LibcGetchar, LibcPuts, LibcFputs, LibcPutc, LibcFputc, LibcPrintf, LibcFprintf, LibcSprintf, LibcSnprintf, LibcScanf, LibcFscanf, LibcSscanf, LibcFopen, LibcFclose, LibcFflush, // LibcStrlen, LibcStrnlen, LibcStrcpy, LibcStrncpy, LibcStrcat, LibcStrncat, LibcStrcmp, LibcStrncmp, LibcStrstr, LibcStrchr, LibcStrdup, LibcStrndup, LibcStrcpyCheck, LibcMemoryCopyCheck, LibcMemoryMoveCheck, LibcMemorySetCheck, LibcStrcatCheck, _EndLibcIntrinsic, _BeginLibcppIntrinsic, LibcppNew, LibcppNewArray, LibcppDelete, LibcppDeleteArray, LibcppAllocateException, LibcppFreeException, LibcppThrow, LibcppBeginCatch, LibcppEndCatch, _EndLibcppIntrinsic, }; /// \brief Prefix for names of intrinsic functions, ie. "ar." constexpr static const char* Prefix = "ar."; /// \brief Get the type of an intrinsic function static FunctionType* type(Bundle*, ID); /// \brief Get the type of an intrinsic function with a type parameter static FunctionType* type(Bundle*, ID, Type*); /// \brief Get the short name of an intrinsic function static std::string short_name(ID); /// \brief Get the short name of an intrinsic function with a type parameter static std::string short_name(ID, Type*); /// \brief Get the long name of the given intrinsic, ie. short name + prefix static std::string long_name(ID); /// \brief Get the long name of the given intrinsic with a type parameter static std::string long_name(ID, Type*); }; // end class Intrinsic } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/statement.hpp000066400000000000000000001416151473507761200245420ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Statement definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace ar { /// \brief Base class for statements class Statement : public Traceable { public: enum StatementKind { AssignmentKind, UnaryOperationKind, BinaryOperationKind, ComparisonKind, ReturnValueKind, UnreachableKind, AllocateKind, PointerShiftKind, LoadKind, StoreKind, ExtractElementKind, InsertElementKind, ShuffleVectorKind, _BeginCallBaseKind, CallKind, InvokeKind, _EndCallBaseKind, LandingPadKind, ResumeKind, }; public: /// \brief List of operands using Operands = core::SmallVector< Value*, 2 >; /// \brief Iterator on operands using OpIterator = Operands::const_iterator; protected: // Kind of statement StatementKind _kind; // Parent basic block BasicBlock* _parent; // Result variable (or nullptr) Variable* _result; // Operands Operands _operands; protected: /// \brief Protected constructor Statement(StatementKind kind, Variable* result, Operands operands); /// \brief Protected constructor Statement(StatementKind kind, Variable* result, std::initializer_list< Value* > operands); public: /// \brief No copy constructor Statement(const Statement&) = delete; /// \brief No move constructor Statement(Statement&&) = delete; /// \brief No copy assignment operator Statement& operator=(const Statement&) = delete; /// \brief No move assignment operator Statement& operator=(Statement&&) = delete; /// \brief Destructor virtual ~Statement(); /// \brief Get the kind of statement StatementKind kind() const { return this->_kind; } /// \brief Get the parent context Context& context() const { return this->bundle()->context(); } /// \brief Get the parent bundle Bundle* bundle() const { return this->code()->bundle(); } /// \brief Get the parent code Code* code() const { return this->parent()->code(); } /// \brief Does it have a parent basic block? bool has_parent() const { return this->_parent != nullptr; } /// \brief Get the parent basic block BasicBlock* parent() const { ikos_assert_msg(this->has_parent(), "statement has no parent"); return this->_parent; } /// \brief Return an iterator on the statement in the parent basic block BasicBlock::StatementIterator iterator() const; /// \brief Return the previous statement in the parent basic block, or nullptr Statement* prev_statement() const; /// \brief Return the next statement in the parent basic block, or nullptr Statement* next_statement() const; /// \brief Does it have a result variable? bool has_result() const { return this->_result != nullptr; } /// \brief Get the result variable Variable* result() const { ikos_assert_msg(this->has_result(), "statement has no result"); return this->_result; } /// \brief Get the result variable, or null if there is no result Variable* result_or_null() const { return this->_result; } /// \brief Get the number of operands std::size_t num_operands() const { return this->_operands.size(); } /// \brief Begin iterator over the operands OpIterator op_begin() const { return this->_operands.cbegin(); } /// \brief End iterator over the operands OpIterator op_end() const { return this->_operands.cend(); } /// \brief Get the n-th operand Value* operand(std::size_t i) const { ikos_assert_msg(i < this->_operands.size(), "invalid index"); return this->_operands[i]; } /// \brief Return true if one operand is ar::UndefinedConstant bool has_undefined_constant_operand() const; /// \brief Dump the statement for debugging purpose virtual void dump(std::ostream&) const = 0; /// \brief Clone the statement /// /// Returns a fresh statement thas has no parent virtual std::unique_ptr< Statement > clone() const = 0; private: /// \brief Set the parent basic block void set_parent(BasicBlock* parent); // friends friend class BasicBlock; }; // end class Statement /// \brief Assignment statement /// /// It represents an assignment statement, /// where the left-hand-side is an InternalVariable. class Assignment final : public Statement { private: /// \brief Private constructor Assignment(InternalVariable* result, Value* operand); public: /// \brief Static constructor static std::unique_ptr< Assignment > create(InternalVariable* result, Value* operand); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the operand Value* operand() const { return this->_operands[0]; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == AssignmentKind; } }; // end class Assignment /// \brief Unary operation class UnaryOperation final : public Statement { public: /// \brief List of operators enum Operator { UTrunc, STrunc, ZExt, SExt, FPTrunc, FPExt, FPToUI, FPToSI, UIToFP, SIToFP, PtrToUI, PtrToSI, UIToPtr, SIToPtr, Bitcast }; private: // Operator Operator _op; private: /// \brief Private constructor UnaryOperation(Operator op, InternalVariable* result, Value* operand); public: /// \brief Static constructor static std::unique_ptr< UnaryOperation > create(Operator op, InternalVariable* result, Value* operand); /// \brief Get the operator Operator op() const { return this->_op; } /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the operand Value* operand() const { return this->_operands[0]; } /// \brief Get a textual representation of the given operator static std::string operator_text(Operator op); /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == UnaryOperationKind; } }; // end class UnaryOperation /// \brief Binary operation class BinaryOperation final : public Statement { public: /// \brief List of operators enum Operator { _BeginIntegerOp, _BeginUnsignedIntegerOp, UAdd, USub, UMul, UDiv, URem, UShl, ULShr, UAShr, UAnd, UOr, UXor, _EndUnsignedIntegerOp, _BeginSignedIntegerOp, SAdd, SSub, SMul, SDiv, SRem, SShl, SLShr, SAShr, SAnd, SOr, SXor, _EndSignedIntegerOp, _EndIntegerOp, _BeginFloatOp, FAdd, FSub, FMul, FDiv, FRem, _EndFloatOp, }; private: /// \brief Operator Operator _op; /// \brief No wrap flag /// /// Indicate that the operation must not wrap, i.e, if an integer overflow /// occurs, it is considered an error that traps the program. /// /// This flag is available for operators: /// UAdd, SAdd, USub, SSub, UMul, SMul, UShl and SShl bool _no_wrap : 1; /// \brief Exact flag /// /// Indicate that if the integer operation is not exact, it is considered an /// error that traps the program. /// /// This flag is available for operators: /// UDiv, SDiv, ULShr, SLShr, UAShr and SAShr bool _exact : 1; private: /// \brief Private constructor BinaryOperation(Operator op, InternalVariable* result, Value* left, Value* right, bool no_wrap, bool exact); public: /// \brief Static constructor static std::unique_ptr< BinaryOperation > create(Operator op, InternalVariable* result, Value* left, Value* right, bool no_wrap = false, bool exact = false); /// \brief Get the operator Operator op() const { return this->_op; } /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the left operand (index 0) Value* left() const { return this->_operands[0]; } /// \brief Get the right operand (index 1) Value* right() const { return this->_operands[1]; } /// \brief Is it an integer operation? bool is_integer_op() const { return this->_op >= _BeginIntegerOp && this->_op <= _EndIntegerOp; } /// \brief Is it an unsigned integer operation? bool is_unsigned_op() const { return this->_op >= _BeginUnsignedIntegerOp && this->_op <= _EndUnsignedIntegerOp; } /// \brief Is it a signed integer operation? bool is_signed_op() const { return this->_op >= _BeginSignedIntegerOp && this->_op <= _EndSignedIntegerOp; } /// \brief Is it a floating point operation? bool is_float_op() const { return this->_op >= _BeginFloatOp && this->_op <= _EndFloatOp; } /// \brief Check if the given operator wraps integers static bool is_wrapping_operator(Operator op) { return op == UAdd || op == SAdd || op == USub || op == SSub || op == UMul || op == SMul || op == UShl || op == SShl; } /// \brief Check if the given operator can be exact static bool is_exact_operator(Operator op) { return op == UDiv || op == SDiv || op == ULShr || op == SLShr || op == UAShr || op == SAShr; } /// \brief Check if the operation must not wrap integers /// /// In this case, If an integer overflow occurs, it is considered an error /// that traps the program. bool has_no_wrap() const { return this->_no_wrap; } /// \brief Check if the operation must be exact /// /// In this case, If the integer operation is not exact, it is considered an /// error that traps the program. bool is_exact() const { return this->_exact; } /// \brief Get a textual representation of the given operator static std::string operator_text(Operator op); /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == BinaryOperationKind; } }; // end class BinaryOperation /// \brief Comparison statement class Comparison final : public Statement { public: /// \brief List of predicates enum Predicate { _BeginIntegerPred, _BeginUnsignedIntegerPred, UIEQ, UINE, UIGT, UIGE, UILT, UILE, _EndUnsignedIntegerPred, _BeginSignedIntegerPred, SIEQ, SINE, SIGT, SIGE, SILT, SILE, _EndSignedIntegerPred, _EndIntegerPred, _BeginFloatPred, FOEQ, FOGT, FOGE, FOLT, FOLE, FONE, FORD, FUNO, FUEQ, FUGT, FUGE, FULT, FULE, FUNE, _EndFloatPred, _BeginPointerPred, PEQ, PNE, PGT, PGE, PLT, PLE, _EndPointerPred, }; private: // Predicate Predicate _predicate; private: /// \brief Private constructor Comparison(Predicate predicate, Value* left, Value* right); public: /// \brief Static constructor static std::unique_ptr< Comparison > create(Predicate predicate, Value* left, Value* right); /// \brief Get the predicate Predicate predicate() const { return this->_predicate; } /// \brief Get the left operand (index 0) Value* left() const { return this->_operands[0]; } /// \brief Get the right operand (index 1) Value* right() const { return this->_operands[1]; } /// \brief Is it an integer comparison? bool is_integer_predicate() const { return this->_predicate >= _BeginIntegerPred && this->_predicate <= _EndIntegerPred; } /// \brief Is it an unsigned integer comparison? bool is_unsigned_predicate() const { return this->_predicate >= _BeginUnsignedIntegerPred && this->_predicate <= _EndUnsignedIntegerPred; } /// \brief Is it a signed integer comparison? bool is_signed_predicate() const { return this->_predicate >= _BeginSignedIntegerPred && this->_predicate <= _EndSignedIntegerPred; } /// \brief Is it a floating point comparison? bool is_float_predicate() const { return this->_predicate >= _BeginFloatPred && this->_predicate <= _EndFloatPred; } /// \brief Is it a pointer comparison? bool is_pointer_predicate() const { return this->_predicate >= _BeginPointerPred && this->_predicate <= _EndPointerPred; } /// \brief Get a textual representation of the given predicate static std::string predicate_text(Predicate pred); /// \brief Get the opposite predicate /// /// For example: /// inverse_predicate(uieq) = uine /// inverse_predicate(silt) = sige static Predicate inverse_predicate(Predicate pred); /// \brief Create the opposite comparison statement /// /// For example: /// inverse(x uieq y) -> x uine y /// inverse(x silt y) -> x sige y std::unique_ptr< Comparison > inverse() const; /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == ComparisonKind; } }; // end class Comparison /// \brief Return statement class ReturnValue final : public Statement { private: /// \brief Private constructor explicit ReturnValue(Value* operand); public: /// \brief Static constructor /// /// \param operand The returned value, or null static std::unique_ptr< ReturnValue > create(Value* operand = nullptr); /// \brief Does it have an operand? bool has_operand() const { return !this->_operands.empty(); } /// \brief Get the operand Value* operand() const { ikos_assert_msg(this->has_operand(), "return has no operand"); return this->_operands[0]; } /// \brief Get the operand, or null if there is none Value* operand_or_null() const { if (this->_operands.empty()) { return nullptr; } else { return this->_operands[0]; } } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == ReturnValueKind; } }; // end class ReturnValue /// \brief Unreachable statement class Unreachable final : public Statement { private: /// \brief Private constructor Unreachable(); public: /// \brief Static constructor static std::unique_ptr< Unreachable > create(); /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == UnreachableKind; } }; // end class Unreachable /// \brief Stack allocation statement class Allocate final : public Statement { private: // Allocated type Type* _allocated_type; private: /// \brief Private constructor Allocate(LocalVariable* result, Type* allocated_type, Value* array_size); public: /// \brief Static constructor static std::unique_ptr< Allocate > create(LocalVariable* result, Type* allocated_type, Value* array_size); /// \brief Get the result local variable LocalVariable* result() const { return cast< LocalVariable >(this->_result); } /// \brief Get the allocated type Type* allocated_type() const { return this->_allocated_type; } /// \brief Get the array size operand Value* array_size() const { return this->_operands[0]; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == AllocateKind; } }; // end class Allocate /// \brief Pointer shift statement /// /// It represents a pointer arithmetic operation. /// It basically represents the operation: /// p = base + a * x + b * y + ... /// /// Note that offsets are in bytes. /// Factors should have type `IntegerType::size_type()`. /// Operands can have any integer type. class PointerShift final : public Statement { public: /// \brief Term /// /// A term is the product of a constant and a value using Term = std::pair< MachineInt, Value* >; private: /// \brief List of factors using Factors = core::SmallVector< MachineInt, 2 >; /// \brief Iterator over the factors using FactorIterator = Factors::const_iterator; public: /// \brief Iterator on the terms class TermIterator : public boost::iterator_facade< TermIterator, const Term, boost::random_access_traversal_tag, const Term > { private: friend class boost::iterator_core_access; private: FactorIterator _factor_it; OpIterator _value_it; public: TermIterator(const FactorIterator& factor_it, const OpIterator& value_it) : _factor_it(factor_it), _value_it(value_it) {} void increment() { ++this->_factor_it; ++this->_value_it; } void decrement() { --this->_factor_it; --this->_value_it; } void advance(std::ptrdiff_t n) { std::advance(this->_factor_it, n); std::advance(this->_value_it, n); } bool equal(const TermIterator& o) const { return this->_factor_it == o._factor_it && this->_value_it == o._value_it; } std::ptrdiff_t distance_to(const TermIterator& o) const { return std::distance(this->_factor_it, o._factor_it); } const Term dereference() const { return {*this->_factor_it, *this->_value_it}; } /// \brief Cannot be implemented const Term* operator->() const = delete; }; // end class TermIterator private: /// \brief List of factors Factors _factors; private: /// \brief Private constructor PointerShift(InternalVariable* result, Value* pointer, const std::vector< Term >& terms); /// \brief Private constructor /// /// Only used by clone() PointerShift(InternalVariable* result, Factors factors, Operands operands); public: /// \brief Static constructor static std::unique_ptr< PointerShift > create( InternalVariable* result, Value* pointer, const std::vector< Term >& terms); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the base pointer Value* pointer() const { return this->_operands[0]; } /// \brief Get the number of terms std::size_t num_terms() const { return this->_factors.size(); } /// \brief Get an operand Term term(std::size_t i) const { ikos_assert_msg(i < this->num_terms(), "invalid index"); return {this->_factors[i], this->_operands[i + 1]}; } /// \brief Begin iterator over the list of operands TermIterator term_begin() const { return {this->_factors.cbegin(), this->op_begin() + 1}; } /// \brief End iterator over the list of operands TermIterator term_end() const { return {this->_factors.cend(), this->op_end()}; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == PointerShiftKind; } }; // end class PointerShift /// \brief Load statement class Load final : public Statement { private: // Alignment of the memory access, in bytes (0 if unspecified) uint64_t _alignment; // Load from a volatile memory location bool _is_volatile; private: /// \brief Private constructor Load(InternalVariable* result, Value* operand, uint64_t alignment, bool is_volatile); public: /// \brief Static constructor static std::unique_ptr< Load > create(InternalVariable* result, Value* operand, uint64_t alignment, bool is_volatile); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the pointer operand Value* operand() const { return this->_operands[0]; } /// \brief Get the alignment of the memory access, in bytes (0 if unspecified) uint64_t alignment() const { return this->_alignment; } /// \brief Return true if this statement has an alignment constraint bool has_alignment() const { return this->alignment() > 0; } /// \brief Return true if this is a load from a volatile memory location bool is_volatile() const { return this->_is_volatile; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == LoadKind; } }; // end class Load /// \brief Store statement class Store final : public Statement { private: // Alignment of the memory access, in bytes (0 if unspecified) uint64_t _alignment; // Load from a volatile memory location bool _is_volatile; private: /// \brief Private constructor Store(Value* pointer, Value* value, uint64_t alignment, bool is_volatile); public: /// \brief Static constructor static std::unique_ptr< Store > create(Value* pointer, Value* value, uint64_t alignment, bool is_volatile); /// \brief Get the pointer operand Value* pointer() const { return this->_operands[0]; } /// \brief Get the value operand Value* value() const { return this->_operands[1]; } /// \brief Get the alignment of the memory access, in bytes (0 if unspecified) uint64_t alignment() const { return this->_alignment; } /// \brief Return true if this statement has an alignment constraint bool has_alignment() const { return this->alignment() > 0; } /// \brief Return true if this is a store to a volatile memory location bool is_volatile() const { return this->_is_volatile; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == StoreKind; } }; // end class Store /// \brief Extract element from an aggregate class ExtractElement final : public Statement { private: /// \brief Private constructor ExtractElement(InternalVariable* result, Value* aggregate, Value* offset); public: /// \brief Static constructor static std::unique_ptr< ExtractElement > create(InternalVariable* result, Value* aggregate, Value* offset); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the aggregate operand Value* aggregate() const { return this->_operands[0]; } /// \brief Get the offset operand Value* offset() const { return this->_operands[1]; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == ExtractElementKind; } }; // end class ExtractElement /// \brief Insert element into an aggregate class InsertElement final : public Statement { private: /// \brief Private constructor InsertElement(InternalVariable* result, Value* aggregate, Value* offset, Value* element); public: /// \brief Static constructor static std::unique_ptr< InsertElement > create(InternalVariable* result, Value* aggregate, Value* offset, Value* element); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the aggregate operand Value* aggregate() const { return this->_operands[0]; } /// \brief Get the offset operand Value* offset() const { return this->_operands[1]; } /// \brief Get the element operand Value* element() const { return this->_operands[2]; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == InsertElementKind; } }; // end class InsertElement /// \brief Shuffle vector statement class ShuffleVector final : public Statement { private: /// \brief Private constructor ShuffleVector(InternalVariable* result, Value* left, Value* right); public: /// \brief Static constructor static std::unique_ptr< ShuffleVector > create(InternalVariable* result, Value* left, Value* right); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Get the left operand Value* left() const { return this->_operands[0]; } /// \brief Get the right operand Value* right() const { return this->_operands[1]; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == ShuffleVectorKind; } }; // end class ShuffleVector /// \brief Base class for Call and Invoke instructions class CallBase : public Statement { public: /// \brief Iterator over the list of arguments using ArgIterator = OpIterator; protected: /// \brief Protected constructor CallBase(StatementKind kind, InternalVariable* result, Value* called, const std::vector< Value* >& arguments); /// \brief Protected constructor /// /// Helper for Call::clone() and Invoke::clone() methods CallBase(StatementKind kind, InternalVariable* result, const Operands& operands); public: /// \brief Get the result variable InternalVariable* result() const { ikos_assert_msg(this->has_result(), "call has no result"); return cast< InternalVariable >(this->_result); } /// \brief Get the result variable, or null if there is none InternalVariable* result_or_null() const { return cast_or_null< InternalVariable >(this->_result); } /// \brief Get the called value Value* called() const { return this->_operands[0]; } /// \brief Begin iterator over the arguments ArgIterator arg_begin() const { return this->op_begin() + 1; } /// \brief End iterator over the arguments ArgIterator arg_end() const { return this->op_end(); } /// \brief Get the number of arguments std::size_t num_arguments() const { return this->num_operands() - 1; } /// \brief Get the n-th argument Value* argument(std::size_t i) const { ikos_assert_msg(i < this->num_arguments(), "invalid index"); return this->_operands[i + 1]; } /// \brief Is it a call to assembly code? bool is_asm() const { return isa< InlineAssemblyConstant >(this->called()); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() >= _BeginCallBaseKind && s->kind() <= _EndCallBaseKind; } }; // end class CallBase /// \brief Call instruction class Call : public CallBase { protected: /// \brief Private constructor Call(InternalVariable* result, Value* called, const std::vector< Value* >& arguments); /// \brief Private constructor /// /// Only used by clone() Call(InternalVariable* result, const Operands& operands); public: /// \brief Static constructor /// /// \param result The result variable, or null /// \param called The called value (e.g, a FunctionPointerConstant) /// \param arguments The list of arguments static std::unique_ptr< Call > create(InternalVariable* result, Value* called, const std::vector< Value* >& arguments); /// \brief Static constructor /// /// \param result The result variable, or null /// \param function The called function /// \param arguments The list of arguments static std::unique_ptr< Call > create(InternalVariable* result, Function* function, const std::vector< Value* >& arguments); /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == CallKind; } }; // end class Call /// \brief Intrinsic call statement class IntrinsicCall : public Call { protected: /// \brief Protected constructor IntrinsicCall(InternalVariable* result, Function* function, const std::vector< Value* >& arguments); public: /// \brief Get the called function pointer FunctionPointerConstant* called() const { return cast< FunctionPointerConstant >(this->_operands[0]); } /// \brief Get the called function Function* called_function() const { return this->called()->function(); } /// \brief Get the intrinsic ID Intrinsic::ID intrinsic_id() const { return this->called_function()->intrinsic_id(); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< Call >(s) && classof(cast< Call >(s)); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Call* s) { return isa< FunctionPointerConstant >(s->called()) && cast< FunctionPointerConstant >(s->called()) ->function() ->is_intrinsic(); } }; // end class IntrinsicCall /// \brief Invoke statement class Invoke : public CallBase { private: // Normal basic block destination BasicBlock* _normal_dest; // Exception basic block destination BasicBlock* _exception_dest; private: /// \brief Private constructor Invoke(InternalVariable* result, Value* called, const std::vector< Value* >& arguments, BasicBlock* normal_dest, BasicBlock* exception_dest); /// \brief Private constructor /// /// Only used by clone() Invoke(InternalVariable* result, const Operands& operands, BasicBlock* normal_dest, BasicBlock* exception_dest); public: /// \brief Static constructor /// /// \param result The result variable, or null /// \param called The called value (e.g, a FunctionPointerConstant) /// \param arguments The list of arguments /// \param normal_dest The normal basic block destination /// \param exception_dest The exception basic block destination static std::unique_ptr< Invoke > create( InternalVariable* result, Value* called, const std::vector< Value* >& arguments, BasicBlock* normal_dest, BasicBlock* exception_dest); /// \brief Static constructor /// /// \param result The result variable, or null /// \param function The called function /// \param arguments The list of arguments /// \param normal_dest The normal basic block destination /// \param exception_dest The exception basic block destination static std::unique_ptr< Invoke > create( InternalVariable* result, Function* function, const std::vector< Value* >& arguments, BasicBlock* normal_dest, BasicBlock* exception_dest); /// \brief Get the normal basic block destination BasicBlock* normal_dest() const { return this->_normal_dest; } /// \brief Set the normal basic block destination void set_normal_dest(BasicBlock* bb) { this->_normal_dest = bb; } /// \brief Get the exception basic block destination BasicBlock* exception_dest() const { return this->_exception_dest; } /// \brief Set the exception basic block destination void set_exception_dest(BasicBlock* bb) { this->_exception_dest = bb; } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == InvokeKind; } }; // end class Invoke /// \brief Intrinsic invoke statement class IntrinsicInvoke : public Invoke { public: /// \brief Get the called function pointer FunctionPointerConstant* called() const { return cast< FunctionPointerConstant >(this->_operands[0]); } /// \brief Get the called function Function* called_function() const { return this->called()->function(); } /// \brief Get the intrinsic ID Intrinsic::ID intrinsic_id() const { return this->called_function()->intrinsic_id(); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< Invoke >(s) && classof(cast< Invoke >(s)); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Invoke* s) { return isa< FunctionPointerConstant >(s->called()) && cast< FunctionPointerConstant >(s->called()) ->function() ->is_intrinsic(); } }; // end class IntrinsicInvoke /// \brief Memory copy statement (memcpy) class MemoryCopy final : public IntrinsicCall { private: /// \brief Private constructor MemoryCopy(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile); public: /// \brief Static constructor static std::unique_ptr< MemoryCopy > create(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile); /// \brief Get the destination operand Value* destination() const { return this->argument(0); } /// \brief Get the source operand Value* source() const { return this->argument(1); } /// \brief Get the length operand Value* length() const { return this->argument(2); } /// \brief Get the alignment of the destination, in bytes (0 if unspecified) uint64_t destination_alignment() const { return cast< IntegerConstant >(this->argument(3))->value().to< uint64_t >(); } /// \brief Get the alignment of the source, in bytes (0 if unspecified) uint64_t source_alignment() const { return cast< IntegerConstant >(this->argument(4))->value().to< uint64_t >(); } /// \brief Return true if the source or destination is volatile bool is_volatile() const { return cast< IntegerConstant >(this->argument(5))->value() != 0; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::MemoryCopy; } }; // end class MemoryCopy /// \brief Memory move statement (memmove) class MemoryMove final : public IntrinsicCall { private: /// \brief Private constructor MemoryMove(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile); public: /// \brief Static constructor static std::unique_ptr< MemoryMove > create(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile); /// \brief Get the destination operand Value* destination() const { return this->argument(0); } /// \brief Get the source operand Value* source() const { return this->argument(1); } /// \brief Get the length operand Value* length() const { return this->argument(2); } /// \brief Get the alignment of the destination, in bytes (0 if unspecified) uint64_t destination_alignment() const { return cast< IntegerConstant >(this->argument(3))->value().to< uint64_t >(); } /// \brief Get the alignment of the source, in bytes (0 if unspecified) uint64_t source_alignment() const { return cast< IntegerConstant >(this->argument(4))->value().to< uint64_t >(); } /// \brief Return true if the source or destination is volatile bool is_volatile() const { return cast< IntegerConstant >(this->argument(5))->value() != 0; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::MemoryMove; } }; // end class MemoryMove /// \brief Memory set statement (memset) class MemorySet final : public IntrinsicCall { private: /// \brief Private constructor MemorySet(Bundle* bundle, Value* pointer, Value* value, Value* length, uint64_t alignment, bool is_volatile); public: /// \brief Static constructor static std::unique_ptr< MemorySet > create(Bundle* bundle, Value* pointer, Value* value, Value* length, uint64_t alignment, bool is_volatile); /// \brief Get the pointer Value* pointer() const { return this->argument(0); } /// \brief Get the value Value* value() const { return this->argument(1); } /// \brief Get the length Value* length() const { return this->argument(2); } /// \brief Get the alignment of the memory access, in bytes (0 if unspecified) uint64_t alignment() const { return cast< IntegerConstant >(this->argument(3))->value().to< uint64_t >(); } /// \brief Return true if this statement has an alignment constraint bool has_alignment() const { return this->alignment() > 0; } /// \brief Return true if the destination is volatile bool is_volatile() const { return cast< IntegerConstant >(this->argument(4))->value() != 0; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::MemorySet; } }; // end class MemorySet /// \brief Variable argument start statement (va_start) class VarArgStart final : public IntrinsicCall { private: /// \brief Private constructor VarArgStart(Bundle* bundle, Value* operand); public: /// \brief Static constructor static std::unique_ptr< VarArgStart > create(Bundle* bundle, Value* operand); /// \brief Get the operand Value* operand() const { return this->argument(0); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::VarArgStart; } }; // end class VarArgStart /// \brief Variable argument end statement (va_end) class VarArgEnd final : public IntrinsicCall { private: /// \brief Private constructor VarArgEnd(Bundle* bundle, Value* operand); public: /// \brief Static constructor static std::unique_ptr< VarArgEnd > create(Bundle* bundle, Value* operand); /// \brief Get the operand Value* operand() const { return this->argument(0); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::VarArgEnd; } }; // end class VarArgEnd /// \brief Variable argument get statement (va_arg) class VarArgGet final : public IntrinsicCall { private: /// \brief Private constructor VarArgGet(Bundle* bundle, InternalVariable* result, Value* operand); public: /// \brief Static constructor static std::unique_ptr< VarArgGet > create(Bundle* bundle, InternalVariable* result, Value* operand); /// \brief Get the operand Value* operand() const { return this->argument(0); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::VarArgGet; } }; // end class VarArgGet /// \brief Variable argument copy statement (va_copy) class VarArgCopy final : public IntrinsicCall { private: /// \brief Private constructor VarArgCopy(Bundle* bundle, Value* destination, Value* source); public: /// \brief Static constructor static std::unique_ptr< VarArgCopy > create(Bundle* bundle, Value* destination, Value* source); /// \brief Get the destination operand Value* destination() const { return this->argument(0); } /// \brief Get the source operand Value* source() const { return this->argument(1); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::VarArgCopy; } }; // end class VarArgCopy /// \brief Save the current state of the function stack class StackSave final : public IntrinsicCall { private: /// \brief Private constructor StackSave(Bundle* bundle, InternalVariable* result); public: /// \brief Static constructor static std::unique_ptr< StackSave > create(Bundle* bundle, InternalVariable* result); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::StackSave; } }; // end class StackSave /// \brief Restore the state of the function stack corresponding to a stacksave class StackRestore final : public IntrinsicCall { private: /// \brief Private constructor StackRestore(Bundle* bundle, Value* operand); public: /// \brief Static constructor static std::unique_ptr< StackRestore > create(Bundle* bundle, Value* operand); /// \brief Get the pointer operand Value* operand() const { return this->argument(0); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return isa< IntrinsicCall >(s) && cast< IntrinsicCall >(s)->intrinsic_id() == Intrinsic::StackRestore; } }; // end class StackRestore /// \brief Landing pad statement /// // The landingpad instruction holds all of the information necessary to generate // correct exception handling. class LandingPad final : public Statement { private: /// \brief Private constructor explicit LandingPad(InternalVariable* result); public: /// \brief Static constructor static std::unique_ptr< LandingPad > create(InternalVariable* result); /// \brief Get the result variable InternalVariable* result() const { return cast< InternalVariable >(this->_result); } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == LandingPadKind; } }; // end class LandingPad /// \brief Resume statement class Resume final : public Statement { private: /// \brief Private constructor explicit Resume(InternalVariable* operand); public: /// \brief Static constructor static std::unique_ptr< Resume > create(InternalVariable* operand); /// \brief Get the operand InternalVariable* operand() const { return cast< InternalVariable >(this->_operands[0]); } /// \brief Dump the statement for debugging purpose void dump(std::ostream&) const override; /// \brief Clone the statement std::unique_ptr< Statement > clone() const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Statement* s) { return s->kind() == ResumeKind; } }; // end class Resume } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/statement_visitor.hpp000066400000000000000000000164421473507761200263200ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Statement visitor definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace ar { /// \brief Apply a statement visitor on a statement /// /// A statement visitor looks like: /// /// \code{.cpp} /// struct MyStatementVisitor { /// using ResultType = int; /// /// int operator()(Assignment* s) { ... } /// int operator()(UnaryOperation* s) { ... } /// int operator()(BinaryOperation* s) { ... } /// int operator()(Comparison* s) { ... } /// int operator()(ReturnValue* s) { ... } /// int operator()(Unreachable* s) { ... } /// int operator()(Allocate* s) { ... } /// int operator()(PointerShift* s) { ... } /// int operator()(Load* s) { ... } /// int operator()(Store* s) { ... } /// int operator()(ExtractElement* s) { ... } /// int operator()(InsertElement* s) { ... } /// int operator()(ShuffleVector* s) { ... } /// int operator()(Call* s) { ... } /// int operator()(Invoke* s) { ... } /// int operator()(LandingPad* s) { ... } /// int operator()(Resume* s) { ... } /// }; /// \endcode template < typename Visitor > typename Visitor::ResultType apply_visitor(Visitor& visitor, Statement* s) { switch (s->kind()) { case Statement::AssignmentKind: return visitor(cast< Assignment >(s)); case Statement::UnaryOperationKind: return visitor(cast< UnaryOperation >(s)); case Statement::BinaryOperationKind: return visitor(cast< BinaryOperation >(s)); case Statement::ComparisonKind: return visitor(cast< Comparison >(s)); case Statement::ReturnValueKind: return visitor(cast< ReturnValue >(s)); case Statement::UnreachableKind: return visitor(cast< Unreachable >(s)); case Statement::AllocateKind: return visitor(cast< Allocate >(s)); case Statement::PointerShiftKind: return visitor(cast< PointerShift >(s)); case Statement::LoadKind: return visitor(cast< Load >(s)); case Statement::StoreKind: return visitor(cast< Store >(s)); case Statement::ExtractElementKind: return visitor(cast< ExtractElement >(s)); case Statement::InsertElementKind: return visitor(cast< InsertElement >(s)); case Statement::ShuffleVectorKind: return visitor(cast< ShuffleVector >(s)); case Statement::CallKind: return visitor(cast< Call >(s)); case Statement::InvokeKind: return visitor(cast< Invoke >(s)); case Statement::LandingPadKind: return visitor(cast< LandingPad >(s)); case Statement::ResumeKind: return visitor(cast< Resume >(s)); default: ikos_unreachable("unexpected statement"); } } /// \brief Apply a const statement visitor on a statement /// /// A const statement visitor looks like: /// /// \code{.cpp} /// struct MyStatementVisitor { /// using ResultType = int; /// /// int operator()(Assignment* s) const { ... } /// int operator()(UnaryOperation* s) const { ... } /// int operator()(BinaryOperation* s) const { ... } /// int operator()(Comparison* s) const { ... } /// int operator()(ReturnValue* s) const { ... } /// int operator()(Unreachable* s) const { ... } /// int operator()(Allocate* s) const { ... } /// int operator()(PointerShift* s) const { ... } /// int operator()(Load* s) const { ... } /// int operator()(Store* s) const { ... } /// int operator()(ExtractElement* s) const { ... } /// int operator()(InsertElement* s) const { ... } /// int operator()(ShuffleVector* s) const { ... } /// int operator()(Call* s) const { ... } /// int operator()(Invoke* s) const { ... } /// int operator()(LandingPad* s) const { ... } /// int operator()(Resume* s) const { ... } /// }; /// \endcode template < typename Visitor > typename Visitor::ResultType apply_visitor(const Visitor& visitor, Statement* s) { switch (s->kind()) { case Statement::AssignmentKind: return visitor(cast< Assignment >(s)); case Statement::UnaryOperationKind: return visitor(cast< UnaryOperation >(s)); case Statement::BinaryOperationKind: return visitor(cast< BinaryOperation >(s)); case Statement::ComparisonKind: return visitor(cast< Comparison >(s)); case Statement::ReturnValueKind: return visitor(cast< ReturnValue >(s)); case Statement::UnreachableKind: return visitor(cast< Unreachable >(s)); case Statement::AllocateKind: return visitor(cast< Allocate >(s)); case Statement::PointerShiftKind: return visitor(cast< PointerShift >(s)); case Statement::LoadKind: return visitor(cast< Load >(s)); case Statement::StoreKind: return visitor(cast< Store >(s)); case Statement::ExtractElementKind: return visitor(cast< ExtractElement >(s)); case Statement::InsertElementKind: return visitor(cast< InsertElement >(s)); case Statement::ShuffleVectorKind: return visitor(cast< ShuffleVector >(s)); case Statement::CallKind: return visitor(cast< Call >(s)); case Statement::InvokeKind: return visitor(cast< Invoke >(s)); case Statement::ResumeKind: return visitor(cast< Resume >(s)); default: ikos_unreachable("unexpected statement"); } } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/symbol_table.hpp000066400000000000000000000131521473507761200252040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Symbol table definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace ar { /// \brief Symbol table /// /// Represents a list of symbols. template < typename T > class SymbolTable { private: // Map from names to symbols std::unordered_map< std::string, std::unique_ptr< T > > _map; public: /// \brief Iterator over the symbols using Iterator = boost::transform_iterator< MapExposeRawPtr< std::string, T >, typename std::unordered_map< std::string, std::unique_ptr< T > >::const_iterator >; public: /// \brief Default constructor explicit SymbolTable() = default; /// \brief Copy constructor SymbolTable(const SymbolTable&) = default; /// \brief Move constructor SymbolTable(SymbolTable&&) = default; /// \brief Copy assignment operator SymbolTable& operator=(const SymbolTable&) = default; /// \brief Move assignment operator SymbolTable& operator=(SymbolTable&&) = default; /// \brief Destructor ~SymbolTable() = default; /// \brief Add a symbol /// /// This is undefined behavior if the symbol name is already taken. void add(std::unique_ptr< T > symbol) { ikos_assert_msg(!symbol->name().empty(), "name is empty"); ikos_assert_msg(!this->contains(symbol->name()), "name already taken"); this->_map.emplace(symbol->name(), std::move(symbol)); } /// \brief Rename the given symbol /// /// \param symbol The symbol /// \param prev_name The previous name /// \param new_name The new name /// /// This is undefined behavior if the new symbol name is already taken. void rename(T* symbol, const std::string& prev_name, const std::string& new_name) { ikos_assert_msg(!prev_name.empty(), "name is empty"); ikos_assert_msg(this->find(prev_name) == symbol, "symbol not registered"); ikos_assert_msg(!new_name.empty(), "name is empty"); ikos_assert_msg(!this->contains(new_name), "name already taken"); ikos_ignore(symbol); auto it = this->_map.find(prev_name); std::unique_ptr< T > symbol_ptr = std::move(it->second); this->_map.erase(it); this->_map.emplace(new_name, std::move(symbol_ptr)); } /// \brief Return true if the table is empty bool empty() const { return this->_map.empty(); } /// \brief Return the size of the table std::size_t size() const { return this->_map.size(); } /// \brief Begin iterator over the symbols Iterator begin() const { return boost::make_transform_iterator(this->_map.cbegin(), MapExposeRawPtr< std::string, T >()); } /// \brief End iterator over the symbols Iterator end() const { return boost::make_transform_iterator(this->_map.cend(), MapExposeRawPtr< std::string, T >()); } /// \brief Return the symbol with the given name, or nullptr T* find(const std::string& name) const { ikos_assert_msg(!name.empty(), "name is empty"); auto it = this->_map.find(name); if (it != this->_map.end()) { return it->second.get(); } else { return nullptr; } } /// \brief Return true if the table contains a symbol with the given name bool contains(const std::string& name) const { ikos_assert_msg(!name.empty(), "name is empty"); return this->_map.find(name) != this->_map.end(); } }; // end class SymbolTable } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/type.hpp000066400000000000000000000460171473507761200235170ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Type definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace ar { /// \brief Floating point semantic enum FloatSemantic { Half, Float, Double, X86_FP80, FP128, PPC_FP128 }; /// \brief Base class for types /// /// Types are immutable. Once created, they are never changed. /// /// Note that only one instance of each type is ever created (except for /// StructType and OpaqueType). Thus, you can compare two types using a /// pointer comparison. /// /// To enforce this, each type should be created using the static method get(). class Type { public: enum TypeKind { VoidKind, _BeginScalarKind, IntegerKind, FloatKind, PointerKind, _EndScalarKind, _BeginAggregateKind, StructKind, _BeginSequentialKind, ArrayKind, VectorKind, _EndSequentialKind, OpaqueKind, _EndAggregateKind, FunctionKind }; protected: // Kind of type TypeKind _kind; protected: /// \brief Protected constructor explicit Type(TypeKind kind); public: /// \brief No copy constructor Type(const Type&) = delete; /// \brief No move constructor Type(Type&&) = delete; /// \brief No copy assignment operator Type& operator=(const Type&) = delete; /// \brief No move assignment operator Type& operator=(Type&&) = delete; /// \brief Destructor virtual ~Type(); /// \brief Get the kind of type TypeKind kind() const { return this->_kind; } /// \brief Dump the type for debugging purpose virtual void dump(std::ostream&) const = 0; public: /// \brief Is it a void type? bool is_void() const { return this->_kind == VoidKind; } /// \brief Is it a scalar type? bool is_scalar() const { return this->_kind >= _BeginScalarKind && this->_kind <= _EndScalarKind; } /// \brief Is it an integer type? bool is_integer() const { return this->_kind == IntegerKind; } /// \brief Is it an unsigned integer type? bool is_unsigned_integer() const; /// \brief Is it a signed integer type? bool is_signed_integer() const; /// \brief Is it a float type? bool is_float() const { return this->_kind == FloatKind; } /// \brief Is it a pointer type? bool is_pointer() const { return this->_kind == PointerKind; } /// \brief Is it an aggregate type? bool is_aggregate() const { return this->_kind >= _BeginAggregateKind && this->_kind <= _EndAggregateKind; } /// \brief Is it a structure type? bool is_struct() const { return this->_kind == StructKind; } /// \brief Is it a sequential type? bool is_sequential() const { return this->_kind >= _BeginSequentialKind && this->_kind <= _EndSequentialKind; } /// \brief Is it an array type? bool is_array() const { return this->_kind == ArrayKind; } /// \brief Is it a vector type? bool is_vector() const { return this->_kind == VectorKind; } /// \brief Is it an opaque type? bool is_opaque() const { return this->_kind == OpaqueKind; } /// \brief Is it a function type? bool is_function() const { return this->_kind == FunctionKind; } /// \brief Is it a primitive type? /// /// A primitive type has a fixed bit-width and is target-independent. This is /// either an integer, a floating point or a vector of integers or floating /// points. bool is_primitive() const; /// \brief Return the bit width of a primitive type /// /// Returns zero for non-primitive type. uint64_t primitive_bit_width() const; protected: /// \brief Get the context implementation /// /// Helper for derived types static ContextImpl& ctx_impl(Context& ctx); }; // end class Type /// \brief Void type /// /// Represents the void type in C. Mainly used for return type of functions. class VoidType final : public Type { private: /// \brief Private constructor VoidType(); public: /// \brief Static constructor static VoidType* get(Context& ctx); /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == VoidKind; } // friends friend class ContextImpl; }; // end class VoidType /// \brief Base class for scalar types class ScalarType : public Type { protected: /// \brief Protected constructor explicit ScalarType(TypeKind kind); public: /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() >= _BeginScalarKind && t->kind() <= _EndScalarKind; } }; // end class ScalarType /// \brief Integer type /// /// Represents any integer type, with its bit-width and sign. class IntegerType final : public ScalarType { private: // Bit width uint64_t _bit_width; // Sign Signedness _sign; private: /// \brief Private constructor IntegerType(uint64_t bit_width, Signedness sign); public: /// \brief Static constructor static IntegerType* get(Context& ctx, uint64_t bit_width, Signedness sign); /// \brief Get the signed 1 bit integer type static IntegerType* si1(Context& ctx); /// \brief Get the unsigned 1 bit integer type static IntegerType* ui1(Context& ctx); /// \brief Get the signed 8 bits integer type static IntegerType* si8(Context& ctx); /// \brief Get the unsigned 8 bits integer type static IntegerType* ui8(Context& ctx); /// \brief Get the signed 32 bits integer type static IntegerType* si32(Context& ctx); /// \brief Get the unsigned 32 bits integer type static IntegerType* ui32(Context& ctx); /// \brief Get the signed 64 bits integer type static IntegerType* si64(Context& ctx); /// \brief Get the unsigned 64 bits integer type static IntegerType* ui64(Context& ctx); /// \brief Get the unsigned integer type that has the bit-width of a pointer static IntegerType* size_type(Bundle* bundle); /// \brief Get the signed integer type that has the bit-width of a pointer static IntegerType* ssize_type(Bundle* bundle); /// \brief Get the bit width uint64_t bit_width() const { return this->_bit_width; } /// \brief Get the sign Signedness sign() const { return this->_sign; } bool is_unsigned() const { return this->_sign == Unsigned; } bool is_signed() const { return this->_sign == Signed; } /// \brief Get the minimum integer represented by this type MachineInt min_value() const; /// \brief Get the maximum integer represented by this type MachineInt max_value() const; /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == IntegerKind; } // friends friend class ContextImpl; }; // end class IntegerType /// \brief Floating point type /// /// Represents any floating point type, with its bit-width and semantic. /// /// See `FloatSemantic`. class FloatType final : public ScalarType { private: // Bit width uint64_t _bit_width; // Float semantic FloatSemantic _float_sem; private: /// \brief Private constructor FloatType(uint64_t bit_width, FloatSemantic float_sem); public: /// \brief Static constructor static FloatType* get(Context& ctx, FloatSemantic float_sem); /// \brief Get the bit width uint64_t bit_width() const { return this->_bit_width; } /// \brief Get the float semantic FloatSemantic float_semantic() const { return this->_float_sem; } /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == FloatKind; } // friends friend class ContextImpl; }; // end class FloatType /// \brief Pointer type /// /// Represents any pointer type. class PointerType final : public ScalarType { private: // Pointee type Type* _pointee; private: /// \brief Private constructor explicit PointerType(Type* pointee); public: /// \brief Static constructor static PointerType* get(Context& ctx, Type* pointee); /// \brief Get the pointee type Type* pointee() const { return this->_pointee; } /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == PointerKind; } // friends friend class ContextImpl; }; // end class PointerType /// \brief Base class for aggregate types /// /// Base class for StructType, ArrayType, VectorType and OpaqueType. class AggregateType : public Type { protected: /// \brief Protected constructor explicit AggregateType(TypeKind kind); public: /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() >= _BeginAggregateKind && t->kind() <= _EndAggregateKind; } }; // end class AggregateType /// \brief Structure type /// /// Structure types might not be unique, so a pointer comparison might not work. /// /// Structure types might also be recursive (a structure can have a pointer /// to itself). class StructType final : public AggregateType { public: /// \brief Structure field struct Field { // Offset, in bytes ZNumber offset; // Type Type* type; }; /// \brief Type of the layout /// /// List of fields, ordered by offset using Layout = std::vector< Field >; /// \brief Iterator over the fields of the structure using FieldIterator = Layout::const_iterator; /// \brief Reverse iterator over the fields of the structure using FieldReverseIterator = Layout::const_reverse_iterator; private: // Layout of the structure Layout _layout; // Is the structure packed? bool _packed; private: /// \brief Private constructor StructType(Layout layout, bool packed); /// \brief Private constructor explicit StructType(bool packed); public: /// \brief Static constructor /// /// Always return a new instance static StructType* create(Context& ctx, Layout layout, bool packed); /// \brief Static constructor /// /// Always return a new instance static StructType* create(Context& ctx, bool packed); /// \brief Set the layout void set_layout(Layout layout); /// \brief Set the packed attribute void set_packed(bool packed); /// \brief Get the layout const Layout& layout() const { return this->_layout; } /// \brief Begin iterator over the fields of the structure FieldIterator field_begin() const { return this->_layout.cbegin(); } /// \brief End iterator over the fields of the structure FieldIterator field_end() const { return this->_layout.cend(); } /// \brief Begin reverse iterator over the fields of the structure FieldReverseIterator field_rbegin() const { return this->_layout.crbegin(); } /// \brief End reverse iterator over the fields of the structure FieldReverseIterator field_rend() const { return this->_layout.crend(); } /// \brief Is the structure empty? bool empty() const { return this->_layout.empty(); } /// \brief Get the number of fields std::size_t num_fields() const { return this->_layout.size(); } /// \brief Is the structure packed? bool packed() const { return this->_packed; } /// \brief Dump the type for debugging purpose /// /// Note: it might produce an infinite loop on recursive types void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == StructKind; } }; // end class StructType /// \brief Base class for sequential types, such as ArrayType and VectorType class SequentialType : public AggregateType { protected: // Element type Type* _element_type; // Number of elements ZNumber _num_elements; protected: /// \brief Private constructor SequentialType(TypeKind kind, Type* element_type, ZNumber num_element); public: /// \brief Get the element type Type* element_type() const { return this->_element_type; } /// \brief Get the number of elements ZNumber num_elements() const { return this->_num_elements; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() >= _BeginSequentialKind && t->kind() <= _EndSequentialKind; } }; // end class SequentialType /// \brief Array type /// /// Represents the array type. /// /// The layout in memory includes padding so that each element is properly /// aligned. This is the equivalent of arrays in C. class ArrayType final : public SequentialType { private: /// \brief Private constructor ArrayType(Type* element_type, ZNumber num_element); public: /// \brief Static constructor static ArrayType* get(Context& ctx, Type* element_type, const ZNumber& num_element); /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == ArrayKind; } // friends friend class ContextImpl; }; // end class ArrayType /// \brief Vector type /// /// Represents the vector type. /// /// This is similar to ArrayType, but can only hold scalars and does not add /// padding between elements. This is mostly used to represent return types of C /// function returning small structures. class VectorType final : public SequentialType { private: /// \brief Private constructor VectorType(ScalarType* element_type, ZNumber num_element); public: /// \brief Static constructor static VectorType* get(Context& ctx, ScalarType* element_type, const ZNumber& num_element); /// \brief Get the element type ScalarType* element_type() const { return cast< ScalarType >(this->_element_type); } /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == VectorKind; } // friends friend class ContextImpl; }; // end class VectorType /// \brief Opaque type /// /// Represents an opaque type. Mainly used to represent a forward declared /// structure in C. // /// Opaque types might not be unique, so a pointer comparison might not work. class OpaqueType final : public AggregateType { private: /// \brief Private constructor OpaqueType(); public: /// \brief Static constructor /// /// Always return a new instance static OpaqueType* create(Context& ctx); /// \brief Get the libc FILE opaque type static OpaqueType* libc_file_type(Context& ctx); /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == OpaqueKind; } // friends friend class ContextImpl; }; // end class OpaqueType /// \brief Function type /// /// Represents a function type, with its return type and parameter types. class FunctionType final : public Type { public: /// \brief Type for a list of parameter types using ParamTypes = std::vector< Type* >; /// \brief Iterator over the list of parameter types using ParamIterator = ParamTypes::const_iterator; private: // Return type Type* _return_type; // List of parameter types ParamTypes _param_types; // Is it a variable argument function call? bool _is_var_arg; private: /// \brief Private constructor FunctionType(Type* return_type, const ParamTypes& param_types, bool is_var_arg); public: /// \brief Static constructor static FunctionType* get(Context& ctx, Type* return_type, const ParamTypes& param_types, bool is_var_arg); /// \brief Get the returned type Type* return_type() const { return this->_return_type; } /// \brief Get the list of parameter types const ParamTypes& param_types() const { return this->_param_types; } /// \brief Get the i-th parameter type ar::Type* param_type(std::size_t i) const { ikos_assert_msg(i < this->_param_types.size(), "invalid index"); return this->_param_types[i]; } /// \brief Begin iterator over the list of parameter types ParamIterator param_begin() const { return this->_param_types.begin(); } /// \brief End iterator over the list of parameter types ParamIterator param_end() const { return this->_param_types.end(); } /// \brief Get the number of parameters std::size_t num_parameters() const { return this->_param_types.size(); } /// \brief Is it a variable argument (var-arg) function call? bool is_var_arg() const { return this->_is_var_arg; } /// \brief Dump the type for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Type* t) { return t->kind() == FunctionKind; } // friends friend class ContextImpl; }; // end class FunctionType } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/type_visitor.hpp000066400000000000000000000121701473507761200252670ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Type visitor definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace ar { /// \brief Apply a type visitor on a type /// /// A type visitor looks like: /// /// \code{.cpp} /// struct MyTypeVisitor { /// using ResultType = int; /// /// int operator()(VoidType* t) { ... } /// int operator()(IntegerType* t) { ... } /// int operator()(FloatType* t) { ... } /// int operator()(PointerType* t) { ... } /// int operator()(StructType* t) { ... } /// int operator()(ArrayType* t) { ... } /// int operator()(VectorType* t) { ... } /// int operator()(OpaqueType* t) { ... } /// int operator()(FunctionType* t) { ... } /// }; /// \endcode template < typename Visitor > typename Visitor::ResultType apply_visitor(Visitor& visitor, Type* t) { switch (t->kind()) { case Type::VoidKind: return visitor(cast< VoidType >(t)); case Type::IntegerKind: return visitor(cast< IntegerType >(t)); case Type::FloatKind: return visitor(cast< FloatType >(t)); case Type::PointerKind: return visitor(cast< PointerType >(t)); case Type::StructKind: return visitor(cast< StructType >(t)); case Type::ArrayKind: return visitor(cast< ArrayType >(t)); case Type::VectorKind: return visitor(cast< VectorType >(t)); case Type::OpaqueKind: return visitor(cast< OpaqueType >(t)); case Type::FunctionKind: return visitor(cast< FunctionType >(t)); default: ikos_unreachable("unexpected type"); } } /// \brief Apply a const type visitor on a type /// /// A const type visitor looks like: /// /// \code{.cpp} /// struct MyTypeVisitor { /// using ResultType = int; /// /// int operator()(VoidType* t) const { ... } /// int operator()(IntegerType* t) const { ... } /// int operator()(FloatType* t) const { ... } /// int operator()(PointerType* t) const { ... } /// int operator()(StructType* t) const { ... } /// int operator()(ArrayType* t) const { ... } /// int operator()(VectorType* t) const { ... } /// int operator()(OpaqueType* t) const { ... } /// int operator()(FunctionType* t) const { ... } /// }; /// \endcode template < typename Visitor > typename Visitor::ResultType apply_visitor(const Visitor& visitor, Type* t) { switch (t->kind()) { case Type::VoidKind: return visitor(cast< VoidType >(t)); case Type::IntegerKind: return visitor(cast< IntegerType >(t)); case Type::FloatKind: return visitor(cast< FloatType >(t)); case Type::PointerKind: return visitor(cast< PointerType >(t)); case Type::StructKind: return visitor(cast< StructType >(t)); case Type::ArrayKind: return visitor(cast< ArrayType >(t)); case Type::VectorKind: return visitor(cast< VectorType >(t)); case Type::OpaqueKind: return visitor(cast< OpaqueType >(t)); case Type::FunctionKind: return visitor(cast< FunctionType >(t)); default: ikos_unreachable("unexpected type"); } } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/value.hpp000066400000000000000000000572231473507761200236530ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Value definitions (variables, constants, etc.) * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace ar { // forward declaration class Code; class Function; /// \brief Base class for values (ie., constants and variables) /// /// Note that only one instance of each value is ever created. Thus, you can /// compare two values using a pointer comparison. /// /// To enforce this, each value should be created using the static method get(). class Value { public: enum ValueKind { _BeginConstantKind, UndefinedConstantKind, IntegerConstantKind, FloatConstantKind, NullConstantKind, StructConstantKind, _BeginSequentialConstantKind, ArrayConstantKind, VectorConstantKind, _EndSequentialConstantKind, AggregateZeroConstantKind, FunctionPointerConstantKind, InlineAssemblyConstantKind, _EndConstantKind, _BeginVariableKind, GlobalVariableKind, LocalVariableKind, InternalVariableKind, _EndVariableKind }; protected: // Kind of value ValueKind _kind; // Type Type* _type; protected: /// \brief Protected constructor Value(ValueKind kind, Type* type); public: /// \brief No copy constructor Value(const Value&) = delete; /// \brief No move constructor Value(Value&&) = delete; /// \brief No copy assignment operator Value& operator=(const Value&) = delete; /// \brief No move assignment operator Value& operator=(Value&&) = delete; /// \brief Destructor virtual ~Value(); /// \brief Get the kind of value ValueKind kind() const { return this->_kind; } /// \brief Get the type Type* type() const { return this->_type; } /// \brief Dump the value for debugging purpose virtual void dump(std::ostream&) const = 0; public: /// \brief Is it a constant? bool is_constant() const { return this->_kind >= _BeginConstantKind && this->_kind <= _EndConstantKind; } /// \brief Is it an undefined constant? bool is_undefined_constant() const { return this->_kind == UndefinedConstantKind; } /// \brief Is it an integer constant? bool is_integer_constant() const { return this->_kind == IntegerConstantKind; } /// \brief Is it a float constant? bool is_float_constant() const { return this->_kind == FloatConstantKind; } /// \brief Is it a null constant? bool is_null_constant() const { return this->_kind == NullConstantKind; } /// \brief Is it a constant structure? bool is_struct_constant() const { return this->_kind == StructConstantKind; } /// \brief Is it a sequential constant? bool is_sequential_constant() const { return this->_kind >= _BeginSequentialConstantKind && this->_kind <= _EndSequentialConstantKind; } /// \brief Is it a constant array? bool is_array_constant() const { return this->_kind == ArrayConstantKind; } /// \brief Is it a constant vector? bool is_vector_constant() const { return this->_kind == VectorConstantKind; } /// \brief Is it a constant aggregate zero? bool is_aggregate_zero_constant() const { return this->_kind == AggregateZeroConstantKind; } /// \brief Is it a constant function pointer? bool is_function_pointer_constant() const { return this->_kind == FunctionPointerConstantKind; } /// \brief Is it an inline assembly? bool is_inline_assembly_constant() const { return this->_kind == InlineAssemblyConstantKind; } /// \brief Is it a variable? bool is_variable() const { return this->_kind >= _BeginVariableKind && this->_kind <= _EndVariableKind; } /// \brief Is it a global variable? bool is_global_variable() const { return this->_kind == GlobalVariableKind; } /// \brief Is it a local variable? bool is_local_variable() const { return this->_kind == LocalVariableKind; } /// \brief Is it an internal variable? bool is_internal_variable() const { return this->_kind == InternalVariableKind; } protected: /// \brief Get the context implementation /// /// Helper for derived values static ContextImpl& ctx_impl(Context& ctx); }; // end class Value /// \brief Base class for constants class Constant : public Value { protected: /// \brief Protected constructor Constant(ValueKind kind, Type* type); public: /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() >= _BeginConstantKind && v->kind() <= _EndConstantKind; } }; // end class Constant /// \brief Undefined constant class UndefinedConstant final : public Constant { private: /// \brief Private constructor explicit UndefinedConstant(Type* type); public: /// \brief Static constructor static UndefinedConstant* get(Context& ctx, Type* type); /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == UndefinedConstantKind; } // friends friend class ContextImpl; }; // end class UndefinedConstant /// \brief Integer constant class IntegerConstant final : public Constant { private: // Normalized value MachineInt _value; private: /// \brief Private constructor IntegerConstant(IntegerType* type, MachineInt value); public: /// \brief Static constructor static IntegerConstant* get(Context& ctx, IntegerType* type, const MachineInt& value); /// \brief Static constructor static IntegerConstant* get(Context& ctx, IntegerType* type, int value); /// \brief Get the type IntegerType* type() const { return cast< IntegerType >(this->_type); } /// \brief Get the value const MachineInt& value() const { return this->_value; } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == IntegerConstantKind; } // friends friend class ContextImpl; }; // end class IntegerConstant /// \brief Floating point constant class FloatConstant final : public Constant { private: // Decimal representation, in scientific notation // TODO(marthaud): use a better representation (see llvm::APFloat for example) // Note: QNumber cannot be used (no representation for +Inf, -Inf, NaN, etc.) std::string _value; private: /// \brief Private constructor FloatConstant(FloatType* type, std::string value); public: /// \brief Static constructor /// /// \param value Decimal representation, in scientific notation static FloatConstant* get(Context& ctx, FloatType* type, const std::string& value); /// \brief Static constructor /// /// \param value Decimal representation, in scientific notation static FloatConstant* get(Context& ctx, FloatType* type, const char* value); /// \brief Get the type FloatType* type() const { return cast< FloatType >(this->_type); } /// \brief Get the decimal representation, in scientific notation const std::string& value() const { return this->_value; } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == FloatConstantKind; } // friends friend class ContextImpl; }; // end class FloatConstant /// \brief Null constant class NullConstant final : public Constant { private: /// \brief Private constructor explicit NullConstant(PointerType* type); public: /// \brief Static constructor static NullConstant* get(Context& ctx, PointerType* type); /// \brief Get the type PointerType* type() const { return cast< PointerType >(this->_type); } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == NullConstantKind; } // friends friend class ContextImpl; }; // end class NullConstant /// \brief Constant structure class StructConstant final : public Constant { public: /// \brief Structure field struct Field { // Offset, in bytes ZNumber offset; // Value Value* value; bool operator<(const Field& o) const { return offset < o.offset || (offset == o.offset && value < o.value); } }; /// \brief Type of the value container /// /// List of fields, ordered by offset using Values = std::vector< Field >; /// \brief Iterator over the fields of the structure using FieldIterator = Values::const_iterator; /// \brief Reverse iterator over the fields of the structure using FieldReverseIterator = Values::const_reverse_iterator; private: // Values in the structure Values _values; private: /// \brief Private constructor StructConstant(StructType* type, Values values); public: /// \brief Static constructor static StructConstant* get(Context& ctx, StructType* type, const Values& values); /// \brief Get the type StructType* type() const { return cast< StructType >(this->_type); } /// \brief Get the values const Values& values() const { return this->_values; } /// \brief Begin iterator over the fields of the structure FieldIterator field_begin() const { return this->_values.cbegin(); } /// \brief End iterator over the fields of the structure FieldIterator field_end() const { return this->_values.cend(); } /// \brief Begin reverse iterator over the fields of the structure FieldReverseIterator field_rbegin() const { return this->_values.crbegin(); } /// \brief End reverse iterator over the fields of the structure FieldReverseIterator field_rend() const { return this->_values.crend(); } /// \brief Get the number of fields std::size_t num_fields() const { return this->_values.size(); } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == StructConstantKind; } // friends friend class ContextImpl; }; // end class StructConstant /// \brief Base class for sequential constants, /// such as ArrayConstant and VectorConstant class SequentialConstant : public Constant { public: /// \brief Type of the value container using Values = std::vector< Value* >; /// \brief Iterator over the elements of the array using ElementIterator = Values::const_iterator; private: // Values Values _values; protected: /// \brief Private constructor SequentialConstant(ValueKind kind, SequentialType* type, const Values& values); public: /// \brief Get the type SequentialType* type() const { return cast< SequentialType >(this->_type); } /// \brief Get the values const Values& values() const { return this->_values; } /// \brief Begin iterator over the elements of the sequence ElementIterator element_begin() const { return this->_values.cbegin(); } /// \brief End iterator over the elements of the sequence ElementIterator element_end() const { return this->_values.cend(); } /// \brief Get the number of elements std::size_t num_elements() const { return this->_values.size(); } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() >= _BeginSequentialConstantKind && v->kind() <= _EndSequentialConstantKind; } }; // end class SequentialConstant /// \brief Constant array class ArrayConstant final : public SequentialConstant { private: /// \brief Private constructor ArrayConstant(ArrayType* type, const Values& values); public: /// \brief Static constructor static ArrayConstant* get(Context& ctx, ArrayType* type, const Values& values); /// \brief Get the type ArrayType* type() const { return cast< ArrayType >(this->_type); } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == ArrayConstantKind; } // friends friend class ContextImpl; }; // end class ArrayConstant /// \brief Constant vector class VectorConstant final : public SequentialConstant { private: /// \brief Private constructor VectorConstant(VectorType* type, const Values& values); public: /// \brief Static constructor static VectorConstant* get(Context& ctx, VectorType* type, const Values& values); /// \brief Get the type VectorType* type() const { return cast< VectorType >(this->_type); } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == VectorConstantKind; } // friends friend class ContextImpl; }; // end class VectorConstant /// \brief Constant aggregate full of zeros class AggregateZeroConstant final : public Constant { private: /// \brief Private constructor explicit AggregateZeroConstant(AggregateType* type); public: /// \brief Static constructor static AggregateZeroConstant* get(Context& ctx, AggregateType* type); /// \brief Get the type AggregateType* type() const { return cast< AggregateType >(this->_type); } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == AggregateZeroConstantKind; } // friends friend class ContextImpl; }; // end class AggregateZeroConstant /// \brief Constant function pointer class FunctionPointerConstant final : public Constant { private: // Function Function* _function; private: /// \brief Private constructor FunctionPointerConstant(PointerType* type, Function* function); public: /// \brief Static constructor static FunctionPointerConstant* get(Context& ctx, Function* function); /// \brief Get the type PointerType* type() const { return cast< PointerType >(this->_type); } /// \brief Get the function Function* function() const { return this->_function; } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == FunctionPointerConstantKind; } // friends friend class ContextImpl; }; // end class FunctionPointerConstant /// \brief Inline Assembly code class InlineAssemblyConstant final : public Constant { private: // Assembly code std::string _code; private: /// \brief Private constructor InlineAssemblyConstant(PointerType* type, std::string code); public: /// \brief Static constructor static InlineAssemblyConstant* get(Context& ctx, PointerType* type, const std::string& code); /// \brief Get the type PointerType* type() const { return cast< PointerType >(this->_type); } /// \brief Get the assembly code as a string const std::string& code() const { return this->_code; } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == InlineAssemblyConstantKind; } // friends friend class ContextImpl; }; // end class InlineAssemblyConstant /// \brief Base class for variables class Variable : public Value, public Traceable { protected: // Name (optional) std::string _name; protected: /// \brief Protected constructor Variable(ValueKind kind, Type* type); public: /// \brief Does the variable have a name? bool has_name() const { return !this->_name.empty(); } /// \brief Get the name const std::string& name() const { ikos_assert_msg(!this->_name.empty(), "variable has no name"); return this->_name; } /// \brief Get the name /// /// Returns an empty string if the variable has no name. const std::string& name_or_empty() const { return this->_name; } /// \brief Set the name virtual void set_name(std::string name); /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() >= _BeginVariableKind && v->kind() <= _EndVariableKind; } }; // end class Variable /// \brief Global variable class GlobalVariable final : public Variable { private: // Parent bundle Bundle* _parent; // Initializer (if definition) std::unique_ptr< Code > _initializer; // Alignment of the global variable, in bytes (0 if unspecified) uint64_t _alignment; private: /// \brief Private constructor GlobalVariable(Bundle* bundle, PointerType* type, std::string name, bool is_definition, uint64_t alignment); public: /// \brief Static constructor /// /// \param bundle Parent bundle /// \param type Type of the global variable /// \param name Name of the global variable /// \param is_definition True if it is a definition, false otherwise /// \param alignment Explicit alignment in bytes, or 0 if unspecified static GlobalVariable* create(Bundle* bundle, PointerType* type, std::string name, bool is_definition, uint64_t alignment); /// \brief Get the parent context Context& context() const { return this->bundle()->context(); } /// \brief Get parent bundle Bundle* bundle() const { return this->_parent; } /// \brief Get the type PointerType* type() const { return cast< PointerType >(this->_type); } /// \brief Set the name void set_name(std::string new_name) override; /// \brief Is this a declaration? bool is_declaration() const { return this->_initializer == nullptr; } /// \brief Is this a definition? bool is_definition() const { return this->_initializer != nullptr; } /// \brief Get the global variable initializer code Code* initializer() const { ikos_assert_msg(this->_initializer, "global variable is a declaration"); return this->_initializer.get(); } /// \brief Get the global variable initializer code, or null Code* initializer_or_null() const { return this->_initializer.get(); } /// \brief Get the alignment of the global variable in memory, in bytes /// /// Returns 0 if the alignment is unspecified. uint64_t alignment() const { return this->_alignment; } /// \brief Return true if the global variable has a specified alignment bool has_alignment() const { return this->alignment() > 0; } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == GlobalVariableKind; } }; // end class GlobalVariable /// \brief Local variable class LocalVariable final : public Variable { private: // Parent function Function* _parent; // Alignment of the local variable, in bytes (0 if unspecified) uint64_t _alignment; private: /// \brief Private constructor LocalVariable(Function* function, PointerType* type, uint64_t alignment); public: /// \brief Static constructor /// /// \param function Parent function /// \param type Type of the local variable /// \param alignment Explicit alignment in bytes, or 0 if unspecified static LocalVariable* create(Function* function, PointerType* type, uint64_t alignment); /// \brief Get the parent context Context& context() const; /// \brief Get the parent bundle Bundle* bundle() const; /// \brief Get parent function Function* function() const { return this->_parent; } /// \brief Get the type PointerType* type() const { return cast< PointerType >(this->_type); } /// \brief Get the alignment of the local variable in memory, in bytes /// /// Returns 0 if the alignment is unspecified. uint64_t alignment() const { return this->_alignment; } /// \brief Return true if the local variable has a specified alignment bool has_alignment() const { return this->alignment() > 0; } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == LocalVariableKind; } }; // end class LocalVariable class InternalVariable final : public Variable { private: // Parent code Code* _parent; private: /// \brief Private constructor InternalVariable(Code* code, Type* type); public: /// \brief Static constructor static InternalVariable* create(Code* code, Type* type); /// \brief Get the parent context Context& context() const; /// \brief Get the parent bundle Bundle* bundle() const; /// \brief Get parent code Code* code() const { return this->_parent; } /// \brief Dump the value for debugging purpose void dump(std::ostream&) const override; /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const Value* v) { return v->kind() == InternalVariableKind; } }; // end class InternalVariable } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/semantic/value_visitor.hpp000066400000000000000000000152161473507761200254260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Value visitor definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace ar { /// \brief Apply a value visitor on a value /// /// A value visitor looks like: /// /// \code{.cpp} /// struct MyValueVisitor { /// using ResultType = int; /// /// int operator()(UndefinedConstant* c) { ... } /// int operator()(IntegerConstant* c) { ... } /// int operator()(FloatConstant* c) { ... } /// int operator()(NullConstant* c) { ... } /// int operator()(StructConstant* c) { ... } /// int operator()(ArrayConstant* c) { ... } /// int operator()(VectorConstant* c) { ... } /// int operator()(AggregateZeroConstant* c) { ... } /// int operator()(FunctionPointerConstant* c) { ... } /// int operator()(InlineAssemblyConstant* c) { ... } /// int operator()(GlobalVariable* v) { ... } /// int operator()(LocalVariable* v) { ... } /// int operator()(InternalVariable* v) { ... } /// }; /// \endcode template < typename Visitor > typename Visitor::ResultType apply_visitor(Visitor& visitor, Value* v) { switch (v->kind()) { case Value::UndefinedConstantKind: return visitor(cast< UndefinedConstant >(v)); case Value::IntegerConstantKind: return visitor(cast< IntegerConstant >(v)); case Value::FloatConstantKind: return visitor(cast< FloatConstant >(v)); case Value::NullConstantKind: return visitor(cast< NullConstant >(v)); case Value::StructConstantKind: return visitor(cast< StructConstant >(v)); case Value::ArrayConstantKind: return visitor(cast< ArrayConstant >(v)); case Value::VectorConstantKind: return visitor(cast< VectorConstant >(v)); case Value::AggregateZeroConstantKind: return visitor(cast< AggregateZeroConstant >(v)); case Value::FunctionPointerConstantKind: return visitor(cast< FunctionPointerConstant >(v)); case Value::InlineAssemblyConstantKind: return visitor(cast< InlineAssemblyConstant >(v)); case Value::GlobalVariableKind: return visitor(cast< GlobalVariable >(v)); case Value::LocalVariableKind: return visitor(cast< LocalVariable >(v)); case Value::InternalVariableKind: return visitor(cast< InternalVariable >(v)); default: ikos_unreachable("unexpected value"); } } /// \brief Apply a const value visitor on a value /// /// A const value visitor looks like: /// /// \code{.cpp} /// struct MyValueVisitor { /// using ResultType = int; /// /// int operator()(UndefinedConstant* c) const { ... } /// int operator()(IntegerConstant* c) const { ... } /// int operator()(FloatConstant* c) const { ... } /// int operator()(NullConstant* c) const { ... } /// int operator()(StructConstant* c) const { ... } /// int operator()(ArrayConstant* c) const { ... } /// int operator()(VectorConstant* c) const { ... } /// int operator()(AggregateZeroConstant* c) const { ... } /// int operator()(FunctionPointerConstant* c) const { ... } /// int operator()(InlineAssemblyConstant* c) const { ... } /// int operator()(GlobalVariable* v) const { ... } /// int operator()(LocalVariable* v) const { ... } /// int operator()(InternalVariable* v) const { ... } /// }; /// \endcode template < typename Visitor > typename Visitor::ResultType apply_visitor(const Visitor& visitor, Value* v) { switch (v->kind()) { case Value::UndefinedConstantKind: return visitor(cast< UndefinedConstant >(v)); case Value::IntegerConstantKind: return visitor(cast< IntegerConstant >(v)); case Value::FloatConstantKind: return visitor(cast< FloatConstant >(v)); case Value::NullConstantKind: return visitor(cast< NullConstant >(v)); case Value::StructConstantKind: return visitor(cast< StructConstant >(v)); case Value::ArrayConstantKind: return visitor(cast< ArrayConstant >(v)); case Value::VectorConstantKind: return visitor(cast< VectorConstant >(v)); case Value::AggregateZeroConstantKind: return visitor(cast< AggregateZeroConstant >(v)); case Value::FunctionPointerConstantKind: return visitor(cast< FunctionPointerConstant >(v)); case Value::InlineAssemblyConstantKind: return visitor(cast< InlineAssemblyConstant >(v)); case Value::GlobalVariableKind: return visitor(cast< GlobalVariable >(v)); case Value::LocalVariableKind: return visitor(cast< LocalVariable >(v)); case Value::InternalVariableKind: return visitor(cast< InternalVariable >(v)); default: ikos_unreachable("unexpected value"); } } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/000077500000000000000000000000001473507761200217265ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/assert.hpp000066400000000000000000000042051473507761200237410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Assertion definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/cast.hpp000066400000000000000000000067551473507761200234060ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Casting definitions (isa, cast, dyn_cast) * * This header includes: * * ikos/core/support/cast.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Check if the parameter is an instance of the template type argument /// /// Used like this: /// /// \code{.cpp} /// if (isa< GlobalVariable >(v)) { ... } /// \endcode using core::isa; /// \brief Return the argument parameter cast to the specified type /// /// This casting operator asserts that the type is correct. It does not allow /// a null argument. /// /// Used like this: /// /// \code{.cpp} /// Instruction* inst = cast< Instruction >(val) /// \endcode using core::cast; /// \brief Return the argument parameter cast to the specified type /// /// This is equivalent to cast< X >, except that a null value is allowed. using core::cast_or_null; /// \brief Return the argument parameter cast to the specified type /// /// This casting operator returns null if the argument is of the wrong type, so /// it can used to test for a type as well as cast if successful. /// /// Used like this: /// /// \code{.cpp} /// if (Instruction* inst = dyn_cast< Instruction >(val)) { ... } /// \endcode using core::dyn_cast; /// \brief Return the argument parameter cast to the specified type /// /// This is equivalent to dyn_cast< X >, except that a null value is allowed. using core::dyn_cast_or_null; } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/flags.hpp000066400000000000000000000111141473507761200235310ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Flags class definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once namespace ikos { namespace ar { /// \brief Type-safe way of storing OR-combinations of enum values template < typename Enum > class Flags { private: static_assert(sizeof(Enum) <= sizeof(unsigned), "enum not supported"); public: using EnumType = Enum; private: // Flags value, as an unsigned integer unsigned _v = 0; private: explicit Flags(unsigned v) : _v(v) {} public: Flags() = default; // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) Flags(Enum v) : _v(v) {} Flags(const Flags&) noexcept = default; Flags(Flags&&) noexcept = default; Flags& operator=(const Flags&) noexcept = default; Flags& operator=(Flags&&) noexcept = default; ~Flags() = default; /// \name Bitwise assignment operators /// @{ Flags& operator&=(Enum f) { _v &= unsigned(f); return *this; } Flags& operator&=(Flags f) { _v &= f._v; return *this; } Flags& operator|=(Enum f) { _v |= unsigned(f); return *this; } Flags& operator|=(Flags f) { _v |= f._v; return *this; } Flags& operator^=(Enum f) { _v ^= unsigned(f); return *this; } Flags& operator^=(Flags f) { _v ^= f._v; return *this; } /// @} /// \name Bitwise operators /// @{ Flags operator&(Enum f) const { return Flags(_v & unsigned(f)); } Flags operator&(Flags f) const { return Flags(_v & f._v); } Flags operator|(Enum f) const { return Flags(_v | unsigned(f)); } Flags operator|(Flags f) const { return Flags(_v | f._v); } Flags operator^(Enum f) const { return Flags(_v ^ unsigned(f)); } Flags operator^(Flags f) const { return Flags(_v ^ f._v); } Flags operator~() const { return Flags(~_v); } bool operator!() const { return _v == 0; } /// @} /// \brief Check whether the given flag is set to 1 bool test(Enum f) const { if (f == 0) { return _v == 0; } else { return (_v & unsigned(f)) == unsigned(f); } } /// \brief Set the given flag to 1 if `on` is true, 0 otherwise Flags& set(Enum f, bool on = true) { if (on) { _v |= unsigned(f); } else { _v &= ~unsigned(f); } return *this; } }; /// \macros IKOS_DECLARE_OPERATORS_FOR_FLAGS /// /// Define operator|(EnumType, EnumType) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define IKOS_DECLARE_OPERATORS_FOR_FLAGS(T) \ inline T operator|(T::EnumType f1, T::EnumType f2) { \ return T(f1) | f2; \ } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/iterator.hpp000066400000000000000000000051321473507761200242710ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Helper for iterators * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Helper for sequential containers of unique_ptr template < typename T > struct SeqExposeRawPtr { T* operator()(const std::unique_ptr< T >& p) const { return p.get(); } }; /// \brief Helper for maps of unique_ptr template < typename K, typename T > struct MapExposeRawPtr { T* operator()(const std::pair< const K, std::unique_ptr< T > >& p) const { return p.second.get(); } }; } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/number.hpp000066400000000000000000000054441473507761200237360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Number definitions * * This header includes: * * ikos/core/number/supported_integral.hpp * * ikos/core/number/z_number.hpp * * ikos/core/number/machine_int.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace ar { /// \brief Signedness (signed or unsigned) using Signedness = ikos::core::Signedness; using ikos::core::Signed; using ikos::core::Unsigned; /// \brief Class for unlimited precision integers using ZNumber = ikos::core::ZNumber; /// \brief Class for arbitrary precision machine integers using MachineInt = ikos::core::MachineInt; } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/string_ref.hpp000066400000000000000000000046051473507761200246060ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Reference to a constant string * * This header includes ikos/core/adt/string_ref.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace ar { /// \brief Represents a reference to a constant string using StringRef = ikos::core::StringRef; } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/support/traceable.hpp000066400000000000000000000122551473507761200243660ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Traceable class definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace ar { /// \brief Add traceability to derived classes /// /// Add the ability to hold a pointer to a front-end object. /// /// This can be used for instance to attach debug information to an object. /// /// Note that Traceable holds a non-owning pointer, so you have to make sure /// the pointee object is still alive before calling frontend(). class Traceable { private: // Pointer to front-end object, or null void* _frontend = nullptr; // Front-end object type info, or null const std::type_info* _frontend_type_info = nullptr; public: /// \brief Default constructor Traceable() = default; /// \brief Constructor taking a pointer to a front-end object template < typename T, class = std::enable_if_t< !std::is_base_of< Traceable, T >::value > > explicit Traceable(T* frontend) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) : _frontend(reinterpret_cast< void* >(frontend)), _frontend_type_info(&typeid(T)) {} /// \brief Copy constructor Traceable(const Traceable&) noexcept = default; /// \brief Move constructor Traceable(Traceable&&) noexcept = default; /// \brief Copy assignment operator Traceable& operator=(const Traceable&) noexcept = default; /// \brief Move assignment operator Traceable& operator=(Traceable&&) noexcept = default; /// \brief Destructor ~Traceable() = default; /// \brief Update the pointer to the front-end object template < typename T, class = std::enable_if_t< !std::is_base_of< Traceable, T >::value > > void set_frontend(T* frontend) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) this->_frontend = reinterpret_cast< void* >(frontend); this->_frontend_type_info = &typeid(T); } /// \brief Update the pointer to the front-end object void set_frontend(const Traceable& o) { this->_frontend = o._frontend; this->_frontend_type_info = o._frontend_type_info; } /// \brief Return true if this object has a pointer to a front-end object bool has_frontend() const { return this->_frontend != nullptr; } /// \brief Return the pointer to a front-end object /// /// Precondition: has_frontend() is true template < typename T > T* frontend() const { ikos_assert_msg(this->_frontend, "no front-end pointer"); ikos_assert_msg(*this->_frontend_type_info == typeid(T), "invalid front-end type"); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast< T* >(this->_frontend); } /// \brief Return the pointer to the front-end object, or null template < typename T > T* frontend_or_null() const { ikos_assert_msg(this->_frontend == nullptr || *this->_frontend_type_info == typeid(T), "invalid front-end type"); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast< T* >(this->_frontend); } }; // end class Traceable } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/verify/000077500000000000000000000000001473507761200215165ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/verify/frontend.hpp000066400000000000000000000077111473507761200240540ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Check that statements have an attached front-end object * * See traceability.hpp for information on front-end object. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace ar { /// \brief Check that statements have an attached front-end object class FrontendVerifier { private: // Find all errors, do not stop at the first one bool _all; public: /// \brief Public constructor /// /// \param all Find all errors, do not stop at the first one explicit FrontendVerifier(bool all = true) : _all(all) {} /// \brief Copy constructor FrontendVerifier(const FrontendVerifier&) noexcept = default; /// \brief Move constructor FrontendVerifier(FrontendVerifier&&) noexcept = default; /// \brief Copy assignment operator FrontendVerifier& operator=(const FrontendVerifier&) noexcept = default; /// \brief Move assignment operator FrontendVerifier& operator=(FrontendVerifier&&) noexcept = default; /// \brief Destructor ~FrontendVerifier() = default; /// \brief Check the given bundle /// /// \param err The output stream for errors bool verify(Bundle* bundle, std::ostream& err) const; /// \brief Check the given global variable /// /// \param err The output stream for errors bool verify(GlobalVariable* gv, std::ostream& err) const; /// \brief Check the given function /// /// \param err The output stream for errors bool verify(Function* f, std::ostream& err) const; /// \brief Check the given code /// /// \param err The output stream for errors bool verify(Code* code, std::ostream& err) const; /// \brief Check the given basic block /// /// \param err The output stream for errors bool verify(BasicBlock* bb, std::ostream& err) const; }; // end class FrontendVerifier } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/include/ikos/ar/verify/type.hpp000066400000000000000000000116111473507761200232100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Type checker for the abstract representation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace ar { /// \brief Type checker class TypeVerifier { private: // Find all errors, do not stop at the first one bool _all; public: /// \brief Public constructor /// /// \param all Find all errors, do not stop at the first one explicit TypeVerifier(bool all = true) : _all(all) {} /// \brief Copy constructor TypeVerifier(const TypeVerifier&) noexcept = default; /// \brief Move constructor TypeVerifier(TypeVerifier&&) noexcept = default; /// \brief Copy assignment operator TypeVerifier& operator=(const TypeVerifier&) noexcept = default; /// \brief Move assignment operator TypeVerifier& operator=(TypeVerifier&&) noexcept = default; /// \brief Destructor ~TypeVerifier() = default; /// \brief Type check the given bundle /// /// \param err The output stream for errors bool verify(Bundle* bundle, std::ostream& err) const; /// \brief Type check the given global variable /// /// \param err The output stream for errors bool verify(GlobalVariable* gv, std::ostream& err) const; /// \brief Type check the given function /// /// \param err The output stream for errors bool verify(Function* f, std::ostream& err) const; /// \brief Type check the given code /// /// \param err The output stream for errors /// \param return_type For a function body, the returned type, otherwise null bool verify(Code* code, std::ostream& err, Type* return_type = nullptr) const; /// \brief Type check the given basic block /// /// \param err The output stream for errors /// \param return_type For a function body, the returned type, otherwise null bool verify(BasicBlock* bb, std::ostream& err, Type* return_type = nullptr) const; public: // Check if there is an implicit bitcast between two types. // // An implicit bitcast is between: // - integer types of the same bit-width (i.e, signed <-> unsigned) // - pointer types (i.e, A* <-> B*) static bool is_implicit_bitcast(Type* a, Type* b) { return (a->is_integer() && b->is_integer() && cast< IntegerType >(a)->bit_width() == cast< IntegerType >(b)->bit_width()) || (a->is_pointer() && b->is_pointer()); } /// \brief Return true if the given call statement is a valid function call to /// the given function type. /// /// Checks the return type and parameter types. /// Does not check the called value type. static bool is_valid_call(ar::CallBase* call, ar::FunctionType* fun_ty); }; // end class TypeVerifier } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/000077500000000000000000000000001473507761200160075ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/src/format/000077500000000000000000000000001473507761200172775ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/src/format/dot.cpp000066400000000000000000000102021473507761200205640ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Dot format for the abstract representation, implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace ar { void DotFormatter::format(std::ostream& o, Function* f) const { if (f->is_declaration()) { return; } o << "digraph \"CFG for '" << f->name() << "' function\" {\n" << "\tlabel=\"CFG for '" << f->name() << "' function\";\n" << "\n"; this->format(o, f->body()); o << "}\n"; } void DotFormatter::format(std::ostream& o, GlobalVariable* gv) const { if (gv->is_declaration()) { return; } o << "digraph \"CFG for initializer of '" << gv->name() << "'\" {\n" << "\tlabel=\"CFG for initializer of '" << gv->name() << "'\";\n" << "\n"; this->format(o, gv->initializer()); o << "}\n"; } void DotFormatter::format(std::ostream& o, Code* code) const { Namer namer(code); for (auto it = code->begin(), et = code->end(); it != et; ++it) { this->format(o, *it, namer); } } void DotFormatter::format(std::ostream& o, BasicBlock* bb, const Namer& namer) const { // Preambule o << "\tNode" << bb << " [shape=record,label=\"{" << "#" << namer.name(bb) << ":\\l"; // Statements TextFormatter formatter(this->_opts); for (auto it = bb->begin(), et = bb->end(); it != et; ++it) { o << " "; // Translate a statement, and escape forbidden characters std::ostringstream buf; formatter.format(buf, *it, namer); o << armor(buf.str()); o << "\\l"; } // Successors o << "}\"];\n"; for (auto it = bb->successor_begin(), et = bb->successor_end(); it != et; ++it) { o << "\tNode" << bb << " -> Node" << *it << ";\n"; } } std::string DotFormatter::armor(StringRef s) { std::string buffer; buffer.reserve(s.size() + 1); for (char c : s) { switch (c) { case '{': case '}': { buffer.push_back('\\'); buffer.push_back(c); } break; default: { buffer.push_back(c); } } } return buffer; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/format/namer.cpp000066400000000000000000000136741473507761200211200ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the Namer * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include namespace ikos { namespace ar { Namer::Namer() = default; Namer::Namer(Code* code) { this->init(code); } void Namer::init(Code* code) { // Counter std::size_t bb_idx = 0; std::size_t var_idx = 0; // Name parameters if (code->is_function_body()) { Function* f = code->function(); for (auto it = f->param_begin(), et = f->param_end(); it != et; ++it) { InternalVariable* v = *it; if (!v->has_name() && this->_variables.find(v) == this->_variables.end()) { this->_variables.emplace(v, std::to_string(++var_idx)); } } } // Top-down walk through the basic blocks std::deque< ar::BasicBlock* > worklist; if (code->has_entry_block()) { worklist.push_back(code->entry_block()); } while (!worklist.empty()) { // Pop the front element ar::BasicBlock* bb = worklist.front(); worklist.pop_front(); // Already processed if (this->_basic_blocks.find(bb) != this->_basic_blocks.end()) { continue; } // Name this basic block if (bb->has_name()) { this->_basic_blocks.emplace(bb, bb->name()); // mark as processed } else { this->_basic_blocks.emplace(bb, std::to_string(++bb_idx)); } // Add successors in the worklist for (auto bb_it = bb->successor_begin(), bb_et = bb->successor_end(); bb_it != bb_et; ++bb_it) { worklist.push_back(*bb_it); } // Name all variables in statements for (auto s_it = bb->begin(), s_et = bb->end(); s_it != s_et; ++s_it) { ar::Statement* stmt = *s_it; // Name operands for (auto op_it = stmt->op_begin(), op_et = stmt->op_end(); op_it != op_et; ++op_it) { if (auto op = dyn_cast< Variable >(*op_it)) { if (!op->has_name() && this->_variables.find(op) == this->_variables.end()) { this->_variables.emplace(op, std::to_string(++var_idx)); } } } // Name result if (stmt->has_result() && !stmt->result()->has_name() && this->_variables.find(stmt->result()) == this->_variables.end()) { this->_variables.emplace(stmt->result(), std::to_string(++var_idx)); } } } // Name unreachable basic blocks for (auto it = code->begin(), et = code->end(); it != et; ++it) { BasicBlock* bb = *it; if (!bb->has_name() && this->_basic_blocks.find(bb) == this->_basic_blocks.end()) { this->_basic_blocks.emplace(bb, std::to_string(++bb_idx)); } } // Name unused local variables if (code->is_function_body()) { Function* f = code->function(); for (auto it = f->local_variable_begin(), et = f->local_variable_end(); it != et; ++it) { LocalVariable* v = *it; if (!v->has_name() && this->_variables.find(v) == this->_variables.end()) { this->_variables.emplace(v, std::to_string(++var_idx)); } } } // Name unused internal variables for (auto it = code->internal_variable_begin(), et = code->internal_variable_end(); it != et; ++it) { InternalVariable* v = *it; if (!v->has_name() && this->_variables.find(v) == this->_variables.end()) { this->_variables.emplace(v, std::to_string(++var_idx)); } } } const std::string& Namer::name(Variable* v) const { if (v->has_name()) { return v->name(); } else { ikos_assert(this->_variables.find(v) != this->_variables.end()); return this->_variables.at(v); } } const std::string& Namer::name(BasicBlock* bb) const { if (bb->has_name()) { return bb->name(); } else { ikos_assert(this->_basic_blocks.find(bb) != this->_basic_blocks.end()); return this->_basic_blocks.at(bb); } } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/format/text.cpp000066400000000000000000000445751473507761200210060ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Text format for the abstract representation, implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include namespace ikos { namespace ar { void TextFormatter::format(std::ostream& o, Bundle* bundle) const { o << "// Bundle\n"; // data layout const DataLayout& data_layout = bundle->data_layout(); // endianness o << "target-endianness = "; if (data_layout.is_little_endian()) { o << "little-endian\n"; } else { o << "big-endian\n"; } // size of pointers o << "target-pointer-size = " << data_layout.pointers.bit_width << " bits\n"; // target triple if (!bundle->target_triple().empty()) { o << "target-triple = " << bundle->target_triple() << "\n"; } if (!this->order_globals()) { // global variables for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { o << "\n"; this->format(o, *it); } // functions for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { o << "\n"; this->format(o, *it); } } else { // sort global variables and functions by name, before formatting std::vector< GlobalVariable* > globals(bundle->global_begin(), bundle->global_end()); std::vector< Function* > functions(bundle->function_begin(), bundle->function_end()); std::sort(globals.begin(), globals.end(), [](GlobalVariable* a, GlobalVariable* b) { return a->name() < b->name(); }); std::sort(functions.begin(), functions.end(), [](Function* a, Function* b) { return a->name() < b->name(); }); // format globals and functions for (GlobalVariable* gv : globals) { o << "\n"; this->format(o, gv); } for (Function* fun : functions) { o << "\n"; this->format(o, fun); } } } void TextFormatter::format(std::ostream& o, GlobalVariable* gv) const { // declare/define if (gv->is_declaration()) { o << "declare "; } else { o << "define "; } // type and name this->format(o, gv->type()); o << " @" << gv->name(); // alignment if (gv->has_alignment()) { o << ", align " << gv->alignment(); } // initializer if (gv->is_declaration()) { o << "\n"; } else { o << ", init {\n"; this->format(o, gv->initializer()); o << "}\n"; } } void TextFormatter::format_header(std::ostream& o, const Function* f, Namer& namer) const { FunctionType* type = f->type(); // declare/define if (f->is_declaration()) { o << "declare "; } else { namer.init(f->body()); // initialize the namer o << "define "; } // return type and name format(o, type->return_type()); o << " @" << f->name(); // parameters o << "("; if (f->is_declaration()) { for (auto it = type->param_begin(), et = type->param_end(); it != et;) { format(o, *it); ++it; if (it != et) { o << ", "; } } } else { for (auto it = f->param_begin(), et = f->param_end(); it != et;) { format(o, *it, namer, true); ++it; if (it != et) { o << ", "; } } } if (f->is_var_arg()) { if (type->num_parameters() > 0) { o << ", "; } o << "..."; } o << ")"; } void TextFormatter::format(std::ostream& o, Function* f) const { Namer namer; this->format_header(o, f, namer); // body if (f->is_declaration()) { o << "\n"; } else { o << " {\n"; this->format(o, f->body(), namer); o << "}\n"; } } void TextFormatter::format(std::ostream& o, Code* code) const { this->format(o, code, Namer(code)); } void TextFormatter::format(std::ostream& o, Code* code, const Namer& namer) const { for (auto it = code->begin(), et = code->end(); it != et; ++it) { this->format(o, *it, namer); } } void TextFormatter::format(std::ostream& o, BasicBlock* bb) const { this->format(o, bb, Namer(bb->code())); } void TextFormatter::format(std::ostream& o, BasicBlock* bb, const Namer& namer) const { Code* code = bb->code(); // name o << "#" << namer.name(bb); // attributes if (code->entry_block() == bb) { o << " !entry"; } if (code->exit_block_or_null() == bb) { o << " !exit"; } // predecessors if (bb->num_predecessors() > 0) { o << " predecessors={"; for (auto it = bb->predecessor_begin(), et = bb->predecessor_end(); it != et;) { o << "#" << namer.name(*it); ++it; if (it != et) { o << ", "; } } o << "}"; } // successors if (bb->num_successors() > 0) { o << " successors={"; for (auto it = bb->successor_begin(), et = bb->successor_end(); it != et;) { o << "#" << namer.name(*it); ++it; if (it != et) { o << ", "; } } o << "}"; } // statements o << " {\n"; for (auto it = bb->begin(), et = bb->end(); it != et; ++it) { o << " "; this->format(o, *it, namer); o << "\n"; } o << "}\n"; } void TextFormatter::format(std::ostream& o, Statement* stmt) const { Namer namer(stmt->code()); this->format(o, stmt, namer); } namespace { /// \brief Visitor to format a statement into text format class FormatTextStatement { public: using ResultType = void; public: const TextFormatter& formatter; std::ostream& o; const Namer& namer; public: FormatTextStatement(const TextFormatter& formatter_, std::ostream& o_, const Namer& namer_) : formatter(formatter_), o(o_), namer(namer_) {} void operator()(Assignment* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = "; formatter.format(o, s->operand(), namer, formatter.show_operand_types()); } void operator()(UnaryOperation* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = " << UnaryOperation::operator_text(s->op()) << " "; formatter.format(o, s->operand(), namer, formatter.show_operand_types()); } void operator()(BinaryOperation* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = "; formatter.format(o, s->left(), namer, formatter.show_operand_types()); o << " "; o << BinaryOperation::operator_text(s->op()); if (s->has_no_wrap()) { o << ".nw"; } if (s->is_exact()) { o << ".exact"; } o << " "; formatter.format(o, s->right(), namer, formatter.show_operand_types()); } void operator()(Comparison* s) { formatter.format(o, s->left(), namer, formatter.show_operand_types()); o << " " << Comparison::predicate_text(s->predicate()) << " "; formatter.format(o, s->right(), namer, formatter.show_operand_types()); } void operator()(ReturnValue* s) { if (s->has_operand()) { o << "return "; formatter.format(o, s->operand(), namer, formatter.show_operand_types()); } else { o << "return"; } } void operator()(Unreachable* /*s*/) { o << "unreachable"; } void operator()(Allocate* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = allocate "; formatter.format(o, s->allocated_type()); o << ", "; formatter.format(o, s->array_size(), namer, formatter.show_operand_types()); if (s->result()->has_alignment()) { o << ", align " << s->result()->alignment(); } } void operator()(PointerShift* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = ptrshift "; formatter.format(o, s->pointer(), namer, formatter.show_operand_types()); // terms for (auto it = s->term_begin(), et = s->term_end(); it != et; ++it) { auto term = *it; o << ", " << term.first << " * "; formatter.format(o, term.second, namer, formatter.show_operand_types()); } } void operator()(Load* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = load "; if (s->is_volatile()) { o << "volatile "; } formatter.format(o, s->operand(), namer, formatter.show_operand_types()); if (s->has_alignment()) { o << ", align " << s->alignment(); } } void operator()(Store* s) { o << "store "; if (s->is_volatile()) { o << "volatile "; } formatter.format(o, s->pointer(), namer, formatter.show_operand_types()); o << ", "; formatter.format(o, s->value(), namer, formatter.show_operand_types()); if (s->has_alignment()) { o << ", align " << s->alignment(); } } void operator()(ExtractElement* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = extractelement "; formatter.format(o, s->aggregate(), namer, formatter.show_operand_types()); o << ", "; formatter.format(o, s->offset(), namer, formatter.show_operand_types()); } void operator()(InsertElement* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = insertelement "; formatter.format(o, s->aggregate(), namer, formatter.show_operand_types()); o << ", "; formatter.format(o, s->offset(), namer, formatter.show_operand_types()); o << ", "; formatter.format(o, s->element(), namer, formatter.show_operand_types()); } void operator()(ShuffleVector* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = shufflevector "; formatter.format(o, s->left(), namer, formatter.show_operand_types()); o << ", "; formatter.format(o, s->right(), namer, formatter.show_operand_types()); } void operator()(Call* s) { // result if (s->has_result()) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = "; } // op o << "call "; // called formatter.format(o, s->called(), namer, formatter.show_operand_types()); // arguments o << "("; for (auto it = s->arg_begin(), et = s->arg_end(); it != et;) { formatter.format(o, *it, namer, formatter.show_operand_types()); ++it; if (it != et) { o << ", "; } } o << ")"; } void operator()(Invoke* s) { // result if (s->has_result()) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = "; } // op o << "invoke "; // called formatter.format(o, s->called(), namer, formatter.show_operand_types()); // arguments o << "("; for (auto it = s->arg_begin(), et = s->arg_end(); it != et;) { formatter.format(o, *it, namer, formatter.show_operand_types()); ++it; if (it != et) { o << ", "; } } o << ")"; // normal/exception o << " normal=#" << namer.name(s->normal_dest()); o << " exc=#" << namer.name(s->exception_dest()); } void operator()(LandingPad* s) { formatter.format(o, s->result(), namer, formatter.show_result_type()); o << " = landingpad"; } void operator()(Resume* s) { o << "resume "; formatter.format(o, s->operand(), namer, formatter.show_operand_types()); } }; // end class FormatTextStatement } // end anonymous namespace void TextFormatter::format(std::ostream& o, Statement* stmt, const Namer& namer) const { FormatTextStatement vis(*this, o, namer); apply_visitor(vis, stmt); } namespace { /// \brief Set of types using TypeSet = boost::container::flat_set< Type* >; /// \brief Visitor to format a type into text format class FormatTextType { public: using ResultType = void; public: std::ostream& o; TypeSet seen; public: explicit FormatTextType(std::ostream& o_) : o(o_) {} FormatTextType(std::ostream& o_, TypeSet seen_) : o(o_), seen(std::move(seen_)) {} void operator()(VoidType* /*t*/) { o << "void"; } void operator()(IntegerType* t) { if (t->is_unsigned()) { o << "ui"; } else { o << "si"; } o << t->bit_width(); } void operator()(FloatType* t) { switch (t->float_semantic()) { case Half: o << "half"; break; case Float: o << "float"; break; case Double: o << "double"; break; case X86_FP80: o << "x86_fp80"; break; case FP128: o << "fp128"; break; case PPC_FP128: o << "ppc_fp128"; break; default: ikos_unreachable("unknown float semantic"); } } void operator()(PointerType* t) { apply_visitor(*this, t->pointee()); o << "*"; } void operator()(StructType* t) { if (t->packed()) { o << "<"; } o << "{"; if (seen.find(t) != seen.end()) { o << "..."; } else { seen.insert(t); for (auto it = t->field_begin(), et = t->field_end(); it != et;) { o << it->offset << ": "; FormatTextType field_visitor(o, seen); apply_visitor(field_visitor, it->type); ++it; if (it != et) { o << ", "; } } } o << "}"; if (t->packed()) { o << ">"; } } void operator()(ArrayType* t) { o << "[" << t->num_elements() << " x "; apply_visitor(*this, t->element_type()); o << "]"; } void operator()(VectorType* t) { o << "<" << t->num_elements() << " x "; apply_visitor(*this, t->element_type()); o << ">"; } void operator()(OpaqueType* /*t*/) { o << "opaque"; } void operator()(FunctionType* t) { apply_visitor(*this, t->return_type()); o << " ("; for (auto it = t->param_begin(), et = t->param_end(); it != et;) { apply_visitor(*this, *it); ++it; if (it != et) { o << ", "; } } if (t->is_var_arg()) { if (t->num_parameters() > 0) { o << ", "; } o << "..."; } o << ")"; } }; // end class FormatTextType } // end anonymous namespace void TextFormatter::format(std::ostream& o, Type* type) const { FormatTextType vis(o); apply_visitor(vis, type); } namespace { /// \brief Visitor to format a value into text format class FormatTextValue { public: using ResultType = void; public: std::ostream& o; const Namer& namer; public: FormatTextValue(std::ostream& o_, const Namer& namer_) : o(o_), namer(namer_) {} void operator()(UndefinedConstant* /*c*/) { o << "undef"; } void operator()(IntegerConstant* c) { o << c->value(); } void operator()(FloatConstant* c) { o << c->value(); } void operator()(NullConstant* /*c*/) { o << "null"; } void operator()(StructConstant* c) { o << "{"; for (auto it = c->field_begin(), et = c->field_end(); it != et;) { o << it->offset << ": "; apply_visitor(*this, it->value); ++it; if (it != et) { o << ", "; } } o << "}"; } void operator()(ArrayConstant* c) { o << "["; for (auto it = c->element_begin(), et = c->element_end(); it != et;) { apply_visitor(*this, *it); ++it; if (it != et) { o << ", "; } } o << "]"; } void operator()(VectorConstant* c) { o << "<"; for (auto it = c->element_begin(), et = c->element_end(); it != et;) { apply_visitor(*this, *it); ++it; if (it != et) { o << ", "; } } o << ">"; } void operator()(AggregateZeroConstant* /*c*/) { o << "aggregate_zero"; } void operator()(FunctionPointerConstant* c) { o << "@" << c->function()->name(); } void operator()(InlineAssemblyConstant* c) { o << "asm \"" << c->code() << "\""; } void operator()(GlobalVariable* v) { o << "@" << v->name(); } void operator()(LocalVariable* v) { o << "$" << namer.name(v); } void operator()(InternalVariable* v) { o << "%" << namer.name(v); } }; // end class FormatTextValue } // end anonymous namespace void TextFormatter::format(std::ostream& o, Value* value, const Namer& namer, bool show_type) const { if (show_type) { this->format(o, value->type()); o << " "; } FormatTextValue vis(o, namer); apply_visitor(vis, value); } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/pass/000077500000000000000000000000001473507761200167555ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/src/pass/add_loop_counters.cpp000066400000000000000000000154131473507761200231700ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of AddLoopCountersPass * * This pass adds a hidden loop counter variable within each loop, using the * `ikos.counter.init` and `ikos.counter.incr` intrinsic functions. * * This can be used by the gauge abstract domain to infer loop invariants. * * Authors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace ar { const char* AddLoopCountersPass::name() const { return "add-loop-counters"; } const char* AddLoopCountersPass::description() const { return "Add loop counters"; } bool AddLoopCountersPass::run(Bundle* bundle) { // Create the counter intrinsic functions before iterating on codes bundle->intrinsic_function(Intrinsic::IkosCounterInit); bundle->intrinsic_function(Intrinsic::IkosCounterIncr); return CodePass::run(bundle); } namespace { /// \brief Iterate over the components in the control flow graph class LoopIterator : public core::WtoComponentVisitor< Code* > { private: using WtoVertexT = core::WtoVertex< Code* >; using WtoCycleT = core::WtoCycle< Code* >; private: // Code Code* _code; // List of basic blocks in the current cycle std::vector< BasicBlock* > _blocks; public: explicit LoopIterator(Code* code) : _code(code) {} void visit(const WtoVertexT& vertex) override { this->_blocks.push_back(vertex.node()); } void visit(const WtoCycleT& cycle) override { std::vector< BasicBlock* > current_blocks = std::move(this->_blocks); // Collect all basic blocks within the cycle this->_blocks.clear(); this->_blocks.push_back(cycle.head()); for (auto it = cycle.begin(), et = cycle.end(); it != et; ++it) { it->accept(*this); } this->add_loop_counter(cycle, this->_blocks); // Update _blocks this->_blocks.insert(this->_blocks.end(), current_blocks.begin(), current_blocks.end()); } /// \brief Add a loop counter in the given cycle void add_loop_counter(const WtoCycleT& cycle, const std::vector< BasicBlock* >& blocks) { Bundle* bundle = this->_code->bundle(); Context& ctx = bundle->context(); // Get the intrinsics for loop counters Function* counter_init = bundle->intrinsic_function(Intrinsic::IkosCounterInit); Function* counter_incr = bundle->intrinsic_function(Intrinsic::IkosCounterIncr); // Create the loop counter variable IntegerType* size_ty = IntegerType::size_type(this->_code->bundle()); InternalVariable* var = InternalVariable::create(this->_code, size_ty); // Constants IntegerConstant* zero = IntegerConstant::get(ctx, size_ty, 0); IntegerConstant* one = IntegerConstant::get(ctx, size_ty, 1); // Add initialization statement in parent blocks that aren't in the cycle std::size_t blocks_incoming_edge = 0; for (BasicBlock* bb : blocks) { bool has_incoming_edge = false; for (auto it = bb->predecessor_begin(), et = bb->predecessor_end(); it != et; ++it) { BasicBlock* pred = *it; if (std::find(blocks.begin(), blocks.end(), pred) == blocks.end()) { // predecessor is not in the cycle has_incoming_edge = true; pred->push_back(Call::create(/* result = */ var, /* function = */ counter_init, /* arguments = */ {zero})); } } if (has_incoming_edge) { blocks_incoming_edge++; } } if (blocks_incoming_edge > 1) { // Cycle with multiple blocks having incoming edges from outside of the // cycle. This pattern is unusual. We cannot know where to put the // increment statement, so just abort silently. return; } // Add an increment statement in incoming blocks of the head that are in the // cycle BasicBlock* head = cycle.head(); for (auto it = head->predecessor_begin(), et = head->predecessor_end(); it != et; ++it) { BasicBlock* pred = *it; if (std::find(blocks.begin(), blocks.end(), pred) != blocks.end()) { pred->push_back(Call::create(/* result = */ var, /* function = */ counter_incr, /* arguments = */ {var, one})); } } } }; // end class LoopIterator } // end anonymous namespace bool AddLoopCountersPass::run_on_code(Code* code) { // Compute the weak topological order core::Wto< Code* > wto(code); // Add a loop counter in each cycle LoopIterator it(code); wto.accept(it); return true; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/pass/add_partitioning_variables.cpp000066400000000000000000000221611473507761200250320ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of AddPartitioningVariablesPass * * This pass adds annotations to functions that return an error code. It * detects integer variables containing the error code and adds calls to the * `ikos.partitioning.var.*` intrinsic functions. * * Authors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019-2023 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include namespace ikos { namespace ar { /// \brief Bit-width of integer types used for partitioning constexpr static const std::array< unsigned, 4 > bit_widths = {1, 8, 32, 64}; const char* AddPartitioningVariablesPass::name() const { return "add-partitioning-variables"; } const char* AddPartitioningVariablesPass::description() const { return "Add partitioning variables"; } bool AddPartitioningVariablesPass::run(Bundle* bundle) { // Create the partitioning intrinsic functions before iterating on the bundle for (unsigned bit_width : bit_widths) { bundle->intrinsic_function(Intrinsic::IkosPartitioningVar, IntegerType::get(bundle->context(), bit_width, Signed)); bundle->intrinsic_function(Intrinsic::IkosPartitioningVar, IntegerType::get(bundle->context(), bit_width, Unsigned)); } bool change = false; for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { change = this->run_on_function(*it) || change; } return change; } namespace { /// \brief A pair containing a basic block and an internal variable struct BasicBlockVarPair { BasicBlock* bb; InternalVariable* var; }; } // end anonymous namespace bool AddPartitioningVariablesPass::run_on_function(Function* fun) { if (fun->is_declaration()) { // Function has no implementation return false; } Bundle* bundle = fun->bundle(); auto return_type = dyn_cast< IntegerType >(fun->type()->return_type()); if (return_type == nullptr) { // Return type is not an integer return false; } if (std::find(bit_widths.begin(), bit_widths.end(), return_type->bit_width()) == bit_widths.end()) { // Return type bit width is not supported return false; } Code* body = fun->body(); if (!body->has_exit_block()) { // Function has no exit block return false; } BasicBlock* exit_block = body->exit_block(); BasicBlock* return_block = nullptr; if (exit_block->empty()) { // Exit block is empty, check the predecessors for (auto it = exit_block->predecessor_begin(), et = exit_block->predecessor_end(); it != et; ++it) { BasicBlock* bb = *it; if (bb->empty()) { // Predecessor is empty return false; } if (isa< Unreachable >(bb->back())) { // Predecessor with an unreachable statement, ignore continue; } if (return_block != nullptr) { // Multiple return blocks return false; } return_block = bb; } } else { return_block = exit_block; } if (return_block == nullptr) { // Function has no return block return false; } auto return_stmt = dyn_cast< ReturnValue >(return_block->back()); if (return_stmt == nullptr) { // Return block does not end with a return return false; } if (!return_stmt->has_operand()) { // Return statement has no operand return false; } auto return_var = dyn_cast< InternalVariable >(return_stmt->operand()); if (return_var == nullptr) { // Function does not return a variable return false; } // Check if the return variable is defined in multiple basic blocks BasicBlock* bb = return_block; InternalVariable* var = return_var; while (bb != nullptr) { if (bb == body->entry_block()) { // Return variable is defined in the entry block return false; } for (auto it = bb->rbegin(), et = bb->rend(); it != et; ++it) { Statement* stmt = *it; if (stmt->result_or_null() == var) { if (isa< Assignment >(stmt) && isa< InternalVariable >(stmt->operand(0))) { // Track the operand variable var = cast< InternalVariable >(stmt->operand(0)); } else { // Return variable is defined in one basic block return false; } } } if (bb->num_predecessors() == 1) { bb = *bb->predecessor_begin(); } else if (bb->num_predecessors() >= 2) { bb = nullptr; // Return variable can be used for partitioning } else { ikos_unreachable("non-entry basic block with no predecessor"); } } // Annotate the function // Function to mark a variable as a partitioning variable Function* partitioning_var_fun = bundle->intrinsic_function(Intrinsic::IkosPartitioningVar, return_type); // List of predecessors that define the return variable std::vector< BasicBlockVarPair > preds = { BasicBlockVarPair{return_block, return_var}}; // List of basic blocks already seen std::unordered_set< BasicBlock* > seen; while (!preds.empty()) { bb = preds.back().bb; // Current basic block var = preds.back().var; // Tracked variable preds.pop_back(); auto res = seen.insert(bb); if (!res.second) { continue; // Already seen } for (auto it = bb->end(); it != bb->begin();) { --it; Statement* stmt = *it; if (stmt->result_or_null() == var) { if (isa< Assignment >(stmt) && isa< InternalVariable >(stmt->operand(0))) { // Statement assigns the tracked variable to another variable // Insert the partitioning annotation auto partitioning_annotation = Call::create(/* result = */ nullptr, /* function = */ partitioning_var_fun, /* arguments = */ {var}); it = bb->insert_after(it, std::move(partitioning_annotation)); --it; // Track the operand variable var = cast< InternalVariable >(stmt->operand(0)); } else { // Statement defines the tracked variable // Insert a partitioning annotation auto partitioning_annotation = Call::create(/* result = */ nullptr, /* function = */ partitioning_var_fun, /* arguments = */ {var}); it = bb->insert_after(it, std::move(partitioning_annotation)); --it; // Stop tracking the variable var = nullptr; break; } } } if (var == nullptr) { continue; } // Basic block does not define this variable, look at predecessors for (auto it = bb->predecessor_begin(), et = bb->predecessor_end(); it != et; ++it) { preds.push_back(BasicBlockVarPair{*it, var}); } } return true; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/pass/name_values.cpp000066400000000000000000000073001473507761200217600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of NameValuesPass * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace ar { const char* NameValuesPass::name() const { return "name-values"; } const char* NameValuesPass::description() const { return "Name variables and basic blocks"; } bool NameValuesPass::run_on_code(Code* code) { // Generate all the names Namer namer(code); // Prefix to add, if requested std::string prefix; if (code->is_function_body()) { prefix = code->function()->name() + "."; } else { prefix = code->global_var()->name() + "."; } // Assign the generated names if (code->is_function_body()) { Function* f = code->function(); // Name local variables for (auto it = f->local_variable_begin(), et = f->local_variable_end(); it != et; ++it) { LocalVariable* v = *it; if (!v->has_name()) { v->set_name(namer.name(v)); } if (this->_prefix) { v->set_name(prefix + v->name()); } } } // Name basic blocks for (auto it = code->begin(), et = code->end(); it != et; ++it) { BasicBlock* bb = *it; if (!bb->has_name()) { bb->set_name(namer.name(bb)); } } // Name internal variables for (auto it = code->internal_variable_begin(), et = code->internal_variable_end(); it != et; ++it) { InternalVariable* v = *it; if (!v->has_name()) { v->set_name(namer.name(v)); } if (this->_prefix) { v->set_name(prefix + v->name()); } } return false; // the semantic hasn't changed } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/pass/pass.cpp000066400000000000000000000054111473507761200204300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of base classes for passes * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace ar { // CodePass bool CodePass::run(Bundle* bundle) { bool change = false; for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et; ++it) { GlobalVariable* gv = *it; if (gv->is_definition()) { change = this->run_on_code(gv->initializer()) || change; } } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { Function* fun = *it; if (fun->is_definition()) { change = this->run_on_code(fun->body()) || change; } } return change; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/pass/simplify_cfg.cpp000066400000000000000000000113261473507761200221370ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of SimplifyCFGPass * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace ar { /// \brief Merge the given basic block with its child, if possible static bool merge_single_block(Code* code, BasicBlock* bb) { if (bb->num_successors() != 1) { return false; } BasicBlock* child = *bb->successor_begin(); if (bb == child || child->num_predecessors() != 1 || child->is_successor(child) || code->entry_block() == child) { return false; } // Move the statements from child to bb std::vector< std::unique_ptr< Statement > > stmts; stmts.reserve(child->num_statements()); while (!child->empty()) { stmts.push_back(child->pop_back()); } while (!stmts.empty()) { bb->push_back(std::move(stmts.back())); stmts.pop_back(); } // Update edges bb->clear_successors(); for (auto it = child->successor_begin(), et = child->successor_end(); it != et; ++it) { bb->add_successor(*it); } child->clear_predecessors(); child->clear_successors(); // child will be removed later, see remove_unreachable_blocks() // Update exit block if (code->exit_block_or_null() == child) { code->set_exit_block(bb); } // Update traceability if (!bb->has_frontend()) { bb->set_frontend(*child); } return true; } /// \brief Merge basic blocks whenever possible static bool merge_single_blocks(Code* code) { bool change = false; bool done = false; while (!done) { done = true; for (auto it = code->begin(), et = code->end(); it != et; ++it) { while (merge_single_block(code, *it)) { change = true; done = false; } } } return change; } /// \brief Remove unreachable basic blocks static bool remove_unreachable_blocks(Code* code) { bool change = false; bool done = false; while (!done) { std::vector< BasicBlock* > to_remove; done = true; for (auto it = code->begin(), et = code->end(); it != et; ++it) { BasicBlock* bb = *it; if (bb->num_predecessors() == 0 && code->entry_block() != bb) { to_remove.push_back(bb); } } for (BasicBlock* bb : to_remove) { code->erase_basic_block(bb); change = true; done = false; } } return change; } const char* SimplifyCFGPass::name() const { return "simplify-cfg"; } const char* SimplifyCFGPass::description() const { return "Simplify the Control Flow Graphs"; } bool SimplifyCFGPass::run_on_code(Code* code) { bool change = false; change |= merge_single_blocks(code); change |= remove_unreachable_blocks(code); return change; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/pass/simplify_upcast_comparison.cpp000066400000000000000000000176611473507761200251410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of SimplifyUpcastComparisonPass * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace ar { const char* SimplifyUpcastComparisonPass::name() const { return "simplify-upcast-comparison"; } const char* SimplifyUpcastComparisonPass::description() const { return "Simplify upcast comparison"; } bool SimplifyUpcastComparisonPass::run_on_code(Code* code) { bool change = false; for (BasicBlock* bb : *code) { if (!bb->empty()) { change = this->run_on_statement(bb->front()) || change; } } return change; } bool SimplifyUpcastComparisonPass::run_on_statement(Statement* stmt) { if (auto cmp = dyn_cast< Comparison >(stmt)) { if (cmp->is_integer_predicate()) { if (cmp->left()->is_integer_constant() && cmp->right()->is_internal_variable()) { return this->run_on_comparison(cmp, cast< IntegerConstant >(cmp->left()), cmp->right()); } else if (cmp->left()->is_internal_variable() && cmp->right()->is_integer_constant()) { return this->run_on_comparison(cmp, cast< IntegerConstant >(cmp->right()), cmp->left()); } } } return false; } bool SimplifyUpcastComparisonPass::run_on_comparison(Comparison* cmp, IntegerConstant* constant, Value* var) { BasicBlock* bb = cmp->parent(); auto it = bb->rend(); auto et = bb->rend(); // track variable if bitcast occurs Value* tracked_variable = var; bool bitcast = false; UnaryOperation* upcast = nullptr; // backtrace and find the upcast while (true) { // beginning of a block if (it == et) { if (bb->num_predecessors() == 1) { // move to the parent bb = *bb->predecessor_begin(); it = bb->rbegin(); et = bb->rend(); continue; } else { return false; } } auto stmt = *it; if (stmt->result_or_null() == tracked_variable) { if (!isa< UnaryOperation >(stmt)) { return false; } upcast = cast< UnaryOperation >(stmt); if (!bitcast && upcast->op() == UnaryOperation::Bitcast) { tracked_variable = upcast->operand(); upcast = nullptr; bitcast = true; } else if (!bitcast && (upcast->op() == UnaryOperation::SExt || upcast->op() == UnaryOperation::ZExt)) { break; } else if (bitcast && upcast->op() == UnaryOperation::ZExt) { break; } else { return false; } } it++; } if (auto new_constant = this->run_on_upcast(cmp->context(), upcast->operand(), constant)) { // add assert this->insert_assert(cmp, upcast->operand(), constant, *new_constant, bitcast); return true; } else { return false; } } boost::optional< IntegerConstant* > SimplifyUpcastComparisonPass::run_on_upcast( Context& context, Value* tracked_variable, IntegerConstant* constant) { auto type = cast< IntegerType >(tracked_variable->type()); ZInterval top = IntInterval::top(type->bit_width(), type->sign()).to_z_interval(); ZNumber zvalue = constant->value().to_z_number(); // if the constant is superior to the maximum value of the original type // (before the cast), then this is an inifinite loop if (top.contains(zvalue)) { return IntegerConstant::get(context, IntegerType::get(context, type->bit_width(), type->sign()), constant->value().cast(type->bit_width(), type->sign())); } else { return boost::none; } } void SimplifyUpcastComparisonPass::insert_assert(Comparison* cmp, Value* tracked_variable, IntegerConstant* constant, IntegerConstant* new_constant, bool bitcast) { Value* left; Value* right; if (cmp->left() == constant) { left = new_constant; right = tracked_variable; } else { left = tracked_variable; right = new_constant; } Comparison::Predicate predicate = cmp->predicate(); if (bitcast) { switch (cmp->predicate()) { case Comparison::UIGT: predicate = Comparison::SIGT; break; case Comparison::UIGE: predicate = Comparison::SIGE; break; case Comparison::UILT: predicate = Comparison::SILT; break; case Comparison::UILE: predicate = Comparison::SILE; break; case Comparison::SIGT: predicate = Comparison::UIGT; break; case Comparison::SIGE: predicate = Comparison::UIGE; break; case Comparison::SILT: predicate = Comparison::UILT; break; case Comparison::SILE: predicate = Comparison::UILE; break; case Comparison::UIEQ: predicate = Comparison::SIEQ; break; case Comparison::UINE: predicate = Comparison::SINE; break; case Comparison::SIEQ: predicate = Comparison::UIEQ; break; case Comparison::SINE: predicate = Comparison::UINE; break; default: ikos_unreachable("unreachable"); } } auto c = Comparison::create(predicate, left, right); auto bb = cmp->parent(); auto it = bb->begin(); bb->insert_after(it, std::move(c)); } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/000077500000000000000000000000001473507761200176125ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/bundle.cpp000066400000000000000000000116031473507761200215700ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of Bundle * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include "context_impl.hpp" namespace ikos { namespace ar { Bundle::Bundle(Context& ctx, std::unique_ptr< DataLayout > data_layout, std::string triple) : _context(ctx), _data_layout(std::move(data_layout)), _target_triple(std::move(triple)) {} Bundle::~Bundle() = default; Bundle* Bundle::create(Context& ctx, std::unique_ptr< DataLayout > data_layout, std::string triple) { Bundle* bundle = new Bundle(ctx, std::move(data_layout), std::move(triple)); ctx._impl->add_bundle(std::unique_ptr< Bundle >(bundle)); return bundle; } Function* Bundle::intrinsic_function(Intrinsic::ID id) { std::string name = Intrinsic::long_name(id); Function* fun = this->_functions.find(name); if (fun != nullptr) { return fun; } ar::FunctionType* type = Intrinsic::type(this, id); return Function::create(this, type, name, /*is_definition = */ false, id); } Function* Bundle::intrinsic_function(Intrinsic::ID id, Type* template_ty) { std::string name = Intrinsic::long_name(id, template_ty); Function* fun = this->_functions.find(name); if (fun != nullptr) { return fun; } ar::FunctionType* type = Intrinsic::type(this, id, template_ty); return Function::create(this, type, name, /*is_definition = */ false, id); } bool Bundle::is_name_available(const std::string& name) const { return !this->_globals.contains(name) && !this->_functions.contains(name); } std::string Bundle::find_available_name(StringRef prefix) const { ikos_assert_msg(!prefix.empty(), "empty prefix"); // Add a numerical suffix, e.g, ".1" std::string name = prefix.to_string(); name += "."; std::size_t idx = 1; while (!this->is_name_available(name + std::to_string(idx))) { ++idx; } name += std::to_string(idx); return name; } void Bundle::add_global_variable(std::unique_ptr< GlobalVariable > gv) { this->_globals.add(std::move(gv)); } void Bundle::rename_global_variable(GlobalVariable* gv, const std::string& prev_name, const std::string& new_name) { this->_globals.rename(gv, prev_name, new_name); } void Bundle::add_function(std::unique_ptr< Function > fun) { this->_functions.add(std::move(fun)); } void Bundle::rename_function(Function* fun, const std::string& prev_name, const std::string& new_name) { this->_functions.rename(fun, prev_name, new_name); } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/code.cpp000066400000000000000000000240041473507761200212300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Control flow graph implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace ar { // BasicBlock BasicBlock::BasicBlock(Code* code) : _parent(code) { ikos_assert_msg(code, "code is null"); } BasicBlock::~BasicBlock() = default; BasicBlock* BasicBlock::create(Code* code) { auto bb = std::unique_ptr< BasicBlock >(new BasicBlock(code)); return code->add_basic_block(std::move(bb)); } Context& BasicBlock::context() const { return this->bundle()->context(); } Bundle* BasicBlock::bundle() const { return this->code()->bundle(); } void BasicBlock::push_front(std::unique_ptr< Statement > stmt) { stmt->set_parent(this); this->_statements.insert(this->_statements.begin(), std::move(stmt)); } void BasicBlock::push_back(std::unique_ptr< Statement > stmt) { stmt->set_parent(this); this->_statements.emplace_back(std::move(stmt)); } BasicBlock::StatementIterator BasicBlock::insert_before( StatementIterator it, std::unique_ptr< Statement > stmt) { stmt->set_parent(this); auto new_it = this->_statements.insert(it.base(), std::move(stmt)); return boost::make_transform_iterator(new_it, SeqExposeRawPtr< Statement >()); } BasicBlock::StatementIterator BasicBlock::insert_after( StatementIterator it, std::unique_ptr< Statement > stmt) { ikos_assert(it != this->end()); stmt->set_parent(this); auto new_it = this->_statements.insert(std::next(it).base(), std::move(stmt)); return boost::make_transform_iterator(new_it, SeqExposeRawPtr< Statement >()); } std::unique_ptr< Statement > BasicBlock::replace( StatementIterator it, std::unique_ptr< Statement > stmt) { ikos_assert(it != this->end()); // Create a non-const iterator on the statement auto index = std::distance(this->_statements.cbegin(), it.base()); auto stmt_it = std::next(this->_statements.begin(), index); // Remove current statement std::unique_ptr< Statement > old = std::move(*stmt_it); old->set_parent(nullptr); // Add the new statement stmt->set_parent(this); *stmt_it = std::move(stmt); return old; } BasicBlock::StatementIterator BasicBlock::remove(StatementIterator it) { ikos_assert(it != this->end()); (*it.base())->set_parent(nullptr); auto new_it = this->_statements.erase(it.base()); return boost::make_transform_iterator(new_it, SeqExposeRawPtr< Statement >()); } std::unique_ptr< Statement > BasicBlock::pop_back() { ikos_assert_msg(!this->_statements.empty(), "basic block is empty"); std::unique_ptr< Statement > stmt = std::move(this->_statements.back()); this->_statements.pop_back(); stmt->set_parent(nullptr); return stmt; } void BasicBlock::clear_statements() { this->_statements.clear(); } bool BasicBlock::is_successor(BasicBlock* bb) const { return std::find(this->_successors.begin(), this->_successors.end(), bb) != this->_successors.end(); } bool BasicBlock::is_predecessor(BasicBlock* bb) const { return std::find(this->_predecessors.begin(), this->_predecessors.end(), bb) != this->_predecessors.end(); } void BasicBlock::add_successor(BasicBlock* bb) { if (!this->is_successor(bb)) { this->_successors.push_back(bb); bb->_predecessors.push_back(this); } } void BasicBlock::add_predecessor(BasicBlock* bb) { if (!this->is_predecessor(bb)) { this->_predecessors.push_back(bb); bb->_successors.push_back(this); } } void BasicBlock::remove_successor(BasicBlock* bb) { if (this->is_successor(bb)) { this->_successors.erase(std::remove(this->_successors.begin(), this->_successors.end(), bb), this->_successors.end()); bb->_predecessors.erase(std::remove(bb->_predecessors.begin(), bb->_predecessors.end(), this), bb->_predecessors.end()); } } void BasicBlock::clear_successors() { // Remove this from predecessors of our successors for (BasicBlock* succ : this->_successors) { succ->_predecessors.erase(std::remove(succ->_predecessors.begin(), succ->_predecessors.end(), this), succ->_predecessors.end()); } this->_successors.clear(); } void BasicBlock::remove_predecessor(BasicBlock* bb) { if (this->is_predecessor(bb)) { this->_predecessors.erase(std::remove(this->_predecessors.begin(), this->_predecessors.end(), bb), this->_predecessors.end()); bb->_successors.erase(std::remove(bb->_successors.begin(), bb->_successors.end(), this), bb->_successors.end()); } } void BasicBlock::clear_predecessors() { // Remove this from successors of our predecessors for (BasicBlock* pred : this->_predecessors) { pred->_successors.erase(std::remove(pred->_successors.begin(), pred->_successors.end(), this), pred->_successors.end()); } this->_predecessors.clear(); } void BasicBlock::set_name(std::string name) { this->_name = std::move(name); } void BasicBlock::dump(std::ostream& o) const { o << "#"; if (this->has_name()) { o << this->name(); } else { o << this; } } void BasicBlock::full_dump(std::ostream& o) const { // name this->dump(o); // predecessors o << " predecessors={"; for (auto it = this->_predecessors.cbegin(), et = this->_predecessors.cend(); it != et;) { BasicBlock* pred = *it; pred->dump(o); o << "#"; ++it; if (it != et) { o << ", "; } } o << "}"; // successors o << " successors={"; for (auto it = this->_successors.cbegin(), et = this->_successors.cend(); it != et;) { BasicBlock* succ = *it; succ->dump(o); ++it; if (it != et) { o << ", "; } } o << "}"; // statements o << " {\n"; for (const auto& stmt : this->_statements) { o << " "; stmt->dump(o); o << "\n"; } o << "}\n"; } // Code Code::Code(Function* function) : _entry_block(nullptr), _exit_block(nullptr), _function(function), _global_var(nullptr), _bundle(function->bundle()) { ikos_assert_msg(function, "function is null"); } Code::Code(GlobalVariable* gv) : _entry_block(nullptr), _exit_block(nullptr), _function(nullptr), _global_var(gv), _bundle(gv->bundle()) { ikos_assert_msg(gv, "gv is null"); } Code::~Code() = default; void Code::set_entry_block(BasicBlock* bb) { this->_entry_block = bb; } void Code::set_exit_block(BasicBlock* bb) { this->_exit_block = bb; } BasicBlock* Code::add_basic_block(std::unique_ptr< BasicBlock > bb) { this->_blocks.emplace_back(std::move(bb)); return this->_blocks.back().get(); } void Code::erase_basic_block(BasicBlock* bb) { ikos_assert_msg(this->_entry_block != bb, "cannot erase the entry block"); ikos_assert_msg(this->_exit_block != bb, "cannot erase the exit block"); bb->clear_statements(); bb->clear_predecessors(); bb->clear_successors(); this->_blocks.erase(std::remove_if(this->_blocks.begin(), this->_blocks.end(), [=](const auto& bb_ptr) { return bb_ptr.get() == bb; }), this->_blocks.end()); } InternalVariable* Code::add_internal_variable( std::unique_ptr< InternalVariable > iv) { this->_internal_vars.emplace_back(std::move(iv)); return this->_internal_vars.back().get(); } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/context.cpp000066400000000000000000000045301473507761200220040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of Context * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include "context_impl.hpp" namespace ikos { namespace ar { Context::Context() : _impl(std::make_unique< ContextImpl >()) {} Context::~Context() = default; } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/context_impl.cpp000066400000000000000000000266531473507761200230370ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of ContextImpl * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include "context_impl.hpp" namespace ikos { namespace ar { ContextImpl::ContextImpl() : _ui1_ty(1, Unsigned), _ui8_ty(8, Unsigned), _ui16_ty(16, Unsigned), _ui32_ty(32, Unsigned), _ui64_ty(64, Unsigned), _si1_ty(1, Signed), _si8_ty(8, Signed), _si16_ty(16, Signed), _si32_ty(32, Signed), _si64_ty(64, Signed), _half_ty(16, Half), _float_ty(32, Float), _double_ty(64, Double), _x86_fp80_ty(80, X86_FP80), _fp128_ty(128, FP128), _ppc_fp128_ty(128, PPC_FP128) {} ContextImpl::~ContextImpl() = default; void ContextImpl::add_bundle(std::unique_ptr< Bundle > bundle) { this->_bundles.emplace_back(std::move(bundle)); } IntegerType* ContextImpl::integer_type(uint64_t bit_width, Signedness sign) { auto it = this->_integer_types.find(std::make_tuple(bit_width, sign)); if (it == this->_integer_types.end()) { auto type = std::unique_ptr< IntegerType >(new IntegerType(bit_width, sign)); auto res = this->_integer_types.emplace(std::make_tuple(bit_width, sign), std::move(type)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } PointerType* ContextImpl::pointer_type(Type* pointee) { auto it = this->_pointer_types.find(pointee); if (it == this->_pointer_types.end()) { auto type = std::unique_ptr< PointerType >(new PointerType(pointee)); auto res = this->_pointer_types.emplace(pointee, std::move(type)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } ArrayType* ContextImpl::array_type(Type* element_type, const ZNumber& num_element) { auto it = this->_array_types.find(std::make_tuple(element_type, num_element)); if (it == this->_array_types.end()) { auto type = std::unique_ptr< ArrayType >(new ArrayType(element_type, num_element)); auto res = this->_array_types.emplace(std::make_tuple(element_type, num_element), std::move(type)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } VectorType* ContextImpl::vector_type(ScalarType* element_type, const ZNumber& num_element) { auto it = this->_vector_types.find(std::make_tuple(element_type, num_element)); if (it == this->_vector_types.end()) { auto type = std::unique_ptr< VectorType >( new VectorType(element_type, num_element)); auto res = this->_vector_types.emplace(std::make_tuple(element_type, num_element), std::move(type)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } FunctionType* ContextImpl::function_type( Type* return_type, const FunctionType::ParamTypes& param_types, bool is_var_arg) { auto it = this->_function_types.find( std::make_tuple(return_type, param_types, is_var_arg)); if (it == this->_function_types.end()) { auto type = std::unique_ptr< FunctionType >( new FunctionType(return_type, param_types, is_var_arg)); auto res = this->_function_types.emplace(std::make_tuple(return_type, param_types, is_var_arg), std::move(type)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } Type* ContextImpl::add_type(std::unique_ptr< Type > type) { this->_types.emplace_back(std::move(type)); return this->_types.back().get(); } UndefinedConstant* ContextImpl::undefined_cst(Type* type) { auto it = this->_undefined_constants.find(type); if (it == this->_undefined_constants.end()) { auto cst = std::unique_ptr< UndefinedConstant >(new UndefinedConstant(type)); auto res = this->_undefined_constants.emplace(type, std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } IntegerConstant* ContextImpl::integer_cst(IntegerType* type, const MachineInt& value) { auto it = this->_integer_constants.find(std::make_tuple(type, value)); if (it == this->_integer_constants.end()) { auto cst = std::unique_ptr< IntegerConstant >(new IntegerConstant(type, value)); auto res = this->_integer_constants.emplace(std::make_tuple(type, value), std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } FloatConstant* ContextImpl::float_cst(FloatType* type, const std::string& value) { auto it = this->_float_constants.find(std::make_tuple(type, value)); if (it == this->_float_constants.end()) { auto cst = std::unique_ptr< FloatConstant >(new FloatConstant(type, value)); auto res = this->_float_constants.emplace(std::make_tuple(type, value), std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } NullConstant* ContextImpl::null_cst(PointerType* type) { auto it = this->_null_constants.find(type); if (it == this->_null_constants.end()) { auto cst = std::unique_ptr< NullConstant >(new NullConstant(type)); auto res = this->_null_constants.emplace(type, std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } StructConstant* ContextImpl::struct_cst(StructType* type, const StructConstant::Values& values) { auto it = this->_struct_constants.find(std::make_tuple(type, values)); if (it == this->_struct_constants.end()) { auto cst = std::unique_ptr< StructConstant >(new StructConstant(type, values)); auto res = this->_struct_constants.emplace(std::make_tuple(type, values), std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } ArrayConstant* ContextImpl::array_cst(ArrayType* type, const ArrayConstant::Values& values) { auto it = this->_array_constants.find(std::make_tuple(type, values)); if (it == this->_array_constants.end()) { auto cst = std::unique_ptr< ArrayConstant >(new ArrayConstant(type, values)); auto res = this->_array_constants.emplace(std::make_tuple(type, values), std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } VectorConstant* ContextImpl::vector_cst(VectorType* type, const VectorConstant::Values& values) { auto it = this->_vector_constants.find(std::make_tuple(type, values)); if (it == this->_vector_constants.end()) { auto cst = std::unique_ptr< VectorConstant >(new VectorConstant(type, values)); auto res = this->_vector_constants.emplace(std::make_tuple(type, values), std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } AggregateZeroConstant* ContextImpl::aggregate_zero_cst(AggregateType* type) { auto it = this->_aggregate_zero_constants.find(type); if (it == this->_aggregate_zero_constants.end()) { auto cst = std::unique_ptr< AggregateZeroConstant >( new AggregateZeroConstant(type)); auto res = this->_aggregate_zero_constants.emplace(type, std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } FunctionPointerConstant* ContextImpl::function_pointer_cst(Function* function) { auto it = this->_function_pointer_constants.find(function); if (it == this->_function_pointer_constants.end()) { ikos_assert_msg(function, "function is null"); PointerType* fun_ptr_type = this->pointer_type(function->type()); auto cst = std::unique_ptr< FunctionPointerConstant >( new FunctionPointerConstant(fun_ptr_type, function)); auto res = this->_function_pointer_constants.emplace(function, std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } InlineAssemblyConstant* ContextImpl::inline_assembly_cst( PointerType* type, const std::string& code) { auto it = this->_inline_assembly_constants.find(std::make_tuple(type, code)); if (it == this->_inline_assembly_constants.end()) { auto cst = std::unique_ptr< InlineAssemblyConstant >( new InlineAssemblyConstant(type, code)); auto res = this->_inline_assembly_constants.emplace(std::make_tuple(type, code), std::move(cst)); ikos_assert(res.second); return res.first->second.get(); } else { return it->second.get(); } } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/context_impl.hpp000066400000000000000000000230731473507761200230350ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief ContextImpl definition * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace ar { class ContextImpl { private: // List of owned bundles std::vector< std::unique_ptr< Bundle > > _bundles; // Pre-allocated void type VoidType _void_ty; // Pre-allocated unsigned integer types IntegerType _ui1_ty; IntegerType _ui8_ty; IntegerType _ui16_ty; IntegerType _ui32_ty; IntegerType _ui64_ty; // Pre-allocated signed integer types IntegerType _si1_ty; IntegerType _si8_ty; IntegerType _si16_ty; IntegerType _si32_ty; IntegerType _si64_ty; // Pre-allocated float types FloatType _half_ty; FloatType _float_ty; FloatType _double_ty; FloatType _x86_fp80_ty; FloatType _fp128_ty; FloatType _ppc_fp128_ty; // Libc FILE opaque type (used for intrinsics) OpaqueType _libc_file_ty; // Using boost::container::flat_map with std::pair causes crashes on FreeBSD. // As a workaround, we use std::tuple instead of std::pair here. // see https://github.com/NASA-SW-VnV/ikos/issues/22 // see https://github.com/boostorg/container/issues/97 // Integer types boost::container::flat_map< std::tuple< uint64_t, Signedness >, std::unique_ptr< IntegerType > > _integer_types; // Pointer types boost::container::flat_map< Type*, std::unique_ptr< PointerType > > _pointer_types; // Array types boost::container::flat_map< std::tuple< Type*, ZNumber >, std::unique_ptr< ArrayType > > _array_types; // Vector types boost::container::flat_map< std::tuple< ScalarType*, ZNumber >, std::unique_ptr< VectorType > > _vector_types; // Function types boost::container::flat_map< std::tuple< Type*, FunctionType::ParamTypes, bool >, std::unique_ptr< FunctionType > > _function_types; // Other types (struct and opaque) std::vector< std::unique_ptr< Type > > _types; // Undefined constants boost::container::flat_map< Type*, std::unique_ptr< UndefinedConstant > > _undefined_constants; // Integer constants boost::container::flat_map< std::tuple< IntegerType*, MachineInt >, std::unique_ptr< IntegerConstant > > _integer_constants; // Float constants boost::container::flat_map< std::tuple< FloatType*, std::string >, std::unique_ptr< FloatConstant > > _float_constants; // Null constants boost::container::flat_map< PointerType*, std::unique_ptr< NullConstant > > _null_constants; // Structure constants boost::container::flat_map< std::tuple< StructType*, StructConstant::Values >, std::unique_ptr< StructConstant > > _struct_constants; // Array constants boost::container::flat_map< std::tuple< ArrayType*, ArrayConstant::Values >, std::unique_ptr< ArrayConstant > > _array_constants; // Vector constants boost::container::flat_map< std::tuple< VectorType*, VectorConstant::Values >, std::unique_ptr< VectorConstant > > _vector_constants; // Aggregate zero constants boost::container::flat_map< AggregateType*, std::unique_ptr< AggregateZeroConstant > > _aggregate_zero_constants; // Function pointer constants boost::container::flat_map< Function*, std::unique_ptr< FunctionPointerConstant > > _function_pointer_constants; // Inline assembly constants boost::container::flat_map< std::tuple< PointerType*, std::string >, std::unique_ptr< InlineAssemblyConstant > > _inline_assembly_constants; public: /// \brief Default constructor ContextImpl(); /// \brief No copy constructor ContextImpl(const ContextImpl&) = delete; /// \brief No move constructor ContextImpl(ContextImpl&&) = delete; /// \brief No copy assignment operator ContextImpl& operator=(const ContextImpl&) = delete; /// \brief No move assignment operator ContextImpl& operator=(ContextImpl&&) = delete; /// \brief Destructor ~ContextImpl(); /// \brief Add a bundle in the ContextImpl void add_bundle(std::unique_ptr< Bundle >); // type management VoidType* void_type() { return &_void_ty; } IntegerType* ui1_type() { return &_ui1_ty; } IntegerType* ui8_type() { return &_ui8_ty; } IntegerType* ui16_type() { return &_ui16_ty; } IntegerType* ui32_type() { return &_ui32_ty; } IntegerType* ui64_type() { return &_ui64_ty; } IntegerType* si1_type() { return &_si1_ty; } IntegerType* si8_type() { return &_si8_ty; } IntegerType* si16_type() { return &_si16_ty; } IntegerType* si32_type() { return &_si32_ty; } IntegerType* si64_type() { return &_si64_ty; } FloatType* half_type() { return &_half_ty; } FloatType* float_type() { return &_float_ty; } FloatType* double_type() { return &_double_ty; } FloatType* x86_fp80_type() { return &_x86_fp80_ty; } FloatType* fp128_type() { return &_fp128_ty; } FloatType* ppc_fp128_type() { return &_ppc_fp128_ty; } /// \brief Get the libc FILE opaque type OpaqueType* libc_file_type() { return &_libc_file_ty; } /// \brief Get or create an integer type IntegerType* integer_type(uint64_t bit_width, Signedness sign); /// \brief Get or create a pointer type PointerType* pointer_type(Type* pointee); /// \brief Get or create an array type ArrayType* array_type(Type* element_type, const ZNumber& num_element); /// \brief Get or create a vector type VectorType* vector_type(ScalarType* element_type, const ZNumber& num_element); /// \brief Get or create a function type FunctionType* function_type(Type* return_type, const FunctionType::ParamTypes& param_types, bool is_var_arg); /// \brief Add a type in the ContextImpl /// /// \returns a pointer on the type Type* add_type(std::unique_ptr< Type >); // value management /// \brief Get or create an undefined constant UndefinedConstant* undefined_cst(Type* type); /// \brief Get or create an integer constant IntegerConstant* integer_cst(IntegerType* type, const MachineInt& value); /// \brief Get or create a float constant FloatConstant* float_cst(FloatType* type, const std::string& value); /// \brief Get or create a null constant NullConstant* null_cst(PointerType* type); /// \brief Get or create a structure constant StructConstant* struct_cst(StructType* type, const StructConstant::Values& values); /// \brief Get or create an array constant ArrayConstant* array_cst(ArrayType* type, const ArrayConstant::Values& values); /// \brief Get or create a vector constant VectorConstant* vector_cst(VectorType* type, const VectorConstant::Values& values); /// \brief Get or create an aggregate zero constant AggregateZeroConstant* aggregate_zero_cst(AggregateType* type); /// \brief Get or create a function pointer constant FunctionPointerConstant* function_pointer_cst(Function* function); /// \brief Get or create an inline assembly constant InlineAssemblyConstant* inline_assembly_cst(PointerType* type, const std::string& code); }; // end class ContextImpl } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/data_layout.cpp000066400000000000000000000230701473507761200226260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of DataLayout * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace ar { DataLayout::DataLayout(Endianness endianness_, DataLayoutInfo pointers_) : endianness(endianness_), pointers(pointers_) { // Default alignments for integers integers.emplace_back(DataLayoutInfo(1, 1, 1)); integers.emplace_back(DataLayoutInfo(8, 1, 1)); integers.emplace_back(DataLayoutInfo(16, 2, 2)); integers.emplace_back(DataLayoutInfo(32, 4, 4)); integers.emplace_back(DataLayoutInfo(64, 8, 8)); // Default alignments for floats floats.emplace_back(DataLayoutInfo(16, 2, 2)); floats.emplace_back(DataLayoutInfo(32, 4, 4)); floats.emplace_back(DataLayoutInfo(64, 8, 8)); floats.emplace_back(DataLayoutInfo(128, 16, 16)); } DataLayout::~DataLayout() = default; std::unique_ptr< DataLayout > DataLayout::create(Endianness endianness, DataLayoutInfo pointers) { return std::unique_ptr< DataLayout >(new DataLayout(endianness, pointers)); } /// \brief Return the next power of two that is strictly greater than n static ZNumber next_power_of_2(const ZNumber& n) { ZNumber r(1); while (r <= n) { r <<= 1; } return r; } /// \brief Return the power of 2 which is greater than or equal to the given /// value static ZNumber power_of_2_ceil(const ZNumber& n) { if (n <= 2) { return n; } else { return next_power_of_2(n - 1); } } /// \brief Add a DataLayoutInfo into a vector of DataLayoutInfo static void update_data_layout_infos(std::vector< DataLayoutInfo >& v, DataLayoutInfo info) { auto it = std::lower_bound(v.begin(), v.end(), info, [](const DataLayoutInfo& lhs, const DataLayoutInfo& rhs) { return lhs.bit_width < rhs.bit_width; }); if (it != v.end() && it->bit_width == info.bit_width) { // Update an existing entry it->abi_alignment = info.abi_alignment; it->pref_alignment = info.pref_alignment; } else { // Otherwise, create it v.insert(it, info); } } /// \brief Find the best alignment for a bit width static uint64_t find_alignment_info(const std::vector< DataLayoutInfo >& v, uint64_t bit_width, bool abi) { ikos_assert(!v.empty()); auto it = std::lower_bound(v.begin(), v.end(), DataLayoutInfo(bit_width, 0, 0), [](const DataLayoutInfo& lhs, const DataLayoutInfo& rhs) { return lhs.bit_width < rhs.bit_width; }); if (it == v.end()) { // If we didn't have a larger value, use the largest value we have it = std::prev(v.end()); } // Else, use the exact match or first larger value if (abi) { return it->abi_alignment; } else { return it->pref_alignment; } } void DataLayout::set_integer_alignment(DataLayoutInfo info) { update_data_layout_infos(this->integers, info); } void DataLayout::set_float_alignment(DataLayoutInfo info) { update_data_layout_infos(this->floats, info); } namespace { /// \brief Compute the alignment (ABI or Preferred) for a given type class TypeAlignmentVisitor { public: using ResultType = ZNumber; public: // Data layout const DataLayout& data_layout; // ABI or Preferred alignment (true = abi, false = preferred) bool abi; public: /// \brief Constructor TypeAlignmentVisitor(const DataLayout& data_layout_, bool abi_) : data_layout(data_layout_), abi(abi_) {} public: ZNumber operator()(VoidType* /*type*/) const { ikos_unreachable("no alignment"); } ZNumber operator()(IntegerType* type) const { return ZNumber( find_alignment_info(data_layout.integers, type->bit_width(), abi)); } ZNumber operator()(FloatType* type) const { return ZNumber( find_alignment_info(data_layout.floats, type->bit_width(), abi)); } ZNumber operator()(PointerType* /*type*/) const { if (abi) { return ZNumber(data_layout.pointers.abi_alignment); } else { return ZNumber(data_layout.pointers.pref_alignment); } } ZNumber operator()(StructType* type) const { if (type->packed()) { // Packed structures have alignment of 1 byte return ZNumber(1); } // Find the max of the alignment of all fields ZNumber alignment(0); for (auto it = type->field_begin(), et = type->field_end(); it != et; ++it) { alignment = std::max(alignment, apply_visitor(*this, it->type)); } if (alignment == 0) { // Empty structures have alignment of 1 byte alignment = 1; } return alignment; } ZNumber operator()(ArrayType* t) const { return apply_visitor(*this, t->element_type()); } ZNumber operator()(VectorType* t) const { ZNumber align = data_layout.alloc_size_in_bytes(t->element_type()); align *= t->num_elements(); align = power_of_2_ceil(align); return align; } ZNumber operator()(OpaqueType* /*t*/) const { ikos_unreachable("no alignment"); } ZNumber operator()(FunctionType* /*t*/) const { ikos_unreachable("no alignment"); } }; // end class TypeAlignmentVisitor } // end anonymous namespace ZNumber DataLayout::abi_alignment(Type* type) const { return apply_visitor(TypeAlignmentVisitor(*this, true), type); } ZNumber DataLayout::pref_alignment(Type* type) const { return apply_visitor(TypeAlignmentVisitor(*this, false), type); } namespace { /// \brief Compute the size (in bits) for a given type class TypeSizeVisitor { public: using ResultType = ZNumber; public: // Data layout const DataLayout& data_layout; public: /// \brief Constructor explicit TypeSizeVisitor(const DataLayout& data_layout_) : data_layout(data_layout_) {} public: ZNumber operator()(VoidType*) const { return ZNumber(0); } ZNumber operator()(IntegerType* type) const { return ZNumber(type->bit_width()); } ZNumber operator()(FloatType* type) const { return ZNumber(type->bit_width()); } ZNumber operator()(PointerType*) const { return ZNumber(data_layout.pointers.bit_width); } ZNumber operator()(StructType* type) const { if (type->empty()) { return ZNumber(0); } // Get the last field auto it = type->field_rbegin(); // Offset of last field (in bytes) ZNumber size = it->offset; // Size of last field type (in bytes) size += data_layout.alloc_size_in_bytes(it->type); // Add padding to the end of the struct so that it could be put in an array // and all array elements would be aligned correctly. size = align_to(size, data_layout.abi_alignment(type)); // In bits return size * 8; } ZNumber operator()(ArrayType* t) const { return t->num_elements() * data_layout.alloc_size_in_bits(t->element_type()); } ZNumber operator()(VectorType* t) const { return t->num_elements() * apply_visitor(*this, t->element_type()); } ZNumber operator()(OpaqueType* /*t*/) const { return ZNumber(0); } ZNumber operator()(FunctionType* /*t*/) const { return ZNumber(0); } }; // end class TypeSizeVisitor } // end anonymous namespace ZNumber DataLayout::size_in_bits(Type* t) const { return apply_visitor(TypeSizeVisitor(*this), t); } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/function.cpp000066400000000000000000000112211473507761200221400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Function implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include namespace ikos { namespace ar { Function::Function(Bundle* bundle, FunctionType* type, std::string name, bool is_definition, Intrinsic::ID intrinsic_id) : _parent(bundle), _type(type), _intrinsic_id(intrinsic_id), _body(nullptr) { ikos_assert_msg(bundle, "bundle is null"); ikos_assert_msg(type, "type is null"); ikos_assert_msg(!name.empty(), "function name is empty"); ikos_assert_msg(intrinsic_id == Intrinsic::NotIntrinsic || !is_definition, "intrinsic function cannot be a definition"); if (!name.empty() && bundle->is_name_available(name)) { this->_name = std::move(name); } else { this->_name = bundle->find_available_name(name); } if (is_definition) { // Create function body this->_body = std::unique_ptr< Code >(new Code(this)); // Create unnamed parameters _parameters.reserve(type->num_parameters()); for (auto it = type->param_begin(), et = type->param_end(); it != et; ++it) { InternalVariable* param = InternalVariable::create(this->_body.get(), *it); _parameters.push_back(param); } } } Function::~Function() = default; Function* Function::create(Bundle* bundle, FunctionType* type, std::string name, bool is_definition, Intrinsic::ID intrinsic_id) { auto fun = new Function(bundle, type, std::move(name), is_definition, intrinsic_id); bundle->add_function(std::unique_ptr< Function >(fun)); return fun; } void Function::set_name(std::string new_name) { // In this case, we need to notify the bundle, // because it keeps a map from name to functions ikos_assert_msg(!new_name.empty(), "name is empty"); std::string prev_name = this->name(); if (!new_name.empty() && this->_parent->is_name_available(new_name)) { this->_name = std::move(new_name); } else { this->_name = this->_parent->find_available_name(new_name); } this->_parent->rename_function(this, prev_name, this->_name); } LocalVariable* Function::add_local_variable( std::unique_ptr< LocalVariable > lv) { this->_local_vars.emplace_back(std::move(lv)); return this->_local_vars.back().get(); } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/intrinsic.cpp000066400000000000000000000606001473507761200223220ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of Intrinsic * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace ar { FunctionType* Intrinsic::type(Bundle* bundle, ID id) { return type(bundle, id, /* template_ty = */ nullptr); } FunctionType* Intrinsic::type(Bundle* bundle, ID id, Type* template_ty) { ikos_assert(id != NotIntrinsic); // Helpers Context& ctx = bundle->context(); VoidType* void_ty = VoidType::get(ctx); IntegerType* ui1_ty = IntegerType::ui1(ctx); IntegerType* si8_ty = IntegerType::si8(ctx); IntegerType* ui32_ty = IntegerType::ui32(ctx); IntegerType* si32_ty = IntegerType::si32(ctx); IntegerType* size_ty = IntegerType::size_type(bundle); IntegerType* ssize_ty = IntegerType::ssize_type(bundle); PointerType* void_ptr_ty = PointerType::get(ctx, si8_ty); PointerType* char_ptr_ty = PointerType::get(ctx, si8_ty); PointerType* file_ptr_ty = PointerType::get(ctx, OpaqueType::libc_file_type(ctx)); Type* ret_ty = nullptr; FunctionType::ParamTypes params; bool var_arg = false; switch (id) { case MemoryCopy: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // dest params.push_back(void_ptr_ty); // src params.push_back(size_ty); // length params.push_back(ui32_ty); // dest_alignment params.push_back(ui32_ty); // src_alignment params.push_back(ui1_ty); // volatile } break; case MemoryMove: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // dest params.push_back(void_ptr_ty); // src params.push_back(size_ty); // length params.push_back(ui32_ty); // dest_alignment params.push_back(ui32_ty); // src_alignment params.push_back(ui1_ty); // volatile } break; case MemorySet: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(si8_ty); // value params.push_back(size_ty); // length params.push_back(ui32_ty); // alignment params.push_back(ui1_ty); // volatile } break; case VarArgStart: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // va_list } break; case VarArgEnd: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // va_list } break; case VarArgGet: { // Suppose that va_arg always returns a void* ret_ty = void_ptr_ty; // ret params.push_back(void_ptr_ty); // va_list } break; case VarArgCopy: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // dest params.push_back(void_ptr_ty); // src } break; case StackSave: { ret_ty = void_ptr_ty; // ret } break; case StackRestore: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // stack ptr } break; case LifetimeStart: { ret_ty = void_ty; // ret params.push_back(size_ty); // size params.push_back(void_ptr_ty); // ptr } break; case LifetimeEnd: { ret_ty = void_ty; // ret params.push_back(size_ty); // size params.push_back(void_ptr_ty); // ptr } break; case EhTypeidFor: { ret_ty = si32_ty; // ret params.push_back(void_ptr_ty); // exception ptr } break; case Trap: { ret_ty = void_ty; // ret } break; // case IkosAssert: { ret_ty = void_ty; // ret params.push_back(ui32_ty); // condition } break; case IkosAssume: { ret_ty = void_ty; // ret params.push_back(ui32_ty); // condition } break; case IkosNonDet: { ikos_assert(template_ty != nullptr); ret_ty = template_ty; // ret } break; case IkosCounterInit: { ret_ty = size_ty; // ret params.push_back(size_ty); // initial value } break; case IkosCounterIncr: { ret_ty = size_ty; // ret params.push_back(size_ty); // counter params.push_back(size_ty); // increment } break; case IkosCheckMemAccess: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(size_ty); // size } break; case IkosCheckStringAccess: { ret_ty = void_ty; // ret params.push_back(char_ptr_ty); // str } break; case IkosAssumeMemSize: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(size_ty); // size } break; case IkosForgetMemory: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(size_ty); // size } break; case IkosAbstractMemory: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(size_ty); // size } break; case IkosWatchMemory: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(size_ty); // size } break; case IkosPartitioningVar: { ikos_assert(template_ty != nullptr); ret_ty = void_ty; // ret params.push_back(template_ty); // x } break; case IkosPartitioningJoin: { ret_ty = void_ty; // ret } break; case IkosPartitioningDisable: { ret_ty = void_ty; // ret } break; case IkosPrintInvariant: { ret_ty = void_ty; // ret } break; case IkosPrintValues: { ret_ty = void_ty; // ret params.push_back(char_ptr_ty); // dest var_arg = true; } break; // case LibcMalloc: { ret_ty = void_ptr_ty; // ret params.push_back(size_ty); // size } break; case LibcCalloc: { ret_ty = void_ptr_ty; // ret params.push_back(size_ty); // count params.push_back(size_ty); // size } break; case LibcValloc: { ret_ty = void_ptr_ty; // ret params.push_back(size_ty); // size } break; case LibcAlignedAlloc: { ret_ty = void_ptr_ty; // ret params.push_back(size_ty); // alignment params.push_back(size_ty); // size } break; case LibcRealloc: { ret_ty = void_ptr_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(size_ty); // size } break; case LibcFree: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr } break; case LibcAbs: { ret_ty = si32_ty; // ret params.push_back(si32_ty); // i } break; case LibcRand: { ret_ty = si32_ty; // ret } break; case LibcSrand: { ret_ty = void_ty; // ret params.push_back(ui32_ty); // seed } break; case LibcExit: { ret_ty = void_ty; // ret params.push_back(si32_ty); // status } break; case LibcAbort: { ret_ty = void_ty; // ret } break; // case LibcErrnoLocation: { ret_ty = PointerType::get(ctx, si32_ty); // ret } break; // case LibcOpen: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // path params.push_back(si32_ty); // oflags var_arg = true; } break; // case LibcClose: { ret_ty = si32_ty; // ret params.push_back(si32_ty); // fildes } break; case LibcRead: { ret_ty = ssize_ty; // ret params.push_back(si32_ty); // fildes params.push_back(void_ptr_ty); // buffer params.push_back(size_ty); // nbytes } break; case LibcWrite: { ret_ty = ssize_ty; // ret params.push_back(si32_ty); // fildes params.push_back(void_ptr_ty); // buffer params.push_back(size_ty); // nbytes } break; // case LibcGets: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // str } break; case LibcFgets: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // str params.push_back(si32_ty); // size params.push_back(file_ptr_ty); // stream } break; case LibcGetc: { ret_ty = si32_ty; // ret params.push_back(file_ptr_ty); // stream } break; case LibcFgetc: { ret_ty = si32_ty; // ret params.push_back(file_ptr_ty); // stream } break; case LibcGetchar: { ret_ty = si32_ty; // ret } break; case LibcPuts: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // s } break; case LibcFputs: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // s params.push_back(file_ptr_ty); // stream } break; case LibcPutc: { ret_ty = si32_ty; // ret params.push_back(si32_ty); // c params.push_back(file_ptr_ty); // stream } break; case LibcFputc: { ret_ty = si32_ty; // ret params.push_back(si32_ty); // c params.push_back(file_ptr_ty); // stream } break; case LibcPrintf: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // format var_arg = true; } break; case LibcFprintf: { ret_ty = si32_ty; // ret params.push_back(file_ptr_ty); // stream params.push_back(char_ptr_ty); // format var_arg = true; } break; case LibcSprintf: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // buffer params.push_back(char_ptr_ty); // format var_arg = true; } break; case LibcSnprintf: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // buffer params.push_back(size_ty); // size params.push_back(char_ptr_ty); // format var_arg = true; } break; case LibcScanf: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // format var_arg = true; } break; case LibcFscanf: { ret_ty = si32_ty; // ret params.push_back(file_ptr_ty); // stream params.push_back(char_ptr_ty); // format var_arg = true; } break; case LibcSscanf: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // buffer params.push_back(char_ptr_ty); // format var_arg = true; } break; case LibcFopen: { ret_ty = file_ptr_ty; // ret params.push_back(char_ptr_ty); // filename params.push_back(char_ptr_ty); // mode } break; case LibcFclose: { ret_ty = si32_ty; // ret params.push_back(file_ptr_ty); // stream } break; case LibcFflush: { ret_ty = si32_ty; // ret params.push_back(file_ptr_ty); // stream } break; // case LibcStrlen: { ret_ty = size_ty; // ret params.push_back(char_ptr_ty); // s } break; case LibcStrnlen: { ret_ty = size_ty; // ret params.push_back(char_ptr_ty); // s params.push_back(size_ty); // maxlen } break; case LibcStrcpy: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // dest params.push_back(char_ptr_ty); // src } break; case LibcStrncpy: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // dest params.push_back(char_ptr_ty); // src params.push_back(size_ty); // maxlen } break; case LibcStrcat: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // s1 params.push_back(char_ptr_ty); // s2 } break; case LibcStrncat: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // s1 params.push_back(char_ptr_ty); // s2 params.push_back(size_ty); // maxlen } break; case LibcStrcmp: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // s1 params.push_back(char_ptr_ty); // s2 } break; case LibcStrncmp: { ret_ty = si32_ty; // ret params.push_back(char_ptr_ty); // s1 params.push_back(char_ptr_ty); // s2 params.push_back(size_ty); // n } break; case LibcStrstr: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // haystack params.push_back(char_ptr_ty); // needle } break; case LibcStrchr: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // s params.push_back(si32_ty); // c } break; case LibcStrdup: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // s } break; case LibcStrndup: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // s params.push_back(size_ty); // n } break; case LibcStrcpyCheck: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // dest params.push_back(char_ptr_ty); // src params.push_back(size_ty); // maxlen } break; case LibcMemoryCopyCheck: { ret_ty = void_ptr_ty; // ret params.push_back(void_ptr_ty); // dest params.push_back(void_ptr_ty); // src params.push_back(size_ty); // length params.push_back(size_ty); // maxlen } break; case LibcMemoryMoveCheck: { ret_ty = void_ptr_ty; // ret params.push_back(void_ptr_ty); // dest params.push_back(void_ptr_ty); // src params.push_back(size_ty); // length params.push_back(size_ty); // maxlen } break; case LibcMemorySetCheck: { ret_ty = void_ptr_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(si32_ty); // value params.push_back(size_ty); // length params.push_back(size_ty); // maxlen } break; case LibcStrcatCheck: { ret_ty = char_ptr_ty; // ret params.push_back(char_ptr_ty); // s1 params.push_back(char_ptr_ty); // s2 params.push_back(size_ty); // maxlen } break; case LibcppNew: { ret_ty = void_ptr_ty; // ret params.push_back(size_ty); // size } break; case LibcppNewArray: { ret_ty = void_ptr_ty; // ret params.push_back(size_ty); // size } break; case LibcppDelete: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr } break; case LibcppDeleteArray: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr } break; case LibcppAllocateException: { ret_ty = void_ptr_ty; // ret params.push_back(size_ty); // size } break; case LibcppFreeException: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr } break; case LibcppThrow: { ret_ty = void_ty; // ret params.push_back(void_ptr_ty); // ptr params.push_back(void_ptr_ty); // ptr params.push_back(void_ptr_ty); // ptr } break; case LibcppBeginCatch: { ret_ty = void_ptr_ty; // ret params.push_back(void_ptr_ty); // exception ptr } break; case LibcppEndCatch: { ret_ty = void_ty; // ret } break; default: { ikos_unreachable("unreachable"); } } return FunctionType::get(ctx, ret_ty, params, var_arg); } std::string Intrinsic::short_name(ID id) { return short_name(id, /* template_ty = */ nullptr); } /// \brief Return the short name for a template type parameter static std::string template_type_name(Type* ty) { ikos_assert(ty != nullptr); struct TypeVisitor { using ResultType = std::string; std::string operator()(VoidType*) const { return "void"; } std::string operator()(IntegerType* t) const { if (t->is_unsigned()) { return "ui" + std::to_string(t->bit_width()); } else { return "si" + std::to_string(t->bit_width()); } } std::string operator()(FloatType* t) const { switch (t->float_semantic()) { case Half: return "half"; case Float: return "float"; case Double: return "double"; case X86_FP80: return "x86_fp80"; case FP128: return "fp128"; case PPC_FP128: return "ppc_fp128"; default: ikos_unreachable("unknown float semantic"); } } std::string operator()(PointerType* t) const { return template_type_name(t->pointee()) + "*"; } std::string operator()(StructType*) const { ikos_unreachable("unreachable"); } std::string operator()(ArrayType*) const { ikos_unreachable("unreachable"); } std::string operator()(VectorType*) const { ikos_unreachable("unreachable"); } std::string operator()(OpaqueType*) const { ikos_unreachable("unreachable"); } std::string operator()(FunctionType*) const { ikos_unreachable("unreachable"); } }; return apply_visitor(TypeVisitor{}, ty); } std::string Intrinsic::short_name(ID id, Type* template_ty) { ikos_assert(id != NotIntrinsic); switch (id) { case MemoryCopy: return "memcpy"; case MemoryMove: return "memmove"; case MemorySet: return "memset"; case VarArgStart: return "va_start"; case VarArgEnd: return "va_end"; case VarArgGet: return "va_arg"; case VarArgCopy: return "va_copy"; case StackSave: return "stacksave"; case StackRestore: return "stackrestore"; case LifetimeStart: return "lifetime.start"; case LifetimeEnd: return "lifetime.end"; case EhTypeidFor: return "eh.typeid.for"; case Trap: return "trap"; // case IkosAssert: return "ikos.assert"; case IkosAssume: return "ikos.assume"; case IkosNonDet: return "ikos.nondet." + template_type_name(template_ty); case IkosCounterInit: return "ikos.counter.init"; case IkosCounterIncr: return "ikos.counter.incr"; case IkosCheckMemAccess: return "ikos.check_mem_access"; case IkosCheckStringAccess: return "ikos.check_string_access"; case IkosAssumeMemSize: return "ikos.assume_mem_size"; case IkosForgetMemory: return "ikos.forget_memory"; case IkosAbstractMemory: return "ikos.abstract_memory"; case IkosWatchMemory: return "ikos.watch_memory"; case IkosPartitioningVar: return "ikos.partitioning.var." + template_type_name(template_ty); case IkosPartitioningJoin: return "ikos.partitioning.join"; case IkosPartitioningDisable: return "ikos.partitioning.disable"; case IkosPrintInvariant: return "ikos.print_invariant"; case IkosPrintValues: return "ikos.print_values"; // case LibcMalloc: return "libc.malloc"; case LibcCalloc: return "libc.calloc"; case LibcValloc: return "libc.valloc"; case LibcAlignedAlloc: return "libc.aligned_alloc"; case LibcRealloc: return "libc.realloc"; case LibcFree: return "libc.free"; case LibcAbs: return "libc.abs"; case LibcRand: return "libc.rand"; case LibcSrand: return "libc.srand"; case LibcExit: return "libc.exit"; case LibcAbort: return "libc.abort"; // case LibcErrnoLocation: return "libc.errno_location"; // case LibcOpen: return "libc.open"; // case LibcClose: return "libc.close"; case LibcRead: return "libc.read"; case LibcWrite: return "libc.write"; // case LibcGets: return "libc.gets"; case LibcFgets: return "libc.fgets"; case LibcGetc: return "libc.getc"; case LibcFgetc: return "libc.fgetc"; case LibcGetchar: return "libc.getchar"; case LibcPuts: return "libc.puts"; case LibcFputs: return "libc.fputs"; case LibcPutc: return "libc.putc"; case LibcFputc: return "libc.fputc"; case LibcPrintf: return "libc.printf"; case LibcFprintf: return "libc.fprintf"; case LibcSprintf: return "libc.sprintf"; case LibcSnprintf: return "libc.snprintf"; case LibcScanf: return "libc.scanf"; case LibcFscanf: return "libc.fscanf"; case LibcSscanf: return "libc.sscanf"; case LibcFopen: return "libc.fopen"; case LibcFclose: return "libc.fclose"; case LibcFflush: return "libc.fflush"; // case LibcStrlen: return "libc.strlen"; case LibcStrnlen: return "libc.strnlen"; case LibcStrcpy: return "libc.strcpy"; case LibcStrncpy: return "libc.strncpy"; case LibcStrcat: return "libc.strcat"; case LibcStrncat: return "libc.strncat"; case LibcStrcmp: return "libc.strcmp"; case LibcStrncmp: return "libc.strncmp"; case LibcStrstr: return "libc.strstr"; case LibcStrchr: return "libc.strchr"; case LibcStrdup: return "libc.strdup"; case LibcStrndup: return "libc.strndup"; case LibcStrcpyCheck: return "libc.strcpy.check"; case LibcMemoryCopyCheck: return "libc.memcpy.check"; case LibcMemoryMoveCheck: return "libc.memmove.check"; case LibcMemorySetCheck: return "libc.memset.check"; case LibcStrcatCheck: return "libc.strcat.check"; case LibcppNew: return "libcpp.new"; case LibcppNewArray: return "libcpp.new[]"; case LibcppDelete: return "libcpp.delete"; case LibcppDeleteArray: return "libcpp.delete[]"; case LibcppAllocateException: return "libcpp.allocate_exception"; case LibcppFreeException: return "libcpp.free_exception"; case LibcppThrow: return "libcpp.throw"; case LibcppBeginCatch: return "libcpp.begincatch"; case LibcppEndCatch: return "libcpp.endcatch"; default: ikos_unreachable("unreachable"); } } std::string Intrinsic::long_name(ID id) { return Prefix + short_name(id); } std::string Intrinsic::long_name(ID id, Type* template_ty) { return Prefix + short_name(id, template_ty); } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/statement.cpp000066400000000000000000001102261473507761200223240ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Statement implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace ar { // Statement Statement::Statement(StatementKind kind, Variable* result, Operands operands) : _kind(kind), _parent(nullptr), _result(result), _operands(std::move(operands)) {} Statement::Statement(StatementKind kind, Variable* result, std::initializer_list< Value* > operands) : _kind(kind), _parent(nullptr), _result(result), _operands(operands) {} Statement::~Statement() = default; BasicBlock::StatementIterator Statement::iterator() const { return std::find(this->parent()->begin(), this->parent()->end(), this); } Statement* Statement::prev_statement() const { auto it = this->iterator(); if (it != this->parent()->begin()) { --it; return *it; } else { return nullptr; } } Statement* Statement::next_statement() const { auto it = this->iterator(); ++it; if (it != this->parent()->end()) { return *it; } else { return nullptr; } } bool Statement::has_undefined_constant_operand() const { return std::any_of(this->_operands.begin(), this->_operands.end(), [](Value* op) { return isa< UndefinedConstant >(op); }); } void Statement::set_parent(BasicBlock* parent) { this->_parent = parent; } // Assignment Assignment::Assignment(InternalVariable* result, Value* operand) : Statement(AssignmentKind, result, {operand}) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< Assignment > Assignment::create(InternalVariable* result, Value* operand) { return std::unique_ptr< Assignment >(new Assignment(result, operand)); } void Assignment::dump(std::ostream& o) const { this->result()->dump(o); o << " = "; this->operand()->dump(o); } std::unique_ptr< Statement > Assignment::clone() const { std::unique_ptr< Statement > stmt( new Assignment(this->result(), this->operand())); stmt->set_frontend(*this); return stmt; } // UnaryOperation UnaryOperation::UnaryOperation(Operator op, InternalVariable* result, Value* operand) : Statement(UnaryOperationKind, result, {operand}), _op(op) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< UnaryOperation > UnaryOperation::create( Operator op, InternalVariable* result, Value* operand) { return std::unique_ptr< UnaryOperation >( new UnaryOperation(op, result, operand)); } std::string UnaryOperation::operator_text(Operator op) { switch (op) { case UTrunc: return "utrunc"; case STrunc: return "strunc"; case ZExt: return "zext"; case SExt: return "sext"; case FPTrunc: return "fptrunc"; case FPExt: return "fpext"; case FPToUI: return "fptoui"; case FPToSI: return "fptosi"; case UIToFP: return "uitofp"; case SIToFP: return "sitofp"; case PtrToUI: return "ptrtoui"; case PtrToSI: return "ptrtosi"; case UIToPtr: return "uitoptr"; case SIToPtr: return "sitoptr"; case Bitcast: return "bitcast"; default: ikos_unreachable("unexpected operator"); } } void UnaryOperation::dump(std::ostream& o) const { this->result()->dump(o); o << " = " << operator_text(this->_op) << " "; this->operand()->dump(o); } std::unique_ptr< Statement > UnaryOperation::clone() const { std::unique_ptr< Statement > stmt( new UnaryOperation(this->op(), this->result(), this->operand())); stmt->set_frontend(*this); return stmt; } // BinaryOperation BinaryOperation::BinaryOperation(Operator op, InternalVariable* result, Value* left, Value* right, bool no_wrap, bool exact) : Statement(BinaryOperationKind, result, {left, right}), _op(op), _no_wrap(no_wrap), _exact(exact) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(left, "left is null"); ikos_assert_msg(right, "right is null"); ikos_assert(!no_wrap || is_wrapping_operator(op)); ikos_assert(!exact || is_exact_operator(op)); } std::unique_ptr< BinaryOperation > BinaryOperation::create( Operator op, InternalVariable* result, Value* left, Value* right, bool no_wrap, bool exact) { return std::unique_ptr< BinaryOperation >( new BinaryOperation(op, result, left, right, no_wrap, exact)); } std::string BinaryOperation::operator_text(Operator op) { switch (op) { case UAdd: return "uadd"; case USub: return "usub"; case UMul: return "umul"; case UDiv: return "udiv"; case URem: return "urem"; case UShl: return "ushl"; case ULShr: return "ulshr"; case UAShr: return "uashr"; case UAnd: return "uand"; case UOr: return "uor"; case UXor: return "uxor"; case SAdd: return "sadd"; case SSub: return "ssub"; case SMul: return "smul"; case SDiv: return "sdiv"; case SRem: return "srem"; case SShl: return "sshl"; case SLShr: return "slshr"; case SAShr: return "sashr"; case SAnd: return "sand"; case SOr: return "sor"; case SXor: return "sxor"; case FAdd: return "fadd"; case FSub: return "fsub"; case FMul: return "fmul"; case FDiv: return "fdiv"; case FRem: return "frem"; default: ikos_unreachable("unexpected operator"); } } void BinaryOperation::dump(std::ostream& o) const { this->result()->dump(o); o << " = "; this->left()->dump(o); o << " "; o << operator_text(this->op()); if (this->has_no_wrap()) { o << ".nw"; } if (this->is_exact()) { o << ".exact"; } o << " "; this->right()->dump(o); } std::unique_ptr< Statement > BinaryOperation::clone() const { std::unique_ptr< Statement > stmt(new BinaryOperation(this->op(), this->result(), this->left(), this->right(), this->has_no_wrap(), this->is_exact())); stmt->set_frontend(*this); return stmt; } // Comparison Comparison::Comparison(Predicate predicate, Value* left, Value* right) : Statement(ComparisonKind, nullptr, {left, right}), _predicate(predicate) { ikos_assert_msg(left, "left is null"); ikos_assert_msg(right, "right is null"); } std::unique_ptr< Comparison > Comparison::create(Predicate predicate, Value* left, Value* right) { return std::unique_ptr< Comparison >(new Comparison(predicate, left, right)); } std::string Comparison::predicate_text(Predicate pred) { switch (pred) { case UIEQ: return "uieq"; case UINE: return "uine"; case UIGT: return "uigt"; case UIGE: return "uige"; case UILT: return "uilt"; case UILE: return "uile"; case SIEQ: return "sieq"; case SINE: return "sine"; case SIGT: return "sigt"; case SIGE: return "sige"; case SILT: return "silt"; case SILE: return "sile"; case FOEQ: return "foeq"; case FOGT: return "fogt"; case FOGE: return "foge"; case FOLT: return "folt"; case FOLE: return "fole"; case FONE: return "fone"; case FORD: return "ford"; case FUNO: return "funo"; case FUEQ: return "fueq"; case FUGT: return "fugt"; case FUGE: return "fuge"; case FULT: return "fult"; case FULE: return "fule"; case FUNE: return "fune"; case PEQ: return "peq"; case PNE: return "pne"; case PGT: return "pgt"; case PGE: return "pge"; case PLT: return "plt"; case PLE: return "ple"; default: ikos_unreachable("unexpected operator"); } } Comparison::Predicate Comparison::inverse_predicate(Predicate pred) { switch (pred) { case UIEQ: return UINE; case UINE: return UIEQ; case UIGT: return UILE; case UIGE: return UILT; case UILT: return UIGE; case UILE: return UIGT; case SIEQ: return SINE; case SINE: return SIEQ; case SIGT: return SILE; case SIGE: return SILT; case SILT: return SIGE; case SILE: return SIGT; case FOEQ: return FUNE; case FOGT: return FULE; case FOGE: return FULT; case FOLT: return FUGE; case FOLE: return FUGT; case FONE: return FUEQ; case FORD: return FUNO; case FUNO: return FORD; case FUEQ: return FONE; case FUGT: return FOLE; case FUGE: return FOLT; case FULT: return FOGE; case FULE: return FOGT; case FUNE: return FOEQ; case PEQ: return PNE; case PNE: return PEQ; case PGT: return PLE; case PGE: return PLT; case PLT: return PGE; case PLE: return PGT; default: ikos_unreachable("unexpected operator"); } } std::unique_ptr< Comparison > Comparison::inverse() const { std::unique_ptr< Comparison > stmt( new Comparison(inverse_predicate(this->predicate()), this->left(), this->right())); stmt->set_frontend(*this); return stmt; } void Comparison::dump(std::ostream& o) const { this->left()->dump(o); o << " " << predicate_text(this->predicate()) << " "; this->right()->dump(o); } std::unique_ptr< Statement > Comparison::clone() const { std::unique_ptr< Statement > stmt( new Comparison(this->predicate(), this->left(), this->right())); stmt->set_frontend(*this); return stmt; } // ReturnValue ReturnValue::ReturnValue(Value* operand) : Statement(ReturnValueKind, nullptr, {}) { if (operand != nullptr) { this->_operands.push_back(operand); } } std::unique_ptr< ReturnValue > ReturnValue::create(Value* operand) { return std::unique_ptr< ReturnValue >(new ReturnValue(operand)); } void ReturnValue::dump(std::ostream& o) const { if (this->has_operand()) { o << "return "; this->operand()->dump(o); } else { o << "return"; } } std::unique_ptr< Statement > ReturnValue::clone() const { std::unique_ptr< Statement > stmt(new ReturnValue(this->operand_or_null())); stmt->set_frontend(*this); return stmt; } // Unreachable Unreachable::Unreachable() : Statement(UnreachableKind, nullptr, {}) {} std::unique_ptr< Unreachable > Unreachable::create() { return std::unique_ptr< Unreachable >(new Unreachable()); } void Unreachable::dump(std::ostream& o) const { o << "unreachable"; } std::unique_ptr< Statement > Unreachable::clone() const { std::unique_ptr< Statement > stmt(new Unreachable()); stmt->set_frontend(*this); return stmt; } // Allocate Allocate::Allocate(LocalVariable* result, Type* allocated_type, Value* array_size) : Statement(AllocateKind, result, {array_size}), _allocated_type(allocated_type) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(allocated_type, "allocated type is null"); ikos_assert_msg(array_size, "array size is null"); } std::unique_ptr< Allocate > Allocate::create(LocalVariable* result, Type* allocated_type, Value* array_size) { return std::unique_ptr< Allocate >( new Allocate(result, allocated_type, array_size)); } void Allocate::dump(std::ostream& o) const { this->result()->dump(o); o << " = allocate "; this->allocated_type()->dump(o); o << ", "; this->array_size()->dump(o); } std::unique_ptr< Statement > Allocate::clone() const { std::unique_ptr< Statement > stmt( new Allocate(this->result(), this->allocated_type(), this->array_size())); stmt->set_frontend(*this); return stmt; } // PointerShift PointerShift::PointerShift(InternalVariable* result, Value* pointer, const std::vector< Term >& terms) : Statement(PointerShiftKind, result, {pointer}) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(pointer, "pointer is null"); ikos_assert_msg(!terms.empty(), "terms is empty"); this->_factors.reserve(terms.size()); this->_operands.reserve(1 + terms.size()); for (const auto& term : terms) { this->_factors.push_back(term.first); this->_operands.push_back(term.second); } } PointerShift::PointerShift(InternalVariable* result, Factors factors, Operands operands) : Statement(PointerShiftKind, result, std::move(operands)), _factors(std::move(factors)) {} std::unique_ptr< PointerShift > PointerShift::create( InternalVariable* result, Value* pointer, const std::vector< Term >& terms) { return std::unique_ptr< PointerShift >( new PointerShift(result, pointer, terms)); } void PointerShift::dump(std::ostream& o) const { this->result()->dump(o); o << " = ptrshift "; this->pointer()->dump(o); for (auto it = this->term_begin(), et = this->term_end(); it != et; ++it) { auto term = *it; o << ", " << term.first << " * "; term.second->dump(o); } } std::unique_ptr< Statement > PointerShift::clone() const { std::unique_ptr< Statement > stmt( new PointerShift(this->result(), this->_factors, this->_operands)); stmt->set_frontend(*this); return stmt; } // Load Load::Load(InternalVariable* result, Value* operand, uint64_t alignment, bool is_volatile) : Statement(LoadKind, result, {operand}), _alignment(alignment), _is_volatile(is_volatile) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< Load > Load::create(InternalVariable* result, Value* operand, uint64_t alignment, bool is_volatile) { return std::unique_ptr< Load >( new Load(result, operand, alignment, is_volatile)); } void Load::dump(std::ostream& o) const { this->result()->dump(o); o << " = load "; if (this->is_volatile()) { o << "volatile "; } this->operand()->dump(o); if (this->has_alignment()) { o << ", align " << this->alignment(); } } std::unique_ptr< Statement > Load::clone() const { std::unique_ptr< Statement > stmt(new Load(this->result(), this->operand(), this->alignment(), this->is_volatile())); stmt->set_frontend(*this); return stmt; } // Store Store::Store(Value* pointer, Value* value, uint64_t alignment, bool is_volatile) : Statement(StoreKind, nullptr, {pointer, value}), _alignment(alignment), _is_volatile(is_volatile) { ikos_assert_msg(pointer, "pointer is null"); ikos_assert_msg(value, "value is null"); } std::unique_ptr< Store > Store::create(Value* pointer, Value* value, uint64_t alignment, bool is_volatile) { return std::unique_ptr< Store >( new Store(pointer, value, alignment, is_volatile)); } void Store::dump(std::ostream& o) const { o << "store "; if (this->is_volatile()) { o << "volatile "; } this->pointer()->dump(o); o << ", "; this->value()->dump(o); if (this->has_alignment()) { o << ", align " << this->alignment(); } } std::unique_ptr< Statement > Store::clone() const { std::unique_ptr< Statement > stmt(new Store(this->pointer(), this->value(), this->alignment(), this->is_volatile())); stmt->set_frontend(*this); return stmt; } // ExtractElement ExtractElement::ExtractElement(InternalVariable* result, Value* aggregate, Value* offset) : Statement(ExtractElementKind, result, {aggregate, offset}) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(aggregate, "aggregate is null"); ikos_assert_msg(offset, "offset is null"); } std::unique_ptr< ExtractElement > ExtractElement::create( InternalVariable* result, Value* aggregate, Value* offset) { return std::unique_ptr< ExtractElement >( new ExtractElement(result, aggregate, offset)); } void ExtractElement::dump(std::ostream& o) const { this->result()->dump(o); o << " = extractelement "; this->aggregate()->dump(o); o << ", "; this->offset()->dump(o); } std::unique_ptr< Statement > ExtractElement::clone() const { std::unique_ptr< Statement > stmt( new ExtractElement(this->result(), this->aggregate(), this->offset())); stmt->set_frontend(*this); return stmt; } // InsertElement InsertElement::InsertElement(InternalVariable* result, Value* aggregate, Value* offset, Value* element) : Statement(InsertElementKind, result, {aggregate, offset, element}) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(aggregate, "aggregate is null"); ikos_assert_msg(offset, "offset is null"); ikos_assert_msg(element, "element is null"); } std::unique_ptr< InsertElement > InsertElement::create(InternalVariable* result, Value* aggregate, Value* offset, Value* element) { return std::unique_ptr< InsertElement >( new InsertElement(result, aggregate, offset, element)); } void InsertElement::dump(std::ostream& o) const { this->result()->dump(o); o << " = insertelement "; this->aggregate()->dump(o); o << ", "; this->offset()->dump(o); o << ", "; this->element()->dump(o); } std::unique_ptr< Statement > InsertElement::clone() const { std::unique_ptr< Statement > stmt(new InsertElement(this->result(), this->aggregate(), this->offset(), this->element())); stmt->set_frontend(*this); return stmt; } // ShuffleVector ShuffleVector::ShuffleVector(InternalVariable* result, Value* left, Value* right) : Statement(ShuffleVectorKind, result, {left, right}) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(left, "left is null"); ikos_assert_msg(right, "right is null"); } std::unique_ptr< ShuffleVector > ShuffleVector::create(InternalVariable* result, Value* left, Value* right) { return std::unique_ptr< ShuffleVector >( new ShuffleVector(result, left, right)); } void ShuffleVector::dump(std::ostream& o) const { this->result()->dump(o); o << " = shufflevector "; this->left()->dump(o); o << ", "; this->right()->dump(o); } std::unique_ptr< Statement > ShuffleVector::clone() const { std::unique_ptr< Statement > stmt( new ShuffleVector(this->result(), this->left(), this->right())); stmt->set_frontend(*this); return stmt; } // CallBase CallBase::CallBase(StatementKind kind, InternalVariable* result, Value* called, const std::vector< Value* >& arguments) : Statement(kind, result, {called}) { ikos_assert_msg(called, "called is null"); ikos_assert_msg(std::all_of(arguments.begin(), arguments.end(), [](Value* arg) { return arg; }), "argument is null"); this->_operands.reserve(1 + arguments.size()); std::copy(arguments.begin(), arguments.end(), std::back_inserter(this->_operands)); } CallBase::CallBase(StatementKind kind, InternalVariable* result, const Operands& operands) : Statement(kind, result, operands) {} // Call Call::Call(InternalVariable* result, Value* called, const std::vector< Value* >& arguments) : CallBase(CallKind, result, called, arguments) {} Call::Call(InternalVariable* result, const Operands& operands) : CallBase(CallKind, result, operands) {} std::unique_ptr< Call > Call::create(InternalVariable* result, Value* called, const std::vector< Value* >& arguments) { return std::unique_ptr< Call >(new Call(result, called, arguments)); } std::unique_ptr< Call > Call::create(InternalVariable* result, Function* function, const std::vector< Value* >& arguments) { return std::unique_ptr< Call >( new Call(result, function->pointer(), arguments)); } void Call::dump(std::ostream& o) const { if (this->has_result()) { this->result()->dump(o); o << " = "; } o << "call "; this->called()->dump(o); o << "("; for (auto it = this->arg_begin(), et = this->arg_end(); it != et;) { (*it)->dump(o); ++it; if (it != et) { o << ", "; } } o << ")"; } std::unique_ptr< Statement > Call::clone() const { std::unique_ptr< Statement > stmt( new Call(this->result_or_null(), this->_operands)); stmt->set_frontend(*this); return stmt; } // IntrinsicCall IntrinsicCall::IntrinsicCall(InternalVariable* result, Function* function, const std::vector< Value* >& arguments) : Call(result, function->pointer(), arguments) {} // Invoke Invoke::Invoke(InternalVariable* result, Value* called, const std::vector< Value* >& arguments, BasicBlock* normal_dest, BasicBlock* exception_dest) : CallBase(InvokeKind, result, called, arguments), _normal_dest(normal_dest), _exception_dest(exception_dest) { ikos_assert_msg(normal_dest, "normal_dest is null"); ikos_assert_msg(exception_dest, "exception_dest is null"); } Invoke::Invoke(InternalVariable* result, const Operands& operands, BasicBlock* normal_dest, BasicBlock* exception_dest) : CallBase(InvokeKind, result, operands), _normal_dest(normal_dest), _exception_dest(exception_dest) {} std::unique_ptr< Invoke > Invoke::create(InternalVariable* result, Value* called, const std::vector< Value* >& arguments, BasicBlock* normal_dest, BasicBlock* exception_dest) { return std::unique_ptr< Invoke >( new Invoke(result, called, arguments, normal_dest, exception_dest)); } std::unique_ptr< Invoke > Invoke::create(InternalVariable* result, Function* function, const std::vector< Value* >& arguments, BasicBlock* normal_dest, BasicBlock* exception_dest) { return std::unique_ptr< Invoke >(new Invoke(result, function->pointer(), arguments, normal_dest, exception_dest)); } void Invoke::dump(std::ostream& o) const { if (this->has_result()) { this->result()->dump(o); o << " = "; } o << "invoke "; this->called()->dump(o); o << "("; for (auto it = this->arg_begin(), et = this->arg_end(); it != et;) { (*it)->dump(o); ++it; if (it != et) { o << ", "; } } o << ")"; } std::unique_ptr< Statement > Invoke::clone() const { std::unique_ptr< Statement > stmt(new Invoke(this->result_or_null(), this->_operands, this->normal_dest(), this->exception_dest())); stmt->set_frontend(*this); return stmt; } // Helper for alignment constant static IntegerConstant* alignment_constant(Bundle* bundle, uint64_t value) { return IntegerConstant::get(bundle->context(), IntegerType::ui32(bundle->context()), MachineInt(value, 32, Unsigned)); } // Helper for volatile constant static IntegerConstant* volatile_constant(Bundle* bundle, bool value) { return IntegerConstant::get(bundle->context(), IntegerType::ui1(bundle->context()), value ? 1 : 0); } // MemoryCopy MemoryCopy::MemoryCopy(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile) : IntrinsicCall(nullptr, bundle->intrinsic_function(Intrinsic::MemoryCopy), {destination, source, length, alignment_constant(bundle, destination_alignment), alignment_constant(bundle, source_alignment), volatile_constant(bundle, is_volatile)}) { ikos_assert_msg(destination, "destination is null"); ikos_assert_msg(source, "source is null"); ikos_assert_msg(length, "length is null"); } std::unique_ptr< MemoryCopy > MemoryCopy::create(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile) { return std::unique_ptr< MemoryCopy >(new MemoryCopy(bundle, destination, source, length, destination_alignment, source_alignment, is_volatile)); } // MemoryMove MemoryMove::MemoryMove(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile) : IntrinsicCall(nullptr, bundle->intrinsic_function(Intrinsic::MemoryMove), {destination, source, length, alignment_constant(bundle, destination_alignment), alignment_constant(bundle, source_alignment), volatile_constant(bundle, is_volatile)}) { ikos_assert_msg(destination, "destination is null"); ikos_assert_msg(source, "source is null"); ikos_assert_msg(length, "length is null"); } std::unique_ptr< MemoryMove > MemoryMove::create(Bundle* bundle, Value* destination, Value* source, Value* length, uint64_t destination_alignment, uint64_t source_alignment, bool is_volatile) { return std::unique_ptr< MemoryMove >(new MemoryMove(bundle, destination, source, length, destination_alignment, source_alignment, is_volatile)); } // MemorySet MemorySet::MemorySet(Bundle* bundle, Value* pointer, Value* value, Value* length, uint64_t alignment, bool is_volatile) : IntrinsicCall(nullptr, bundle->intrinsic_function(Intrinsic::MemorySet), {pointer, value, length, alignment_constant(bundle, alignment), volatile_constant(bundle, is_volatile)}) { ikos_assert_msg(pointer, "pointer is null"); ikos_assert_msg(value, "value is null"); ikos_assert_msg(length, "length is null"); } std::unique_ptr< MemorySet > MemorySet::create(Bundle* bundle, Value* pointer, Value* value, Value* length, uint64_t alignment, bool is_volatile) { return std::unique_ptr< MemorySet >( new MemorySet(bundle, pointer, value, length, alignment, is_volatile)); } // VarArgStart VarArgStart::VarArgStart(Bundle* bundle, Value* operand) : IntrinsicCall(nullptr, bundle->intrinsic_function(Intrinsic::VarArgStart), {operand}) { ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< VarArgStart > VarArgStart::create(Bundle* bundle, Value* operand) { return std::unique_ptr< VarArgStart >(new VarArgStart(bundle, operand)); } // VarArgEnd VarArgEnd::VarArgEnd(Bundle* bundle, Value* operand) : IntrinsicCall(nullptr, bundle->intrinsic_function(Intrinsic::VarArgEnd), {operand}) { ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< VarArgEnd > VarArgEnd::create(Bundle* bundle, Value* operand) { return std::unique_ptr< VarArgEnd >(new VarArgEnd(bundle, operand)); } // VarArgGet VarArgGet::VarArgGet(Bundle* bundle, InternalVariable* result, Value* operand) : IntrinsicCall(result, bundle->intrinsic_function(Intrinsic::VarArgGet), {operand}) { ikos_assert_msg(result, "result is null"); ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< VarArgGet > VarArgGet::create(Bundle* bundle, InternalVariable* result, Value* operand) { return std::unique_ptr< VarArgGet >(new VarArgGet(bundle, result, operand)); } // VarArgCopy VarArgCopy::VarArgCopy(Bundle* bundle, Value* destination, Value* source) : IntrinsicCall(nullptr, bundle->intrinsic_function(Intrinsic::VarArgCopy), {destination, source}) { ikos_assert_msg(destination, "destination is null"); ikos_assert_msg(source, "source is null"); } std::unique_ptr< VarArgCopy > VarArgCopy::create(Bundle* bundle, Value* destination, Value* source) { return std::unique_ptr< VarArgCopy >( new VarArgCopy(bundle, destination, source)); } // StackSave StackSave::StackSave(Bundle* bundle, InternalVariable* result) : IntrinsicCall(result, bundle->intrinsic_function(Intrinsic::StackSave), {}) { ikos_assert_msg(result, "result is null"); } std::unique_ptr< StackSave > StackSave::create(Bundle* bundle, InternalVariable* result) { return std::unique_ptr< StackSave >(new StackSave(bundle, result)); } // StackRestore StackRestore::StackRestore(Bundle* bundle, Value* operand) : IntrinsicCall(nullptr, bundle->intrinsic_function(Intrinsic::StackRestore), {operand}) { ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< StackRestore > StackRestore::create(Bundle* bundle, Value* operand) { return std::unique_ptr< StackRestore >(new StackRestore(bundle, operand)); } // LandingPad LandingPad::LandingPad(InternalVariable* result) : Statement(LandingPadKind, result, {}) { ikos_assert_msg(result, "result is null"); } std::unique_ptr< LandingPad > LandingPad::create(InternalVariable* result) { return std::unique_ptr< LandingPad >(new LandingPad(result)); } void LandingPad::dump(std::ostream& o) const { this->result()->dump(o); o << " = landingpad"; } std::unique_ptr< Statement > LandingPad::clone() const { std::unique_ptr< Statement > stmt(new LandingPad(this->result())); stmt->set_frontend(*this); return stmt; } // Resume Resume::Resume(InternalVariable* operand) : Statement(ResumeKind, nullptr, {operand}) { ikos_assert_msg(operand, "operand is null"); } std::unique_ptr< Resume > Resume::create(InternalVariable* operand) { return std::unique_ptr< Resume >(new Resume(operand)); } void Resume::dump(std::ostream& o) const { o << "resume "; this->operand()->dump(o); } std::unique_ptr< Statement > Resume::clone() const { std::unique_ptr< Statement > stmt(new Resume(this->operand())); stmt->set_frontend(*this); return stmt; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/type.cpp000066400000000000000000000315161473507761200213050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of types * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include "context_impl.hpp" namespace ikos { namespace ar { // Type Type::Type(TypeKind kind) : _kind(kind) {} Type::~Type() = default; bool Type::is_unsigned_integer() const { return isa< IntegerType >(this) && cast< IntegerType >(this)->is_unsigned(); } bool Type::is_signed_integer() const { return isa< IntegerType >(this) && cast< IntegerType >(this)->is_signed(); } bool Type::is_primitive() const { switch (this->_kind) { case IntegerKind: return true; case FloatKind: return true; case VectorKind: { Type* element = cast< VectorType >(this)->element_type(); return element->is_integer() || element->is_float(); } default: return false; } } uint64_t Type::primitive_bit_width() const { switch (this->_kind) { case IntegerKind: return cast< IntegerType >(this)->bit_width(); case FloatKind: return cast< FloatType >(this)->bit_width(); case VectorKind: { auto vector = cast< VectorType >(this); return vector->num_elements().to< uint64_t >() * vector->element_type()->primitive_bit_width(); } default: return 0; } } ContextImpl& Type::ctx_impl(Context& ctx) { return *(ctx._impl); } // VoidType VoidType::VoidType() : Type(VoidKind) {} VoidType* VoidType::get(Context& ctx) { return ctx_impl(ctx).void_type(); } void VoidType::dump(std::ostream& o) const { o << "void"; } // ScalarType ScalarType::ScalarType(TypeKind kind) : Type(kind) {} // IntegerType IntegerType::IntegerType(uint64_t bit_width, Signedness sign) : ScalarType(IntegerKind), _bit_width(bit_width), _sign(sign) { ikos_assert_msg(bit_width >= 1, "invalid bit width"); } IntegerType* IntegerType::get(Context& ctx, uint64_t bit_width, Signedness sign) { if (bit_width == 1) { if (sign == Unsigned) { return ctx_impl(ctx).ui1_type(); } else { return ctx_impl(ctx).si1_type(); } } else if (bit_width == 8) { if (sign == Unsigned) { return ctx_impl(ctx).ui8_type(); } else { return ctx_impl(ctx).si8_type(); } } else if (bit_width == 16) { if (sign == Unsigned) { return ctx_impl(ctx).ui16_type(); } else { return ctx_impl(ctx).si16_type(); } } else if (bit_width == 32) { if (sign == Unsigned) { return ctx_impl(ctx).ui32_type(); } else { return ctx_impl(ctx).si32_type(); } } else if (bit_width == 64) { if (sign == Unsigned) { return ctx_impl(ctx).ui64_type(); } else { return ctx_impl(ctx).si64_type(); } } else { return ctx_impl(ctx).integer_type(bit_width, sign); } } IntegerType* IntegerType::si1(Context& ctx) { return ctx_impl(ctx).si1_type(); } IntegerType* IntegerType::ui1(Context& ctx) { return ctx_impl(ctx).ui1_type(); } IntegerType* IntegerType::si8(Context& ctx) { return ctx_impl(ctx).si8_type(); } IntegerType* IntegerType::ui8(Context& ctx) { return ctx_impl(ctx).ui8_type(); } IntegerType* IntegerType::si32(Context& ctx) { return ctx_impl(ctx).si32_type(); } IntegerType* IntegerType::ui32(Context& ctx) { return ctx_impl(ctx).ui32_type(); } IntegerType* IntegerType::si64(Context& ctx) { return ctx_impl(ctx).si64_type(); } IntegerType* IntegerType::ui64(Context& ctx) { return ctx_impl(ctx).ui64_type(); } IntegerType* IntegerType::size_type(Bundle* bundle) { return IntegerType::get(bundle->context(), static_cast< uint64_t >( bundle->data_layout().pointers.bit_width), Unsigned); } IntegerType* IntegerType::ssize_type(Bundle* bundle) { return IntegerType::get(bundle->context(), static_cast< uint64_t >( bundle->data_layout().pointers.bit_width), Signed); } MachineInt IntegerType::min_value() const { return MachineInt::min(this->_bit_width, this->_sign); } MachineInt IntegerType::max_value() const { return MachineInt::max(this->_bit_width, this->_sign); } void IntegerType::dump(std::ostream& o) const { if (this->is_unsigned()) { o << "ui"; } else { o << "si"; } o << this->_bit_width; } // FloatType FloatType::FloatType(uint64_t bit_width, FloatSemantic float_sem) : ScalarType(FloatKind), _bit_width(bit_width), _float_sem(float_sem) { ikos_assert_msg(bit_width >= 1, "invalid bit width"); } FloatType* FloatType::get(Context& ctx, FloatSemantic float_sem) { switch (float_sem) { case Half: return ctx_impl(ctx).half_type(); case Float: return ctx_impl(ctx).float_type(); case Double: return ctx_impl(ctx).double_type(); case X86_FP80: return ctx_impl(ctx).x86_fp80_type(); case FP128: return ctx_impl(ctx).fp128_type(); case PPC_FP128: return ctx_impl(ctx).ppc_fp128_type(); default: ikos_unreachable("unknown float semantic"); } } void FloatType::dump(std::ostream& o) const { switch (this->_float_sem) { case Half: o << "half"; break; case Float: o << "float"; break; case Double: o << "double"; break; case X86_FP80: o << "x86_fp80"; break; case FP128: o << "fp128"; break; case PPC_FP128: o << "ppc_fp128"; break; default: ikos_unreachable("unknown float semantic"); } } // PointerType PointerType::PointerType(Type* pointee) : ScalarType(PointerKind), _pointee(pointee) { ikos_assert_msg(pointee, "pointee type is null"); } PointerType* PointerType::get(Context& ctx, Type* pointee) { return ctx_impl(ctx).pointer_type(pointee); } void PointerType::dump(std::ostream& o) const { this->_pointee->dump(o); o << "*"; } // AggregateType AggregateType::AggregateType(TypeKind kind) : Type(kind) {} // StructType StructType::StructType(Layout layout, bool packed) : AggregateType(StructKind), _layout(std::move(layout)), _packed(packed) { ikos_assert_msg(std::is_sorted(this->_layout.begin(), this->_layout.end(), [](const Field& a, const Field& b) { return a.offset < b.offset; }), "layout is not sorted by offset"); } StructType::StructType(bool packed) : AggregateType(StructKind), _packed(packed) {} StructType* StructType::create(Context& ctx, Layout layout, bool packed) { auto t = new StructType(std::move(layout), packed); ctx_impl(ctx).add_type(std::unique_ptr< Type >(t)); return t; } StructType* StructType::create(Context& ctx, bool packed) { auto type = std::unique_ptr< StructType >(new StructType(packed)); auto ptr = type.get(); ctx_impl(ctx).add_type(std::move(type)); return ptr; } void StructType::set_layout(Layout layout) { ikos_assert_msg(std::is_sorted(layout.begin(), layout.end(), [](const Field& a, const Field& b) { return a.offset < b.offset; }), "layout is not sorted by offset"); this->_layout = std::move(layout); } void StructType::set_packed(bool packed) { this->_packed = packed; } void StructType::dump(std::ostream& o) const { if (this->_packed) { o << "<"; } o << "{"; for (auto it = this->_layout.cbegin(), et = this->_layout.cend(); it != et;) { o << it->offset << ": "; it->type->dump(o); ++it; if (it != et) { o << ", "; } } o << "}"; if (this->_packed) { o << ">"; } } // SequentialType SequentialType::SequentialType(TypeKind kind, Type* element_type, ZNumber num_element) : AggregateType(kind), _element_type(element_type), _num_elements(std::move(num_element)) { ikos_assert_msg(this->_element_type, "element type is null"); ikos_assert_msg(this->_num_elements >= 0, "invalid number of elements"); } // ArrayType ArrayType::ArrayType(Type* element_type, ZNumber num_element) : SequentialType(ArrayKind, element_type, std::move(num_element)) {} ArrayType* ArrayType::get(Context& ctx, Type* element_type, const ZNumber& num_element) { return ctx_impl(ctx).array_type(element_type, num_element); } void ArrayType::dump(std::ostream& o) const { o << "[" << this->num_elements() << " x "; this->element_type()->dump(o); o << "]"; } // VectorType VectorType::VectorType(ScalarType* element_type, ZNumber num_element) : SequentialType(VectorKind, element_type, std::move(num_element)) {} VectorType* VectorType::get(Context& ctx, ScalarType* element_type, const ZNumber& num_element) { return ctx_impl(ctx).vector_type(element_type, num_element); } void VectorType::dump(std::ostream& o) const { o << "<" << this->num_elements() << " x "; this->element_type()->dump(o); o << ">"; } // OpaqueType OpaqueType::OpaqueType() : AggregateType(OpaqueKind) {} OpaqueType* OpaqueType::create(Context& ctx) { auto type = std::unique_ptr< OpaqueType >(new OpaqueType()); auto ptr = type.get(); ctx_impl(ctx).add_type(std::move(type)); return ptr; } OpaqueType* OpaqueType::libc_file_type(Context& ctx) { return ctx_impl(ctx).libc_file_type(); } void OpaqueType::dump(std::ostream& o) const { o << "opaque"; } // FunctionType FunctionType::FunctionType(Type* return_type, const ParamTypes& param_types, bool is_var_arg) : Type(FunctionKind), _return_type(return_type), _param_types(param_types), _is_var_arg(is_var_arg) { ikos_assert_msg(return_type, "return type is null"); ikos_assert_msg(std::all_of(param_types.begin(), param_types.end(), [](Type* p) { return p; }), "one parameter type is null"); } FunctionType* FunctionType::get(Context& ctx, Type* return_type, const ParamTypes& param_types, bool is_var_arg) { return ctx_impl(ctx).function_type(return_type, param_types, is_var_arg); } void FunctionType::dump(std::ostream& o) const { this->_return_type->dump(o); o << " ("; for (auto it = this->_param_types.cbegin(), et = this->_param_types.cend(); it != et;) { (*it)->dump(o); ++it; if (it != et) { o << ", "; } } if (this->_is_var_arg) { if (!this->_param_types.empty()) { o << ", "; } o << "..."; } o << ")"; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/semantic/value.cpp000066400000000000000000000320531473507761200214350ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Value implementation (variables, constants, etc.) * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include "context_impl.hpp" namespace ikos { namespace ar { // Value Value::Value(ValueKind kind, Type* type) : _kind(kind), _type(type) { ikos_assert_msg(type, "type is null"); } Value::~Value() = default; ContextImpl& Value::ctx_impl(Context& ctx) { return *(ctx._impl); } // Constant Constant::Constant(ValueKind kind, Type* type) : Value(kind, type) {} // UndefinedConstant UndefinedConstant::UndefinedConstant(Type* type) : Constant(UndefinedConstantKind, type) {} UndefinedConstant* UndefinedConstant::get(Context& ctx, Type* type) { return ctx_impl(ctx).undefined_cst(type); } void UndefinedConstant::dump(std::ostream& o) const { o << "undef"; } // IntegerConstant IntegerConstant::IntegerConstant(IntegerType* type, MachineInt value) : Constant(IntegerConstantKind, type), _value(std::move(value)) { ikos_assert(this->_value.bit_width() == type->bit_width()); ikos_assert(this->_value.sign() == type->sign()); } IntegerConstant* IntegerConstant::get(Context& ctx, IntegerType* type, const MachineInt& value) { return ctx_impl(ctx).integer_cst(type, value); } IntegerConstant* IntegerConstant::get(Context& ctx, IntegerType* type, int value) { return ctx_impl(ctx) .integer_cst(type, MachineInt(value, type->bit_width(), type->sign())); } void IntegerConstant::dump(std::ostream& o) const { o << this->_value; } // FloatConstant FloatConstant::FloatConstant(FloatType* type, std::string value) : Constant(FloatConstantKind, type), _value(std::move(value)) {} FloatConstant* FloatConstant::get(Context& ctx, FloatType* type, const std::string& value) { return ctx_impl(ctx).float_cst(type, value); } FloatConstant* FloatConstant::get(Context& ctx, FloatType* type, const char* value) { return ctx_impl(ctx).float_cst(type, value); } void FloatConstant::dump(std::ostream& o) const { o << this->_value; } // NullConstant NullConstant::NullConstant(PointerType* type) : Constant(NullConstantKind, type) {} NullConstant* NullConstant::get(Context& ctx, PointerType* type) { return ctx_impl(ctx).null_cst(type); } void NullConstant::dump(std::ostream& o) const { o << "null"; } // StructConstant StructConstant::StructConstant(StructType* type, Values values) : Constant(StructConstantKind, type), _values(std::move(values)) { ikos_assert_msg(std::equal(type->field_begin(), type->field_end(), this->_values.begin(), this->_values.end(), [](const StructType::Field& l, const Field& r) { return l.offset == r.offset && l.type == r.value->type(); }), "type does not match"); } StructConstant* StructConstant::get(Context& ctx, StructType* type, const Values& values) { return ctx_impl(ctx).struct_cst(type, values); } void StructConstant::dump(std::ostream& o) const { o << "{"; for (auto it = this->_values.cbegin(), et = this->_values.cend(); it != et;) { o << it->offset << ": "; it->value->dump(o); ++it; if (it != et) { o << ", "; } } o << "}"; } // SequentialConstant SequentialConstant::SequentialConstant(ValueKind kind, SequentialType* type, const Values& values) : Constant(kind, type), _values(values) { ikos_assert_msg(type->num_elements() == values.size(), "incompatible size"); ikos_assert_msg(std::all_of(values.begin(), values.end(), [=](auto& v) { return type->element_type() == v->type(); }), "type does not match"); } // ArrayConstant ArrayConstant::ArrayConstant(ArrayType* type, const Values& values) : SequentialConstant(ArrayConstantKind, type, values) {} ArrayConstant* ArrayConstant::get(Context& ctx, ArrayType* type, const Values& values) { return ctx_impl(ctx).array_cst(type, values); } void ArrayConstant::dump(std::ostream& o) const { o << "["; for (auto it = this->element_begin(), et = this->element_end(); it != et;) { (*it)->dump(o); ++it; if (it != et) { o << ", "; } } o << "]"; } // VectorConstant VectorConstant::VectorConstant(VectorType* type, const Values& values) : SequentialConstant(VectorConstantKind, type, values) {} VectorConstant* VectorConstant::get(Context& ctx, VectorType* type, const Values& values) { return ctx_impl(ctx).vector_cst(type, values); } void VectorConstant::dump(std::ostream& o) const { o << "<"; for (auto it = this->element_begin(), et = this->element_end(); it != et;) { (*it)->dump(o); ++it; if (it != et) { o << ", "; } } o << ">"; } // AggregateZeroConstant AggregateZeroConstant::AggregateZeroConstant(AggregateType* type) : Constant(AggregateZeroConstantKind, type) {} AggregateZeroConstant* AggregateZeroConstant::get(Context& ctx, AggregateType* type) { return ctx_impl(ctx).aggregate_zero_cst(type); } void AggregateZeroConstant::dump(std::ostream& o) const { o << "aggregate_zero"; } // FunctionPointerConstant FunctionPointerConstant::FunctionPointerConstant(PointerType* type, Function* function) : Constant(FunctionPointerConstantKind, type), _function(function) { ikos_assert_msg(function, "function is null"); ikos_assert_msg(type->pointee() == function->type(), "type does not match"); } FunctionPointerConstant* FunctionPointerConstant::get(Context& ctx, Function* function) { return ctx_impl(ctx).function_pointer_cst(function); } void FunctionPointerConstant::dump(std::ostream& o) const { o << "@" << this->_function->name(); } // InlineAssemblyConstant InlineAssemblyConstant::InlineAssemblyConstant(PointerType* type, std::string code) : Constant(InlineAssemblyConstantKind, type), _code(std::move(code)) {} InlineAssemblyConstant* InlineAssemblyConstant::get(Context& ctx, PointerType* type, const std::string& code) { return ctx_impl(ctx).inline_assembly_cst(type, code); } void InlineAssemblyConstant::dump(std::ostream& o) const { o << "asm \"" << this->_code << "\""; } // Variable Variable::Variable(ValueKind kind, Type* type) : Value(kind, type) {} void Variable::set_name(std::string name) { this->_name = std::move(name); } // GlobalVariable GlobalVariable::GlobalVariable(Bundle* bundle, PointerType* type, std::string name, bool is_definition, uint64_t alignment) : Variable(GlobalVariableKind, type), _parent(bundle), _initializer(nullptr), _alignment(alignment) { ikos_assert_msg(bundle, "bundle is null"); ikos_assert_msg(!name.empty(), "global variable name is empty"); if (!name.empty() && bundle->is_name_available(name)) { Variable::set_name(std::move(name)); } else { Variable::set_name(bundle->find_available_name(name)); } if (is_definition) { this->_initializer = std::unique_ptr< Code >(new Code(this)); } } GlobalVariable* GlobalVariable::create(Bundle* bundle, PointerType* type, std::string name, bool is_definition, uint64_t alignment) { GlobalVariable* gv = new GlobalVariable(bundle, type, std::move(name), is_definition, alignment); bundle->add_global_variable(std::unique_ptr< GlobalVariable >(gv)); return gv; } void GlobalVariable::set_name(std::string new_name) { // In this case, we need to notify the bundle, // because it keeps a map from name to global variables ikos_assert_msg(!new_name.empty(), "global variable name is empty"); std::string prev_name = this->name(); if (!new_name.empty() && this->_parent->is_name_available(new_name)) { Variable::set_name(std::move(new_name)); } else { Variable::set_name(this->_parent->find_available_name(new_name)); } this->_parent->rename_global_variable(this, prev_name, this->name()); } void GlobalVariable::dump(std::ostream& o) const { o << "@" << this->name(); } // LocalVariable LocalVariable::LocalVariable(Function* function, PointerType* type, uint64_t alignment) : Variable(LocalVariableKind, type), _parent(function), _alignment(alignment) { ikos_assert_msg(function, "function is null"); } LocalVariable* LocalVariable::create(Function* function, PointerType* type, uint64_t alignment) { auto lv = std::unique_ptr< LocalVariable >( new LocalVariable(function, type, alignment)); return function->add_local_variable(std::move(lv)); } Context& LocalVariable::context() const { return this->bundle()->context(); } Bundle* LocalVariable::bundle() const { return this->function()->bundle(); } void LocalVariable::dump(std::ostream& o) const { o << "$"; if (this->has_name()) { o << this->name(); } else { o << this; } } // InternalVariable InternalVariable::InternalVariable(Code* code, Type* type) : Variable(InternalVariableKind, type), _parent(code) { ikos_assert_msg(code, "code is null"); } InternalVariable* InternalVariable::create(Code* code, Type* type) { auto iv = std::unique_ptr< InternalVariable >(new InternalVariable(code, type)); return code->add_internal_variable(std::move(iv)); } Context& InternalVariable::context() const { return this->bundle()->context(); } Bundle* InternalVariable::bundle() const { return this->code()->bundle(); } void InternalVariable::dump(std::ostream& o) const { o << "%"; if (this->has_name()) { o << this->name(); } else { o << this; } } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/verify/000077500000000000000000000000001473507761200173135ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/ar/src/verify/frontend.cpp000066400000000000000000000100721473507761200216360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the frontend checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include namespace ikos { namespace ar { // Warning: it is very important to write: // valid = f(err, ...) && valid; // And not: // valid = valid && f(err, ...); // // This is because f(err, ...) can have side effects (typically, writes to err), // and with the second pattern, the compiler will remove the call to f() if // valid is false because of short-circuiting. bool FrontendVerifier::verify(Bundle* bundle, std::ostream& err) const { bool valid = true; for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et && (this->_all || valid); ++it) { valid = this->verify(*it, err) && valid; } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et && (this->_all || valid); ++it) { valid = this->verify(*it, err) && valid; } return valid; } bool FrontendVerifier::verify(GlobalVariable* /*gv*/, std::ostream& /*err*/) const { // Ignore statements in global variable initializer return true; } bool FrontendVerifier::verify(Function* f, std::ostream& err) const { return f->is_declaration() || this->verify(f->body(), err); } bool FrontendVerifier::verify(Code* code, std::ostream& err) const { bool valid = true; for (auto it = code->begin(), et = code->end(); it != et && (this->_all || valid); ++it) { valid = this->verify(*it, err) && valid; } return valid; } bool FrontendVerifier::verify(BasicBlock* bb, std::ostream& err) const { bool valid = true; for (auto it = bb->begin(), et = bb->end(); it != et && (this->_all || valid); ++it) { Statement* stmt = *it; if (!stmt->has_frontend()) { err << "error: missing debug info for statement '"; TextFormatter().format(err, stmt); err << "'\n"; valid = false; } } return valid; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/ar/src/verify/type.cpp000066400000000000000000000706261473507761200210130ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the type checker * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace ar { // Warning: it is very important to write: // valid = f(err, ...) && valid; // And not: // valid = valid && f(err, ...); // // This is because f(err, ...) can have side effects (typically, writes to err), // and with the second pattern, the compiler will remove the call to f() if // valid is false because of short-circuiting. bool TypeVerifier::verify(Bundle* bundle, std::ostream& err) const { bool valid = true; for (auto it = bundle->global_begin(), et = bundle->global_end(); it != et && (this->_all || valid); ++it) { valid = this->verify(*it, err) && valid; } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et && (this->_all || valid); ++it) { valid = this->verify(*it, err) && valid; } return valid; } bool TypeVerifier::verify(GlobalVariable* gv, std::ostream& err) const { return gv->is_declaration() || this->verify(gv->initializer(), err, nullptr); } bool TypeVerifier::verify(Function* f, std::ostream& err) const { if (f->is_declaration()) { return true; } bool valid = true; FunctionType* type = f->type(); // check var arg if ((this->_all || valid) && f->is_var_arg() != type->is_var_arg()) { valid = false; err << "error: function '" << f->name() << "' "; err << (f->is_var_arg() ? "is marked" : "is not marked"); err << " var-arg but its type "; err << (type->is_var_arg() ? "is marked" : "is not marked"); err << " var-arg\n"; } // check the number of parameters if ((this->_all || valid) && f->num_parameters() != type->num_parameters()) { valid = false; err << "error: number of parameters of function '" << f->name() << "' does not match its type (" << f->num_parameters() << " != " << type->num_parameters() << ")\n"; } // check each parameter auto fun_param_it = f->param_begin(); auto fun_param_et = f->param_end(); auto type_param_it = type->param_begin(); auto type_param_et = type->param_end(); while (fun_param_it != fun_param_et && type_param_it != type_param_et && (this->_all || valid)) { if ((*fun_param_it)->type() != *type_param_it) { valid = false; err << "error: type of parameter "; TextFormatter().format(err, *fun_param_it, Namer(f->body())); err << " of function '" << f->name() << "' does not match the function type ("; TextFormatter().format(err, (*fun_param_it)->type()); err << " != "; TextFormatter().format(err, (*type_param_it)); err << ")\n"; } ++fun_param_it; ++type_param_it; } // check the function body if (this->_all || valid) { valid = this->verify(f->body(), err, type->return_type()) && valid; } return valid; } bool TypeVerifier::verify(Code* code, std::ostream& err, Type* return_type) const { bool valid = true; for (auto it = code->begin(), et = code->end(); it != et && (this->_all || valid); ++it) { valid = this->verify(*it, err, return_type) && valid; } return valid; } /// \brief Type checker for statements class StatementTypeVerifier { public: using ResultType = bool; public: std::ostream& err; Type* return_type; public: StatementTypeVerifier(std::ostream& err_, Type* return_type_) : err(err_), return_type(return_type_) {} private: // // Helpers for type checking // /// \brief Check that the given type is an unsigned integer type bool check_unsigned_int(Statement* s, Type* ty, const char* desc) { if (!ty->is_unsigned_integer()) { err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' is not an unsigned integer\n"; return false; } return true; } /// \brief Check that the given type is a signed integer type bool check_signed_int(Statement* s, Type* ty, const char* desc) { if (!ty->is_signed_integer()) { err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' is not a signed integer\n"; return false; } return true; } /// \brief Check that the given type is a floating point type bool check_float(Statement* s, Type* ty, const char* desc) { if (!ty->is_float()) { err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' is not a floating point\n"; return false; } return true; } /// \brief Check that the given type is a pointer type bool check_pointer(Statement* s, Type* ty, const char* desc) { if (!ty->is_pointer()) { err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' is not a pointer\n"; return false; } return true; } /// \brief Check that the given type is an aggregate type bool check_aggregate(Statement* s, Type* ty, const char* desc) { if (!ty->is_aggregate()) { err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' is not an aggregate\n"; return false; } return true; } /// \brief Check that the given type is a vector type bool check_vector(Statement* s, Type* ty, const char* desc) { if (!ty->is_vector()) { err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' is not a vector\n"; return false; } return true; } /// \brief Check that the given types are equals bool check_type_match(Statement* s, Type* t1, Type* t2) { if (t1 != t2) { err << "error: type mismatch in statement '"; TextFormatter().format(err, s); err << "' ("; TextFormatter().format(err, t1); err << " != "; TextFormatter().format(err, t2); err << ")\n"; return false; } return true; } /// \brief Check that the given types are equals bool check_equals(Statement* s, Type* t1, Type* t2, const char* desc) { if (t1 != t2) { err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' has type "; TextFormatter().format(err, t1); err << ", was expecting type "; TextFormatter().format(err, t2); err << "\n"; return false; } return true; } /// \brief Check that the given type is an exception structure type /// /// Checks that the type is equivalent to {ui8*, ui32} bool check_exception_struct(Statement* s, Type* ty, const char* desc) { if (ty->is_struct()) { auto sty = cast< StructType >(ty); if (sty->num_fields() == 2) { auto it = sty->field_begin(); Type* first_ty = it->type; ++it; Type* second_ty = it->type; if (first_ty == PointerType::get(s->context(), IntegerType::si8(s->context())) && second_ty == IntegerType::si32(s->context())) { return true; } } } err << "error: " << desc << " of statement '"; TextFormatter().format(err, s); err << "' is not an exception structure\n"; return false; } public: // // visit statements // bool operator()(Assignment* s) { return this->check_type_match(s, s->result()->type(), s->operand()->type()); } bool operator()(UnaryOperation* s) { Type* result_ty = s->result()->type(); Type* operand_ty = s->operand()->type(); switch (s->op()) { case UnaryOperation::UTrunc: { if (!this->check_unsigned_int(s, result_ty, "result") || !this->check_unsigned_int(s, operand_ty, "operand")) { return false; } auto int_result_ty = cast< IntegerType >(result_ty); auto int_operand_ty = cast< IntegerType >(operand_ty); if (int_result_ty->bit_width() >= int_operand_ty->bit_width()) { err << "error: the result type of statement '"; TextFormatter().format(err, s); err << "' is bigger than the operand type (" << int_result_ty->bit_width() << " >= " << int_operand_ty->bit_width() << ")\n"; return false; } return true; } case UnaryOperation::STrunc: { if (!this->check_signed_int(s, result_ty, "result") || !this->check_signed_int(s, operand_ty, "operand")) { return false; } auto int_result_ty = cast< IntegerType >(result_ty); auto int_operand_ty = cast< IntegerType >(operand_ty); if (int_result_ty->bit_width() >= int_operand_ty->bit_width()) { err << "error: the result type of statement '"; TextFormatter().format(err, s); err << "' is bigger than the operand type (" << int_result_ty->bit_width() << " >= " << int_operand_ty->bit_width() << ")\n"; return false; } return true; } case UnaryOperation::ZExt: { if (!this->check_unsigned_int(s, result_ty, "result") || !this->check_unsigned_int(s, operand_ty, "operand")) { return false; } auto int_result_ty = cast< IntegerType >(result_ty); auto int_operand_ty = cast< IntegerType >(operand_ty); if (int_result_ty->bit_width() <= int_operand_ty->bit_width()) { err << "error: the result type of statement '"; TextFormatter().format(err, s); err << "' is smaller than the operand type (" << int_result_ty->bit_width() << " <= " << int_operand_ty->bit_width() << ")\n"; return false; } return true; } case UnaryOperation::SExt: { if (!this->check_signed_int(s, result_ty, "result") || !this->check_signed_int(s, operand_ty, "operand")) { return false; } auto int_result_ty = cast< IntegerType >(result_ty); auto int_operand_ty = cast< IntegerType >(operand_ty); if (int_result_ty->bit_width() <= int_operand_ty->bit_width()) { err << "error: the result type of statement '"; TextFormatter().format(err, s); err << "' is smaller than the operand type (" << int_result_ty->bit_width() << " <= " << int_operand_ty->bit_width() << ")\n"; return false; } return true; } case UnaryOperation::FPTrunc: { if (!this->check_float(s, result_ty, "result") || !this->check_float(s, operand_ty, "operand")) { return false; } auto float_result_ty = cast< FloatType >(result_ty); auto float_operand_ty = cast< FloatType >(operand_ty); if (float_result_ty->bit_width() >= float_operand_ty->bit_width()) { err << "error: the result type of statement '"; TextFormatter().format(err, s); err << "' is bigger than the operand type (" << float_result_ty->bit_width() << " >= " << float_operand_ty->bit_width() << ")\n"; return false; } return true; } case UnaryOperation::FPExt: { if (!this->check_float(s, result_ty, "result") || !this->check_float(s, operand_ty, "operand")) { return false; } auto float_result_ty = cast< FloatType >(result_ty); auto float_operand_ty = cast< FloatType >(operand_ty); if (float_result_ty->bit_width() <= float_operand_ty->bit_width()) { err << "error: the result type of statement '"; TextFormatter().format(err, s); err << "' is smaller than the operand type (" << float_result_ty->bit_width() << " <= " << float_operand_ty->bit_width() << ")\n"; return false; } return true; } case UnaryOperation::FPToUI: { // note: the bit-width might be different return this->check_unsigned_int(s, result_ty, "result") && this->check_float(s, operand_ty, "operand"); } case UnaryOperation::FPToSI: { // note: the bit-width might be different return this->check_signed_int(s, result_ty, "result") && this->check_float(s, operand_ty, "operand"); } case UnaryOperation::UIToFP: { // note: the bit-width might be different return this->check_float(s, result_ty, "result") && this->check_unsigned_int(s, operand_ty, "operand"); } case UnaryOperation::SIToFP: { // note: the bit-width might be different return this->check_float(s, result_ty, "result") && this->check_signed_int(s, operand_ty, "operand"); } case UnaryOperation::PtrToUI: { // note: the bit-width might be different return this->check_unsigned_int(s, result_ty, "result") && this->check_pointer(s, operand_ty, "operand"); } case UnaryOperation::PtrToSI: { // note: the bit-width might be different return this->check_signed_int(s, result_ty, "result") && this->check_pointer(s, operand_ty, "operand"); } case UnaryOperation::UIToPtr: { // note: the bit-width might be different return this->check_pointer(s, result_ty, "result") && this->check_unsigned_int(s, operand_ty, "operand"); } case UnaryOperation::SIToPtr: { // note: the bit-width might be different return this->check_pointer(s, result_ty, "result") && this->check_signed_int(s, operand_ty, "operand"); } case UnaryOperation::Bitcast: { // Valid bitcasts are: // * pointer casts: A* to B* // * primitive type casts with the same bit-width // // A primitive type is either an integer, a floating point or a vector // of integers or floating points. if ((result_ty->is_pointer() && operand_ty->is_pointer()) || (result_ty->is_primitive() && operand_ty->is_primitive() && result_ty->primitive_bit_width() == operand_ty->primitive_bit_width())) { return true; } else { err << "error: invalid bitcast '"; TextFormatter().format(err, s); err << "' from "; TextFormatter().format(err, operand_ty); err << " to "; TextFormatter().format(err, result_ty); err << "\n"; return false; } } default: { ikos_unreachable("unexpected operator"); } } } bool operator()(BinaryOperation* s) { Type* result_ty = s->result()->type(); Type* left_ty = s->left()->type(); Type* right_ty = s->right()->type(); if (!this->check_type_match(s, result_ty, left_ty) || !this->check_type_match(s, result_ty, right_ty)) { return false; } // Allow vector types if (result_ty->is_vector()) { result_ty = cast< VectorType >(result_ty)->element_type(); } if (s->is_unsigned_op()) { return this->check_unsigned_int(s, result_ty, "result"); } else if (s->is_signed_op()) { return this->check_signed_int(s, result_ty, "result"); } else if (s->is_float_op()) { return this->check_float(s, result_ty, "result"); } else { ikos_unreachable("unexpected operator"); } } bool operator()(Comparison* s) { Type* left_ty = s->left()->type(); Type* right_ty = s->right()->type(); if (s->is_unsigned_predicate()) { return this->check_unsigned_int(s, left_ty, "left operand") && this->check_unsigned_int(s, right_ty, "right operand") && this->check_type_match(s, left_ty, right_ty); } else if (s->is_signed_predicate()) { return this->check_signed_int(s, left_ty, "left operand") && this->check_signed_int(s, right_ty, "right operand") && this->check_type_match(s, left_ty, right_ty); } else if (s->is_float_predicate()) { return this->check_float(s, left_ty, "left operand") && this->check_float(s, right_ty, "right operand") && this->check_type_match(s, left_ty, right_ty); } else if (s->is_pointer_predicate()) { // note: the type of the operands might be different return this->check_pointer(s, left_ty, "left operand") && this->check_pointer(s, right_ty, "right operand"); } else { ikos_unreachable("unexpected operator"); } } bool operator()(ReturnValue* s) { if (return_type->is_void()) { if (s->has_operand()) { err << "error: statement '"; TextFormatter().format(err, s); err << "' was not expecting an operand\n"; return false; } else { return true; } } else { if (s->has_operand()) { if (return_type != s->operand()->type()) { err << "error: statement '"; TextFormatter().format(err, s); err << "' returns a "; TextFormatter().format(err, s->operand()->type()); err << " but function return type is "; TextFormatter().format(err, return_type); err << "\n"; return false; } else { return true; } } else { err << "error: statement '"; TextFormatter().format(err, s); err << "', was expecting an operand of type "; TextFormatter().format(err, return_type); err << "\n"; return false; } } } bool operator()(Unreachable* /*unreachable*/) { return true; } bool operator()(Allocate* s) { return this->check_equals(s, s->array_size()->type(), IntegerType::size_type(s->bundle()), "array size operand"); } bool operator()(PointerShift* s) { if (!this->check_pointer(s, s->result()->type(), "result") || !this->check_pointer(s, s->pointer()->type(), "first operand")) { return false; } // check all operands std::size_t n = 2; IntegerType* size_type = IntegerType::size_type(s->bundle()); for (auto it = s->term_begin(), et = s->term_end(); it != et; ++it, ++n) { Value* op = (*it).second; // accept integers of any bit-width and sign if (!op->type()->is_integer()) { err << "error: operand " << n << " of statement '"; TextFormatter().format(err, s); err << "' is not an integer\n"; return false; } MachineInt factor = (*it).first; if (factor.bit_width() != size_type->bit_width() || factor.sign() != size_type->sign()) { err << "error: factor " << n << " of statement '"; TextFormatter().format(err, s); err << "' is not a "; TextFormatter().format(err, size_type); err << "\n"; return false; } } return true; } bool operator()(Load* s) { Type* result_ty = s->result()->type(); Type* operand_ty = s->operand()->type(); if (!this->check_pointer(s, operand_ty, "operand")) { return false; } auto ptr_operand_ty = cast< PointerType >(operand_ty); return this->check_equals(s, result_ty, ptr_operand_ty->pointee(), "result"); } bool operator()(Store* s) { Type* pointer_ty = s->pointer()->type(); Type* value_ty = s->value()->type(); if (!this->check_pointer(s, pointer_ty, "first operand")) { return false; } auto ptr_pointer_ty = cast< PointerType >(pointer_ty); return this->check_equals(s, value_ty, ptr_pointer_ty->pointee(), "second operand"); } bool operator()(ExtractElement* s) { return this->check_aggregate(s, s->aggregate()->type(), "aggregate operand") && this->check_equals(s, s->offset()->type(), IntegerType::size_type(s->bundle()), "offset operand"); } bool operator()(InsertElement* s) { return this->check_aggregate(s, s->aggregate()->type(), "aggregate operand") && this->check_equals(s, s->offset()->type(), IntegerType::size_type(s->bundle()), "offset operand"); } bool operator()(ShuffleVector* s) { return (this->check_vector(s, s->left()->type(), "left operand") && this->check_vector(s, s->right()->type(), "right operand") && this->check_type_match(s, s->result()->type(), s->left()->type()) && this->check_type_match(s, s->result()->type(), s->right()->type())); } bool operator()(CallBase* s) { // Check called value Type* called_ty = s->called()->type(); if (!this->check_pointer(s, called_ty, "called value")) { return false; } auto ptr_called_ty = cast< PointerType >(called_ty); if (!ptr_called_ty->pointee()->is_function()) { err << "error: called value of statement '"; TextFormatter().format(err, s); err << "' is not a function pointer\n"; return false; } auto fun_ty = cast< FunctionType >(ptr_called_ty->pointee()); // Check the result type if (isa< FunctionPointerConstant >(s->called()) && cast< FunctionPointerConstant >(s->called()) ->function() ->intrinsic_id() == Intrinsic::VarArgGet) { // except for VarArgGet, do nothing } else if (fun_ty->return_type()->is_void() && s->has_result()) { err << "error: called value of statement '"; TextFormatter().format(err, s); err << "' has return type void, but the statement has a result\n"; return false; } else if (!fun_ty->return_type()->is_void() && s->has_result() && fun_ty->return_type() != s->result()->type()) { err << "error: called value of statement '"; TextFormatter().format(err, s); err << "' has return type "; TextFormatter().format(err, fun_ty->return_type()); err << " but the statement has a result of type"; TextFormatter().format(err, s->result()->type()); err << "\n"; return false; } // Check the number of parameters if (fun_ty->is_var_arg() && s->num_arguments() < fun_ty->num_parameters()) { err << "error: number of parameters of function call '"; TextFormatter().format(err, s); err << "' is smaller than the function type (" << s->num_arguments() << " < " << fun_ty->num_parameters() << ")\n"; return false; } else if (!fun_ty->is_var_arg() && s->num_arguments() != fun_ty->num_parameters()) { err << "error: number of parameters of function call '"; TextFormatter().format(err, s); err << "' does not match the function type (" << s->num_arguments() << " != " << fun_ty->num_parameters() << ")\n"; return false; } // Allow implicit casts if this is a call on a function pointer, or inline // assembly bool allow_implicit_bitcast = !isa< FunctionPointerConstant >(s->called()) || isa< InlineAssemblyConstant >(s->called()); // Check each parameter auto call_arg_it = s->arg_begin(); auto call_arg_et = s->arg_end(); auto ty_param_it = fun_ty->param_begin(); auto ty_param_et = fun_ty->param_end(); while (call_arg_it != call_arg_et && ty_param_it != ty_param_et) { Type* call_arg_type = (*call_arg_it)->type(); Type* fun_param_type = *ty_param_it; if (call_arg_type != fun_param_type && !(allow_implicit_bitcast && TypeVerifier::is_implicit_bitcast(call_arg_type, fun_param_type))) { err << "error: type of parameter "; Namer namer(s->code()); TextFormatter().format(err, *call_arg_it, namer); err << " of function call '"; TextFormatter().format(err, s); err << "' does not match the function type ("; TextFormatter().format(err, call_arg_type); err << " != "; TextFormatter().format(err, fun_param_type); err << ")\n"; return false; } ++call_arg_it; ++ty_param_it; } return true; } bool operator()(Call* s) { return this->operator()(cast< CallBase >(s)); } bool operator()(Invoke* s) { if (s->normal_dest() == s->exception_dest()) { err << "error: statement '"; TextFormatter().format(err, s); err << "' has the same normal and exception destination\n"; return false; } return this->operator()(cast< CallBase >(s)); } bool operator()(LandingPad* s) { return this->check_exception_struct(s, s->result()->type(), "result"); } bool operator()(Resume* s) { return this->check_exception_struct(s, s->operand()->type(), "operand"); } }; // end class StatementTypeVerifier bool TypeVerifier::verify(BasicBlock* bb, std::ostream& err, Type* return_type) const { StatementTypeVerifier vis(err, return_type); bool valid = true; for (auto it = bb->begin(), et = bb->end(); it != et && (this->_all || valid); ++it) { valid = apply_visitor(vis, *it) && valid; } return valid; } bool TypeVerifier::is_valid_call(ar::CallBase* call, ar::FunctionType* fun_ty) { // Check the result type if (fun_ty->return_type()->is_void() && call->has_result()) { return false; } else if (!fun_ty->return_type()->is_void() && call->has_result() && call->result()->type() != fun_ty->return_type()) { return false; } // Check the number of parameters if (fun_ty->is_var_arg() && call->num_arguments() < fun_ty->num_parameters()) { return false; } else if (!fun_ty->is_var_arg() && call->num_arguments() != fun_ty->num_parameters()) { return false; } // Check each parameter auto call_arg_it = call->arg_begin(); auto call_arg_et = call->arg_end(); auto ty_param_it = fun_ty->param_begin(); auto ty_param_et = fun_ty->param_end(); while (call_arg_it != call_arg_et && ty_param_it != ty_param_et) { Type* call_arg_type = (*call_arg_it)->type(); Type* fun_param_type = *ty_param_it; if (call_arg_type != fun_param_type && !TypeVerifier::is_implicit_bitcast(call_arg_type, fun_param_type)) { return false; } ++call_arg_it; ++ty_param_it; } return true; } } // end namespace ar } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/cmake/000077500000000000000000000000001473507761200156765ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/cmake/AddFlagUtils.cmake000066400000000000000000000015421473507761200212050ustar00rootroot00000000000000include(CheckCXXCompilerFlag) function(check_cxx_compiler_linker_flag flag out_var) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flag}") check_cxx_compiler_flag(${flag} ${out_var}) endfunction() macro(add_compiler_flag policy name flag) check_cxx_compiler_flag(${flag} "CXX_SUPPORTS_${name}") if (CXX_SUPPORTS_${name}) add_definitions(${flag}) elseif (NOT (${policy} STREQUAL "OPTIONAL")) message(FATAL_ERROR "${flag} flag is not supported by ${CMAKE_CXX_COMPILER}") endif() endmacro() macro(add_compiler_linker_flag policy name flag) check_cxx_compiler_linker_flag(${flag} "CXX_SUPPORTS_${name}") if (CXX_SUPPORTS_${name}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") elseif (NOT (${policy} STREQUAL "OPTIONAL")) message(FATAL_ERROR "${flag} flag is not supported by ${CMAKE_CXX_COMPILER}") endif() endmacro() NASA-SW-VnV-ikos-1d98c65/cmake/FindAPRON.cmake000066400000000000000000000103411473507761200203570ustar00rootroot00000000000000############################################################################### # # Find APRON headers and libraries. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT APRON_FOUND) set(APRON_ROOT "" CACHE PATH "Path to apron install directory") set(APRON_INCLUDE_SEARCH_DIRS "") set(APRON_LIBRARY_SEARCH_DIRS "") if (APRON_ROOT) list(APPEND APRON_INCLUDE_SEARCH_DIRS "${APRON_ROOT}/include") list(APPEND APRON_LIBRARY_SEARCH_DIRS "${APRON_ROOT}/lib") endif() if (DEFINED ENV{APRON_INSTALL}) list(APPEND APRON_INCLUDE_SEARCH_DIRS "$ENV{APRON_INSTALL}/include") list(APPEND APRON_LIBRARY_SEARCH_DIRS "$ENV{APRON_INSTALL}/lib") endif() find_package(GMP) find_package(MPFR) find_package(PPL) find_path(APRON_INCLUDE_DIR NAMES ap_abstract0.h HINTS ${APRON_INCLUDE_SEARCH_DIRS} DOC "Path to apron include directory" ) find_library(APRON_APRON_LIB NAMES apron HINTS ${APRON_LIBRARY_SEARCH_DIRS} DOC "Path to apron library" ) find_library(APRON_BOX_LIB NAMES boxMPQ HINTS ${APRON_LIBRARY_SEARCH_DIRS} DOC "Path to apron boxMPQ library" ) find_library(APRON_OCT_LIB NAMES octMPQ HINTS ${APRON_LIBRARY_SEARCH_DIRS} DOC "Path to apron octMPQ library" ) find_library(APRON_POLKA_LIB NAMES polkaMPQ HINTS ${APRON_LIBRARY_SEARCH_DIRS} DOC "Path to apron polkaMPQ library" ) find_library(APRON_PPL_LIB NAMES ap_ppl HINTS ${APRON_LIBRARY_SEARCH_DIRS} DOC "Path to apron ap_ppl library" ) find_library(APRON_PKGRID_LIB NAMES ap_pkgrid HINTS ${APRON_LIBRARY_SEARCH_DIRS} DOC "Path to apron ap_pkgrid library" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(APRON REQUIRED_VARS APRON_INCLUDE_DIR APRON_APRON_LIB APRON_BOX_LIB APRON_OCT_LIB APRON_POLKA_LIB APRON_PPL_LIB APRON_PKGRID_LIB GMP_FOUND MPFR_FOUND PPL_FOUND FAIL_MESSAGE "Could NOT find APRON. Please provide -DAPRON_ROOT=/path/to/apron") endif() set(APRON_INCLUDE_DIRS ${APRON_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${GMPXX_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ${PPL_INCLUDE_DIR}) set(APRON_LIBRARIES ${APRON_APRON_LIB} ${APRON_BOX_LIB} ${APRON_OCT_LIB} ${APRON_POLKA_LIB} ${APRON_PPL_LIB} ${APRON_PKGRID_LIB} ${GMP_LIB} ${GMPXX_LIB} ${MPFR_LIB} ${PPL_LIB}) NASA-SW-VnV-ikos-1d98c65/cmake/FindAR.cmake000066400000000000000000000073041473507761200200070ustar00rootroot00000000000000############################################################################### # # Find IKOS AR headers and library. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT AR_FOUND) set(AR_INCLUDE_SEARCH_DIRS "") set(AR_LIB_SEARCH_DIRS "") # use AR_ROOT as a hint set(AR_ROOT "" CACHE PATH "Path to ikos ar install directory") if (AR_ROOT) list(APPEND AR_INCLUDE_SEARCH_DIRS "${AR_ROOT}/include") list(APPEND AR_LIB_SEARCH_DIRS "${AR_ROOT}/lib") endif() # use ikos-config as a hint find_program(IKOS_CONFIG_EXECUTABLE CACHE NAMES ikos-config DOC "Path to ikos-config binary") if (IKOS_CONFIG_EXECUTABLE) function(run_ikos_config FLAG OUTPUT_VAR) execute_process( COMMAND "${IKOS_CONFIG_EXECUTABLE}" "${FLAG}" RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE ${OUTPUT_VAR} OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE ) if (HAD_ERROR) message(FATAL_ERROR "ikos-config failed with status: ${HAD_ERROR}") endif() set(${OUTPUT_VAR} "${${OUTPUT_VAR}}" PARENT_SCOPE) endfunction() run_ikos_config("--includedir" IKOS_CONFIG_INCLUDE_DIR) run_ikos_config("--libdir" IKOS_CONFIG_LIB_DIR) list(APPEND AR_INCLUDE_SEARCH_DIRS "${IKOS_CONFIG_INCLUDE_DIR}") list(APPEND AR_LIB_SEARCH_DIRS "${IKOS_CONFIG_LIB_DIR}") endif() find_path(AR_INCLUDE_DIR NAMES ikos/ar/semantic/context.hpp HINTS ${AR_INCLUDE_SEARCH_DIRS} DOC "Path to ikos ar include directory" ) find_library(AR_LIB NAMES ikos-ar HINTS ${AR_LIB_SEARCH_DIRS} DOC "Path to ikos ar library" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(AR REQUIRED_VARS AR_INCLUDE_DIR AR_LIB FAIL_MESSAGE "Could NOT find ikos AR. Please provide -DAR_ROOT=/path/to/ar") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindBoost.cmake000066400000000000000000001555011473507761200205760ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #.rst: # FindBoost # --------- # # Find Boost include dirs and libraries # # Use this module by invoking find_package with the form:: # # find_package(Boost # [version] [EXACT] # Minimum or EXACT version e.g. 1.36.0 # [REQUIRED] # Fail with error if Boost is not found # [COMPONENTS ...] # Boost libraries by their canonical name # ) # e.g. "date_time" for "libboost_date_time" # # This module finds headers and requested component libraries OR a CMake # package configuration file provided by a "Boost CMake" build. For the # latter case skip to the "Boost CMake" section below. For the former # case results are reported in variables:: # # Boost_FOUND - True if headers and requested libraries were found # Boost_INCLUDE_DIRS - Boost include directories # Boost_LIBRARY_DIRS - Link directories for Boost libraries # Boost_LIBRARIES - Boost component libraries to be linked # Boost__FOUND - True if component was found ( is upper-case) # Boost__LIBRARY - Libraries to link for component (may include # target_link_libraries debug/optimized keywords) # Boost_VERSION - BOOST_VERSION value from boost/version.hpp # Boost_LIB_VERSION - Version string appended to library filenames # Boost_MAJOR_VERSION - Boost major version number (X in X.y.z) # Boost_MINOR_VERSION - Boost minor version number (Y in x.Y.z) # Boost_SUBMINOR_VERSION - Boost subminor version number (Z in x.y.Z) # Boost_LIB_DIAGNOSTIC_DEFINITIONS (Windows) # - Pass to add_definitions() to have diagnostic # information about Boost's automatic linking # displayed during compilation # # This module reads hints about search locations from variables:: # # BOOST_ROOT - Preferred installation prefix # (or BOOSTROOT) # BOOST_INCLUDEDIR - Preferred include directory e.g. /include # BOOST_LIBRARYDIR - Preferred library directory e.g. /lib # Boost_NO_SYSTEM_PATHS - Set to ON to disable searching in locations not # specified by these hint variables. Default is OFF. # Boost_ADDITIONAL_VERSIONS # - List of Boost versions not known to this module # (Boost install locations may contain the version) # # and saves search results persistently in CMake cache entries:: # # Boost_INCLUDE_DIR - Directory containing Boost headers # Boost_LIBRARY_DIR_RELEASE - Directory containing release Boost libraries # Boost_LIBRARY_DIR_DEBUG - Directory containing debug Boost libraries # Boost__LIBRARY_DEBUG - Component library debug variant # Boost__LIBRARY_RELEASE - Component library release variant # # Users may set these hints or results as cache entries. Projects # should not read these entries directly but instead use the above # result variables. Note that some hint names start in upper-case # "BOOST". One may specify these as environment variables if they are # not specified as CMake variables or cache entries. # # This module first searches for the Boost header files using the above # hint variables (excluding BOOST_LIBRARYDIR) and saves the result in # Boost_INCLUDE_DIR. Then it searches for requested component libraries # using the above hints (excluding BOOST_INCLUDEDIR and # Boost_ADDITIONAL_VERSIONS), "lib" directories near Boost_INCLUDE_DIR, # and the library name configuration settings below. It saves the # library directories in Boost_LIBRARY_DIR_DEBUG and # Boost_LIBRARY_DIR_RELEASE and individual library # locations in Boost__LIBRARY_DEBUG and Boost__LIBRARY_RELEASE. # When one changes settings used by previous searches in the same build # tree (excluding environment variables) this module discards previous # search results affected by the changes and searches again. # # Boost libraries come in many variants encoded in their file name. # Users or projects may tell this module which variant to find by # setting variables:: # # Boost_USE_MULTITHREADED - Set to OFF to use the non-multithreaded # libraries ('mt' tag). Default is ON. # Boost_USE_STATIC_LIBS - Set to ON to force the use of the static # libraries. Default is OFF. # Boost_USE_STATIC_RUNTIME - Set to ON or OFF to specify whether to use # libraries linked statically to the C++ runtime # ('s' tag). Default is platform dependent. # Boost_USE_DEBUG_RUNTIME - Set to ON or OFF to specify whether to use # libraries linked to the MS debug C++ runtime # ('g' tag). Default is ON. # Boost_USE_DEBUG_PYTHON - Set to ON to use libraries compiled with a # debug Python build ('y' tag). Default is OFF. # Boost_USE_STLPORT - Set to ON to use libraries compiled with # STLPort ('p' tag). Default is OFF. # Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS # - Set to ON to use libraries compiled with # STLPort deprecated "native iostreams" # ('n' tag). Default is OFF. # Boost_COMPILER - Set to the compiler-specific library suffix # (e.g. "-gcc43"). Default is auto-computed # for the C++ compiler in use. # Boost_THREADAPI - Suffix for "thread" component library name, # such as "pthread" or "win32". Names with # and without this suffix will both be tried. # Boost_NAMESPACE - Alternate namespace used to build boost with # e.g. if set to "myboost", will search for # myboost_thread instead of boost_thread. # # Other variables one may set to control this module are:: # # Boost_DEBUG - Set to ON to enable debug output from FindBoost. # Please enable this before filing any bug report. # Boost_DETAILED_FAILURE_MSG # - Set to ON to add detailed information to the # failure message even when the REQUIRED option # is not given to the find_package call. # Boost_REALPATH - Set to ON to resolve symlinks for discovered # libraries to assist with packaging. For example, # the "system" component library may be resolved to # "/usr/lib/libboost_system.so.1.42.0" instead of # "/usr/lib/libboost_system.so". This does not # affect linking and should not be enabled unless # the user needs this information. # Boost_LIBRARY_DIR - Default value for Boost_LIBRARY_DIR_RELEASE and # Boost_LIBRARY_DIR_DEBUG. # # On Visual Studio and Borland compilers Boost headers request automatic # linking to corresponding libraries. This requires matching libraries # to be linked explicitly or available in the link library search path. # In this case setting Boost_USE_STATIC_LIBS to OFF may not achieve # dynamic linking. Boost automatic linking typically requests static # libraries with a few exceptions (such as Boost.Python). Use:: # # add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) # # to ask Boost to report information about automatic linking requests. # # Example to find Boost headers only:: # # find_package(Boost 1.36.0) # if(Boost_FOUND) # include_directories(${Boost_INCLUDE_DIRS}) # add_executable(foo foo.cc) # endif() # # Example to find Boost headers and some *static* libraries:: # # set(Boost_USE_STATIC_LIBS ON) # only find static libs # set(Boost_USE_MULTITHREADED ON) # set(Boost_USE_STATIC_RUNTIME OFF) # find_package(Boost 1.36.0 COMPONENTS date_time filesystem system ...) # if(Boost_FOUND) # include_directories(${Boost_INCLUDE_DIRS}) # add_executable(foo foo.cc) # target_link_libraries(foo ${Boost_LIBRARIES}) # endif() # # Boost CMake # ^^^^^^^^^^^ # # If Boost was built using the boost-cmake project it provides a package # configuration file for use with find_package's Config mode. This # module looks for the package configuration file called # BoostConfig.cmake or boost-config.cmake and stores the result in cache # entry "Boost_DIR". If found, the package configuration file is loaded # and this module returns with no further action. See documentation of # the Boost CMake package configuration for details on what it provides. # # Set Boost_NO_BOOST_CMAKE to ON to disable the search for boost-cmake. #------------------------------------------------------------------------------- # Before we go searching, check whether boost-cmake is available, unless the # user specifically asked NOT to search for boost-cmake. # # If Boost_DIR is set, this behaves as any find_package call would. If not, # it looks at BOOST_ROOT and BOOSTROOT to find Boost. # if (NOT Boost_NO_BOOST_CMAKE) # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, # since these are more conventional for Boost. if ("$ENV{Boost_DIR}" STREQUAL "") if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") set(ENV{Boost_DIR} $ENV{BOOSTROOT}) endif() endif() # Do the same find_package call but look specifically for the CMake version. # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no # need to delegate them to this find_package call. find_package(Boost QUIET NO_MODULE) mark_as_advanced(Boost_DIR) # If we found boost-cmake, then we're done. Print out what we found. # Otherwise let the rest of the module try to find it. if (Boost_FOUND) message("Found Boost: ${Boost_DIR} (found version \"${Boost_FIND_VERSION}\")") if (Boost_FIND_COMPONENTS) message("Found Boost components:") message(" ${Boost_FIND_COMPONENTS}") endif() return() endif() endif() #------------------------------------------------------------------------------- # FindBoost functions & macros # ############################################ # # Check the existence of the libraries. # ############################################ # This macro was taken directly from the FindQt4.cmake file that is included # with the CMake distribution. This is NOT my work. All work was done by the # original authors of the FindQt4.cmake file. Only minor modifications were # made to remove references to Qt and make this file more generally applicable # And ELSE/ENDIF pairs were removed for readability. ######################################################################### macro(_Boost_ADJUST_LIB_VARS basename) if(Boost_INCLUDE_DIR ) if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) # if the generator supports configuration types then set # optimized and debug libraries, or if the CMAKE_BUILD_TYPE has a value if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) else() # if there are no configuration types and CMAKE_BUILD_TYPE has no value # then just use the release libraries set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) endif() # FIXME: This probably should be set for both cases set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) endif() # If the debug & release library ends up being the same, omit the keywords if(${Boost_${basename}_LIBRARY_RELEASE} STREQUAL ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) endif() if(Boost_${basename}_LIBRARY) set(Boost_${basename}_FOUND ON) endif() endif() # Make variables changeable to the advanced user mark_as_advanced( Boost_${basename}_LIBRARY_RELEASE Boost_${basename}_LIBRARY_DEBUG ) endmacro() # Detect changes in used variables. # Compares the current variable value with the last one. # In short form: # v != v_LAST -> CHANGED = 1 # v is defined, v_LAST not -> CHANGED = 1 # v is not defined, but v_LAST is -> CHANGED = 1 # otherwise -> CHANGED = 0 # CHANGED is returned in variable named ${changed_var} macro(_Boost_CHANGE_DETECT changed_var) set(${changed_var} 0) foreach(v ${ARGN}) if(DEFINED _Boost_COMPONENTS_SEARCHED) if(${v}) if(_${v}_LAST) string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED) else() set(_${v}_CHANGED 1) endif() elseif(_${v}_LAST) set(_${v}_CHANGED 1) endif() if(_${v}_CHANGED) set(${changed_var} 1) endif() else() set(_${v}_CHANGED 0) endif() endforeach() endmacro() # # Find the given library (var). # Use 'build_type' to support different lib paths for RELEASE or DEBUG builds # macro(_Boost_FIND_LIBRARY var build_type) find_library(${var} ${ARGN}) if(${var}) # If this is the first library found then save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. if(NOT Boost_LIBRARY_DIR_${build_type}) get_filename_component(_dir "${${var}}" PATH) set(Boost_LIBRARY_DIR_${build_type} "${_dir}" CACHE PATH "Boost library directory ${build_type}" FORCE) endif() elseif(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) # Try component-specific hints but do not save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. find_library(${var} HINTS ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT} ${ARGN}) endif() # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there. if(Boost_LIBRARY_DIR_${build_type}) set(_boost_LIBRARY_SEARCH_DIRS_${build_type} ${Boost_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " Boost_LIBRARY_DIR_${build_type} = ${Boost_LIBRARY_DIR_${build_type}}" " _boost_LIBRARY_SEARCH_DIRS_${build_type} = ${_boost_LIBRARY_SEARCH_DIRS_${build_type}}") endif() endif() endmacro() #------------------------------------------------------------------------------- # # Runs compiler with "-dumpversion" and parses major/minor # version with a regex. # function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION) exec_program(${CMAKE_CXX_COMPILER} ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion OUTPUT_VARIABLE _boost_COMPILER_VERSION ) string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" _boost_COMPILER_VERSION ${_boost_COMPILER_VERSION}) set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) endfunction() # # Take a list of libraries with "thread" in it # and prepend duplicates with "thread_${Boost_THREADAPI}" # at the front of the list # function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) set(_orig_libnames ${ARGN}) string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}") set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) endfunction() # # If a library is found, replace its cache entry with its REALPATH # function(_Boost_SWAP_WITH_REALPATH _library _docstring) if(${_library}) get_filename_component(_boost_filepathreal ${${_library}} REALPATH) unset(${_library} CACHE) set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") endif() endfunction() function(_Boost_CHECK_SPELLING _var) if(${_var}) string(TOUPPER ${_var} _var_UC) message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") endif() endfunction() # Guesses Boost's compiler prefix used in built library names # Returns the guess by setting the variable pointed to by _ret function(_Boost_GUESS_COMPILER_PREFIX _ret) if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER MATCHES "icl" OR CMAKE_CXX_COMPILER MATCHES "icpc") if(WIN32) set (_boost_COMPILER "-iw") else() set (_boost_COMPILER "-il") endif() elseif (GHSMULTI) set(_boost_COMPILER "-ghs") elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) set(_boost_COMPILER "-vc150") elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) set(_boost_COMPILER "-vc140") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18) set(_boost_COMPILER "-vc120") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17) set(_boost_COMPILER "-vc110") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16) set(_boost_COMPILER "-vc100") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15) set(_boost_COMPILER "-vc90") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) set(_boost_COMPILER "-vc80") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10) set(_boost_COMPILER "-vc71") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) # Good luck! set(_boost_COMPILER "-vc7") # yes, this is correct else() # MSVC60 Good luck! set(_boost_COMPILER "-vc6") # yes, this is correct endif() elseif (BORLAND) set(_boost_COMPILER "-bcb") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") set(_boost_COMPILER "-sw") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "XL") set(_boost_COMPILER "-xlc") elseif (MINGW) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") endif() elseif (UNIX) if (CMAKE_COMPILER_IS_GNUCXX) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) # Determine which version of GCC we have. if(APPLE) if(Boost_MINOR_VERSION) if(${Boost_MINOR_VERSION} GREATER 35) # In Boost 1.36.0 and newer, the mangled compiler name used # on Mac OS X/Darwin is "xgcc". set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") else() # In Boost <= 1.35.0, there is no mangled compiler name for # the Mac OS X/Darwin version of GCC. set(_boost_COMPILER "") endif() else() # We don't know the Boost version, so assume it's # pre-1.36.0. set(_boost_COMPILER "") endif() else() set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") endif() endif() endif () else() # TODO at least Boost_DEBUG here? set(_boost_COMPILER "") endif() set(${_ret} ${_boost_COMPILER} PARENT_SCOPE) endfunction() # # Update library search directory hint variable with paths used by prebuilt boost binaries. # # Prebuilt windows binaries (https://sourceforge.net/projects/boost/files/boost-binaries/) # have library directories named using MSVC compiler version and architecture. # This function would append corresponding directories if MSVC is a current compiler, # so having `BOOST_ROOT` would be enough to specify to find everything. # macro(_Boost_UPDATE_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS componentlibvar basedir) if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_arch_suffix 64) else() set(_arch_suffix 32) endif() if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-15.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-14.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-12.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-11.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-10.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-9.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-8.0) endif() endif() endmacro() # # End functions/macros # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # main. #------------------------------------------------------------------------------- # If the user sets Boost_LIBRARY_DIR, use it as the default for both # configurations. if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR) set(Boost_LIBRARY_DIR_RELEASE "${Boost_LIBRARY_DIR}") endif() if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR) set(Boost_LIBRARY_DIR_DEBUG "${Boost_LIBRARY_DIR}") endif() if(NOT DEFINED Boost_USE_MULTITHREADED) set(Boost_USE_MULTITHREADED TRUE) endif() if(NOT DEFINED Boost_USE_DEBUG_RUNTIME) set(Boost_USE_DEBUG_RUNTIME TRUE) endif() # Check the version of Boost against the requested version. if(Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") endif() if(Boost_FIND_VERSION_EXACT) # The version may appear in a directory with or without the patch # level, even when the patch level is non-zero. set(_boost_TEST_VERSIONS "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}" "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") else() # The user has not requested an exact version. Among known # versions, find those that are acceptable to the user request. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55" "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51" "1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" "1.34" "1.33.1" "1.33.0" "1.33") set(_boost_TEST_VERSIONS) if(Boost_FIND_VERSION) set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") # Select acceptable versions. foreach(version ${_Boost_KNOWN_VERSIONS}) if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}") # This version is high enough. list(APPEND _boost_TEST_VERSIONS "${version}") elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99") # This version is a short-form for the requested version with # the patch level dropped. list(APPEND _boost_TEST_VERSIONS "${version}") endif() endforeach() else() # Any version is acceptable. set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}") endif() endif() # The reason that we failed to find Boost. This will be set to a # user-friendly message when we fail to find some necessary piece of # Boost. set(Boost_ERROR_REASON) if(Boost_DEBUG) # Output some of their choices message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_MULTITHREADED = ${Boost_USE_MULTITHREADED}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_STATIC_LIBS = ${Boost_USE_STATIC_LIBS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_STATIC_RUNTIME = ${Boost_USE_STATIC_RUNTIME}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_ADDITIONAL_VERSIONS = ${Boost_ADDITIONAL_VERSIONS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}") endif() if(WIN32) # In windows, automatic linking is performed, so you do not have # to specify the libraries. If you are linking to a dynamic # runtime, then you can choose to link to either a static or a # dynamic Boost library, the default is to do a static link. You # can alter this for a specific library "whatever" by defining # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be # linked dynamically. Alternatively you can force all Boost # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. # This feature can be disabled for Boost library "whatever" by # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining # BOOST_ALL_NO_LIB. # If you want to observe which libraries are being linked against # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking # code to emit a #pragma message each time a library is selected # for linking. set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") endif() _Boost_CHECK_SPELLING(Boost_ROOT) _Boost_CHECK_SPELLING(Boost_LIBRARYDIR) _Boost_CHECK_SPELLING(Boost_INCLUDEDIR) # Collect environment variable inputs as hints. Do not consider changes. foreach(v BOOSTROOT BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR) set(_env $ENV{${v}}) if(_env) file(TO_CMAKE_PATH "${_env}" _ENV_${v}) else() set(_ENV_${v} "") endif() endforeach() if(NOT _ENV_BOOST_ROOT AND _ENV_BOOSTROOT) set(_ENV_BOOST_ROOT "${_ENV_BOOSTROOT}") endif() # Collect inputs and cached results. Detect changes since the last run. if(NOT BOOST_ROOT AND BOOSTROOT) set(BOOST_ROOT "${BOOSTROOT}") endif() set(_Boost_VARS_DIR BOOST_ROOT Boost_NO_SYSTEM_PATHS ) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Declared as CMake or Environmental Variables:") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_ROOT = ${BOOST_ROOT}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_INCLUDEDIR = ${BOOST_INCLUDEDIR}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_LIBRARYDIR = ${BOOST_LIBRARYDIR}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") endif() # ------------------------------------------------------------------------ # Search for Boost include DIR # ------------------------------------------------------------------------ set(_Boost_VARS_INC BOOST_INCLUDEDIR Boost_INCLUDE_DIR Boost_ADDITIONAL_VERSIONS) _Boost_CHANGE_DETECT(_Boost_CHANGE_INCDIR ${_Boost_VARS_DIR} ${_Boost_VARS_INC}) # Clear Boost_INCLUDE_DIR if it did not change but other input affecting the # location did. We will find a new one based on the new inputs. if(_Boost_CHANGE_INCDIR AND NOT _Boost_INCLUDE_DIR_CHANGED) unset(Boost_INCLUDE_DIR CACHE) endif() if(NOT Boost_INCLUDE_DIR) set(_boost_INCLUDE_SEARCH_DIRS "") if(BOOST_INCLUDEDIR) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR}) elseif(_ENV_BOOST_INCLUDEDIR) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_INCLUDEDIR}) endif() if( BOOST_ROOT ) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_ROOT}/include ${BOOST_ROOT}) elseif( _ENV_BOOST_ROOT ) list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_ROOT}/include ${_ENV_BOOST_ROOT}) endif() if( Boost_NO_SYSTEM_PATHS) list(APPEND _boost_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) else() list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS C:/boost/include C:/boost /sw/local/include ) endif() # Try to find Boost by stepping backwards through the Boost versions # we know about. # Build a list of path suffixes for each version. set(_boost_PATH_SUFFIXES) foreach(_boost_VER ${_boost_TEST_VERSIONS}) # Add in a path suffix, based on the required version, ideally # we could read this from version.hpp, but for that to work we'd # need to know the include dir already set(_boost_BOOSTIFIED_VERSION) # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 if(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") set(_boost_BOOSTIFIED_VERSION "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}_${CMAKE_MATCH_3}") elseif(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)") set(_boost_BOOSTIFIED_VERSION "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") endif() list(APPEND _boost_PATH_SUFFIXES "boost-${_boost_BOOSTIFIED_VERSION}" "boost_${_boost_BOOSTIFIED_VERSION}" "boost/boost-${_boost_BOOSTIFIED_VERSION}" "boost/boost_${_boost_BOOSTIFIED_VERSION}" ) endforeach() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Include debugging info:") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _boost_INCLUDE_SEARCH_DIRS = ${_boost_INCLUDE_SEARCH_DIRS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _boost_PATH_SUFFIXES = ${_boost_PATH_SUFFIXES}") endif() # Look for a standard boost header file. find_path(Boost_INCLUDE_DIR NAMES boost/config.hpp HINTS ${_boost_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${_boost_PATH_SUFFIXES} ) endif() # ------------------------------------------------------------------------ # Extract version information from version.hpp # ------------------------------------------------------------------------ # Set Boost_FOUND based only on header location and version. # It will be updated below for component libraries. if(Boost_INCLUDE_DIR) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") endif() # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp set(Boost_VERSION 0) set(Boost_LIB_VERSION "") file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ") set(_Boost_VERSION_REGEX "([0-9]+)") set(_Boost_LIB_VERSION_REGEX "\"([0-9_]+)\"") foreach(v VERSION LIB_VERSION) if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_${v} ${_Boost_${v}_REGEX}") set(Boost_${v} "${CMAKE_MATCH_1}") endif() endforeach() unset(_boost_VERSION_HPP_CONTENTS) math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}") if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "version.hpp reveals boost " "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") endif() if(Boost_FIND_VERSION) # Set Boost_FOUND based on requested version. set(_Boost_VERSION "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") if("${_Boost_VERSION}" VERSION_LESS "${Boost_FIND_VERSION}") set(Boost_FOUND 0) set(_Boost_VERSION_AGE "old") elseif(Boost_FIND_VERSION_EXACT AND NOT "${_Boost_VERSION}" VERSION_EQUAL "${Boost_FIND_VERSION}") set(Boost_FOUND 0) set(_Boost_VERSION_AGE "new") else() set(Boost_FOUND 1) endif() if(NOT Boost_FOUND) # State that we found a version of Boost that is too new or too old. set(Boost_ERROR_REASON "${Boost_ERROR_REASON}\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") if (Boost_FIND_VERSION_PATCH) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.${Boost_FIND_VERSION_PATCH}") endif () if (NOT Boost_FIND_VERSION_EXACT) set(Boost_ERROR_REASON "${Boost_ERROR_REASON} (or newer)") endif () set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.") endif () else() # Caller will accept any Boost version. set(Boost_FOUND 1) endif() else() set(Boost_FOUND 0) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.") endif() # ------------------------------------------------------------------------ # Prefix initialization # ------------------------------------------------------------------------ set(Boost_LIB_PREFIX "") if ( (GHSMULTI AND Boost_USE_STATIC_LIBS) OR (WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) ) set(Boost_LIB_PREFIX "lib") endif() if ( NOT Boost_NAMESPACE ) set(Boost_NAMESPACE "boost") endif() # ------------------------------------------------------------------------ # Suffix initialization and compiler suffix detection. # ------------------------------------------------------------------------ set(_Boost_VARS_NAME Boost_NAMESPACE Boost_COMPILER Boost_THREADAPI Boost_USE_DEBUG_PYTHON Boost_USE_MULTITHREADED Boost_USE_STATIC_LIBS Boost_USE_STATIC_RUNTIME Boost_USE_STLPORT Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS ) _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBNAME ${_Boost_VARS_NAME}) # Setting some more suffixes for the library if (Boost_COMPILER) set(_boost_COMPILER ${Boost_COMPILER}) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "using user-specified Boost_COMPILER = ${_boost_COMPILER}") endif() else() # Attempt to guess the compiler suffix # NOTE: this is not perfect yet, if you experience any issues # please report them and use the Boost_COMPILER variable # to work around the problems. _Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "guessed _boost_COMPILER = ${_boost_COMPILER}") endif() endif() set (_boost_MULTITHREADED "-mt") if( NOT Boost_USE_MULTITHREADED ) set (_boost_MULTITHREADED "") endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_MULTITHREADED = ${_boost_MULTITHREADED}") endif() #====================== # Systematically build up the Boost ABI tag # http://boost.org/doc/libs/1_41_0/more/getting_started/windows.html#library-naming set( _boost_RELEASE_ABI_TAG "-") set( _boost_DEBUG_ABI_TAG "-") # Key Use this library when: # s linking statically to the C++ standard library and # compiler runtime support libraries. if(Boost_USE_STATIC_RUNTIME) set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") endif() # g using debug versions of the standard and runtime # support libraries if(WIN32 AND Boost_USE_DEBUG_RUNTIME) if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}g") endif() endif() # y using special debug build of python if(Boost_USE_DEBUG_PYTHON) set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}y") endif() # d using a debug version of your code set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}d") # p using the STLport standard library rather than the # default one supplied with your compiler if(Boost_USE_STLPORT) set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}p") set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}p") endif() # n using the STLport deprecated "native iostreams" feature if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}n") set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}n") endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_DEBUG_ABI_TAG = ${_boost_DEBUG_ABI_TAG}") endif() # ------------------------------------------------------------------------ # Begin finding boost libraries # ------------------------------------------------------------------------ set(_Boost_VARS_LIB "") foreach(c DEBUG RELEASE) set(_Boost_VARS_LIB_${c} BOOST_LIBRARYDIR Boost_LIBRARY_DIR_${c}) list(APPEND _Boost_VARS_LIB ${_Boost_VARS_LIB_${c}}) _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBDIR_${c} ${_Boost_VARS_DIR} ${_Boost_VARS_LIB_${c}} Boost_INCLUDE_DIR) # Clear Boost_LIBRARY_DIR_${c} if it did not change but other input affecting the # location did. We will find a new one based on the new inputs. if(_Boost_CHANGE_LIBDIR_${c} AND NOT _Boost_LIBRARY_DIR_${c}_CHANGED) unset(Boost_LIBRARY_DIR_${c} CACHE) endif() # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value. if(Boost_LIBRARY_DIR_${c}) set(_boost_LIBRARY_SEARCH_DIRS_${c} ${Boost_LIBRARY_DIR_${c}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) else() set(_boost_LIBRARY_SEARCH_DIRS_${c} "") if(BOOST_LIBRARYDIR) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_LIBRARYDIR}) elseif(_ENV_BOOST_LIBRARYDIR) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_LIBRARYDIR}) endif() if(BOOST_ROOT) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_ROOT}/lib ${BOOST_ROOT}/stage/lib) _Boost_UPDATE_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} BOOST_ROOT) elseif(_ENV_BOOST_ROOT) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_ROOT}/lib ${_ENV_BOOST_ROOT}/stage/lib) _Boost_UPDATE_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} _ENV_BOOST_ROOT) endif() list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${Boost_INCLUDE_DIR}/lib ${Boost_INCLUDE_DIR}/../lib ${Boost_INCLUDE_DIR}/stage/lib ) if( Boost_NO_SYSTEM_PATHS ) list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) else() list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} PATHS C:/boost/lib C:/boost /sw/local/lib ) endif() endif() endforeach() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_LIBRARY_SEARCH_DIRS_RELEASE = ${_boost_LIBRARY_SEARCH_DIRS_RELEASE}" "_boost_LIBRARY_SEARCH_DIRS_DEBUG = ${_boost_LIBRARY_SEARCH_DIRS_DEBUG}") endif() # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES if( Boost_USE_STATIC_LIBS ) set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(WIN32) list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) else() set(CMAKE_FIND_LIBRARY_SUFFIXES .a) endif() endif() # We want to use the tag inline below without risking double dashes if(_boost_RELEASE_ABI_TAG) if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") set(_boost_RELEASE_ABI_TAG "") endif() endif() if(_boost_DEBUG_ABI_TAG) if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") set(_boost_DEBUG_ABI_TAG "") endif() endif() # The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled # on WIN32 was to: # 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) # 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) # We maintain this behavior since changing it could break people's builds. # To disable the ambiguous behavior, the user need only # set Boost_USE_STATIC_RUNTIME either ON or OFF. set(_boost_STATIC_RUNTIME_WORKAROUND false) if(WIN32 AND Boost_USE_STATIC_LIBS) if(NOT DEFINED Boost_USE_STATIC_RUNTIME) set(_boost_STATIC_RUNTIME_WORKAROUND TRUE) endif() endif() # On versions < 1.35, remove the System library from the considered list # since it wasn't added until 1.35. if(Boost_VERSION AND Boost_FIND_COMPONENTS) if(Boost_VERSION LESS 103500) list(REMOVE_ITEM Boost_FIND_COMPONENTS system) endif() endif() # If the user changed any of our control inputs flush previous results. if(_Boost_CHANGE_LIBDIR OR _Boost_CHANGE_LIBNAME) foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) foreach(c DEBUG RELEASE) set(_var Boost_${UPPERCOMPONENT}_LIBRARY_${c}) unset(${_var} CACHE) set(${_var} "${_var}-NOTFOUND") endforeach() endforeach() set(_Boost_COMPONENTS_SEARCHED "") endif() foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) set( _boost_docstring_release "Boost ${COMPONENT} library (release)") set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") # Compute component-specific hints. set(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT "") if(${COMPONENT} STREQUAL "mpi" OR ${COMPONENT} STREQUAL "mpi_python" OR ${COMPONENT} STREQUAL "graph_parallel") foreach(lib ${MPI_CXX_LIBRARIES} ${MPI_C_LIBRARIES}) if(IS_ABSOLUTE "${lib}") get_filename_component(libdir "${lib}" PATH) string(REPLACE "\\" "/" libdir "${libdir}") list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT ${libdir}) endif() endforeach() endif() # Consolidate and report component-specific hints. if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Component-specific library search paths for ${COMPONENT}: " "${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}") endif() endif() # # Find RELEASE libraries # set(_boost_RELEASE_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT} ) if(_boost_STATIC_RUNTIME_WORKAROUND) set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") list(APPEND _boost_RELEASE_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) endif() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") endif() # if Boost_LIBRARY_DIR_RELEASE is not defined, # but Boost_LIBRARY_DIR_DEBUG is, look there first for RELEASE libs if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR_DEBUG) list(INSERT _boost_LIBRARY_SEARCH_DIRS_RELEASE 0 ${Boost_LIBRARY_DIR_DEBUG}) endif() # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_RELEASE}") _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE RELEASE NAMES ${_boost_RELEASE_NAMES} HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} NAMES_PER_DIR DOC "${_boost_docstring_release}" ) # # Find DEBUG libraries # set(_boost_DEBUG_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT} ) if(_boost_STATIC_RUNTIME_WORKAROUND) set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") list(APPEND _boost_DEBUG_NAMES ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) endif() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") endif() # if Boost_LIBRARY_DIR_DEBUG is not defined, # but Boost_LIBRARY_DIR_RELEASE is, look there first for DEBUG libs if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR_RELEASE) list(INSERT _boost_LIBRARY_SEARCH_DIRS_DEBUG 0 ${Boost_LIBRARY_DIR_RELEASE}) endif() # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_DEBUG}") _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG DEBUG NAMES ${_boost_DEBUG_NAMES} HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} NAMES_PER_DIR DOC "${_boost_docstring_debug}" ) if(Boost_REALPATH) _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) endif() _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) endforeach() # Restore the original find library ordering if( Boost_USE_STATIC_LIBS ) set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) endif() # ------------------------------------------------------------------------ # End finding boost libraries # ------------------------------------------------------------------------ set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) set(Boost_LIBRARY_DIRS) if(Boost_LIBRARY_DIR_RELEASE) list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_RELEASE}) endif() if(Boost_LIBRARY_DIR_DEBUG) list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_DEBUG}) endif() if(Boost_LIBRARY_DIRS) list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) endif() # The above setting of Boost_FOUND was based only on the header files. # Update it for the requested component libraries. if(Boost_FOUND) # The headers were found. Check for requested component libs. set(_boost_CHECKED_COMPONENT FALSE) set(_Boost_MISSING_COMPONENTS "") foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} COMPONENT) set(_boost_CHECKED_COMPONENT TRUE) if(NOT Boost_${COMPONENT}_FOUND) string(TOLOWER ${COMPONENT} COMPONENT) list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT}) endif() endforeach() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] Boost_FOUND = ${Boost_FOUND}") endif() if (_Boost_MISSING_COMPONENTS) set(Boost_FOUND 0) # We were unable to find some libraries, so generate a sensible # error message that lists the libraries we were unable to find. set(Boost_ERROR_REASON "${Boost_ERROR_REASON}\nCould not find the following") if(Boost_USE_STATIC_LIBS) set(Boost_ERROR_REASON "${Boost_ERROR_REASON} static") endif() set(Boost_ERROR_REASON "${Boost_ERROR_REASON} Boost libraries:\n") foreach(COMPONENT ${_Boost_MISSING_COMPONENTS}) set(Boost_ERROR_REASON "${Boost_ERROR_REASON} ${Boost_NAMESPACE}_${COMPONENT}\n") endforeach() list(LENGTH Boost_FIND_COMPONENTS Boost_NUM_COMPONENTS_WANTED) list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS) if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") else () set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") endif () endif () if( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) # Compatibility Code for backwards compatibility with CMake # 2.4's FindBoost module. # Look for the boost library path. # Note that the user may not have installed any libraries # so it is quite possible the Boost_LIBRARY_DIRS may not exist. set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) endif() if("${_boost_LIB_DIR}" MATCHES "/include$") # Strip off the trailing "/include" in the path. get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) endif() if(EXISTS "${_boost_LIB_DIR}/lib") set(_boost_LIB_DIR ${_boost_LIB_DIR}/lib) elseif(EXISTS "${_boost_LIB_DIR}/stage/lib") set(_boost_LIB_DIR ${_boost_LIB_DIR}/stage/lib) else() set(_boost_LIB_DIR "") endif() if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR}) endif() endif() else() # Boost headers were not found so no components were found. foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) set(Boost_${UPPERCOMPONENT}_FOUND 0) endforeach() endif() # ------------------------------------------------------------------------ # Notification to end user about what was found # ------------------------------------------------------------------------ set(Boost_LIBRARIES "") if(Boost_FOUND) if(NOT Boost_FIND_QUIETLY) message(STATUS "Found Boost: ${Boost_INCLUDE_DIRS} (found version \"${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\")") if(Boost_FIND_COMPONENTS) message(STATUS "Found the following Boost libraries:") endif() endif() foreach( COMPONENT ${Boost_FIND_COMPONENTS} ) string( TOUPPER ${COMPONENT} UPPERCOMPONENT ) if( Boost_${UPPERCOMPONENT}_FOUND ) if(NOT Boost_FIND_QUIETLY) message(STATUS " ${COMPONENT}") endif() list(APPEND Boost_LIBRARIES ${Boost_${UPPERCOMPONENT}_LIBRARY}) endif() endforeach() else() if(Boost_FIND_REQUIRED) message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}") else() if(NOT Boost_FIND_QUIETLY) # we opt not to automatically output Boost_ERROR_REASON here as # it could be quite lengthy and somewhat imposing in its requests # Since Boost is not always a required dependency we'll leave this # up to the end-user. if(Boost_DEBUG OR Boost_DETAILED_FAILURE_MSG) message(STATUS "Could NOT find Boost\n${Boost_ERROR_REASON}") else() message(STATUS "Could NOT find Boost") endif() endif() endif() endif() # Configure display of cache entries in GUI. foreach(v BOOSTROOT BOOST_ROOT ${_Boost_VARS_INC} ${_Boost_VARS_LIB}) get_property(_type CACHE ${v} PROPERTY TYPE) if(_type) set_property(CACHE ${v} PROPERTY ADVANCED 1) if("x${_type}" STREQUAL "xUNINITIALIZED") if("x${v}" STREQUAL "xBoost_ADDITIONAL_VERSIONS") set_property(CACHE ${v} PROPERTY TYPE STRING) else() set_property(CACHE ${v} PROPERTY TYPE PATH) endif() endif() endif() endforeach() # Record last used values of input variables so we can # detect on the next run if the user changed them. foreach(v ${_Boost_VARS_INC} ${_Boost_VARS_LIB} ${_Boost_VARS_DIR} ${_Boost_VARS_NAME} ) if(DEFINED ${v}) set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.") else() unset(_${v}_LAST CACHE) endif() endforeach() # Maintain a persistent list of components requested anywhere since # the last flush. set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}") list(APPEND _Boost_COMPONENTS_SEARCHED ${Boost_FIND_COMPONENTS}) list(REMOVE_DUPLICATES _Boost_COMPONENTS_SEARCHED) list(SORT _Boost_COMPONENTS_SEARCHED) set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}" CACHE INTERNAL "Components requested for this build tree.") NASA-SW-VnV-ikos-1d98c65/cmake/FindClang.cmake000066400000000000000000000064741473507761200205400ustar00rootroot00000000000000############################################################################### # # Find clang binary. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT CLANG_FOUND) find_program(CLANG_EXECUTABLE CACHE NAMES clang HINTS ${LLVM_TOOLS_BINARY_DIR} DOC "Path to clang binary") if (CLANG_EXECUTABLE) get_filename_component(CLANG_BINARY_DIR "${CLANG_EXECUTABLE}" DIRECTORY) find_program(CLANGXX_EXECUTABLE CACHE NAMES clang++ HINTS ${CLANG_BINARY_DIR} ${LLVM_TOOLS_BINARY_DIR} DOC "Path to clang++ binary") endif() if (CLANG_EXECUTABLE) # Detect the version using `clang --version` execute_process( COMMAND ${CLANG_EXECUTABLE} --version RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE CLANG_VERSION_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE ) if (HAD_ERROR) message(FATAL_ERROR "clang failed with status: ${HAD_ERROR}") endif() if (NOT (CLANG_VERSION_OUTPUT MATCHES "clang version ([0-9]+(\\.[0-9]+)*)")) message(FATAL_ERROR "unexpected output for `clang --version`: ${CLANG_VERSION_OUTPUT}") endif() set(CLANG_VERSION "${CMAKE_MATCH_1}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Clang REQUIRED_VARS CLANG_EXECUTABLE CLANGXX_EXECUTABLE CLANG_VERSION VERSION_VAR CLANG_VERSION FAIL_MESSAGE "Could NOT find Clang. Please provide -DCLANG_EXECUTABLE=/path/to/clang") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindCore.cmake000066400000000000000000000066651473507761200204060ustar00rootroot00000000000000############################################################################### # # Find IKOS Core headers. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT CORE_FOUND) set(CORE_INCLUDE_SEARCH_DIRS "") # use CORE_ROOT as a hint set(CORE_ROOT "" CACHE PATH "Path to ikos core install directory") if (CORE_ROOT) list(APPEND CORE_INCLUDE_SEARCH_DIRS "${CORE_ROOT}/include") endif() # use `ikos-config --includedir` as a hint find_program(IKOS_CONFIG_EXECUTABLE CACHE NAMES ikos-config DOC "Path to ikos-config binary") if (IKOS_CONFIG_EXECUTABLE) function(run_ikos_config FLAG OUTPUT_VAR) execute_process( COMMAND "${IKOS_CONFIG_EXECUTABLE}" "${FLAG}" RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE ${OUTPUT_VAR} OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE ) if (HAD_ERROR) message(FATAL_ERROR "ikos-config failed with status: ${HAD_ERROR}") endif() set(${OUTPUT_VAR} "${${OUTPUT_VAR}}" PARENT_SCOPE) endfunction() run_ikos_config("--includedir" IKOS_CONFIG_INCLUDE_DIR) list(APPEND CORE_INCLUDE_SEARCH_DIRS "${IKOS_CONFIG_INCLUDE_DIR}") endif() find_path(CORE_INCLUDE_DIR NAMES ikos/core/domain/numeric/interval.hpp HINTS ${CORE_INCLUDE_SEARCH_DIRS} DOC "Path to ikos core include directory" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Core REQUIRED_VARS CORE_INCLUDE_DIR FAIL_MESSAGE "Could NOT find ikos core. Please provide -DCORE_ROOT=/path/to/core") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindFrontendLLVM.cmake000066400000000000000000000106271473507761200217610ustar00rootroot00000000000000############################################################################### # # Find IKOS LLVM frontend headers and library. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT FRONTEND_LLVM_FOUND) set(FRONTEND_LLVM_INCLUDE_SEARCH_DIRS "") set(FRONTEND_LLVM_LIB_SEARCH_DIRS "") set(FRONTEND_LLVM_BIN_SEARCH_DIRS "") # use FRONTEND_LLVM_ROOT as a hint set(FRONTEND_LLVM_ROOT "" CACHE PATH "Path to ikos llvm frontend install directory") if (FRONTEND_LLVM_ROOT) list(APPEND FRONTEND_LLVM_INCLUDE_SEARCH_DIRS "${FRONTEND_LLVM_ROOT}/include") list(APPEND FRONTEND_LLVM_LIB_SEARCH_DIRS "${FRONTEND_LLVM_ROOT}/lib") list(APPEND FRONTEND_LLVM_BIN_SEARCH_DIRS "${FRONTEND_LLVM_ROOT}/bin") endif() # use ikos-config as a hint find_program(IKOS_CONFIG_EXECUTABLE CACHE NAMES ikos-config DOC "Path to ikos-config binary") if (IKOS_CONFIG_EXECUTABLE) function(run_ikos_config FLAG OUTPUT_VAR) execute_process( COMMAND "${IKOS_CONFIG_EXECUTABLE}" "${FLAG}" RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE ${OUTPUT_VAR} OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE ) if (HAD_ERROR) message(FATAL_ERROR "ikos-config failed with status: ${HAD_ERROR}") endif() set(${OUTPUT_VAR} "${${OUTPUT_VAR}}" PARENT_SCOPE) endfunction() run_ikos_config("--includedir" IKOS_CONFIG_INCLUDE_DIR) run_ikos_config("--libdir" IKOS_CONFIG_LIB_DIR) run_ikos_config("--bindir" IKOS_CONFIG_BIN_DIR) list(APPEND FRONTEND_LLVM_INCLUDE_SEARCH_DIRS "${IKOS_CONFIG_INCLUDE_DIR}") list(APPEND FRONTEND_LLVM_LIB_SEARCH_DIRS "${IKOS_CONFIG_LIB_DIR}") list(APPEND FRONTEND_LLVM_BIN_SEARCH_DIRS "${IKOS_CONFIG_BIN_DIR}") endif() find_path(FRONTEND_LLVM_INCLUDE_DIR NAMES ikos/frontend/llvm/import.hpp HINTS ${FRONTEND_LLVM_INCLUDE_SEARCH_DIRS} DOC "Path to ikos llvm frontend include directory" ) find_library(FRONTEND_LLVM_TO_AR_LIB NAMES ikos-llvm-to-ar HINTS ${FRONTEND_LLVM_LIB_SEARCH_DIRS} DOC "Path to ikos llvm-to-ar library" ) find_program(FRONTEND_LLVM_IKOS_PP_EXECUTABLE NAMES ikos-pp HINTS ${FRONTEND_LLVM_BIN_SEARCH_DIRS} DOC "Path to ikos-pp binary" ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(FrontendLLVM REQUIRED_VARS FRONTEND_LLVM_INCLUDE_DIR FRONTEND_LLVM_TO_AR_LIB FRONTEND_LLVM_IKOS_PP_EXECUTABLE FAIL_MESSAGE "Could NOT find ikos llvm frontend. Please provide -DFRONTEND_LLVM_ROOT=/path/to/frontend") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindGMP.cmake000066400000000000000000000076321473507761200201340ustar00rootroot00000000000000############################################################################### # # Find GMP headers and libraries. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT GMP_FOUND) set(GMP_ROOT "" CACHE PATH "Path to gmp install directory") find_path(GMP_INCLUDE_DIR NAMES gmp.h HINTS "${GMP_ROOT}/include" DOC "Path to gmp include directory" ) find_library(GMP_LIB NAMES gmp HINTS "${GMP_ROOT}/lib" DOC "Path to gmp library" ) find_path(GMPXX_INCLUDE_DIR NAMES gmpxx.h HINTS "${GMP_ROOT}/include" DOC "Path to gmpxx include directory" ) find_library(GMPXX_LIB NAMES gmpxx HINTS "${GMP_ROOT}/lib" DOC "Path to gmpxx library" ) if (GMP_INCLUDE_DIR AND GMP_LIB) file(WRITE "${PROJECT_BINARY_DIR}/FindGMPVersion.c" " #include #include #include int main() { mpz_t i, j, k; mpz_init_set_str(i, \"1a\", 16); mpz_init(j); mpz_init(k); mpz_sqrtrem(j, k, i); assert(mpz_get_si(j) == 5 && mpz_get_si(k) == 1); printf(\"%s\", gmp_version); return 0; } ") try_run( RUN_RESULT COMPILE_RESULT "${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}/FindGMPVersion.c" CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${GMP_INCLUDE_DIR}" "-DLINK_LIBRARIES:STRING=${GMP_LIB}" COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT RUN_OUTPUT_VARIABLE GMP_VERSION ) if (NOT COMPILE_RESULT) message(FATAL_ERROR "error when trying to compile a program with GMP:\n${COMPILE_OUTPUT}") endif() if (RUN_RESULT) message(FATAL_ERROR "error when running a program linked with GMP:\n${GMP_VERSION}") endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GMP REQUIRED_VARS GMP_INCLUDE_DIR GMP_LIB GMPXX_INCLUDE_DIR GMPXX_LIB VERSION_VAR GMP_VERSION FAIL_MESSAGE "Could NOT find GMP. Please provide -DGMP_ROOT=/path/to/gmp") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindLLVM.cmake000066400000000000000000000100771473507761200202600ustar00rootroot00000000000000############################################################################### # # Find LLVM headers and libraries. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT LLVM_FOUND) find_program(LLVM_CONFIG_EXECUTABLE CACHE NAMES llvm-config DOC "Path to llvm-config binary") if (LLVM_CONFIG_EXECUTABLE) function(run_llvm_config FLAG OUTPUT_VAR) execute_process( COMMAND "${LLVM_CONFIG_EXECUTABLE}" "${FLAG}" RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE ${OUTPUT_VAR} OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE ) if (HAD_ERROR) message(FATAL_ERROR "llvm-config failed with status: ${HAD_ERROR}") endif() set(${OUTPUT_VAR} "${${OUTPUT_VAR}}" PARENT_SCOPE) endfunction() run_llvm_config("--version" LLVM_VERSION) run_llvm_config("--prefix" LLVM_ROOT) file(TO_CMAKE_PATH "${LLVM_ROOT}" LLVM_ROOT) set(LLVM_ROOT "${LLVM_ROOT}" CACHE PATH "Path to llvm install directory") run_llvm_config("--includedir" LLVM_INCLUDE_DIR) file(TO_CMAKE_PATH "${LLVM_INCLUDE_DIR}" LLVM_INCLUDE_DIR) set(LLVM_INCLUDE_DIR "${LLVM_INCLUDE_DIR}" CACHE PATH "Path to llvm include directory") run_llvm_config("--bindir" LLVM_TOOLS_BINARY_DIR) file(TO_CMAKE_PATH "${LLVM_TOOLS_BINARY_DIR}" LLVM_TOOLS_BINARY_DIR) set(LLVM_TOOLS_BINARY_DIR "${LLVM_TOOLS_BINARY_DIR}" CACHE PATH "Path to llvm binary directory") run_llvm_config("--libdir" LLVM_LIBRARY_DIR) file(TO_CMAKE_PATH "${LLVM_LIBRARY_DIR}" LLVM_LIBRARY_DIR) set(LLVM_LIBRARY_DIR "${LLVM_LIBRARY_DIR}" CACHE PATH "Path to llvm library directory") run_llvm_config("--cmakedir" LLVM_CMAKE_DIR) file(TO_CMAKE_PATH "${LLVM_CMAKE_DIR}" LLVM_CMAKE_DIR) set(LLVM_CMAKE_DIR "${LLVM_CMAKE_DIR}" CACHE PATH "Path to llvm cmake directory") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LLVM REQUIRED_VARS LLVM_ROOT LLVM_INCLUDE_DIR LLVM_TOOLS_BINARY_DIR LLVM_LIBRARY_DIR LLVM_CMAKE_DIR LLVM_VERSION VERSION_VAR LLVM_VERSION FAIL_MESSAGE "Could NOT find LLVM. Please provide -DLLVM_CONFIG_EXECUTABLE=/path/to/llvm-config") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindMPFR.cmake000066400000000000000000000071631473507761200202540ustar00rootroot00000000000000############################################################################### # # Find MPFR headers and libraries. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT MPFR_FOUND) set(MPFR_ROOT "" CACHE PATH "Path to mpfr install directory") find_package(GMP) find_path(MPFR_INCLUDE_DIR NAMES mpfr.h HINTS "${MPFR_ROOT}/include" DOC "Path to mpfr include directory" ) find_library(MPFR_LIB NAMES mpfr HINTS "${MPFR_ROOT}/lib" DOC "Path to mpfr library" ) if (MPFR_INCLUDE_DIR AND MPFR_LIB AND GMP_FOUND) file(WRITE "${PROJECT_BINARY_DIR}/FindMPFRVersion.c" " #include #include int main() { mpfr_t x; mpfr_init_set_ui(x, 2, MPFR_RNDN); printf(\"%s\", mpfr_get_version()); return 0; } ") try_run( RUN_RESULT COMPILE_RESULT "${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}/FindMPFRVersion.c" CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${MPFR_INCLUDE_DIR};${GMP_INCLUDE_DIR}" "-DLINK_LIBRARIES:STRING=${MPFR_LIB};${GMP_LIB}" COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT RUN_OUTPUT_VARIABLE MPFR_VERSION ) if (NOT COMPILE_RESULT) message(FATAL_ERROR "error when trying to compile a program with MPFR:\n${COMPILE_OUTPUT}") endif() if (RUN_RESULT) message(FATAL_ERROR "error when running a program linked with MPFR:\n${MPFR_VERSION}") endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MPFR REQUIRED_VARS MPFR_INCLUDE_DIR MPFR_LIB MPFR_VERSION GMP_FOUND VERSION_VAR MPFR_VERSION FAIL_MESSAGE "Could NOT find MPFR. Please provide -DMPFR_ROOT=/path/to/mpfr") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindPPL.cmake000066400000000000000000000115351473507761200201410ustar00rootroot00000000000000############################################################################### # # Find PPL headers and libraries. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT PPL_FOUND) set(PPL_ROOT "" CACHE PATH "Path to ppl install directory") set(PPL_INCLUDE_SEARCH_DIRS "") set(PPL_LIB_SEARCH_DIRS "") if (PPL_ROOT) list(APPEND PPL_INCLUDE_SEARCH_DIRS "${PPL_ROOT}/include") list(APPEND PPL_LIB_SEARCH_DIRS "${PPL_ROOT}/lib") endif() # Try to use ppl-config if available find_program(PPL_CONFIG_EXECUTABLE CACHE NAMES ppl-config DOC "Path to ppl-config binary") if (PPL_CONFIG_EXECUTABLE) function(run_ppl_config FLAG OUTPUT_VAR) execute_process( COMMAND "${PPL_CONFIG_EXECUTABLE}" "${FLAG}" RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE ${OUTPUT_VAR} OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE ) if (HAD_ERROR) message(FATAL_ERROR "ppl-config failed with status: ${HAD_ERROR}") endif() set(${OUTPUT_VAR} "${${OUTPUT_VAR}}" PARENT_SCOPE) endfunction() run_ppl_config("--includedir" PPL_CONFIG_INCLUDE_DIR) run_ppl_config("--libdir" PPL_CONFIG_LIB_DIR) list(APPEND PPL_INCLUDE_SEARCH_DIRS ${PPL_CONFIG_INCLUDE_DIR}) list(APPEND PPL_LIB_SEARCH_DIRS ${PPL_CONFIG_LIB_DIR}) endif() find_package(GMP) find_path(PPL_INCLUDE_DIR NAMES ppl_c.h HINTS ${PPL_INCLUDE_SEARCH_DIRS} DOC "Path to ppl include directory" ) find_library(PPL_LIB NAMES ppl HINTS ${PPL_LIB_SEARCH_DIRS} DOC "Path to ppl library" ) find_library(PPL_C_LIB NAMES ppl_c HINTS ${PPL_LIB_SEARCH_DIRS} DOC "Path to ppl_c library" ) if (PPL_INCLUDE_DIR AND PPL_C_LIB AND GMP_FOUND) file(WRITE "${PROJECT_BINARY_DIR}/FindPPLVersion.c" " #include #include int main() { const char* version; ppl_initialize(); ppl_version(&version); printf(\"%s\", version); return ppl_finalize(); } ") try_run( RUN_RESULT COMPILE_RESULT "${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}/FindPPLVersion.c" CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${PPL_INCLUDE_DIR};${GMP_INCLUDE_DIR}" "-DLINK_LIBRARIES:STRING=${PPL_C_LIB};${GMP_LIB}" COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT RUN_OUTPUT_VARIABLE PPL_VERSION ) if (NOT COMPILE_RESULT) message(FATAL_ERROR "error when trying to compile a program with PPL:\n${COMPILE_OUTPUT}") endif() if (RUN_RESULT) message(FATAL_ERROR "error when running a program linked with PPL:\n${PPL_VERSION}") endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(PPL REQUIRED_VARS PPL_INCLUDE_DIR PPL_LIB PPL_C_LIB GMP_FOUND VERSION_VAR PPL_VERSION FAIL_MESSAGE "Could NOT find PPL. Please provide -DPPL_ROOT=/path/to/ppl") endif() set(PPL_LIBRARIES ${PPL_LIB} ${PPL_C_LIB} ) NASA-SW-VnV-ikos-1d98c65/cmake/FindSQLite3.cmake000066400000000000000000000075701473507761200207360ustar00rootroot00000000000000############################################################################### # # Find SQLite 3 headers and libraries. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2018-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### if (NOT SQLITE3_FOUND) set(SQLITE3_ROOT "" CACHE PATH "Path to sqlite3 install directory") find_path(SQLITE3_INCLUDE_DIR NAMES sqlite3.h HINTS "${SQLITE3_ROOT}/include" DOC "Path to sqlite3 include directory" ) find_library(SQLITE3_LIB NAMES sqlite3 HINTS "${SQLITE3_ROOT}/lib" DOC "Path to sqlite3 library" ) if (SQLITE3_INCLUDE_DIR AND SQLITE3_LIB) file(WRITE "${PROJECT_BINARY_DIR}/FindSQLite3Version.c" " #include #include #include #include int main() { // The following assertion does not always hold on macs, due to a bug in // the sqlite3 setup shipped on Mac. So, we only check if the OS is not // Apple. #ifndef __APPLE__ assert(strcmp(SQLITE_VERSION, sqlite3_libversion()) == 0); #endif printf(\"%s\", sqlite3_libversion()); return 0; } ") try_run( RUN_RESULT COMPILE_RESULT "${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}/FindSQLite3Version.c" CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${SQLITE3_INCLUDE_DIR}" "-DLINK_LIBRARIES:STRING=${SQLITE3_LIB}" COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT RUN_OUTPUT_VARIABLE SQLITE3_VERSION ) if (NOT COMPILE_RESULT) message(FATAL_ERROR "error when trying to compile a program with SQLite3:\n${COMPILE_OUTPUT}") endif() if (RUN_RESULT) message(FATAL_ERROR "error when running a program linked with SQLite3:\n${SQLITE3_VERSION}") endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(SQLite3 REQUIRED_VARS SQLITE3_INCLUDE_DIR SQLITE3_LIB VERSION_VAR SQLITE3_VERSION FAIL_MESSAGE "Could NOT find SQLite3. Please provide -DSQLITE3_ROOT=/path/to/sqlite3") endif() NASA-SW-VnV-ikos-1d98c65/cmake/FindTBB.cmake000066400000000000000000000265761473507761200201300ustar00rootroot00000000000000# The MIT License (MIT) # # Copyright (c) 2015 Justus Calvin # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # # FindTBB # ------- # # Find TBB include directories and libraries. # # Usage: # # find_package(TBB [major[.minor]] [EXACT] # [QUIET] [REQUIRED] # [[COMPONENTS] [components...]] # [OPTIONAL_COMPONENTS components...]) # # where the allowed components are tbbmalloc and tbb_preview. Users may modify # the behavior of this module with the following variables: # # * TBB_ROOT - The base directory the of TBB installation. # * TBB_INCLUDE_DIR - The directory that contains the TBB headers files. # * TBB_LIBRARY - The directory that contains the TBB library files. # * TBB__LIBRARY - The path of the TBB the corresponding TBB library. # These libraries, if specified, override the # corresponding library search results, where # may be tbb, tbb_debug, tbbmalloc, tbbmalloc_debug, # tbb_preview, or tbb_preview_debug. # * TBB_USE_DEBUG_BUILD - The debug version of tbb libraries, if present, will # be used instead of the release version. # # Users may modify the behavior of this module with the following environment # variables: # # * TBB_INSTALL # * TBBROOT # * LIBRARY_PATH # # This module will set the following variables: # # * TBB_FOUND - Set to false, or undefined, if we haven’t found, or # don’t want to use TBB. # * TBB__FOUND - If False, optional part of TBB sytem is # not available. # * TBB_VERSION - The full version string # * TBB_VERSION_MAJOR - The major version # * TBB_VERSION_MINOR - The minor version # * TBB_INTERFACE_VERSION - The interface version number defined in # tbb/tbb_stddef.h. # * TBB__LIBRARY_RELEASE - The path of the TBB release version of # , where may be tbb, tbb_debug, # tbbmalloc, tbbmalloc_debug, tbb_preview, or # tbb_preview_debug. # * TBB__LIBRARY_DEGUG - The path of the TBB release version of # , where may be tbb, tbb_debug, # tbbmalloc, tbbmalloc_debug, tbb_preview, or # tbb_preview_debug. # # The following varibles should be used to build and link with TBB: # # * TBB_INCLUDE_DIRS - The include directory for TBB. # * TBB_LIBRARIES - The libraries to link against to use TBB. # * TBB_LIBRARIES_RELEASE - The release libraries to link against to use TBB. # * TBB_LIBRARIES_DEBUG - The debug libraries to link against to use TBB. # * TBB_DEFINITIONS - Definitions to use when compiling code that uses # TBB. # * TBB_DEFINITIONS_RELEASE - Definitions to use when compiling release code that # uses TBB. # * TBB_DEFINITIONS_DEBUG - Definitions to use when compiling debug code that # uses TBB. # # This module will also create the "tbb" target that may be used when building # executables and libraries. if(NOT TBB_FOUND) ################################## # Check the build type ################################## if(NOT DEFINED TBB_USE_DEBUG_BUILD) set(TBB_BUILD_TYPE RELEASE) elseif(TBB_USE_DEBUG_BUILD) set(TBB_BUILD_TYPE DEBUG) else() set(TBB_BUILD_TYPE RELEASE) endif() ################################## # Set the TBB search directories ################################## # Define search paths based on user input and environment variables set(TBB_ROOT "" CACHE PATH "Path to tbb install directory") set(TBB_SEARCH_DIR ${TBB_ROOT} $ENV{TBB_INSTALL} $ENV{TBBROOT}) # Define the search directories based on the current platform if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set(TBB_DEFAULT_SEARCH_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB" ) # Set the target architecture if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(TBB_ARCHITECTURE "intel64") else() set(TBB_ARCHITECTURE "ia32") endif() # Set the TBB search library path search suffix based on the version of VC if(WINDOWS_STORE) set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11_ui") elseif(MSVC14) set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc14") elseif(MSVC12) set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc12") elseif(MSVC11) set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11") elseif(MSVC10) set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc10") endif() # Add the library path search suffix for the VC independent version of TBB list(APPEND TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc_mt") elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") # OS X set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb" "/usr/local/opt/tbb" ) # TODO: Check to see which C++ library is being used by the compiler. if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0) # The default C++ library on OS X 10.9 and later is libc++ set(TBB_LIB_PATH_SUFFIX "lib/libc++" "lib") else() set(TBB_LIB_PATH_SUFFIX "lib") endif() elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") # Linux set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") # TODO: Check compiler version to see the suffix should be /gcc4.1 or # /gcc4.1. For now, assume that the compiler is more recent than # gcc 4.4.x or later. if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") set(TBB_LIB_PATH_SUFFIX "lib/intel64/gcc4.4") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") set(TBB_LIB_PATH_SUFFIX "lib/ia32/gcc4.4") endif() endif() ################################## # Find the TBB include dir ################################## find_path(TBB_INCLUDE_DIRS tbb/tbb.h HINTS ${TBB_INCLUDE_DIR} ${TBB_SEARCH_DIR} PATHS ${TBB_DEFAULT_SEARCH_DIR} PATH_SUFFIXES include) ################################## # Set version strings ################################## if(TBB_INCLUDE_DIRS) file(READ "${TBB_INCLUDE_DIRS}/oneapi/tbb/version.h" _tbb_version_file) string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" TBB_VERSION_MAJOR "${_tbb_version_file}") string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" TBB_VERSION_MINOR "${_tbb_version_file}") string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_tbb_version_file}") set(TBB_VERSION "${TBB_INTERFACE_VERSION}") endif() ################################## # Find TBB components ################################## if(TBB_VERSION VERSION_LESS 4.3) set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc tbb) else() set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc_proxy tbbmalloc tbb) endif() # Find each component foreach(_comp ${TBB_SEARCH_COMPOMPONENTS}) if(";${TBB_FIND_COMPONENTS};tbb;" MATCHES ";${_comp};") # Search for the libraries find_library(TBB_${_comp}_LIBRARY_RELEASE ${_comp} HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) find_library(TBB_${_comp}_LIBRARY_DEBUG ${_comp}_debug HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) if(TBB_${_comp}_LIBRARY_DEBUG) list(APPEND TBB_LIBRARIES_DEBUG "${TBB_${_comp}_LIBRARY_DEBUG}") endif() if(TBB_${_comp}_LIBRARY_RELEASE) list(APPEND TBB_LIBRARIES_RELEASE "${TBB_${_comp}_LIBRARY_RELEASE}") endif() if(TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE} AND NOT TBB_${_comp}_LIBRARY) set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE}}") endif() if(TBB_${_comp}_LIBRARY AND EXISTS "${TBB_${_comp}_LIBRARY}") set(TBB_${_comp}_FOUND TRUE) else() set(TBB_${_comp}_FOUND FALSE) endif() # Mark internal variables as advanced mark_as_advanced(TBB_${_comp}_LIBRARY_RELEASE) mark_as_advanced(TBB_${_comp}_LIBRARY_DEBUG) mark_as_advanced(TBB_${_comp}_LIBRARY) endif() endforeach() ################################## # Set compile flags and libraries ################################## set(TBB_DEFINITIONS_RELEASE "") set(TBB_DEFINITIONS_DEBUG "-DTBB_USE_DEBUG=1") if(TBB_LIBRARIES_${TBB_BUILD_TYPE}) set(TBB_DEFINITIONS "${TBB_DEFINITIONS_${TBB_BUILD_TYPE}}") set(TBB_LIBRARIES "${TBB_LIBRARIES_${TBB_BUILD_TYPE}}") elseif(TBB_LIBRARIES_RELEASE) set(TBB_DEFINITIONS "${TBB_DEFINITIONS_RELEASE}") set(TBB_LIBRARIES "${TBB_LIBRARIES_RELEASE}") elseif(TBB_LIBRARIES_DEBUG) set(TBB_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}") set(TBB_LIBRARIES "${TBB_LIBRARIES_DEBUG}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(TBB REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES HANDLE_COMPONENTS VERSION_VAR TBB_VERSION FAIL_MESSAGE "Could NOT find TBB. Please provide -DTBB_ROOT=/path/to/tbb") ################################## # Create targets ################################## if(NOT CMAKE_VERSION VERSION_LESS 3.0 AND TBB_FOUND) add_library(tbb SHARED IMPORTED) set_target_properties(tbb PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS} IMPORTED_LOCATION ${TBB_LIBRARIES}) if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG) set_target_properties(tbb PROPERTIES INTERFACE_COMPILE_DEFINITIONS "$<$,$>:TBB_USE_DEBUG=1>" IMPORTED_LOCATION_DEBUG ${TBB_LIBRARIES_DEBUG} IMPORTED_LOCATION_RELWITHDEBINFO ${TBB_LIBRARIES_DEBUG} IMPORTED_LOCATION_RELEASE ${TBB_LIBRARIES_RELEASE} IMPORTED_LOCATION_MINSIZEREL ${TBB_LIBRARIES_RELEASE} ) elseif(TBB_LIBRARIES_RELEASE) set_target_properties(tbb PROPERTIES IMPORTED_LOCATION ${TBB_LIBRARIES_RELEASE}) else() set_target_properties(tbb PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}" IMPORTED_LOCATION ${TBB_LIBRARIES_DEBUG} ) endif() endif() mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES) unset(TBB_ARCHITECTURE) unset(TBB_BUILD_TYPE) unset(TBB_LIB_PATH_SUFFIX) unset(TBB_DEFAULT_SEARCH_DIR) endif() NASA-SW-VnV-ikos-1d98c65/cmake/HandleOptions.cmake000066400000000000000000000056171473507761200214600ustar00rootroot00000000000000# Check the build type set(CMAKE_BUILD_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel") if (NOT (CMAKE_BUILD_TYPE IN_LIST CMAKE_BUILD_TYPES)) message(FATAL_ERROR "Unsupported build type: ${CMAKE_BUILD_TYPE}") endif() # Option to enable assertions if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug")) option(ENABLE_ASSERTIONS "Enable assertions" OFF) else() option(ENABLE_ASSERTIONS "Enable assertions" ON) endif() if (ENABLE_ASSERTIONS) # On non-Debug builds, cmake automatically defines NDEBUG, so we undefine it. if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug")) add_definitions("-UNDEBUG") endif() else() if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_definitions("-DNDEBUG") endif() endif() # Option to enable sanitizers set(USE_SANITIZER "" CACHE STRING "Define the sanitizer used to build binaries and tests") if (USE_SANITIZER) include(AddFlagUtils) if (USE_SANITIZER STREQUAL "Address") message(STATUS "Using Address Sanitizer, expect slow down in the analysis.") add_compiler_linker_flag(REQUIRED "FSANITIZE_ADDRESS" "-fsanitize=address") add_compiler_linker_flag(OPTIONAL "FSANITIZE_ADDRESS_USE_AFTER_SCOPE" "-fsanitize-address-use-after-scope") elseif (USE_SANITIZER STREQUAL "Undefined") message(STATUS "Using Undefined Behavior Sanitizer, expect slow down in the analysis.") add_compiler_linker_flag(REQUIRED "FSANITIZE_UNDEFINED" "-fsanitize=undefined") add_compiler_linker_flag(REQUIRED "FNO_SANITIZE_VPTR" "-fno-sanitize=vptr") elseif (USE_SANITIZER STREQUAL "Address;Undefined" OR USE_SANITIZER STREQUAL "Undefined;Address") message(STATUS "Using Address Sanitizer and Undefined Behavior Sanitizer, expect slow down in the analysis.") add_compiler_linker_flag(REQUIRED "FSANITIZE_ADDRESS" "-fsanitize=address") add_compiler_linker_flag(REQUIRED "FSANITIZE_UNDEFINED" "-fsanitize=undefined") add_compiler_linker_flag(REQUIRED "FNO_SANITIZE_VPTR" "-fno-sanitize=vptr") elseif (USE_SANITIZER MATCHES "Memory(WithOrigins)?") message(STATUS "Using Memory Sanitizer, expect slow down in the analysis.") add_compiler_linker_flag(REQUIRED "FSANITIZE_MEMORY" "-fsanitize=memory") if(USE_SANITIZER STREQUAL "MemoryWithOrigins") add_compiler_linker_flag(REQUIRED "FSANITIZE_MEMORY_TRACK_ORIGINS" "-fsanitize-memory-track-origins") endif() elseif (USE_SANITIZER STREQUAL "Thread") message(STATUS "Using Thread Sanitizer, expect slow down in the analysis.") add_compiler_linker_flag(REQUIRED "FSANITIZE_THREAD" "-fsanitize=thread") elseif (USE_SANITIZER STREQUAL "Leak") message(STATUS "Using Leak Sanitizer, expect slow down in the analysis.") add_compiler_linker_flag(REQUIRED "FSANITIZE_LEAK" "-fsanitize=leak") else() message(FATAL_ERROR "Unsupported value of USE_SANITIZER: ${USE_SANITIZER}") endif() # Flags useful for all sanitizers add_compiler_flag(OPTIONAL "FNO_OMIT_FRAME_POINTER" "-fno-omit-frame-pointer") endif() NASA-SW-VnV-ikos-1d98c65/core/000077500000000000000000000000001473507761200155465ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/CMakeLists.txt000066400000000000000000000130511473507761200203060ustar00rootroot00000000000000#******************************************************************************* # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR) if (POLICY CMP0074) cmake_policy(SET CMP0074 NEW) endif() project(ikos-core) # # Build settings # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "In-source builds are not allowed. Please clean your source tree and try again.") endif() if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE) endif() if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "Install directory" FORCE) endif() if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "CMake generator: ${CMAKE_GENERATOR}") endif() # # Dependency checks # # Add path for custom modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") set(CUSTOM_BOOST_ROOT "" CACHE PATH "Path to custom boost installation") if (CUSTOM_BOOST_ROOT) set(BOOST_ROOT "${CUSTOM_BOOST_ROOT}") set(Boost_NO_SYSTEM_PATHS TRUE) endif() find_package(Boost 1.55.0 REQUIRED COMPONENTS unit_test_framework) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) find_package(GMP REQUIRED) include_directories(SYSTEM ${GMP_INCLUDE_DIR}) include_directories(SYSTEM ${GMPXX_INCLUDE_DIR}) find_package(TBB 2 REQUIRED) include_directories(SYSTEM ${TBB_INCLUDE_DIRS}) find_package(APRON) if (APRON_FOUND) include_directories(SYSTEM ${APRON_INCLUDE_DIRS}) endif() # # Compiler flags # include(AddFlagUtils) add_compiler_flag(REQUIRED "CXX14" "-std=c++1y") add_compiler_flag(REQUIRED "FVISIBILITY_INLINES_HIDDEN" "-fvisibility-inlines-hidden") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compiler_flag(REQUIRED "WEVERYTHING" "-Weverything") add_compiler_flag(OPTIONAL "WNO_SWITCH_ENUM" "-Wno-switch-enum") add_compiler_flag(OPTIONAL "WNO_PADDED" "-Wno-padded") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT" "-Wno-c++98-compat") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT_PEDANTIC" "-Wno-c++98-compat-pedantic") add_compiler_flag(OPTIONAL "WNO_COVERED_SWITCH_DEFAULT" "-Wno-covered-switch-default") add_compiler_flag(OPTIONAL "WNO_WEAK_VTABLES" "-Wno-weak-vtables") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") add_compiler_flag(REQUIRED "WALL" "-Wall") add_compiler_flag(REQUIRED "WEXTRA" "-Wextra") add_compiler_flag(OPTIONAL "WNO_MAYBE_UNINITIALIZED" "-Wno-maybe-uninitialized") add_compiler_flag(OPTIONAL "WNO_REDUNDANT_MOVE" "-Wno-redundant-move") endif() # # Targets # include_directories(include) # install headers install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.hpp" ) # # Unit tests # enable_testing() add_custom_target(build-core-tests) add_subdirectory(test/unit EXCLUDE_FROM_ALL) # # Doxygen # find_package(Doxygen) if (DOXYGEN_FOUND) configure_file(doc/doxygen/Doxyfile.in doc/Doxyfile @ONLY) add_custom_target(doxygen-core ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMENT "Generating IKOS CORE API documentation with Doxygen" VERBATIM ) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doc/html" DESTINATION doc/ikos OPTIONAL) endif() # # If it's the top level CMakeLists.txt, Add some aliases # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS build-core-tests) add_custom_target(doc DEPENDS doxygen-core) endif() NASA-SW-VnV-ikos-1d98c65/core/README.md000066400000000000000000000117571473507761200170400ustar00rootroot00000000000000IKOS Core ========= This folder contains implementation of the theory of Abstract Interpretation. Introduction ------------ The IKOS Core is a C++ library designed to facilitate the development of sound static analyzers based on Abstract Interpretation. Specialization of a static analyzer for an application or family of applications is critical for achieving both precision and scalability. Developing such an analyzer is arduous and requires significant expertise in Abstract Interpretation. The IKOS core library provides a generic and efficient implementation of state-of-the-art Abstract Interpretation data structures and algorithms, such as control-flow graphs, fixpoint iterators, numerical abstract domains, etc. The IKOS code is independent of a particular programming language. In order to build an effective static analyzer, one has to use the IKOS core building blocks in combination with a front-end for a particular language. Installation ------------ IKOS Core is a header-only C++ library. It can be installed independently from the other components. ### Dependencies To use IKOS Core, you will need the following dependencies: * A C++ compiler that supports C++14 (gcc >= 4.9.2 or clang >= 3.4) * CMake >= 2.8.12.2 * GMP >= 4.3.1 * Boost >= 1.55 * (Optional) TBB >= 2 * (Optional) APRON >= 0.9.10 ### Install To install IKOS Core, run the following commands in the `core` directory: ``` $ mkdir build $ cd build $ cmake -DCMAKE_INSTALL_PREFIX=/path/to/core-install-directory .. $ make install ``` ### Tests To build and run the tests, simply type: ``` $ make check ``` ### Documentation To build the documentation, you will need [Doxygen](http://www.doxygen.org). Then, simply type: ``` $ make doc $ open doc/html/index.html ``` Overview of the source code --------------------------- The following illustrates the directory structure of this folder: ``` . ├── doc │ └── doxygen ├── include │ └── ikos │ └── core │ ├── adt │ │ └── patricia_tree │ ├── domain │ │ ├── exception │ │ ├── lifetime │ │ ├── machine_int │ │ ├── memory │ │ │ └── value │ │ ├── nullity │ │ ├── numeric │ │ ├── pointer │ │ └── uninitialized │ ├── example │ │ └── machine_int │ ├── fixpoint │ ├── number │ ├── semantic │ │ ├── machine_int │ │ ├── memory │ │ └── pointer │ ├── support │ └── value │ ├── machine_int │ ├── numeric │ └── pointer └── test └── unit ├── adt │ └── patricia_tree ├── domain │ ├── machine_int │ ├── nullity │ ├── numeric │ │ └── apron │ ├── pointer │ └── uninitialized ├── example ├── number └── value ├── machine_int └── numeric ``` #### doc/ Contains Doxygen files. #### include/ * [include/ikos/core/adt](include/ikos/core/adt) contains implementation of Abstract Data Types, e.g., patricia trees. * [include/ikos/core/domain](include/ikos/core/domain) contains implementation of abstract domains. * [include/ikos/core/domain/machine_int](include/ikos/core/domain/machine_int) contains implementation of machine integer abstract domains. * [include/ikos/core/domain/memory](include/ikos/core/domain/memory) contains implementation of memory abstract domains. * [include/ikos/core/domain/numeric](include/ikos/core/domain/numeric) contains implementation of numerical abstract domains, e.g., the interval, congruence, difference-bound matrices, octagon domains, etc. * [include/ikos/core/domain/pointer](include/ikos/core/domain/pointer) contains implementation of pointer abstract domains and pointer constraints solvers. * [include/ikos/core/example](include/ikos/core/example) contains usage examples, e.g., muZQ: is a micro language for semantic modeling over integer and rational numbers. * [include/ikos/core/fixpoint](include/ikos/core/fixpoint) contains implementation of fixpoint iterators. * [include/ikos/core/number](include/ikos/core/number) contains implementation of numbers, e.g, integers, rationals and machine integers. * [include/ikos/core/semantic](include/ikos/core/semantic) contains definition of traits, e.g., the control flow graph traits. * [include/ikos/core/support](include/ikos/core/support) contains various helpers, e.g, assertions. * [include/ikos/core/value](include/ikos/core/value) contains implementation of abstract values, e.g, intervals, congruences, etc. #### test/ Contains unit tests. NASA-SW-VnV-ikos-1d98c65/core/doc/000077500000000000000000000000001473507761200163135ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/doc/doxygen/000077500000000000000000000000001473507761200177705ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/doc/doxygen/Doxyfile.in000066400000000000000000002336721473507761200221200ustar00rootroot00000000000000#******************************************************************************* # Notices: # # Copyright (c) 2016-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "IKOS CORE" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = "@PACKAGE_VERSION@" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@/doc" # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = "@CMAKE_CURRENT_SOURCE_DIR@/include" # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = "@CMAKE_CURRENT_SOURCE_DIR@/include" # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 2 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = NO # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/include" \ "@CMAKE_CURRENT_SOURCE_DIR@/doc/doxygen/mainpage.dox" # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */.git* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = detail # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 4 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = ikos::core:: #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = pdflatex \\nonstopmode\\input # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = YES # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. EXTERNAL_PAGES = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. DIA_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = NO # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of # processors available in the system. You can set it explicitly to a value # larger than 0 to get control over the balance between CPU load and processing # speed. # Minimum value: 0, maximum value: 32, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. DOT_NUM_THREADS = 0 # When you want a differently looking font n the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by # setting DOT_FONTPATH to the directory containing the font. # The default value is: Helvetica. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size (in points) of the font of # dot graphs. # Minimum value: 4, maximum value: 24, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the default font as specified with # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside the # class node. If there are many fields or methods and many nodes the graph may # become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the # number of items for each type to make the size more manageable. Set this to 0 # for no limit. Note that the threshold may be exceeded by 50% before the limit # is enforced. So when you set the threshold to 10, up to 15 fields may appear, # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. # This tag requires that the tag HAVE_DOT is set to YES. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # # Note that this requires a modern browser other than Internet Explorer. Tested # and working are Firefox, Chrome, Safari, and Opera. # Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make # the SVG files visible. Older versions of IE do not have SVG support. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). DIAFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = YES # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the reference definitions. This must be a list of .bib # files. The .bib extension is automatically appended if omitted. This # requires the bibtex tool to be installed. For LaTeX the style of the # bibliography can be controlled using LATEX_BIB_STYLE. See also \cite # for info how to create references. CITE_BIB_FILES = NASA-SW-VnV-ikos-1d98c65/core/doc/doxygen/mainpage.dox000066400000000000000000000023161473507761200222670ustar00rootroot00000000000000/// \mainpage IKOS: Inference Kernel for Open Static Analyzers /// /// \section Introduction /// Welcome to IKOS. /// /// IKOS is a C++ library designed to facilitate the development of sound static /// analyzers based on Abstract Interpretation. Specialization of a static /// analyzer for an application or family of applications is critical for /// achieving both precision and scalability. Developing such an analyzer is /// arduous and requires significant expertise in Abstract Interpretation. /// /// This documentation describes the core component of ikos: data structures /// and algorithms for state-of-the-art abstract interpretation. This includes /// control-flow graphs, fixpoint iterators and numerical abstract domains. /// /// \section Contact /// Contact us by sending an email to ikos@lists.nasa.gov /// /// \section Contributors /// * Maxime Arthaud /// * Thomas Bailleux /// * Guillaume Brat /// * Clément Decoodt /// * Arnaud Hamon /// * Jorge Navas /// * Elodie-Jane Simms /// * Nija Shi /// * Sarah Thompson /// * Arnaud Venet /// * Alexandre Wimmers /// /// \section License /// This software is released under the terms and conditions of the NASA Open /// Source Agreement (NOSA) Version 1.3 or later. NASA-SW-VnV-ikos-1d98c65/core/include/000077500000000000000000000000001473507761200171715ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/000077500000000000000000000000001473507761200201365ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/000077500000000000000000000000001473507761200210665ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/adt/000077500000000000000000000000001473507761200216365ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/adt/patricia_tree/000077500000000000000000000000001473507761200244515ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/adt/patricia_tree/map.hpp000066400000000000000000001372711473507761200257520ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Patricia tree map * * Implementation of Patricia trees based on the algorithms described in * C. Okasaki and A. Gill's paper: "Fast Mergeable Integer Maps", * Workshop on ML, September 1998, pages 77-86. * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { // forward declarations namespace patricia_tree_map_impl { // NOLINTNEXTLINE(google-build-using-namespace) using namespace patricia_tree_utils; template < typename Key, typename Value > class PatriciaTree; template < typename Key, typename Value > class PatriciaTreeIterator; template < typename Key, typename Value > inline bool empty( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree); template < typename Key, typename Value > inline std::size_t size( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree); template < typename Key, typename Value > inline boost::optional< const Value& > find_value( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const Key& key); template < typename Key, typename Value, typename Compare > inline bool leq(const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const Compare& cmp); template < typename Key, typename Value, typename Compare > inline bool equals(const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const Compare& cmp); template < typename Key, typename Value > inline std::shared_ptr< const PatriciaTree< Key, Value > > insert_or_assign( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const Key& key, const Value& value); template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > update_or_insert( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const CombiningFunction& combine, const Key& key, const Value& value); template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > update_or_ignore( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const CombiningFunction& combine, const Key& key, const Value& value); template < typename Key, typename Value > inline std::shared_ptr< const PatriciaTree< Key, Value > > erase( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const Key& key); template < typename Key, typename Value, typename UnaryOp > inline std::shared_ptr< const PatriciaTree< Key, Value > > transform( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const UnaryOp& op); template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > join( const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const CombiningFunction& combine); template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > intersect( const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const CombiningFunction& combine); template < typename Key, typename Value, typename BinaryOp > inline typename BinaryOp::ResultType binary_operation( const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const BinaryOp& op); } // end namespace patricia_tree_map_impl /// \brief An implementation of the patricia tree map data structure /// /// Requirements: /// /// Key must implement IndexableTraits /// Key must implement bool Key::operator==(const Key&) const /// Value must implement bool Value::operator==(const Value&) const template < typename Key, typename Value > class PatriciaTreeMap final { public: static_assert(IsIndexable< Key >::value, "Key must implement IndexableTraits"); private: using PatriciaTree = patricia_tree_map_impl::PatriciaTree< Key, Value >; public: using Iterator = patricia_tree_map_impl::PatriciaTreeIterator< Key, Value >; private: std::shared_ptr< const PatriciaTree > _tree; private: /// \brief Private constructor explicit PatriciaTreeMap(std::shared_ptr< const PatriciaTree > tree) : _tree(std::move(tree)) {} public: /// \brief Create an empty patricia tree map PatriciaTreeMap() = default; /// \brief Copy constructor PatriciaTreeMap(const PatriciaTreeMap&) noexcept = default; /// \brief Move constructor PatriciaTreeMap(PatriciaTreeMap&&) noexcept = default; /// \brief Copy assignment operator PatriciaTreeMap& operator=(const PatriciaTreeMap&) noexcept = default; /// \brief Move assignment operator PatriciaTreeMap& operator=(PatriciaTreeMap&&) noexcept = default; /// \brief Destructor ~PatriciaTreeMap() = default; /// \brief Return true if the map is empty bool empty() const { return patricia_tree_map_impl::empty(this->_tree); } /// \brief Return the number of elements in the map std::size_t size() const { return patricia_tree_map_impl::size(this->_tree); } /// \brief Clear the content of the map void clear() { this->_tree.reset(); } /// \brief Find the value associated with the given key boost::optional< const Value& > at(const Key& key) const { return patricia_tree_map_impl::find_value(this->_tree, key); } /// \brief Return the begin iterator over the elements of the map Iterator begin() const { return Iterator(this->_tree); } /// \brief Return the end iterator over the elements of the map Iterator end() const { return Iterator(); } /// \brief Lower or equal comparison /// /// The comparison function needs to be a callable of type: /// bool(const Value& left, const Value& right) template < typename Compare > bool leq(const PatriciaTreeMap& other, const Compare& cmp) const { return patricia_tree_map_impl::leq(this->_tree, other._tree, cmp); } /// \brief Equality comparison /// /// The comparison function should be a callable of type: /// bool(const Value& left, const Value& right) template < typename Compare > bool equals(const PatriciaTreeMap& other, const Compare& cmp) const { return patricia_tree_map_impl::equals(this->_tree, other._tree, cmp); } /// \brief Insert an element or assign a new value for the given `key` void insert_or_assign(const Key& key, const Value& value) { this->_tree = patricia_tree_map_impl::insert_or_assign(this->_tree, key, value); } /// \brief Find the value corresponding to `key` and replace its bound value /// with `combine(old_value, value)`. /// /// If the key is not found, insert (`key`, `value`). /// /// The combining function should be a callable of type: /// boost::optional< Value >(const Value& old, const Value& new) template < typename CombiningFunction > void update_or_insert(const CombiningFunction& combine, const Key& key, const Value& value) { this->_tree = patricia_tree_map_impl::update_or_insert(this->_tree, combine, key, value); } /// \brief Find the value corresponding to `key` and replace its bound value /// with `combine(old_value, value)`. /// /// If the key is not found, leave the map unchanged. /// /// The combining function should be a callable of type: /// boost::optional< Value >(const Value& old, const Value& new) template < typename CombiningFunction > void update_or_ignore(const CombiningFunction& combine, const Key& key, const Value& value) { this->_tree = patricia_tree_map_impl::update_or_ignore(this->_tree, combine, key, value); } /// \brief Remove an element from the map, if present void erase(const Key& key) { this->_tree = patricia_tree_map_impl::erase(this->_tree, key); } /// \brief Apply an unary operator on all the elements /// /// The operator should be a callable of type: /// boost::optional< Value >(const Key& key, const Value& value) template < typename UnaryOp > void transform(const UnaryOp& op) { this->_tree = patricia_tree_map_impl::transform(this->_tree, op); } /// \brief Perform the union of two patricia tree maps /// /// The combining function should be a callable of type: /// boost::optional< Value >(const Value& left, const Value& right) template < typename CombiningFunction > void join_with(const PatriciaTreeMap& other, const CombiningFunction& combine) { this->_tree = patricia_tree_map_impl::join(this->_tree, other._tree, combine); } /// \brief Perform the union of two patricia tree maps /// /// The combining function should be a callable of type: /// boost::optional< Value >(const Value& left, const Value& right) template < typename CombiningFunction > PatriciaTreeMap join(const PatriciaTreeMap& other, const CombiningFunction& combine) const { return PatriciaTreeMap( patricia_tree_map_impl::join(this->_tree, other._tree, combine)); } /// \brief Perform the intersection of two patricia tree maps /// /// The combining function should be a callable of type: /// boost::optional< Value >(const Value& left, const Value& right) template < typename CombiningFunction > void intersect_with(const PatriciaTreeMap& other, const CombiningFunction& combine) { this->_tree = patricia_tree_map_impl::intersect(this->_tree, other._tree, combine); } /// \brief Perform the intersection of two patricia tree maps /// /// The combining function should be a callable of type: /// boost::optional< Value >(const Value& left, const Value& right) template < typename CombiningFunction > PatriciaTreeMap intersect(const PatriciaTreeMap& other, const CombiningFunction& combine) const { return PatriciaTreeMap( patricia_tree_map_impl::intersect(this->_tree, other._tree, combine)); } /// \brief Perform a generic binary operation /// /// Example of binary operator: /// /// \code{.cpp} /// struct MyBinaryOp { /// // Result type /// using ResultType = ...; /// /// // Return true if the binary operator has a special behavior on /// // equality of trees /// bool has_equals() const { ... } /// /// // If has_equals() is true, return the result if two trees are equal, /// // given the tree `t` /// ResultType equals(const PatriciaTreeMap< Key, Value >& t) const { ... } /// /// // Return the result of the binary operation with an empty right hand /// // side tree, given the left hand side tree `l` /// ResultType left(const PatriciaTreeMap< Key, Value >& l) const { ... } /// /// // Return the result of the binary operation with an empty left hand /// // side tree, given the right hand side tree `r` /// ResultType right(const PatriciaTreeMap< Key, Value >& r) const { ... } /// /// // Return the result of the binary operation with a singleton /// // (`k`, `v`) as a right hand side tree, and the left hand side tree `l` /// ResultType left_with_right_leaf(const PatriciaTreeMap< Key, Value >& l, /// const Key& k, /// const Value& v) const { ... } /// /// // Return the result of the binary operation with a singleton /// // (`k`, `v`) as a left hand side tree, and the right hand side tree `r` /// ResultType right_with_left_leaf(const PatriciaTreeMap< Key, Value >& r, /// const Key& k, /// const Value& v) const { ... } /// /// // Return the result of the binary operation, given the results for /// // subtrees with separated keys /// ResultType merge(ResultType l, ResultType r) const { ... } /// }; /// \endcode template < typename BinaryOp > typename BinaryOp::ResultType binary_operation(const PatriciaTreeMap& other, const BinaryOp& op) const { return patricia_tree_map_impl::binary_operation(this->_tree, other._tree, op); } /// \brief Dump the map, for debugging purpose void dump(std::ostream& o) const { static_assert(IsDumpable< Key >::value, "Key must implement DumpableTraits"); static_assert(IsDumpable< Value >::value, "Value must implement DumpableTraits"); o << "{"; for (auto it = this->begin(), et = this->end(); it != et;) { DumpableTraits< Key >::dump(o, it->first); o << " -> "; DumpableTraits< Value >::dump(o, it->second); ++it; if (it != et) { o << "; "; } } o << "}"; } // Allow binary_operation to call the private constructor template < typename K, typename V, typename BinaryOp > friend typename BinaryOp::ResultType patricia_tree_map_impl::binary_operation( const std::shared_ptr< const patricia_tree_map_impl::PatriciaTree< K, V > >& s, const std::shared_ptr< const patricia_tree_map_impl::PatriciaTree< K, V > >& t, const BinaryOp& op); }; // end class PatriciaTreeMap namespace patricia_tree_map_impl { template < typename Key, typename Value > class PatriciaTree { private: std::size_t _size; public: explicit PatriciaTree(std::size_t size) : _size(size) {} // PatriciaTree is immutable PatriciaTree(const PatriciaTree&) = delete; PatriciaTree(PatriciaTree&&) = delete; PatriciaTree& operator=(const PatriciaTree&) = delete; PatriciaTree& operator=(PatriciaTree&&) = delete; virtual ~PatriciaTree() = default; std::size_t size() const { return this->_size; } bool is_leaf() const { return this->_size == 1; } bool is_node() const { return !this->is_leaf(); } }; // end class PatriciaTree template < typename Key, typename Value > class PatriciaTreeNode final : public PatriciaTree< Key, Value > { private: Index _prefix; Index _branching_bit; std::shared_ptr< const PatriciaTree< Key, Value > > _left_tree; std::shared_ptr< const PatriciaTree< Key, Value > > _right_tree; public: PatriciaTreeNode( Index prefix, Index branching_bit, std::shared_ptr< const PatriciaTree< Key, Value > > left_tree, std::shared_ptr< const PatriciaTree< Key, Value > > right_tree) : PatriciaTree< Key, Value >(left_tree->size() + right_tree->size()), _prefix(prefix), _branching_bit(branching_bit), _left_tree(std::move(left_tree)), _right_tree(std::move(right_tree)) {} Index prefix() const { return this->_prefix; } Index branching_bit() const { return this->_branching_bit; } const std::shared_ptr< const PatriciaTree< Key, Value > >& left_tree() const { return this->_left_tree; } const std::shared_ptr< const PatriciaTree< Key, Value > >& right_tree() const { return this->_right_tree; } }; // end class PatriciaTreeNode template < typename Key, typename Value > class PatriciaTreeLeaf final : public PatriciaTree< Key, Value > { private: std::pair< Key, Value > _pair; public: PatriciaTreeLeaf(const Key& key, const Value& value) : PatriciaTree< Key, Value >(1), _pair(key, value) {} const Key& key() const { return this->_pair.first; } const Value& value() const { return this->_pair.second; } const std::pair< Key, Value >& pair() const { return this->_pair; } }; // end class PatriciaTreeLeaf template < typename Key, typename Value > inline bool empty( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree) { return tree == nullptr; } template < typename Key, typename Value > inline std::size_t size( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree) { if (tree != nullptr) { return tree->size(); } else { return 0; } } /// \brief Return the leaf associated with the given key, or nullptr template < typename Key, typename Value > inline std::shared_ptr< const PatriciaTreeLeaf< Key, Value > > find_leaf( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const Key& key) { if (tree == nullptr) { return nullptr; } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(tree); if (leaf->key() != key) { return nullptr; } return leaf; } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(tree); if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { return find_leaf(node->left_tree(), key); } else { return find_leaf(node->right_tree(), key); } } template < typename Key, typename Value > inline boost::optional< const Value& > find_value( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const Key& key) { auto leaf = find_leaf(tree, key); if (leaf == nullptr) { return boost::none; } else { return leaf->value(); } } template < typename Key, typename Value, typename Compare > inline bool leq(const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const Compare& cmp) { if (s == t) { return true; } if (s == nullptr) { return false; } if (t == nullptr) { return true; } if (s->is_leaf()) { if (t->is_node()) { return false; } auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(s); auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(t); return s_leaf->key() == t_leaf->key() && cmp(s_leaf->value(), t_leaf->value()); } if (t->is_leaf()) { auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(t); auto s_value = find_value(s, t_leaf->key()); if (s_value) { return cmp(*s_value, t_leaf->value()); } else { return false; } } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(t); if (s_node->size() < t_node->size()) { return false; } Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { return leq(s_node->left_tree(), t_node->left_tree(), cmp) && leq(s_node->right_tree(), t_node->right_tree(), cmp); } if (m < n && match_prefix(q, p, m)) { if (is_zero_bit(q, m)) { return leq(s_node->left_tree(), t, cmp); } else { return leq(s_node->right_tree(), t, cmp); } } return false; // t contains bindings that are not in s } template < typename Key, typename Value, typename Compare > inline bool equals(const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const Compare& cmp) { if (s == t) { return true; } if (s == nullptr || t == nullptr) { return false; } if (s->is_leaf()) { if (t->is_node()) { return false; } auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(s); auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(t); return s_leaf->key() == t_leaf->key() && cmp(s_leaf->value(), t_leaf->value()); } if (t->is_leaf()) { return false; } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(t); return s_node->size() == t_node->size() && s_node->prefix() == t_node->prefix() && s_node->branching_bit() == t_node->branching_bit() && equals(s_node->left_tree(), t_node->left_tree(), cmp) && equals(s_node->right_tree(), t_node->right_tree(), cmp); } /// \brief Create a node /// /// Prevent the creation of a node with only one child. template < typename Key, typename Value > inline std::shared_ptr< const PatriciaTree< Key, Value > > make_node( Index prefix, Index branching_bit, const std::shared_ptr< const PatriciaTree< Key, Value > >& left_tree, const std::shared_ptr< const PatriciaTree< Key, Value > >& right_tree) { if (left_tree == nullptr) { return right_tree; } if (right_tree == nullptr) { return left_tree; } return std::make_shared< const PatriciaTreeNode< Key, Value > >(prefix, branching_bit, left_tree, right_tree); } /// \brief Join non-null patricia trees template < typename Key, typename Value > inline std::shared_ptr< const PatriciaTreeNode< Key, Value > > join_trees( Index prefix_s, const std::shared_ptr< const PatriciaTree< Key, Value > >& s, Index prefix_t, const std::shared_ptr< const PatriciaTree< Key, Value > >& t) { ikos_assert(s != nullptr && t != nullptr); Index m = branching_bit(prefix_s, prefix_t); if (is_zero_bit(prefix_s, m)) { return std::make_shared< const PatriciaTreeNode< Key, Value > >(mask(prefix_s, m), m, s, t); } else { return std::make_shared< const PatriciaTreeNode< Key, Value > >(mask(prefix_s, m), m, t, s); } } template < typename Key, typename Value > inline std::shared_ptr< const PatriciaTree< Key, Value > > insert_or_assign( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const Key& key, const Value& value) { if (tree == nullptr) { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, value); } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(tree); if (leaf->key() == key) { if (leaf->value() == value) { return tree; } else { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, value); } } auto new_leaf = std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, value); return join_trees< Key, Value >(IndexableTraits< Key >::index(key), new_leaf, IndexableTraits< Key >::index(leaf->key()), leaf); } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(tree); if (match_prefix(IndexableTraits< Key >::index(key), node->prefix(), node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { auto new_left_tree = insert_or_assign(node->left_tree(), key, value); if (new_left_tree == node->left_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), new_left_tree, node->right_tree()); } else { auto new_right_tree = insert_or_assign(node->right_tree(), key, value); if (new_right_tree == node->right_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), node->left_tree(), new_right_tree); } } auto new_leaf = std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, value); return join_trees< Key, Value >(IndexableTraits< Key >::index(key), new_leaf, node->prefix(), node); } template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > update_or_insert( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const CombiningFunction& combine, const Key& key, const Value& value) { if (tree == nullptr) { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, value); } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(tree); if (leaf->key() == key) { boost::optional< Value > new_value = combine(leaf->value(), value); if (new_value) { if (leaf->value() == *new_value) { return tree; } else { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, *new_value); } } return nullptr; } auto new_leaf = std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, value); return join_trees< Key, Value >(IndexableTraits< Key >::index(key), new_leaf, IndexableTraits< Key >::index(leaf->key()), leaf); } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(tree); if (match_prefix(IndexableTraits< Key >::index(key), node->prefix(), node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { auto new_left_tree = update_or_insert(node->left_tree(), combine, key, value); if (new_left_tree == node->left_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), new_left_tree, node->right_tree()); } else { auto new_right_tree = update_or_insert(node->right_tree(), combine, key, value); if (new_right_tree == node->right_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), node->left_tree(), new_right_tree); } } auto new_leaf = std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, value); return join_trees< Key, Value >(IndexableTraits< Key >::index(key), new_leaf, node->prefix(), node); } template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > update_or_ignore( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const CombiningFunction& combine, const Key& key, const Value& value) { if (tree == nullptr) { return nullptr; } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(tree); if (leaf->key() == key) { boost::optional< Value > new_value = combine(leaf->value(), value); if (new_value) { if (leaf->value() == *new_value) { return tree; } else { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(key, *new_value); } } return nullptr; } return tree; } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(tree); if (match_prefix(IndexableTraits< Key >::index(key), node->prefix(), node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { auto new_left_tree = update_or_ignore(node->left_tree(), combine, key, value); if (new_left_tree == node->left_tree()) { return node; } return make_node(node->prefix(), node->branching_bit(), new_left_tree, node->right_tree()); } else { auto new_right_tree = update_or_ignore(node->right_tree(), combine, key, value); if (new_right_tree == node->right_tree()) { return node; } return make_node(node->prefix(), node->branching_bit(), node->left_tree(), new_right_tree); } } return tree; } /// \brief Update or insert an existing leaf `t_leaf` in a tree `s` template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > update_or_insert_leaf( const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTreeLeaf< Key, Value > >& t_leaf, const CombiningFunction& combine) { if (s == t_leaf) { return s; } if (s == nullptr) { return t_leaf; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(s); if (s_leaf->key() == t_leaf->key()) { boost::optional< Value > new_value = combine(s_leaf->value(), t_leaf->value()); if (new_value) { if (s_leaf->value() == *new_value) { return std::move(s_leaf); } else if (t_leaf->value() == *new_value) { return t_leaf; } else { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(s_leaf->key(), *new_value); } } return nullptr; } return join_trees< Key, Value >(IndexableTraits< Key >::index( s_leaf->key()), s_leaf, IndexableTraits< Key >::index( t_leaf->key()), t_leaf); } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(s); if (match_prefix(IndexableTraits< Key >::index(t_leaf->key()), s_node->prefix(), s_node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(t_leaf->key()), s_node->branching_bit())) { auto new_left_tree = update_or_insert_leaf(s_node->left_tree(), t_leaf, combine); if (new_left_tree == s_node->left_tree()) { return std::move(s_node); } return make_node(s_node->prefix(), s_node->branching_bit(), new_left_tree, s_node->right_tree()); } else { auto new_right_tree = update_or_insert_leaf(s_node->right_tree(), t_leaf, combine); if (new_right_tree == s_node->right_tree()) { return std::move(s_node); } return make_node(s_node->prefix(), s_node->branching_bit(), s_node->left_tree(), new_right_tree); } } return join_trees< Key, Value >(s_node->prefix(), s_node, IndexableTraits< Key >::index(t_leaf->key()), t_leaf); } template < typename Key, typename Value > inline std::shared_ptr< const PatriciaTree< Key, Value > > erase( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const Key& key) { if (tree == nullptr) { return nullptr; } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(tree); if (leaf->key() == key) { return nullptr; } else { return tree; } } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(tree); if (match_prefix(IndexableTraits< Key >::index(key), node->prefix(), node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { auto new_left_tree = erase(node->left_tree(), key); if (new_left_tree == node->left_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), new_left_tree, node->right_tree()); } else { auto new_right_tree = erase(node->right_tree(), key); if (new_right_tree == node->right_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), node->left_tree(), new_right_tree); } } return tree; } template < typename Key, typename Value, typename UnaryOp > inline std::shared_ptr< const PatriciaTree< Key, Value > > transform( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree, const UnaryOp& op) { if (tree == nullptr) { return nullptr; } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(tree); boost::optional< Value > new_value = op(leaf->key(), leaf->value()); if (new_value) { if (leaf->value() == *new_value) { return tree; } else { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(leaf->key(), *new_value); } } return nullptr; } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(tree); auto new_left_tree = transform(node->left_tree(), op); auto new_right_tree = transform(node->right_tree(), op); if (node->left_tree() == new_left_tree && node->right_tree() == new_right_tree) { return tree; } else { return make_node(node->prefix(), node->branching_bit(), new_left_tree, new_right_tree); } } template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > join( const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const CombiningFunction& combine) { if (s == t) { return s; } if (s == nullptr) { return t; } if (t == nullptr) { return s; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(s); return update_or_insert_leaf(t, s_leaf, [=](const Value& t_value, const Value& s_value) { // reverse the parameters return combine(s_value, t_value); }); } if (t->is_leaf()) { auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(t); return update_or_insert_leaf(s, t_leaf, combine); } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(t); Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { // The two trees have the same prefix auto new_left = join(s_node->left_tree(), t_node->left_tree(), combine); auto new_right = join(s_node->right_tree(), t_node->right_tree(), combine); if (new_left == s_node->left_tree() && new_right == s_node->right_tree()) { return s; } if (new_left == t_node->left_tree() && new_right == t_node->right_tree()) { return t; } return make_node(p, m, new_left, new_right); } if (m < n && match_prefix(q, p, m)) { // q contains p, join t with a subtree of s if (is_zero_bit(q, m)) { auto new_left = join(s_node->left_tree(), t, combine); if (s_node->left_tree() == new_left) { return s; } return make_node(p, m, new_left, s_node->right_tree()); } else { auto new_right = join(s_node->right_tree(), t, combine); if (s_node->right_tree() == new_right) { return s; } return make_node(p, m, s_node->left_tree(), new_right); } } if (m > n && match_prefix(p, q, n)) { // p contains q. Merge s with a subtree of t. if (is_zero_bit(p, n)) { auto new_left = join(s, t_node->left_tree(), combine); if (t_node->left_tree() == new_left) { return t; } return make_node(q, n, new_left, t_node->right_tree()); } else { auto new_right = join(s, t_node->right_tree(), combine); if (t_node->right_tree() == new_right) { return t; } return make_node(q, n, t_node->left_tree(), new_right); } } // The prefixes disagree return join_trees(p, s, q, t); } template < typename Key, typename Value, typename CombiningFunction > inline std::shared_ptr< const PatriciaTree< Key, Value > > intersect( const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const CombiningFunction& combine) { if (s == t) { return s; } if (s == nullptr || t == nullptr) { return nullptr; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(s); auto t_leaf = find_leaf(t, s_leaf->key()); if (t_leaf) { boost::optional< Value > new_value = combine(s_leaf->value(), t_leaf->value()); if (new_value) { if (s_leaf->value() == *new_value) { return std::move(s_leaf); } else if (t_leaf->value() == *new_value) { return std::move(t_leaf); } else { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(s_leaf->key(), *new_value); } } } return nullptr; } if (t->is_leaf()) { auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(t); auto s_leaf = find_leaf(s, t_leaf->key()); if (s_leaf) { boost::optional< Value > new_value = combine(s_leaf->value(), t_leaf->value()); if (new_value) { if (s_leaf->value() == *new_value) { return std::move(s_leaf); } else if (t_leaf->value() == *new_value) { return std::move(t_leaf); } else { return std::make_shared< const PatriciaTreeLeaf< Key, Value > >(t_leaf->key(), *new_value); } } } return nullptr; } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(t); Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { // The two trees have the same prefix auto new_left = intersect(s_node->left_tree(), t_node->left_tree(), combine); auto new_right = intersect(s_node->right_tree(), t_node->right_tree(), combine); if (new_left == s_node->left_tree() && new_right == s_node->right_tree()) { return s; } if (new_left == t_node->left_tree() && new_right == t_node->right_tree()) { return t; } return make_node(p, m, new_left, new_right); } if (m < n && match_prefix(q, p, m)) { // q contains p, intersect t with a subtree of s if (is_zero_bit(q, m)) { return intersect(s_node->left_tree(), t, combine); } else { return intersect(s_node->right_tree(), t, combine); } } if (m > n && match_prefix(p, q, n)) { // p contains q, intersect s with a subtree of t if (is_zero_bit(p, n)) { return intersect(s, t_node->left_tree(), combine); } else { return intersect(s, t_node->right_tree(), combine); } } // The prefixes disagree return nullptr; } template < typename Key, typename Value, typename BinaryOp > inline typename BinaryOp::ResultType binary_operation( const std::shared_ptr< const PatriciaTree< Key, Value > >& s, const std::shared_ptr< const PatriciaTree< Key, Value > >& t, const BinaryOp& op) { if (op.has_equals() && s == t) { return op.equals(PatriciaTreeMap< Key, Value >(s)); } if (s == nullptr) { return op.right(PatriciaTreeMap< Key, Value >(t)); } if (t == nullptr) { return op.left(PatriciaTreeMap< Key, Value >(s)); } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(s); return op.right_with_left_leaf(PatriciaTreeMap< Key, Value >(t), s_leaf->key(), s_leaf->value()); } if (t->is_leaf()) { auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(t); return op.left_with_right_leaf(PatriciaTreeMap< Key, Value >(s), t_leaf->key(), t_leaf->value()); } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(t); Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { // The two trees have the same prefix return op.merge(binary_operation(s_node->left_tree(), t_node->left_tree(), op), binary_operation(s_node->right_tree(), t_node->right_tree(), op)); } if (m < n && match_prefix(q, p, m)) { // q contains p, join t with a subtree of s if (is_zero_bit(q, m)) { return op.merge(op.left( PatriciaTreeMap< Key, Value >(s_node->right_tree())), binary_operation(s_node->left_tree(), t, op)); } else { return op.merge(op.left( PatriciaTreeMap< Key, Value >(s_node->left_tree())), binary_operation(s_node->right_tree(), t, op)); } } if (m > n && match_prefix(p, q, n)) { // p contains q. Merge s with a subtree of t. if (is_zero_bit(p, n)) { return op.merge(op.right( PatriciaTreeMap< Key, Value >(t_node->right_tree())), binary_operation(s, t_node->left_tree(), op)); } else { return op.merge(op.right( PatriciaTreeMap< Key, Value >(t_node->left_tree())), binary_operation(s, t_node->right_tree(), op)); } } return op.merge(op.left(PatriciaTreeMap< Key, Value >(s)), op.right(PatriciaTreeMap< Key, Value >(t))); } template < typename Key, typename Value > class PatriciaTreeIterator final { public: // Required types for iterators using iterator_category = std::forward_iterator_tag; using value_type = const std::pair< Key, Value >; using difference_type = std::ptrdiff_t; using pointer = const std::pair< Key, Value >*; using reference = const std::pair< Key, Value >&; private: std::shared_ptr< const PatriciaTreeLeaf< Key, Value > > _leaf; std::stack< std::shared_ptr< const PatriciaTreeNode< Key, Value > > > _stack; public: /// \brief Create an end iterator PatriciaTreeIterator() = default; /// \brief Create an iterator on the given patricia tree explicit PatriciaTreeIterator( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree) { if (tree != nullptr) { this->look_for_next_leaf(tree); } } /// \brief Pre-increment the iterator PatriciaTreeIterator& operator++() { ikos_assert(this->_leaf != nullptr); if (this->_stack.empty()) { // We reached the end this->_leaf = nullptr; return *this; } // Otherwise, we pop out a branch from the stack and move to the leftmost // leaf in its right-hand subtree. auto node = this->_stack.top(); this->_stack.pop(); this->look_for_next_leaf(node->right_tree()); return *this; } /// \brief Post-increment the iterator const PatriciaTreeIterator operator++(int) { PatriciaTreeIterator r = *this; ++(*this); return r; } /// \brief Compare two iterators bool operator==(const PatriciaTreeIterator& other) const { // No need to check the stack return this->_leaf == other._leaf; } /// \brief Compare two iterators bool operator!=(const PatriciaTreeIterator& other) const { // No need to check the stack return this->_leaf != other._leaf; } /// \brief Dereference the iterator reference operator*() const { return this->_leaf->pair(); } /// \brief Dereference the iterator pointer operator->() const { return &this->_leaf->pair(); } private: /// \brief Find the leftmost leaf, store all intermediate nodes void look_for_next_leaf( const std::shared_ptr< const PatriciaTree< Key, Value > >& tree) { auto t = tree; ikos_assert(t != nullptr); while (t->is_node()) { auto node = std::static_pointer_cast< const PatriciaTreeNode< Key, Value > >(t); this->_stack.push(node); t = node->left_tree(); ikos_assert(t != nullptr); // a node always has two children } this->_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key, Value > >(t); } }; // end class PatriciaTreeIterator } // end namespace patricia_tree_map_impl } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/adt/patricia_tree/set.hpp000066400000000000000000001004051473507761200257550ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Patricia tree set * * Implementation of Patricia trees based on the algorithms described in * C. Okasaki and A. Gill's paper: "Fast Mergeable Integer Maps", * Workshop on ML, September 1998, pages 77-86. * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace core { // forward declarations namespace patricia_tree_set_impl { // NOLINTNEXTLINE(google-build-using-namespace) using namespace patricia_tree_utils; template < typename Key > class PatriciaTree; template < typename Key > class PatriciaTreeIterator; template < typename Key > inline bool empty(const std::shared_ptr< const PatriciaTree< Key > >& tree); template < typename Key > inline std::size_t size( const std::shared_ptr< const PatriciaTree< Key > >& tree); template < typename Key > inline bool contains(const std::shared_ptr< const PatriciaTree< Key > >& tree, const Key& key); template < typename Key > inline bool is_subset_of(const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t); template < typename Key > inline bool equals(const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t); template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > insert( const std::shared_ptr< const PatriciaTree< Key > >& tree, const Key& key); template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > erase( const std::shared_ptr< const PatriciaTree< Key > >& tree, const Key& key); template < typename Key, typename Predicate > inline std::shared_ptr< const PatriciaTree< Key > > filter( const std::shared_ptr< const PatriciaTree< Key > >& tree, const Predicate& pred); template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > join( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t); template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > intersect( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t); template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > difference( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t); } // end namespace patricia_tree_set_impl /// \brief An implementation of the patricia tree set data structure /// /// Requirements: /// /// Key must implement IndexableTraits /// Key must implement bool Key::operator==(const Key&) const template < typename Key > class PatriciaTreeSet final { public: static_assert(IsIndexable< Key >::value, "Key must implement IndexableTraits"); private: using PatriciaTree = patricia_tree_set_impl::PatriciaTree< Key >; public: using Iterator = patricia_tree_set_impl::PatriciaTreeIterator< Key >; private: std::shared_ptr< const PatriciaTree > _tree; private: /// \brief Private constructor explicit PatriciaTreeSet(std::shared_ptr< const PatriciaTree > tree) : _tree(std::move(tree)) {} public: /// \brief Create an empty patricia tree set PatriciaTreeSet() = default; /// \brief Create a patricia tree set with the given elements PatriciaTreeSet(std::initializer_list< Key > elements) { for (const Key& e : elements) { this->insert(e); } } /// \brief Create a patricia tree set with the content of the range [firt, /// last) template < typename InputIterator > PatriciaTreeSet(InputIterator first, InputIterator last) { for (auto it = first; it != last; ++it) { this->insert(*it); } } /// \brief Copy constructor PatriciaTreeSet(const PatriciaTreeSet&) noexcept = default; /// \brief Move constructor PatriciaTreeSet(PatriciaTreeSet&&) noexcept = default; /// \brief Copy assignment operator PatriciaTreeSet& operator=(const PatriciaTreeSet&) noexcept = default; /// \brief Move assignment operator PatriciaTreeSet& operator=(PatriciaTreeSet&&) noexcept = default; /// \brief Destructor ~PatriciaTreeSet() = default; /// \brief Return true if the set is empty bool empty() const { return patricia_tree_set_impl::empty(this->_tree); } /// \brief Return the number of elements in the set std::size_t size() const { return patricia_tree_set_impl::size(this->_tree); } /// \brief Clear the content of the set void clear() { this->_tree.reset(); } /// \brief Return true if the set contains the given key bool contains(const Key& key) const { return patricia_tree_set_impl::contains(this->_tree, key); } /// \brief Return true if the set is a subset of `other` bool is_subset_of(const PatriciaTreeSet& other) const { return patricia_tree_set_impl::is_subset_of(this->_tree, other._tree); } /// \brief Return true if the sets are equal bool equals(const PatriciaTreeSet& other) const { return patricia_tree_set_impl::equals(this->_tree, other._tree); } /// \brief Return true if the sets are equal bool operator==(const PatriciaTreeSet& other) const { return patricia_tree_set_impl::equals(this->_tree, other._tree); } /// \brief Return the begin iterator over the elements of the set Iterator begin() const { return Iterator(this->_tree); } /// \brief Return the end iterator over the elements of the set Iterator end() const { return Iterator(); } /// \brief Insert an element in the set void insert(const Key& key) { this->_tree = patricia_tree_set_impl::insert(this->_tree, key); } /// \brief Remove an element from the set void erase(const Key& key) { this->_tree = patricia_tree_set_impl::erase(this->_tree, key); } /// \brief Remove the elements for which predicate(e) returns false template < typename Predicate > void filter(const Predicate& pred) { this->_tree = patricia_tree_set_impl::filter(this->_tree, pred); } /// \brief Perform the union of two patricia tree sets void join_with(const PatriciaTreeSet& other) { this->_tree = patricia_tree_set_impl::join(this->_tree, other._tree); } /// \brief Perform the union of two patricia tree sets PatriciaTreeSet join(const PatriciaTreeSet& other) const { return PatriciaTreeSet( patricia_tree_set_impl::join(this->_tree, other._tree)); } /// \brief Perform the intersection of two patricia tree sets void intersect_with(const PatriciaTreeSet& other) { this->_tree = patricia_tree_set_impl::intersect(this->_tree, other._tree); } /// \brief Perform the intersection of two patricia tree sets PatriciaTreeSet intersect(const PatriciaTreeSet& other) const { return PatriciaTreeSet( patricia_tree_set_impl::intersect(this->_tree, other._tree)); } /// \brief Perform the difference of two patricia tree sets void difference_with(const PatriciaTreeSet& other) { this->_tree = patricia_tree_set_impl::difference(this->_tree, other._tree); } /// \brief Perform the difference of two patricia tree sets PatriciaTreeSet difference(const PatriciaTreeSet& other) const { return PatriciaTreeSet( patricia_tree_set_impl::difference(this->_tree, other._tree)); } /// \brief Dump the set, for debugging purpose void dump(std::ostream& o) const { static_assert(IsDumpable< Key >::value, "Key must implement DumpableTraits"); o << "{"; for (auto it = this->begin(), et = this->end(); it != et;) { DumpableTraits< Key >::dump(o, *it); ++it; if (it != et) { o << "; "; } } o << "}"; } }; // end class PatriciaTreeSet /// \brief Write a patricia tree set on a stream template < typename Key > inline std::ostream& operator<<(std::ostream& o, const PatriciaTreeSet< Key >& tree) { tree.dump(o); return o; } namespace patricia_tree_set_impl { template < typename Key > class PatriciaTree { private: std::size_t _size; public: explicit PatriciaTree(std::size_t size) : _size(size) {} // PatriciaTree is immutable PatriciaTree(const PatriciaTree&) = delete; PatriciaTree(PatriciaTree&&) = delete; PatriciaTree& operator=(const PatriciaTree&) = delete; PatriciaTree& operator=(PatriciaTree&&) = delete; virtual ~PatriciaTree() = default; std::size_t size() const { return this->_size; } bool is_leaf() const { return this->_size == 1; } bool is_node() const { return !this->is_leaf(); } }; // end class PatriciaTree template < typename Key > class PatriciaTreeNode final : public PatriciaTree< Key > { private: Index _prefix; Index _branching_bit; std::shared_ptr< const PatriciaTree< Key > > _left_tree; std::shared_ptr< const PatriciaTree< Key > > _right_tree; public: PatriciaTreeNode(Index prefix, Index branching_bit, std::shared_ptr< const PatriciaTree< Key > > left_tree, std::shared_ptr< const PatriciaTree< Key > > right_tree) : PatriciaTree< Key >(left_tree->size() + right_tree->size()), _prefix(prefix), _branching_bit(branching_bit), _left_tree(std::move(left_tree)), _right_tree(std::move(right_tree)) {} Index prefix() const { return this->_prefix; } Index branching_bit() const { return this->_branching_bit; } const std::shared_ptr< const PatriciaTree< Key > >& left_tree() const { return this->_left_tree; } const std::shared_ptr< const PatriciaTree< Key > >& right_tree() const { return this->_right_tree; } }; // end class PatriciaTreeNode template < typename Key > class PatriciaTreeLeaf final : public PatriciaTree< Key > { private: Key _key; public: explicit PatriciaTreeLeaf(Key key) : PatriciaTree< Key >(1), _key(std::move(key)) {} const Key& key() const { return this->_key; } }; // end class PatriciaTreeLeaf template < typename Key > inline bool empty(const std::shared_ptr< const PatriciaTree< Key > >& tree) { return tree == nullptr; } template < typename Key > inline std::size_t size( const std::shared_ptr< const PatriciaTree< Key > >& tree) { if (tree != nullptr) { return tree->size(); } else { return 0; } } template < typename Key > inline bool contains(const std::shared_ptr< const PatriciaTree< Key > >& tree, const Key& key) { if (tree == nullptr) { return false; } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(tree); return leaf->key() == key; } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(tree); if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { return contains(node->left_tree(), key); } else { return contains(node->right_tree(), key); } } template < typename Key > inline bool is_subset_of( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t) { if (s == t) { return true; } if (s == nullptr) { return true; } if (t == nullptr) { return false; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(s); return contains(t, s_leaf->key()); } if (t->is_leaf()) { return false; } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(t); if (s_node->size() > t_node->size()) { return false; } Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { return is_subset_of(s_node->left_tree(), t_node->left_tree()) && is_subset_of(s_node->right_tree(), t_node->right_tree()); } if (m > n && match_prefix(p, q, n)) { if (is_zero_bit(p, n)) { return is_subset_of(s_node->left_tree(), t_node->left_tree()) && is_subset_of(s_node->right_tree(), t_node->left_tree()); } else { return is_subset_of(s_node->left_tree(), t_node->right_tree()) && is_subset_of(s_node->right_tree(), t_node->right_tree()); } } return false; // s contains bindings that are not in t } template < typename Key > inline bool equals(const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t) { if (s == t) { return true; } if (s == nullptr || t == nullptr) { return false; } if (s->is_leaf()) { if (t->is_node()) { return false; } auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(s); auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(t); return s_leaf->key() == t_leaf->key(); } if (t->is_leaf()) { return false; } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(t); return s_node->size() == t_node->size() && s_node->prefix() == t_node->prefix() && s_node->branching_bit() == t_node->branching_bit() && equals(s_node->left_tree(), t_node->left_tree()) && equals(s_node->right_tree(), t_node->right_tree()); } /// \brief Create a node /// /// Prevent the creation of a node with only one child. template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > make_node( Index prefix, Index branching_bit, const std::shared_ptr< const PatriciaTree< Key > >& left_tree, const std::shared_ptr< const PatriciaTree< Key > >& right_tree) { if (left_tree == nullptr) { return right_tree; } if (right_tree == nullptr) { return left_tree; } return std::make_shared< const PatriciaTreeNode< Key > >(prefix, branching_bit, left_tree, right_tree); } /// \brief Join non-null patricia trees template < typename Key > inline std::shared_ptr< const PatriciaTreeNode< Key > > join_trees( Index prefix_s, const std::shared_ptr< const PatriciaTree< Key > >& s, Index prefix_t, const std::shared_ptr< const PatriciaTree< Key > >& t) { ikos_assert(s != nullptr && t != nullptr); Index m = branching_bit(prefix_s, prefix_t); if (is_zero_bit(prefix_s, m)) { return std::make_shared< const PatriciaTreeNode< Key > >(mask(prefix_s, m), m, s, t); } else { return std::make_shared< const PatriciaTreeNode< Key > >(mask(prefix_s, m), m, t, s); } } template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > insert( const std::shared_ptr< const PatriciaTree< Key > >& tree, const Key& key) { if (tree == nullptr) { return std::make_shared< const PatriciaTreeLeaf< Key > >(key); } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(tree); if (leaf->key() == key) { return tree; } auto new_leaf = std::make_shared< const PatriciaTreeLeaf< Key > >(key); return join_trees< Key >(IndexableTraits< Key >::index(key), new_leaf, IndexableTraits< Key >::index(leaf->key()), leaf); } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(tree); if (match_prefix(IndexableTraits< Key >::index(key), node->prefix(), node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { auto new_left_tree = insert(node->left_tree(), key); if (new_left_tree == node->left_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), new_left_tree, node->right_tree()); } else { auto new_right_tree = insert(node->right_tree(), key); if (new_right_tree == node->right_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), node->left_tree(), new_right_tree); } } auto new_leaf = std::make_shared< const PatriciaTreeLeaf< Key > >(key); return join_trees< Key >(IndexableTraits< Key >::index(key), new_leaf, node->prefix(), node); } /// \brief Insert the leaf `t_leaf` into the patricia tree `s` template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > insert_leaf( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTreeLeaf< Key > >& t_leaf) { if (s == t_leaf) { return s; } if (s == nullptr) { return t_leaf; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(s); if (s_leaf->key() == t_leaf->key()) { return std::move(s_leaf); } return join_trees< Key >(IndexableTraits< Key >::index(s_leaf->key()), s_leaf, IndexableTraits< Key >::index(t_leaf->key()), t_leaf); } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(s); if (match_prefix(IndexableTraits< Key >::index(t_leaf->key()), s_node->prefix(), s_node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(t_leaf->key()), s_node->branching_bit())) { auto new_left_tree = insert_leaf(s_node->left_tree(), t_leaf); if (new_left_tree == s_node->left_tree()) { return std::move(s_node); } return make_node(s_node->prefix(), s_node->branching_bit(), new_left_tree, s_node->right_tree()); } else { auto new_right_tree = insert_leaf(s_node->right_tree(), t_leaf); if (new_right_tree == s_node->right_tree()) { return std::move(s_node); } return make_node(s_node->prefix(), s_node->branching_bit(), s_node->left_tree(), new_right_tree); } } return join_trees< Key >(s_node->prefix(), s_node, IndexableTraits< Key >::index(t_leaf->key()), t_leaf); } template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > erase( const std::shared_ptr< const PatriciaTree< Key > >& tree, const Key& key) { if (tree == nullptr) { return nullptr; } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(tree); if (leaf->key() == key) { return nullptr; } else { return tree; } } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(tree); if (match_prefix(IndexableTraits< Key >::index(key), node->prefix(), node->branching_bit())) { if (is_zero_bit(IndexableTraits< Key >::index(key), node->branching_bit())) { auto new_left_tree = erase(node->left_tree(), key); if (new_left_tree == node->left_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), new_left_tree, node->right_tree()); } else { auto new_right_tree = erase(node->right_tree(), key); if (new_right_tree == node->right_tree()) { return std::move(node); } return make_node(node->prefix(), node->branching_bit(), node->left_tree(), new_right_tree); } } return tree; } template < typename Key, typename Predicate > inline std::shared_ptr< const PatriciaTree< Key > > filter( const std::shared_ptr< const PatriciaTree< Key > >& tree, const Predicate& pred) { if (tree == nullptr) { return nullptr; } if (tree->is_leaf()) { auto leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(tree); if (pred(leaf->key())) { return tree; } else { return nullptr; } } auto node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(tree); auto new_left_tree = filter(node->left_tree(), pred); auto new_right_tree = filter(node->right_tree(), pred); if (new_left_tree == node->left_tree() && new_right_tree == node->right_tree()) { return tree; } else { return make_node(node->prefix(), node->branching_bit(), new_left_tree, new_right_tree); } } template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > join( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t) { if (s == t) { return s; } if (s == nullptr) { return t; } if (t == nullptr) { return s; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(s); return insert_leaf(t, s_leaf); } if (t->is_leaf()) { auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(t); return insert_leaf(s, t_leaf); } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(t); Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { // The two trees have the same prefix auto new_left = join(s_node->left_tree(), t_node->left_tree()); auto new_right = join(s_node->right_tree(), t_node->right_tree()); if (new_left == s_node->left_tree() && new_right == s_node->right_tree()) { return s; } if (new_left == t_node->left_tree() && new_right == t_node->right_tree()) { return t; } return make_node(p, m, new_left, new_right); } if (m < n && match_prefix(q, p, m)) { // q contains p, join t with a subtree of s if (is_zero_bit(q, m)) { auto new_left = join(s_node->left_tree(), t); if (s_node->left_tree() == new_left) { return s; } return make_node(p, m, new_left, s_node->right_tree()); } else { auto new_right = join(s_node->right_tree(), t); if (s_node->right_tree() == new_right) { return s; } return make_node(p, m, s_node->left_tree(), new_right); } } if (m > n && match_prefix(p, q, n)) { // p contains q. Merge s with a subtree of t. if (is_zero_bit(p, n)) { auto new_left = join(s, t_node->left_tree()); if (t_node->left_tree() == new_left) { return t; } return make_node(q, n, new_left, t_node->right_tree()); } else { auto new_right = join(s, t_node->right_tree()); if (t_node->right_tree() == new_right) { return t; } return make_node(q, n, t_node->left_tree(), new_right); } } // The prefixes disagree return join_trees(p, s, q, t); } template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > intersect( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t) { if (s == t) { return s; } if (s == nullptr || t == nullptr) { return nullptr; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(s); if (contains(t, s_leaf->key())) { return s; } else { return nullptr; } } if (t->is_leaf()) { auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(t); if (contains(s, t_leaf->key())) { return t; } else { return nullptr; } } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(t); Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { // The two trees have the same prefix auto new_left = intersect(s_node->left_tree(), t_node->left_tree()); auto new_right = intersect(s_node->right_tree(), t_node->right_tree()); if (new_left == s_node->left_tree() && new_right == s_node->right_tree()) { return s; } if (new_left == t_node->left_tree() && new_right == t_node->right_tree()) { return t; } return make_node(p, m, new_left, new_right); } if (m < n && match_prefix(q, p, m)) { // q contains p, intersect t with a subtree of s if (is_zero_bit(q, m)) { return intersect(s_node->left_tree(), t); } else { return intersect(s_node->right_tree(), t); } } if (m > n && match_prefix(p, q, n)) { // p contains q, intersect s with a subtree of t if (is_zero_bit(p, n)) { return intersect(s, t_node->left_tree()); } else { return intersect(s, t_node->right_tree()); } } // The prefixes disagree return nullptr; } template < typename Key > inline std::shared_ptr< const PatriciaTree< Key > > difference( const std::shared_ptr< const PatriciaTree< Key > >& s, const std::shared_ptr< const PatriciaTree< Key > >& t) { if (s == t) { return nullptr; } if (s == nullptr) { return nullptr; } if (t == nullptr) { return s; } if (s->is_leaf()) { auto s_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(s); if (contains(t, s_leaf->key())) { return nullptr; } else { return s; } } if (t->is_leaf()) { auto t_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(t); return erase(s, t_leaf->key()); } auto s_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(s); auto t_node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(t); Index m = s_node->branching_bit(); Index n = t_node->branching_bit(); Index p = s_node->prefix(); Index q = t_node->prefix(); if (m == n && p == q) { // The two trees have the same prefix auto new_left = difference(s_node->left_tree(), t_node->left_tree()); auto new_right = difference(s_node->right_tree(), t_node->right_tree()); if (new_left == s_node->left_tree() && new_right == s_node->right_tree()) { return s; } if (new_left == t_node->left_tree() && new_right == t_node->right_tree()) { return t; } return make_node(p, m, new_left, new_right); } if (m < n && match_prefix(q, p, m)) { // q contains p, diff t with a subtree of s if (is_zero_bit(q, m)) { auto new_left = difference(s_node->left_tree(), t); if (s_node->left_tree() == new_left) { return s; } return make_node(p, m, new_left, s_node->right_tree()); } else { auto new_right = difference(s_node->right_tree(), t); if (s_node->right_tree() == new_right) { return s; } return make_node(p, m, s_node->left_tree(), new_right); } } if (m > n && match_prefix(p, q, n)) { // p contains q, diff s with a subtree of t if (is_zero_bit(p, n)) { return difference(s, t_node->left_tree()); } else { return difference(s, t_node->right_tree()); } } // The prefixes disagree return s; } template < typename Key > class PatriciaTreeIterator final { public: // Required types for iterators using iterator_category = std::forward_iterator_tag; using value_type = const Key&; using difference_type = std::ptrdiff_t; using pointer = const Key*; using reference = const Key&; private: std::shared_ptr< const PatriciaTreeLeaf< Key > > _leaf; std::stack< std::shared_ptr< const PatriciaTreeNode< Key > > > _stack; public: /// \brief Create an end iterator PatriciaTreeIterator() = default; /// \brief Create an iterator on the given patricia tree explicit PatriciaTreeIterator( const std::shared_ptr< const PatriciaTree< Key > >& tree) { if (tree != nullptr) { this->look_for_next_leaf(tree); } } /// \brief Pre-increment the iterator PatriciaTreeIterator& operator++() { ikos_assert(this->_leaf != nullptr); if (this->_stack.empty()) { // We reached the end this->_leaf = nullptr; return *this; } // Otherwise, we pop out a branch from the stack and move to the leftmost // leaf in its right-hand subtree. auto node = this->_stack.top(); this->_stack.pop(); this->look_for_next_leaf(node->right_tree()); return *this; } /// \brief Post-increment the iterator const PatriciaTreeIterator operator++(int) { PatriciaTreeIterator r = *this; ++(*this); return r; } /// \brief Compare two iterators bool operator==(const PatriciaTreeIterator& other) const { // No need to check the stack return this->_leaf == other._leaf; } /// \brief Compare two iterators bool operator!=(const PatriciaTreeIterator& other) const { // No need to check the stack return this->_leaf != other._leaf; } /// \brief Dereference the iterator reference operator*() const { return this->_leaf->key(); } /// \brief Dereference the iterator pointer operator->() const { return &this->_leaf->key(); } private: /// \brief Find the leftmost leaf, store all intermediate nodes void look_for_next_leaf( const std::shared_ptr< const PatriciaTree< Key > >& tree) { auto t = tree; ikos_assert(t != nullptr); while (t->is_node()) { auto node = std::static_pointer_cast< const PatriciaTreeNode< Key > >(t); this->_stack.push(node); t = node->left_tree(); ikos_assert(t != nullptr); // a node always has two children } this->_leaf = std::static_pointer_cast< const PatriciaTreeLeaf< Key > >(t); } }; // end class PatriciaTreeIterator } // end namespace patricia_tree_set_impl } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/adt/patricia_tree/utils.hpp000066400000000000000000000057111473507761200263260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Patricia tree utils * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { namespace patricia_tree_utils { // Requirements on the Index type defined in indexable.hpp static_assert(std::is_unsigned< Index >::value, "Index must be unsigned"); static_assert(sizeof(Index) >= sizeof(std::intptr_t), "Index must be capable of holding a pointer"); inline bool is_zero_bit(Index k, Index m) { return (k & m) == 0; } inline Index mask(Index k, Index m) { return k & (m - 1); } inline bool match_prefix(Index k, Index p, Index m) { return mask(k, m) == p; } inline Index lowest_bit(Index x) { return x & (~x + 1); } inline Index branching_bit(Index prefix0, Index prefix1) { return lowest_bit(prefix0 ^ prefix1); } } // end namespace patricia_tree_utils } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/adt/small_vector.hpp000066400000000000000000000060771473507761200250530ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Vector container optimized for a small number of elements * * It uses boost::container::small_vector if available, * otherwise falls back to std::vector. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #if BOOST_VERSION >= 105800 // Use boost::container::small_vector #include namespace ikos { namespace core { /// \brief Vector container optimized for a small number of elements template < typename T, std::size_t N, typename Allocator = boost::container::new_allocator< T > > using SmallVector = boost::container::small_vector< T, N, Allocator >; } // end namespace core } // end namespace ikos #else // Fall back to the good old std::vector #include namespace ikos { namespace core { /// \brief Vector container optimized for a small number of elements template < typename T, std::size_t N, typename Allocator = std::allocator< T > > using SmallVector = std::vector< T, Allocator >; } // end namespace core } // end namespace ikos #endif NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/adt/string_ref.hpp000066400000000000000000000054531473507761200245200ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Reference to a constant string * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { /// \brief Represents a reference to a constant string /// /// This class does not own the string data, it is expected to be used in /// situations where the character data resides in some other buffer, whose /// lifetime extends past that of the StringRef. For this reason, it is not in /// general safe to store a StringRef. using StringRef = boost::string_ref; /// \brief Append a StringRef to the end of a std::string inline std::string& operator+=(std::string& buffer, StringRef string) { return buffer.append(string.data(), string.size()); } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/000077500000000000000000000000001473507761200223355ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/abstract_domain.hpp000066400000000000000000000220711473507761200262020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Base class for abstract domains /// /// Abstract domains should be thread-safe: /// * It should be safe to call a `const` method on an abstract value shared /// between multiple threads; /// * It should be safe to copy an abstract value between multiple threads; /// * It is NOT safe to call a non-`const` method on an abstract value /// shared between multiple threads; template < typename Derived > class AbstractDomain { public: virtual ~AbstractDomain() { // Checks only when the Derived class is instantiated static_assert(std::is_base_of< AbstractDomain< Derived >, Derived >::value, "Derived must inherit from AbstractDomain"); static_assert(std::is_final< Derived >::value, "Derived must be final"); static_assert(!std::is_default_constructible< Derived >::value, "Derived must NOT be default constructible"); static_assert(std::is_copy_constructible< Derived >::value, "Derived must be copy constructible"); static_assert(std::is_move_constructible< Derived >::value, "Derived must be move constructible"); static_assert(std::is_copy_assignable< Derived >::value, "Derived must be copy assignable"); static_assert(std::is_move_assignable< Derived >::value, "Derived must be move assignable"); // Derived must provide Derived::name() static_assert(std::is_same< decltype(Derived::name()), std::string >::value, "Derived::name() does not exist"); } /// \brief Create the top abstract value AbstractDomain() = default; /// \brief Copy constructor AbstractDomain(const AbstractDomain&) noexcept = default; /// \brief Move constructor AbstractDomain(AbstractDomain&&) noexcept = default; /// \brief Copy assignment operator AbstractDomain& operator=(const AbstractDomain&) noexcept = default; /// \brief Move assignment operator AbstractDomain& operator=(AbstractDomain&&) noexcept = default; /// \brief Normalize the abstract value virtual void normalize() = 0; /// \brief Check if the abstract value is bottom /// /// Consider calling `normalize()` before calling `is_bottom()`, otherwise /// it might normalize a temporary copy. virtual bool is_bottom() const = 0; /// \brief Check if the abstract value is top virtual bool is_top() const = 0; /// \brief Set the abstract value to bottom virtual void set_to_bottom() = 0; /// \brief Set the abstract value to top virtual void set_to_top() = 0; /// \brief Partial order comparison /// /// Check for the semantic inclusion. virtual bool leq(const Derived& other) const = 0; /// \brief Equality comparison /// /// This is semantically equivalent to `a.leq(b) && b.leq(a)` virtual bool equals(const Derived& other) const = 0; /// \brief Equality comparison bool operator==(const Derived& other) const { return this->equals(other); } /// \brief Inequality comparison bool operator!=(const Derived& other) const { return !this->equals(other); } /// \brief Perform the union of two abstract values /// /// If the abstract domain is a lattice, this is the least upper bound /// operation. virtual void join_with(Derived&& other) { this->join_with(other); } /// \brief Perform the union of two abstract values /// /// If the abstract domain is a lattice, this is the least upper bound /// operation. virtual void join_with(const Derived& other) = 0; /// \brief Perform a union on a loop head /// /// Example: `pre_in.join_loop_with(pre_back)` /// /// For most abstract domains, this is equivalent to join_with. virtual void join_loop_with(Derived&& other) { this->join_with(std::move(other)); } /// \brief Perform a union on a loop head /// /// Example: `pre_in.join_loop_with(pre_back)` /// /// For most abstract domains, this is equivalent to join_with. virtual void join_loop_with(const Derived& other) { this->join_with(other); } /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm /// /// Example: `x(n).join_iter_with(x(n+1))` /// /// For most abstract domains, this is equivalent to join_with. virtual void join_iter_with(Derived&& other) { this->join_with(std::move(other)); } /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm /// /// Example: `x(n).join_iter_with(x(n+1))` /// /// For most abstract domains, this is equivalent to join_with. virtual void join_iter_with(const Derived& other) { this->join_with(other); } /// \brief Perform the widening of two abstract values /// /// If the abstract domain has finite ascending chains, one doesn't need to /// define a widening operator and can simply use the join instead. virtual void widen_with(const Derived& other) = 0; /// \brief Perform the intersection of two abstract values /// /// If the abstract domain is a lattice, this is the greatest lower bound /// operation. virtual void meet_with(const Derived& other) = 0; /// \brief Perform the narrowing of two abstract values /// /// If the abstract domain has finite descending chains, one doesn't need to /// define a narrowing operator and can simply use the meet instead. virtual void narrow_with(const Derived& other) = 0; /// \brief Perform the union of two abstract values virtual Derived join(const Derived& other) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.join_with(other); return tmp; } /// \brief Perform a union on a loop head virtual Derived join_loop(const Derived& other) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.join_loop_with(other); return tmp; } /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm virtual Derived join_iter(const Derived& other) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.join_iter_with(other); return tmp; } /// \brief Perform the widening of two abstract values virtual Derived widening(const Derived& other) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.widen_with(other); return tmp; } /// \brief Perform the intersection of two abstract values virtual Derived meet(const Derived& other) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.meet_with(other); return tmp; } /// \brief Perform the narrowing of two abstract values virtual Derived narrowing(const Derived& other) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.narrow_with(other); return tmp; } /// \brief Dump the abstract value, for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class AbstractDomain /// \brief Check if a type is an abstract domain template < typename T > struct IsAbstractDomain : std::is_base_of< AbstractDomain< T >, T > {}; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/discrete_domain.hpp000066400000000000000000000163421473507761200262050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Discrete domain based on Patricia trees * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Discrete abstract domain /// /// The implementation is based on patricia trees. template < typename Element > class DiscreteDomain final : public AbstractDomain< DiscreteDomain< Element > > { private: using PatriciaTreeSetT = PatriciaTreeSet< Element >; public: using Iterator = typename PatriciaTreeSetT::Iterator; private: PatriciaTreeSetT _set; bool _top; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top discrete domain explicit DiscreteDomain(TopTag) : _top(true) {} /// \brief Create the bottom discrete domain explicit DiscreteDomain(BottomTag) : _top(false) {} public: /// \brief Create the top discrete domain static DiscreteDomain top() { return DiscreteDomain(TopTag{}); } /// \brief Create the bottom discrete domain static DiscreteDomain bottom() { return DiscreteDomain(BottomTag{}); } /// \brief Create the discrete domain with the given elements DiscreteDomain(std::initializer_list< Element > elements) : _set(elements), _top(false) {} /// \brief Copy constructor DiscreteDomain(const DiscreteDomain&) noexcept = default; /// \brief Move constructor DiscreteDomain(DiscreteDomain&&) noexcept = default; /// \brief Copy assignment operator DiscreteDomain& operator=(const DiscreteDomain&) noexcept = default; /// \brief Move assignment operator DiscreteDomain& operator=(DiscreteDomain&&) noexcept = default; /// \brief Destructor ~DiscreteDomain() override = default; /// \brief Return the number of elements in the discrete domain std::size_t size() const { ikos_assert(!this->is_top()); return this->_set.size(); } /// \brief Begin iterator over the elements Iterator begin() const { ikos_assert(!this->is_top()); return this->_set.begin(); } /// \brief End iterator over the elements Iterator end() const { ikos_assert(!this->is_top()); return this->_set.end(); } void normalize() override {} bool is_bottom() const override { return !this->_top && this->_set.empty(); } bool is_top() const override { return this->_top; } void set_to_bottom() override { this->_top = false; this->_set.clear(); } void set_to_top() override { this->_top = true; this->_set.clear(); } bool leq(const DiscreteDomain& other) const override { if (other.is_top()) { return true; } else if (this->is_top()) { return false; } else { return this->_set.is_subset_of(other._set); } } bool equals(const DiscreteDomain& other) const override { if (this->is_top()) { return other.is_top(); } else if (other.is_top()) { return false; } else { return this->_set.equals(other._set); } } void join_with(const DiscreteDomain& other) override { if (this->is_top()) { return; } else if (other.is_top()) { this->set_to_top(); } else { this->_set.join_with(other._set); } } void widen_with(const DiscreteDomain& other) override { this->join_with(other); } void meet_with(const DiscreteDomain& other) override { if (this->is_bottom() || other.is_top()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->is_top()) { this->operator=(other); } else { this->_set.intersect_with(other._set); } } void narrow_with(const DiscreteDomain& other) override { this->meet_with(other); } /// \brief Perform the set difference void difference_with(const DiscreteDomain& other) { if (other.is_top()) { this->set_to_bottom(); } else if (this->is_top()) { return; } else { this->_set.difference_with(other._set); } } /// \brief Perform the set difference DiscreteDomain difference(const DiscreteDomain& other) const { DiscreteDomain tmp(*this); tmp.difference_with(other); return tmp; } /// \brief Add an element in the discrete domain void add(const Element& e) { if (this->is_top()) { return; } this->_set.insert(e); } /// \brief Remove an element from the discrete domain void remove(const Element& e) { if (this->is_top()) { return; } this->_set.erase(e); } /// \brief If the discrete domain is a singleton {e}, return e, otherwise /// return boost::none boost::optional< Element > singleton() const { if (!this->is_top() && this->_set.size() == 1) { return *this->_set.begin(); } else { return boost::none; } } /// \brief Return true if the discrete domain contains e bool contains(const Element& e) const { return this->is_top() || this->_set.contains(e); } void dump(std::ostream& o) const override { if (this->is_top()) { o << "⊤"; } else if (this->is_bottom()) { o << "⊥"; } else { this->_set.dump(o); } } static std::string name() { return "discrete domain"; } }; // end class DiscreteDomain } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/domain_product.hpp000066400000000000000000000414521473507761200260630ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Products of abstract domains * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Domain product of 2 abstract domains template < typename Domain1, typename Domain2 > class DomainProduct2 final : public AbstractDomain< DomainProduct2< Domain1, Domain2 > > { public: static_assert(IsAbstractDomain< Domain1 >::value, "Domain1 must implement AbstractDomain"); static_assert(IsAbstractDomain< Domain2 >::value, "Domain2 must implement AbstractDomain"); private: Domain1 _first; Domain2 _second; public: /// \brief Create the abstract value with the given abstract values DomainProduct2(Domain1 first, Domain2 second) : _first(std::move(first)), _second(std::move(second)) { this->normalize(); } /// \brief Copy constructor DomainProduct2(const DomainProduct2&) noexcept( (std::is_nothrow_copy_constructible< Domain1 >::value) && (std::is_nothrow_copy_constructible< Domain2 >::value)) = default; /// \brief Move constructor DomainProduct2(DomainProduct2&&) noexcept( (std::is_nothrow_move_constructible< Domain1 >::value) && (std::is_nothrow_move_constructible< Domain2 >::value)) = default; /// \brief Copy assignment operator DomainProduct2& operator=(const DomainProduct2&) noexcept( (std::is_nothrow_copy_assignable< Domain1 >::value) && (std::is_nothrow_copy_assignable< Domain2 >::value)) = default; /// \brief Move assignment operator DomainProduct2& operator=(DomainProduct2&&) noexcept( (std::is_nothrow_move_assignable< Domain1 >::value) && (std::is_nothrow_move_assignable< Domain2 >::value)) = default; /// \brief Destructor ~DomainProduct2() override = default; /// \brief Return the first abstract value /// /// Note: does not normalize. const Domain1& first() const { return this->_first; } /// \brief Return the first abstract value /// /// Note: does not normalize. Domain1& first() { return this->_first; } /// \brief Return the second abstract value /// /// Note: does not normalize. const Domain2& second() const { return this->_second; } /// \brief Return the second abstract value /// /// Note: does not normalize. Domain2& second() { return this->_second; } void normalize() override { this->_first.normalize(); if (this->_first.is_bottom()) { this->_second.set_to_bottom(); return; } this->_second.normalize(); if (this->_second.is_bottom()) { this->_first.set_to_bottom(); return; } } bool is_bottom() const override { return this->_first.is_bottom() || this->_second.is_bottom(); } bool is_top() const override { return this->_first.is_top() && this->_second.is_top(); } void set_to_bottom() override { this->_first.set_to_bottom(); this->_second.set_to_bottom(); } void set_to_top() override { this->_first.set_to_top(); this->_second.set_to_top(); } bool leq(const DomainProduct2& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_first.leq(other._first) && this->_second.leq(other._second); } } bool equals(const DomainProduct2& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_first.equals(other._first) && this->_second.equals(other._second); } } void join_with(DomainProduct2&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_first.join_with(std::move(other._first)); this->_second.join_with(std::move(other._second)); } } void join_with(const DomainProduct2& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_first.join_with(other._first); this->_second.join_with(other._second); } } void join_loop_with(DomainProduct2&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_first.join_loop_with(std::move(other._first)); this->_second.join_loop_with(std::move(other._second)); } } void join_loop_with(const DomainProduct2& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_first.join_loop_with(other._first); this->_second.join_loop_with(other._second); } } void join_iter_with(DomainProduct2&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_first.join_iter_with(std::move(other._first)); this->_second.join_iter_with(std::move(other._second)); } } void join_iter_with(const DomainProduct2& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_first.join_iter_with(other._first); this->_second.join_iter_with(other._second); } } void widen_with(const DomainProduct2& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_first.widen_with(other._first); this->_second.widen_with(other._second); } } void meet_with(const DomainProduct2& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_first.meet_with(other._first); this->_second.meet_with(other._second); } } void narrow_with(const DomainProduct2& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_first.narrow_with(other._first); this->_second.narrow_with(other._second); } } DomainProduct2 join(const DomainProduct2& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return DomainProduct2(this->_first.join(other._first), this->_second.join(other._second)); } } DomainProduct2 join_loop(const DomainProduct2& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return DomainProduct2(this->_first.join_loop(other._first), this->_second.join_loop(other._second)); } } DomainProduct2 join_iter(const DomainProduct2& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return DomainProduct2(this->_first.join_iter(other._first), this->_second.join_iter(other._second)); } } DomainProduct2 widening(const DomainProduct2& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return DomainProduct2(this->_first.widening(other._first), this->_second.widening(other._second)); } } DomainProduct2 meet(const DomainProduct2& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return DomainProduct2(this->_first.meet(other._first), this->_second.meet(other._second)); } } DomainProduct2 narrowing(const DomainProduct2& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return DomainProduct2(this->_first.narrowing(other._first), this->_second.narrowing(other._second)); } } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "("; this->_first.dump(o); o << ", "; this->_second.dump(o); o << ")"; } } static std::string name() { return "product " + Domain1::name() + " x " + Domain2::name(); } }; // end class DomainProduct2 /// \brief Domain product of 3 abstract domains template < typename Domain1, typename Domain2, typename Domain3 > class DomainProduct3 final : public AbstractDomain< DomainProduct3< Domain1, Domain2, Domain3 > > { public: static_assert(IsAbstractDomain< Domain1 >::value, "Domain1 must implement AbstractDomain"); static_assert(IsAbstractDomain< Domain2 >::value, "Domain2 must implement AbstractDomain"); static_assert(IsAbstractDomain< Domain3 >::value, "Domain3 must implement AbstractDomain"); private: using Product12 = DomainProduct2< Domain1, Domain2 >; using Product123 = DomainProduct2< Product12, Domain3 >; private: Product123 _product; private: /// \brief Private constructor explicit DomainProduct3(Product123 product) : _product(std::move(product)) {} public: /// \brief Create the abstract value with the given abstract values DomainProduct3(Domain1 first, Domain2 second, Domain3 third) : _product(Product12(std::move(first), std::move(second)), std::move(third)) {} /// \brief Copy constructor DomainProduct3(const DomainProduct3&) noexcept( (std::is_nothrow_copy_constructible< Domain1 >::value) && (std::is_nothrow_copy_constructible< Domain2 >::value) && (std::is_nothrow_copy_constructible< Domain3 >::value)) = default; /// \brief Move constructor DomainProduct3(DomainProduct3&&) noexcept( (std::is_nothrow_move_constructible< Domain1 >::value) && (std::is_nothrow_move_constructible< Domain2 >::value) && (std::is_nothrow_move_constructible< Domain3 >::value)) = default; /// \brief Copy assignment operator DomainProduct3& operator=(const DomainProduct3&) noexcept( (std::is_nothrow_copy_assignable< Domain1 >::value) && (std::is_nothrow_copy_assignable< Domain2 >::value) && (std::is_nothrow_copy_assignable< Domain3 >::value)) = default; /// \brief Move assignment operator DomainProduct3& operator=(DomainProduct3&&) noexcept( (std::is_nothrow_move_assignable< Domain1 >::value) && (std::is_nothrow_move_assignable< Domain2 >::value) && (std::is_nothrow_move_assignable< Domain3 >::value)) = default; /// \brief Destructor ~DomainProduct3() override = default; /// \brief Return the first abstract value /// /// Note: does not normalize. const Domain1& first() const { return this->_product.first().first(); } /// \brief Return the first abstract value /// /// Note: does not normalize. Domain1& first() { return this->_product.first().first(); } /// \brief Return the second abstract value /// /// Note: does not normalize. const Domain2& second() const { return this->_product.first().second(); } /// \brief Return the second abstract value /// /// Note: does not normalize. Domain2& second() { return this->_product.first().second(); } /// \brief Return the third abstract value /// /// Note: does not normalize. const Domain3& third() const { return this->_product.second(); } /// \brief Return the third abstract value /// /// Note: does not normalize. Domain3& third() { return this->_product.second(); } void normalize() override { this->_product.normalize(); } bool is_bottom() const override { return this->_product.is_bottom(); } bool is_top() const override { return this->_product.is_top(); } void set_to_bottom() override { this->_product.set_to_bottom(); } void set_to_top() override { this->_product.set_to_top(); } bool leq(const DomainProduct3& other) const override { return this->_product.leq(other._product); } bool equals(const DomainProduct3& other) const override { return this->_product.equals(other._product); } void join_with(DomainProduct3&& other) override { this->_product.join_with(std::move(other._product)); } void join_with(const DomainProduct3& other) override { this->_product.join_with(other._product); } void join_loop_with(DomainProduct3&& other) override { this->_product.join_loop_with(std::move(other._product)); } void join_loop_with(const DomainProduct3& other) override { this->_product.join_loop_with(other._product); } void join_iter_with(DomainProduct3&& other) override { this->_product.join_iter_with(std::move(other._product)); } void join_iter_with(const DomainProduct3& other) override { this->_product.join_iter_with(other._product); } void widen_with(const DomainProduct3& other) override { this->_product.widen_with(other._product); } void meet_with(const DomainProduct3& other) override { this->_product.meet_with(other._product); } void narrow_with(const DomainProduct3& other) override { this->_product.narrow_with(other._product); } DomainProduct3 join(const DomainProduct3& other) const override { return DomainProduct3(this->_product.join(other._product)); } DomainProduct3 join_loop(const DomainProduct3& other) const override { return DomainProduct3(this->_product.join_loop(other._product)); } DomainProduct3 join_iter(const DomainProduct3& other) const override { return DomainProduct3(this->_product.join_iter(other._product)); } DomainProduct3 widening(const DomainProduct3& other) const override { return DomainProduct3(this->_product.widening(other._product)); } DomainProduct3 meet(const DomainProduct3& other) const override { return DomainProduct3(this->_product.meet(other._product)); } DomainProduct3 narrowing(const DomainProduct3& other) const override { return DomainProduct3(this->_product.narrowing(other._product)); } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "("; this->first().dump(o); o << ", "; this->second().dump(o); o << ", "; this->third().dump(o); o << ")"; } } static std::string name() { return "product " + Domain1::name() + " x " + Domain2::name() + " x " + Domain3::name(); } }; // end class DomainProduct3 } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/exception/000077500000000000000000000000001473507761200243335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/exception/abstract_domain.hpp000066400000000000000000000146261473507761200302070ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for abstract domains keeping track of exceptions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace exception { /// \brief Base class for abstract domains supporting exceptions template < typename UnderlyingDomain, typename Derived > class AbstractDomain : public core::AbstractDomain< Derived > { public: static_assert(core::IsAbstractDomain< UnderlyingDomain >::value, "UnderlyingDomain must implement core::AbstractDomain"); public: /// \brief Underlying abstract domain using UnderlyingDomainT = UnderlyingDomain; /// \brief Create the top abstract value AbstractDomain() = default; /// \brief Copy constructor AbstractDomain(const AbstractDomain&) noexcept = default; /// \brief Move constructor AbstractDomain(AbstractDomain&&) noexcept = default; /// \brief Copy assignment operator AbstractDomain& operator=(const AbstractDomain&) noexcept = default; /// \brief Move assignment operator AbstractDomain& operator=(AbstractDomain&&) noexcept = default; /// \brief Provide access to the normal execution flow state virtual UnderlyingDomain& normal() = 0; /// \brief Provide access to the normal execution flow state virtual const UnderlyingDomain& normal() const = 0; /// \brief Provide access to the state of all uncaught exceptions virtual UnderlyingDomain& caught_exceptions() = 0; /// \brief Provide access to the state of all uncaught exceptions virtual const UnderlyingDomain& caught_exceptions() const = 0; /// \brief Provide access to the state of all propagated exceptions virtual UnderlyingDomain propagated_exceptions() = 0; /// \brief Provide access to the state of all propagated exceptions virtual const UnderlyingDomain& propagated_exceptions() const = 0; /// \brief Check if the normal execution flow abstract value is bottom virtual bool is_normal_flow_bottom() const = 0; /// \brief Check if the normal execution flow abstract value is top virtual bool is_normal_flow_top() const = 0; /// \brief Set the normal execution flow state to bottom virtual void set_normal_flow_to_bottom() = 0; /// \brief Set the normal execution flow state to top virtual void set_normal_flow_to_top() = 0; /// \brief Check if the state of all uncaught exceptions is bottom virtual bool is_caught_exceptions_bottom() const = 0; /// \brief Check if the state of all uncaught exceptions is top virtual bool is_caught_exceptions_top() const = 0; /// \brief Set the state of uncaught exceptions to bottom virtual void set_caught_exceptions_to_bottom() = 0; /// \brief Set the state of uncaught exceptions to top virtual void set_caught_exceptions_to_top() = 0; /// \brief Check if the state of all propagated exceptions is bottom virtual bool is_propagated_exceptions_bottom() const = 0; /// \brief Check if the state of all propagated exceptions exceptions is top virtual bool is_propagated_exceptions_top() const = 0; /// \brief Set the state of all propagated exceptions to bottom virtual void set_propagated_exceptions_to_bottom() = 0; /// \brief Set the state of all propagated exceptions to top virtual void set_propagated_exceptions_to_top() = 0; /// \brief Merge propagated exceptions in caught exceptions virtual void merge_propagated_in_caught_exceptions() = 0; /// \brief Merge caught exceptions in propagated exceptions virtual void merge_caught_in_propagated_exceptions() = 0; /// \brief Execute the normal branch after an invoke virtual void enter_normal() = 0; /// \brief Execute the exception branch after an invoke virtual void enter_catch() = 0; /// \brief Disregard the pending exceptions virtual void ignore_exceptions() = 0; /// \brief Throw an exception virtual void throw_exception() = 0; /// \brief Resume/re-throw an exception virtual void resume_exception() = 0; }; // end class AbstractDomain /// \brief Check if a type is an exception abstract domain template < typename T, typename = void > struct IsAbstractDomain : std::false_type {}; template < typename T > struct IsAbstractDomain< T, void_t< typename T::UnderlyingDomainT > > : std::is_base_of< exception::AbstractDomain< typename T::UnderlyingDomainT, T >, T > {}; } // end namespace exception } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/exception/exception.hpp000066400000000000000000000411321473507761200270430ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of an abstract domain keeping track of exceptions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace exception { /// \brief Exception abstract domain /// /// This is basically implemented as a triple (normal, propagated, caught) of /// abstract domains: /// * **normal** represents the normal execution flow state; /// * **caught_exceptions** represents the state of uncaught exceptions; /// * **propagated_exceptions** represents the state of caught exceptions /// that are propagated through the control flow graph. template < typename UnderlyingDomain > class ExceptionDomain final : public exception::AbstractDomain< UnderlyingDomain, ExceptionDomain< UnderlyingDomain > > { private: /// \brief Represents the normal execution flow state UnderlyingDomain _normal; /// \brief Represents the state of uncaught exceptions UnderlyingDomain _caught_exceptions; /// \brief Represents the state of caught exceptions that are propagated /// through the control flow graph UnderlyingDomain _propagated_exceptions; public: /// \brief Create an abstract value with the given underlying abstract values /// /// \param normal Represents the normal execution flow state /// \param caught_exceptions Represents the state of uncaught exceptions /// \param propagated_exceptions Represents the state of caught exceptions /// that are propagated through the control flow graph. ExceptionDomain(UnderlyingDomain normal, UnderlyingDomain caught_exceptions, UnderlyingDomain propagated_exceptions) : _normal(std::move(normal)), _caught_exceptions(std::move(caught_exceptions)), _propagated_exceptions(std::move(propagated_exceptions)) {} /// \brief Copy constructor ExceptionDomain(const ExceptionDomain&) noexcept( std::is_nothrow_copy_constructible< UnderlyingDomain >::value) = default; /// \brief Move constructor ExceptionDomain(ExceptionDomain&&) noexcept( std::is_nothrow_move_constructible< UnderlyingDomain >::value) = default; /// \brief Copy assignment operator ExceptionDomain& operator=(const ExceptionDomain&) noexcept( std::is_nothrow_copy_assignable< UnderlyingDomain >::value) = default; /// \brief Move assignment operator ExceptionDomain& operator=(ExceptionDomain&&) noexcept( std::is_nothrow_move_assignable< UnderlyingDomain >::value) = default; /// \brief Destructor ~ExceptionDomain() override = default; /// \name Implement core abstract domain methods /// @{ void normalize() override { this->_normal.normalize(); this->_caught_exceptions.normalize(); this->_propagated_exceptions.normalize(); } bool is_bottom() const override { return this->_normal.is_bottom() && this->_caught_exceptions.is_bottom() && this->_propagated_exceptions.is_bottom(); } bool is_top() const override { return this->_normal.is_top() && this->_caught_exceptions.is_top() && this->_propagated_exceptions.is_top(); } void set_to_bottom() override { this->_normal.set_to_bottom(); this->_caught_exceptions.set_to_bottom(); this->_propagated_exceptions.set_to_bottom(); } void set_to_top() override { this->_normal.set_to_top(); this->_caught_exceptions.set_to_top(); this->_propagated_exceptions.set_to_top(); } bool leq(const ExceptionDomain& other) const override { return this->_normal.leq(other._normal) && this->_caught_exceptions.leq(other._caught_exceptions) && this->_propagated_exceptions.leq(other._propagated_exceptions); } bool equals(const ExceptionDomain& other) const override { return this->_normal.equals(other._normal) && this->_caught_exceptions.equals(other._caught_exceptions) && this->_propagated_exceptions.equals(other._propagated_exceptions); } void join_with(ExceptionDomain&& other) override { this->_normal.join_with(std::move(other._normal)); this->_caught_exceptions.join_with(std::move(other._caught_exceptions)); this->_propagated_exceptions.join_with( std::move(other._propagated_exceptions)); } void join_with(const ExceptionDomain& other) override { this->_normal.join_with(other._normal); this->_caught_exceptions.join_with(other._caught_exceptions); this->_propagated_exceptions.join_with(other._propagated_exceptions); } void join_loop_with(ExceptionDomain&& other) override { this->_normal.join_loop_with(std::move(other._normal)); this->_caught_exceptions.join_loop_with( std::move(other._caught_exceptions)); this->_propagated_exceptions.join_loop_with( std::move(other._propagated_exceptions)); } void join_loop_with(const ExceptionDomain& other) override { this->_normal.join_loop_with(other._normal); this->_caught_exceptions.join_loop_with(other._caught_exceptions); this->_propagated_exceptions.join_loop_with(other._propagated_exceptions); } void join_iter_with(ExceptionDomain&& other) override { this->_normal.join_iter_with(std::move(other._normal)); this->_caught_exceptions.join_iter_with( std::move(other._caught_exceptions)); this->_propagated_exceptions.join_iter_with( std::move(other._propagated_exceptions)); } void join_iter_with(const ExceptionDomain& other) override { this->_normal.join_iter_with(other._normal); this->_caught_exceptions.join_iter_with(other._caught_exceptions); this->_propagated_exceptions.join_iter_with(other._propagated_exceptions); } void widen_with(const ExceptionDomain& other) override { this->_normal.widen_with(other._normal); this->_caught_exceptions.widen_with(other._caught_exceptions); this->_propagated_exceptions.widen_with(other._propagated_exceptions); } /// \brief Perform the widening of two abstract values with a threshold template < typename Threshold > void widen_threshold_with(const ExceptionDomain& other, const Threshold& threshold) { this->_normal.widen_threshold_with(other._normal, threshold); this->_caught_exceptions.widen_threshold_with(other._caught_exceptions, threshold); this->_propagated_exceptions .widen_threshold_with(other._propagated_exceptions, threshold); } /// \brief Perform the widening of two abstract values with a threshold template < typename Threshold > ExceptionDomain widening_threshold(const ExceptionDomain& other, const Threshold& threshold) const { return ExceptionDomain(this->_normal.widening_threshold(other._normal, threshold), this->_caught_exceptions .widening_threshold(other._caught_exceptions, threshold), this->_propagated_exceptions .widening_threshold(other._propagated_exceptions, threshold)); } void meet_with(const ExceptionDomain& other) override { this->_normal.meet_with(other._normal); this->_caught_exceptions.meet_with(other._caught_exceptions); this->_propagated_exceptions.meet_with(other._propagated_exceptions); } void narrow_with(const ExceptionDomain& other) override { this->_normal.narrow_with(other._normal); this->_caught_exceptions.narrow_with(other._caught_exceptions); this->_propagated_exceptions.narrow_with(other._propagated_exceptions); } /// \brief Perform the narrowing of two abstract values with a threshold template < typename Threshold > void narrow_threshold_with(const ExceptionDomain& other, const Threshold& threshold) { this->_normal.narrow_threshold_with(other._normal, threshold); this->_caught_exceptions.narrow_threshold_with(other._caught_exceptions, threshold); this->_propagated_exceptions .narrow_threshold_with(other._propagated_exceptions, threshold); } /// \brief Perform the narrowing of two abstract values with a threshold template < typename Threshold > ExceptionDomain narrowing_threshold(const ExceptionDomain& other, const Threshold& threshold) const { return ExceptionDomain(this->_normal.narrowing_threshold(other._normal, threshold), this->_caught_exceptions .narrowing_threshold(other._caught_exceptions, threshold), this->_propagated_exceptions .narrowing_threshold(other ._propagated_exceptions, threshold)); } ExceptionDomain join(const ExceptionDomain& other) const override { return ExceptionDomain(this->_normal.join(other._normal), this->_caught_exceptions.join( other._caught_exceptions), this->_propagated_exceptions.join( other._propagated_exceptions)); } ExceptionDomain join_loop(const ExceptionDomain& other) const override { return ExceptionDomain(this->_normal.join_loop(other._normal), this->_caught_exceptions.join_loop( other._caught_exceptions), this->_propagated_exceptions.join_loop( other._propagated_exceptions)); } ExceptionDomain join_iter(const ExceptionDomain& other) const override { return ExceptionDomain(this->_normal.join_iter(other._normal), this->_caught_exceptions.join_iter( other._caught_exceptions), this->_propagated_exceptions.join_iter( other._propagated_exceptions)); } ExceptionDomain widening(const ExceptionDomain& other) const override { return ExceptionDomain(this->_normal.widening(other._normal), this->_caught_exceptions.widening( other._caught_exceptions), this->_propagated_exceptions.widening( other._propagated_exceptions)); } ExceptionDomain meet(const ExceptionDomain& other) const override { return ExceptionDomain(this->_normal.meet(other._normal), this->_caught_exceptions.meet( other._caught_exceptions), this->_propagated_exceptions.meet( other._propagated_exceptions)); } ExceptionDomain narrowing(const ExceptionDomain& other) const override { return ExceptionDomain(this->_normal.narrowing(other._normal), this->_caught_exceptions.narrowing( other._caught_exceptions), this->_propagated_exceptions.narrowing( other._propagated_exceptions)); } /// @} /// \name Implement exception abstract domain methods /// @{ UnderlyingDomain& normal() override { return this->_normal; } const UnderlyingDomain& normal() const override { return this->_normal; } UnderlyingDomain& caught_exceptions() override { return this->_caught_exceptions; } const UnderlyingDomain& caught_exceptions() const override { return this->_caught_exceptions; } UnderlyingDomain propagated_exceptions() override { return this->_propagated_exceptions; } const UnderlyingDomain& propagated_exceptions() const override { return this->_propagated_exceptions; } bool is_normal_flow_bottom() const override { return this->_normal.is_bottom(); } bool is_normal_flow_top() const override { return this->_normal.is_top(); } void set_normal_flow_to_bottom() override { this->_normal.set_to_bottom(); } void set_normal_flow_to_top() override { this->_normal.set_to_top(); } bool is_caught_exceptions_bottom() const override { return this->_caught_exceptions.is_bottom(); } bool is_caught_exceptions_top() const override { return this->_caught_exceptions.is_top(); } void set_caught_exceptions_to_bottom() override { this->_caught_exceptions.set_to_bottom(); } void set_caught_exceptions_to_top() override { this->_caught_exceptions.set_to_top(); } bool is_propagated_exceptions_bottom() const override { return this->_propagated_exceptions.is_bottom(); } bool is_propagated_exceptions_top() const override { return this->_propagated_exceptions.is_top(); } void set_propagated_exceptions_to_bottom() override { this->_propagated_exceptions.set_to_bottom(); } void set_propagated_exceptions_to_top() override { this->_propagated_exceptions.set_to_top(); } void merge_propagated_in_caught_exceptions() override { this->_caught_exceptions.join_with(this->_propagated_exceptions); this->_propagated_exceptions.set_to_bottom(); } void merge_caught_in_propagated_exceptions() override { this->_propagated_exceptions.join_with(this->_caught_exceptions); this->_caught_exceptions.set_to_bottom(); } void enter_normal() override { this->_caught_exceptions.set_to_bottom(); } void enter_catch() override { std::swap(this->_normal, this->_caught_exceptions); this->_caught_exceptions.set_to_bottom(); this->_propagated_exceptions.set_to_bottom(); } void ignore_exceptions() override { this->_caught_exceptions.set_to_bottom(); this->_propagated_exceptions.set_to_bottom(); } void throw_exception() override { this->_caught_exceptions.join_with(this->_normal); this->_normal.set_to_bottom(); } void resume_exception() override { this->_caught_exceptions.join_with(this->_normal); this->_normal.set_to_bottom(); } /// @} void dump(std::ostream& o) const override { o << "(normal="; this->_normal.dump(o); o << ", caught_exceptions="; this->_caught_exceptions.dump(o); o << ", propagated_exceptions="; this->_propagated_exceptions.dump(o); o << ")"; } static std::string name() { return "exception domain of " + UnderlyingDomain::name(); } }; // end class ExceptionDomain } // end namespace exception } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/lifetime/000077500000000000000000000000001473507761200241335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/lifetime/abstract_domain.hpp000066400000000000000000000100661473507761200300010ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief Generic API for abstract domains keeping track of memory location * lifetimes * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace lifetime { /// \brief Base class for abstract domains keeping track of memory location /// lifetimes template < typename MemoryLocationRef, typename Derived > class AbstractDomain : public core::AbstractDomain< Derived > { public: static_assert(core::IsMemoryLocation< MemoryLocationRef >::value, "MemoryLocationRef does not meet the requirements for memory " "location types"); public: /// \brief Assign `m = allocated` virtual void assign_allocated(MemoryLocationRef m) = 0; /// \brief Assign `m = deallocated` virtual void assign_deallocated(MemoryLocationRef m) = 0; /// \brief Add the constraint `m == allocated` virtual void assert_allocated(MemoryLocationRef m) = 0; /// \brief Add the constraint `m == deallocated` virtual void assert_deallocated(MemoryLocationRef m) = 0; /// \brief Return true if `m` is allocated, otherwise false virtual bool is_allocated(MemoryLocationRef m) const = 0; /// \brief Return true if `m` is deallocated, otherwise false virtual bool is_deallocated(MemoryLocationRef m) const = 0; /// \brief Set the lifetime of a memory location virtual void set(MemoryLocationRef m, const Lifetime& value) = 0; /// \brief Forget the lifetime of a memory location virtual void forget(MemoryLocationRef m) = 0; /// \brief Get the lifetime value for the given memory location virtual Lifetime get(MemoryLocationRef m) const = 0; }; // end class AbstractDomain /// \brief Check if a type is a lifetime abstract domain template < typename T, typename MemoryLocationRef > struct IsAbstractDomain : std::is_base_of< lifetime::AbstractDomain< MemoryLocationRef, T >, T > {}; } // end namespace lifetime } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/lifetime/dummy.hpp000066400000000000000000000125371473507761200260070ustar00rootroot00000000000000/****************************************************************************** * * \file * \brief A dummy lifetime abstract domain that is either top or bottom * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { namespace lifetime { /// \brief Dummy lifetime abstract domain that is either top or bottom /// /// This can be used to disable a lifetime analysis in a generic implementation template < typename MemoryLocationRef > class DummyDomain final : public lifetime::AbstractDomain< MemoryLocationRef, DummyDomain< MemoryLocationRef > > { private: bool _is_bottom; private: /// \brief Private constructor explicit DummyDomain(bool is_bottom) : _is_bottom(is_bottom) {} public: /// \brief Create the top abstract value static DummyDomain top() { return DummyDomain(false); } /// \brief Create the bottom abstract value static DummyDomain bottom() { return DummyDomain(true); } /// \brief Copy constructor DummyDomain(const DummyDomain&) noexcept = default; /// \brief Move constructor DummyDomain(DummyDomain&&) noexcept = default; /// \brief Copy assignment operator DummyDomain& operator=(const DummyDomain&) noexcept = default; /// \brief Move assignment operator DummyDomain& operator=(DummyDomain&&) noexcept = default; /// \brief Destructor ~DummyDomain() override = default; void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->_is_bottom; } void set_to_bottom() override { this->_is_bottom = true; } void set_to_top() override { this->_is_bottom = false; } bool leq(const DummyDomain& other) const override { return static_cast< int >(this->_is_bottom) >= static_cast< int >(other._is_bottom); } bool equals(const DummyDomain& other) const override { return this->_is_bottom == other._is_bottom; } void join_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom && other._is_bottom); } void widen_with(const DummyDomain& other) override { this->join_with(other); } void meet_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom || other._is_bottom); } void narrow_with(const DummyDomain& other) override { this->meet_with(other); } void assign_allocated(MemoryLocationRef) override {} void assign_deallocated(MemoryLocationRef) override {} void assert_allocated(MemoryLocationRef) override {} void assert_deallocated(MemoryLocationRef) override {} bool is_allocated(MemoryLocationRef) const override { return this->_is_bottom; } bool is_deallocated(MemoryLocationRef) const override { return this->_is_bottom; } void set(MemoryLocationRef, const Lifetime& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void forget(MemoryLocationRef) override {} Lifetime get(MemoryLocationRef) const override { if (this->_is_bottom) { return Lifetime::bottom(); } else { return Lifetime::top(); } } void dump(std::ostream& o) const override { if (this->_is_bottom) { o << "⊥"; } else { o << "T"; } } static std::string name() { return "dummy lifetime domain"; } }; // end class DummyDomain } // end namespace lifetime } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/lifetime/separate_domain.hpp000066400000000000000000000140571473507761200300060ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of an abstract domain keeping track of memory location * lifetimes using a separate domain. * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace lifetime { /// \brief Lifetime separate abstract domain /// /// Implementation of the lifetime abstract domain interface using /// a separate domain. template < typename MemoryLocationRef > class SeparateDomain final : public lifetime::AbstractDomain< MemoryLocationRef, SeparateDomain< MemoryLocationRef > > { private: using SeparateDomainT = core::SeparateDomain< MemoryLocationRef, Lifetime >; public: using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit SeparateDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static SeparateDomain top() { return SeparateDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static SeparateDomain bottom() { return SeparateDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor SeparateDomain(const SeparateDomain&) noexcept = default; /// \brief Move constructor SeparateDomain(SeparateDomain&&) noexcept = default; /// \brief Copy assignment operator SeparateDomain& operator=(const SeparateDomain&) noexcept = default; /// \brief Move assignment operator SeparateDomain& operator=(SeparateDomain&&) noexcept = default; /// \brief Destructor ~SeparateDomain() override = default; /// \brief Begin iterator over the pairs (memory location, lifetime) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (memory location, lifetime) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const SeparateDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const SeparateDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const SeparateDomain& other) override { this->_inv.join_with(other._inv); } void widen_with(const SeparateDomain& other) override { this->_inv.widen_with(other._inv); } void meet_with(const SeparateDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const SeparateDomain& other) override { this->_inv.narrow_with(other._inv); } void assign_allocated(MemoryLocationRef m) override { this->_inv.set(m, Lifetime::allocated()); } void assign_deallocated(MemoryLocationRef m) override { this->_inv.set(m, Lifetime::deallocated()); } void assert_allocated(MemoryLocationRef m) override { this->_inv.refine(m, Lifetime::allocated()); } void assert_deallocated(MemoryLocationRef m) override { this->_inv.refine(m, Lifetime::deallocated()); } bool is_allocated(MemoryLocationRef m) const override { Lifetime value = this->_inv.get(m); return value.is_bottom() || value.is_allocated(); } bool is_deallocated(MemoryLocationRef m) const override { Lifetime value = this->_inv.get(m); return value.is_bottom() || value.is_deallocated(); } void set(MemoryLocationRef m, const Lifetime& value) override { this->_inv.set(m, value); } void forget(MemoryLocationRef m) override { this->_inv.forget(m); } Lifetime get(MemoryLocationRef m) const override { return this->_inv.get(m); } void dump(std::ostream& o) const override { return this->_inv.dump(o); } static std::string name() { return "lifetime domain"; } }; // end class SeparateDomain } // end namespace lifetime } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/000077500000000000000000000000001473507761200246135ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/abstract_domain.hpp000066400000000000000000000233301473507761200304570ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for machine integer abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Base class for machine integer abstract domains template < typename VariableRef, typename Derived > class AbstractDomain : public core::AbstractDomain< Derived > { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); static_assert(machine_int::IsVariable< VariableRef >::value, "VariableRef must implement machine_int::VariableTraits"); public: using LinearExpressionT = LinearExpression< MachineInt, VariableRef >; public: /// \brief Perform the widening of two abstract values with a threshold virtual void widen_threshold_with(const Derived& other, const MachineInt& threshold) = 0; /// \brief Perform the widening of two abstract values with a threshold virtual Derived widening_threshold(const Derived& other, const MachineInt& threshold) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.widen_threshold_with(other, threshold); return tmp; } /// \brief Perform the narrowing of two abstract values with a threshold virtual void narrow_threshold_with(const Derived& other, const MachineInt& threshold) = 0; /// \brief Perform the narrowing of two abstract values with a threshold virtual Derived narrowing_threshold(const Derived& other, const MachineInt& threshold) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.narrow_threshold_with(other, threshold); return tmp; } /// \brief Assign `x = n` virtual void assign(VariableRef x, const MachineInt& n) = 0; /// \brief Assign `x = y` virtual void assign(VariableRef x, VariableRef y) = 0; /// \brief Assign `x = e` /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of `x`. virtual void assign(VariableRef x, const LinearExpressionT& e) = 0; /// \brief Apply `x = op y` virtual void apply(UnaryOperator op, VariableRef x, VariableRef y) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) = 0; // \brief Add the constraint `x pred y` virtual void add(Predicate pred, VariableRef x, VariableRef y) = 0; // \brief Add the constraint `x pred y` virtual void add(Predicate pred, VariableRef x, const MachineInt& y) = 0; // \brief Add the constraint `x pred y` virtual void add(Predicate pred, const MachineInt& x, VariableRef y) { switch (pred) { case Predicate::EQ: { this->add(Predicate::EQ, y, x); } break; case Predicate::NE: { this->add(Predicate::NE, y, x); } break; case Predicate::GT: { this->add(Predicate::LT, y, x); } break; case Predicate::GE: { this->add(Predicate::LE, y, x); } break; case Predicate::LT: { this->add(Predicate::GT, y, x); } break; case Predicate::LE: { this->add(Predicate::GE, y, x); } break; } } /// \brief Set the interval value of a variable virtual void set(VariableRef x, const Interval& value) = 0; /// \brief Set the congruence value of a variable virtual void set(VariableRef x, const Congruence& value) = 0; /// \brief Set the interval-congruence value of a variable virtual void set(VariableRef x, const IntervalCongruence& value) = 0; /// \brief Refine the value of a variable with an interval virtual void refine(VariableRef x, const Interval& value) = 0; /// \brief Refine the value of a variable with a congruence virtual void refine(VariableRef x, const Congruence& value) = 0; /// \brief Refine the value of a variable with an interval-congruence virtual void refine(VariableRef x, const IntervalCongruence& value) = 0; /// \brief Forget a variable virtual void forget(VariableRef x) = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the value of `x` as an interval virtual Interval to_interval(VariableRef x) const = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the linear expression `e` as an interval /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual Interval to_interval(const LinearExpressionT& e) const = 0; /// \brief Projection to a congruence /// /// Return an overapproximation of the value of `x` as a congruence virtual Congruence to_congruence(VariableRef x) const = 0; /// \brief Projection to a congruence /// /// Return an overapproximation of the linear expression `e` as a congruence /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual Congruence to_congruence(const LinearExpressionT& e) const = 0; /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the value of `x` as an interval-congruence virtual IntervalCongruence to_interval_congruence(VariableRef x) const = 0; /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the linear expression `e` as an /// interval-congruence /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const = 0; /// \name Non-negative loop counter abstract domain methods /// @{ /// \brief Mark the variable `x` as a non-negative loop counter virtual void counter_mark(VariableRef /*x*/) {} /// \brief Mark the variable `x` as a normal variable, without losing /// information virtual void counter_unmark(VariableRef /*x*/) {} /// \brief Initialize a non-negative loop counter: `x = c` /// /// Precondition: `c >= 0` virtual void counter_init(VariableRef x, const MachineInt& c) { this->assign(x, c); } /// \brief Increment a non-negative loop counter counter: `x += k` /// /// Precondition: `k >= 0` virtual void counter_incr(VariableRef x, const MachineInt& k) { this->apply(BinaryOperator::Add, x, x, k); } /// \brief Forget a non-negative loop counter virtual void counter_forget(VariableRef x) { this->forget(x); } /// @} }; // end class AbstractDomain /// \brief Check if a type is a machine integer abstract domain template < typename T, typename VariableRef > struct IsAbstractDomain : std::is_base_of< machine_int::AbstractDomain< VariableRef, T >, T > {}; } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/congruence.hpp000066400000000000000000000241161473507761200274600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Standard domain of congruences for machine integers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Machine integer congruence abstract domain template < typename VariableRef > class CongruenceDomain final : public machine_int::AbstractDomain< VariableRef, CongruenceDomain< VariableRef > > { private: using Parent = machine_int::AbstractDomain< VariableRef, CongruenceDomain< VariableRef > >; using SeparateDomainT = machine_int::SeparateDomain< VariableRef, Congruence >; public: using LinearExpressionT = LinearExpression< MachineInt, VariableRef >; using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit CongruenceDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static CongruenceDomain top() { return CongruenceDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static CongruenceDomain bottom() { return CongruenceDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor CongruenceDomain(const CongruenceDomain&) noexcept = default; /// \brief Move constructor CongruenceDomain(CongruenceDomain&&) noexcept = default; /// \brief Copy assignment operator CongruenceDomain& operator=(const CongruenceDomain&) noexcept = default; /// \brief Move assignment operator CongruenceDomain& operator=(CongruenceDomain&&) noexcept = default; /// \brief Destructor ~CongruenceDomain() override = default; /// \brief Begin iterator over the pairs (variable, congruence) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, congruence) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const CongruenceDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const CongruenceDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const CongruenceDomain& other) override { this->_inv.join_with(other._inv); } void widen_with(const CongruenceDomain& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const CongruenceDomain& other, const MachineInt& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const CongruenceDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const CongruenceDomain& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const CongruenceDomain& other, const MachineInt& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } void assign(VariableRef x, const MachineInt& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(UnaryOperator op, VariableRef x, VariableRef y) override { this->_inv.apply(op, x, y); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(Predicate pred, VariableRef x, VariableRef y) override { if (this->is_bottom()) { return; } Congruence xc = this->_inv.get(x); Congruence yc = this->_inv.get(y); switch (pred) { case Predicate::EQ: { Congruence c = xc.meet(yc); this->_inv.set(x, c); this->_inv.set(y, c); } break; case Predicate::NE: { if (x == y) { this->set_to_bottom(); return; } } break; case Predicate::GT: { this->add(Predicate::LT, y, x); } break; case Predicate::GE: { this->add(Predicate::LE, y, x); } break; case Predicate::LT: { if (x == y) { this->set_to_bottom(); return; } } break; case Predicate::LE: { // nothing } break; } } void add(Predicate pred, VariableRef x, const MachineInt& y) override { if (this->is_bottom()) { return; } Congruence xc = this->_inv.get(x); Congruence yc(y); switch (pred) { case Predicate::EQ: { this->_inv.set(x, xc.meet(yc)); } break; case Predicate::NE: { // nothing } break; case Predicate::GT: { // nothing } break; case Predicate::GE: { // nothing } break; case Predicate::LT: { // nothing } break; case Predicate::LE: { // nothing } break; } } void add(Predicate pred, const MachineInt& x, VariableRef y) override { Parent::add(pred, x, y); } void set(VariableRef x, const Interval& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< MachineInt > n = value.singleton(); if (n) { this->_inv.set(x, Congruence(*n)); } else { this->forget(x); } } } void set(VariableRef x, const Congruence& value) override { this->_inv.set(x, value); } void set(VariableRef x, const IntervalCongruence& value) override { this->_inv.set(x, value.congruence()); } void refine(VariableRef x, const Interval& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruence iv(value, this->_inv.get(x)); this->_inv.set(x, iv.congruence()); } } void refine(VariableRef x, const Congruence& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const IntervalCongruence& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruence iv = IntervalCongruence(this->_inv.get(x)).meet(value); this->_inv.set(x, iv.congruence()); } } void forget(VariableRef x) override { this->_inv.forget(x); } Interval to_interval(VariableRef x) const override { return this->to_interval_congruence(x).interval(); } Interval to_interval(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).interval(); } Congruence to_congruence(VariableRef x) const override { return this->_inv.get(x); } Congruence to_congruence(const LinearExpressionT& e) const override { return this->_inv.project(e); } IntervalCongruence to_interval_congruence(VariableRef x) const override { return IntervalCongruence(this->_inv.get(x)); } IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const override { return IntervalCongruence(this->_inv.project(e)); } void dump(std::ostream& o) const override { return this->_inv.dump(o); } static std::string name() { return "congruence domain"; } }; // end class CongruenceDomain } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/dummy.hpp000066400000000000000000000210241473507761200264560ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief A dummy machine integer abstract domain that is either top or bottom * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { namespace machine_int { /// \brief Dummy machine integer abstract domain that is either top or bottom template < typename VariableRef > class DummyDomain final : public machine_int::AbstractDomain< VariableRef, DummyDomain< VariableRef > > { private: using VariableTrait = machine_int::VariableTraits< VariableRef >; using LinearExpressionT = LinearExpression< MachineInt, VariableRef >; private: bool _is_bottom; private: /// \brief Private constructor explicit DummyDomain(bool is_bottom) : _is_bottom(is_bottom) {} public: /// \brief Create the top abstract value static DummyDomain top() { return DummyDomain(false); } /// \brief Create the bottom abstract value static DummyDomain bottom() { return DummyDomain(true); } /// \brief Copy constructor DummyDomain(const DummyDomain&) noexcept = default; /// \brief Move constructor DummyDomain(DummyDomain&&) noexcept = default; /// \brief Copy assignment operator DummyDomain& operator=(const DummyDomain&) noexcept = default; /// \brief Move assignment operator DummyDomain& operator=(DummyDomain&&) noexcept = default; /// \brief Destructor ~DummyDomain() override = default; void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->_is_bottom; } void set_to_bottom() override { this->_is_bottom = true; } void set_to_top() override { this->_is_bottom = false; } bool leq(const DummyDomain& other) const override { return static_cast< int >(this->_is_bottom) >= static_cast< int >(other._is_bottom); } bool equals(const DummyDomain& other) const override { return this->_is_bottom == other._is_bottom; } void join_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom && other._is_bottom); } void widen_with(const DummyDomain& other) override { this->join_with(other); } void widen_threshold_with(const DummyDomain& other, const MachineInt& /*threshold*/) override { this->join_with(other); } void meet_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom || other._is_bottom); } void narrow_with(const DummyDomain& other) override { this->meet_with(other); } void narrow_threshold_with(const DummyDomain& other, const MachineInt& /*threshold*/) override { this->meet_with(other); } void assign(VariableRef, const MachineInt&) override {} void assign(VariableRef, VariableRef) override {} void assign(VariableRef, const LinearExpressionT&) override {} void apply(UnaryOperator, VariableRef, VariableRef) override {} void apply(BinaryOperator, VariableRef, VariableRef, VariableRef) override {} void apply(BinaryOperator, VariableRef, VariableRef, const MachineInt&) override {} void apply(BinaryOperator, VariableRef, const MachineInt&, VariableRef) override {} void add(Predicate, VariableRef, VariableRef) override {} void add(Predicate, VariableRef, const MachineInt&) override {} void add(Predicate, const MachineInt&, VariableRef) override {} void set(VariableRef, const Interval& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void set(VariableRef, const Congruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void set(VariableRef, const IntervalCongruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void refine(VariableRef, const Interval& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void refine(VariableRef, const Congruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void refine(VariableRef, const IntervalCongruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void forget(VariableRef) override {} Interval to_interval(VariableRef x) const override { if (this->_is_bottom) { return Interval::bottom(VariableTrait::bit_width(x), VariableTrait::sign(x)); } else { return Interval::top(VariableTrait::bit_width(x), VariableTrait::sign(x)); } } Interval to_interval(const LinearExpressionT& e) const override { if (this->_is_bottom) { return Interval::bottom(e.constant().bit_width(), e.constant().sign()); } else { return Interval::top(e.constant().bit_width(), e.constant().sign()); } } Congruence to_congruence(VariableRef x) const override { if (this->_is_bottom) { return Congruence::bottom(VariableTrait::bit_width(x), VariableTrait::sign(x)); } else { return Congruence::top(VariableTrait::bit_width(x), VariableTrait::sign(x)); } } Congruence to_congruence(const LinearExpressionT& e) const override { if (this->_is_bottom) { return Congruence::bottom(e.constant().bit_width(), e.constant().sign()); } else { return Congruence::top(e.constant().bit_width(), e.constant().sign()); } } IntervalCongruence to_interval_congruence(VariableRef x) const override { if (this->_is_bottom) { return IntervalCongruence::bottom(VariableTrait::bit_width(x), VariableTrait::sign(x)); } else { return IntervalCongruence::top(VariableTrait::bit_width(x), VariableTrait::sign(x)); } } IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const override { if (this->_is_bottom) { return IntervalCongruence::bottom(e.constant().bit_width(), e.constant().sign()); } else { return IntervalCongruence::top(e.constant().bit_width(), e.constant().sign()); } } void dump(std::ostream& o) const override { if (this->_is_bottom) { o << "⊥"; } else { o << "T"; } } static std::string name() { return "dummy machine integer domain"; } }; // end class DummyDomain } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/interval.hpp000066400000000000000000000306501473507761200271540ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Standard domain of intervals for machine integers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Trim the bounds of the given interval inline Interval trim_bound(const Interval& i, const MachineInt& b) { assert_compatible(i, b); ikos_assert(!i.is_bottom()); if (i.lb() == b) { if (b.is_max()) { return Interval::bottom(b.bit_width(), b.sign()); } else { return Interval(b + MachineInt(1, b.bit_width(), b.sign()), i.ub()); } } else if (i.ub() == b) { ikos_assert(!b.is_min()); return Interval(i.lb(), b - MachineInt(1, b.bit_width(), b.sign())); } else { return i; } } /// \brief Machine integer interval abstract domain template < typename VariableRef > class IntervalDomain final : public machine_int::AbstractDomain< VariableRef, IntervalDomain< VariableRef > > { private: using Parent = machine_int::AbstractDomain< VariableRef, IntervalDomain< VariableRef > >; using SeparateDomainT = machine_int::SeparateDomain< VariableRef, Interval >; using VariableTrait = machine_int::VariableTraits< VariableRef >; public: using LinearExpressionT = LinearExpression< MachineInt, VariableRef >; using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit IntervalDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static IntervalDomain top() { return IntervalDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static IntervalDomain bottom() { return IntervalDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor IntervalDomain(const IntervalDomain&) noexcept = default; /// \brief Move constructor IntervalDomain(IntervalDomain&&) noexcept = default; /// \brief Copy assignment operator IntervalDomain& operator=(const IntervalDomain&) noexcept = default; /// \brief Move assignment operator IntervalDomain& operator=(IntervalDomain&&) noexcept = default; /// \brief Destructor ~IntervalDomain() override = default; /// \brief Begin iterator over the pairs (variable, interval) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, interval) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const IntervalDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const IntervalDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const IntervalDomain& other) override { this->_inv.join_with(other._inv); } void widen_with(const IntervalDomain& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const IntervalDomain& other, const MachineInt& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const IntervalDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const IntervalDomain& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const IntervalDomain& other, const MachineInt& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } void assign(VariableRef x, const MachineInt& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(UnaryOperator op, VariableRef x, VariableRef y) override { this->_inv.apply(op, x, y); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(Predicate pred, VariableRef x, VariableRef y) override { if (this->is_bottom()) { return; } Interval xi = this->_inv.get(x); Interval yi = this->_inv.get(y); switch (pred) { case Predicate::EQ: { Interval i = xi.meet(yi); this->_inv.set(x, i); this->_inv.set(y, i); } break; case Predicate::NE: { if (x == y) { this->set_to_bottom(); return; } if (xi.singleton()) { this->_inv.set(y, trim_bound(yi, *xi.singleton())); } if (yi.singleton()) { this->_inv.set(x, trim_bound(xi, *yi.singleton())); } } break; case Predicate::GT: { this->add(Predicate::LT, y, x); } break; case Predicate::GE: { this->add(Predicate::LE, y, x); } break; case Predicate::LT: { if (x == y) { this->set_to_bottom(); return; } if (yi.ub().is_min() || xi.lb().is_max()) { this->set_to_bottom(); return; } MachineInt int_min = MachineInt::min(xi.bit_width(), xi.sign()); MachineInt int_max = MachineInt::max(xi.bit_width(), xi.sign()); MachineInt one(1, xi.bit_width(), xi.sign()); this->_inv.refine(x, Interval(int_min, yi.ub() - one)); this->_inv.refine(y, Interval(xi.lb() + one, int_max)); } break; case Predicate::LE: { this->_inv.refine(x, yi.lower_half_line()); this->_inv.refine(y, xi.upper_half_line()); } break; } } void add(Predicate pred, VariableRef x, const MachineInt& y) override { if (this->is_bottom()) { return; } Interval xi = this->_inv.get(x); Interval yi(y); switch (pred) { case Predicate::EQ: { Interval i = xi.meet(yi); this->_inv.set(x, i); } break; case Predicate::NE: { this->_inv.set(x, trim_bound(xi, y)); } break; case Predicate::GT: { if (y.is_max()) { this->set_to_bottom(); return; } MachineInt int_max = MachineInt::max(xi.bit_width(), xi.sign()); MachineInt one(1, xi.bit_width(), xi.sign()); this->_inv.refine(x, Interval(y + one, int_max)); } break; case Predicate::GE: { this->_inv.refine(x, yi.upper_half_line()); } break; case Predicate::LT: { if (y.is_min()) { this->set_to_bottom(); return; } MachineInt int_min = MachineInt::min(xi.bit_width(), xi.sign()); MachineInt one(1, xi.bit_width(), xi.sign()); this->_inv.refine(x, Interval(int_min, y - one)); } break; case Predicate::LE: { this->_inv.refine(x, yi.lower_half_line()); } break; } } void add(Predicate pred, const MachineInt& x, VariableRef y) override { Parent::add(pred, x, y); } void set(VariableRef x, const Interval& value) override { this->_inv.set(x, value); } void set(VariableRef x, const Congruence& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< MachineInt > n = value.singleton(); if (n) { this->_inv.set(x, Interval(*n)); } else { this->forget(x); } } } void set(VariableRef x, const IntervalCongruence& value) override { this->_inv.set(x, value.interval()); } void refine(VariableRef x, const Interval& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const Congruence& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruence iv(this->_inv.get(x), value); this->_inv.set(x, iv.interval()); } } void refine(VariableRef x, const IntervalCongruence& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruence iv = IntervalCongruence(this->_inv.get(x)).meet(value); this->_inv.set(x, iv.interval()); } } void forget(VariableRef x) override { this->_inv.forget(x); } Interval to_interval(VariableRef x) const override { return this->_inv.get(x); } Interval to_interval(const LinearExpressionT& e) const override { return this->_inv.project(e); } Congruence to_congruence(VariableRef x) const override { return this->to_interval_congruence(x).congruence(); } Congruence to_congruence(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).congruence(); } IntervalCongruence to_interval_congruence(VariableRef x) const override { return IntervalCongruence(this->_inv.get(x)); } IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const override { // Result type uint64_t bit_width = e.constant().bit_width(); Signedness sign = e.constant().sign(); if (this->is_bottom()) { return IntervalCongruence::bottom(bit_width, sign); } IntervalCongruence r(e.constant()); for (const auto& term : e) { r = machine_int::add(r, machine_int::mul(IntervalCongruence(term.second), IntervalCongruence( this->_inv.get(term.first) .cast(bit_width, sign)))); } return r; } void dump(std::ostream& o) const override { return this->_inv.dump(o); } static std::string name() { return "interval domain"; } }; // end class IntervalDomain } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/interval_congruence.hpp000066400000000000000000000267211473507761200313700ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Reduced product of intervals and congruences on machine integers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Trim the bounds of the given interval-congruence inline IntervalCongruence trim_bound(const IntervalCongruence& ic, const MachineInt& b) { return IntervalCongruence(trim_bound(ic.interval(), b), ic.to_z_congruence()); } /// \brief Reduced product of intervals and congruences on machine integers template < typename VariableRef > class IntervalCongruenceDomain final : public machine_int::AbstractDomain< VariableRef, IntervalCongruenceDomain< VariableRef > > { private: using Parent = machine_int::AbstractDomain< VariableRef, IntervalCongruenceDomain< VariableRef > >; using SeparateDomainT = machine_int::SeparateDomain< VariableRef, IntervalCongruence >; public: using LinearExpressionT = LinearExpression< MachineInt, VariableRef >; using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit IntervalCongruenceDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static IntervalCongruenceDomain top() { return IntervalCongruenceDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static IntervalCongruenceDomain bottom() { return IntervalCongruenceDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor IntervalCongruenceDomain(const IntervalCongruenceDomain&) noexcept = default; /// \brief Move constructor IntervalCongruenceDomain(IntervalCongruenceDomain&&) noexcept = default; /// \brief Copy assignment operator IntervalCongruenceDomain& operator=( const IntervalCongruenceDomain&) noexcept = default; /// \brief Move assignment operator IntervalCongruenceDomain& operator=(IntervalCongruenceDomain&&) noexcept = default; /// \brief Destructor ~IntervalCongruenceDomain() override = default; /// \brief Begin iterator over the pairs (variable, interval-congruence) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, interval-congruence) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const IntervalCongruenceDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const IntervalCongruenceDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const IntervalCongruenceDomain& other) override { this->_inv.join_with(other._inv); } void widen_with(const IntervalCongruenceDomain& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const IntervalCongruenceDomain& other, const MachineInt& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const IntervalCongruenceDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const IntervalCongruenceDomain& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const IntervalCongruenceDomain& other, const MachineInt& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } void assign(VariableRef x, const MachineInt& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(UnaryOperator op, VariableRef x, VariableRef y) override { this->_inv.apply(op, x, y); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(Predicate pred, VariableRef x, VariableRef y) override { if (this->is_bottom()) { return; } IntervalCongruence xic = this->_inv.get(x); IntervalCongruence yic = this->_inv.get(y); switch (pred) { case Predicate::EQ: { IntervalCongruence ic = xic.meet(yic); this->_inv.set(x, ic); this->_inv.set(y, ic); } break; case Predicate::NE: { if (x == y) { this->set_to_bottom(); return; } if (xic.singleton()) { this->_inv.set(y, trim_bound(yic, *xic.singleton())); } if (yic.singleton()) { this->_inv.set(x, trim_bound(xic, *yic.singleton())); } } break; case Predicate::GT: { this->add(Predicate::LT, y, x); } break; case Predicate::GE: { this->add(Predicate::LE, y, x); } break; case Predicate::LT: { if (x == y) { this->set_to_bottom(); return; } if (yic.ub().is_min() || xic.lb().is_max()) { this->set_to_bottom(); return; } MachineInt int_min = MachineInt::min(xic.bit_width(), xic.sign()); MachineInt int_max = MachineInt::max(xic.bit_width(), xic.sign()); MachineInt one(1, xic.bit_width(), xic.sign()); this->refine(x, Interval(int_min, yic.ub() - one)); this->refine(y, Interval(xic.lb() + one, int_max)); } break; case Predicate::LE: { this->refine(x, yic.interval().lower_half_line()); this->refine(y, xic.interval().upper_half_line()); } break; } } void add(Predicate pred, VariableRef x, const MachineInt& y) override { if (this->is_bottom()) { return; } IntervalCongruence xic = this->_inv.get(x); IntervalCongruence yic(y); switch (pred) { case Predicate::EQ: { IntervalCongruence ic = xic.meet(yic); this->_inv.set(x, ic); } break; case Predicate::NE: { this->_inv.set(x, trim_bound(xic, y)); } break; case Predicate::GT: { if (y.is_max()) { this->set_to_bottom(); return; } MachineInt int_max = MachineInt::max(xic.bit_width(), xic.sign()); MachineInt one(1, xic.bit_width(), xic.sign()); this->refine(x, Interval(y + one, int_max)); } break; case Predicate::GE: { this->refine(x, yic.interval().upper_half_line()); } break; case Predicate::LT: { if (y.is_min()) { this->set_to_bottom(); return; } MachineInt int_min = MachineInt::min(xic.bit_width(), xic.sign()); MachineInt one(1, xic.bit_width(), xic.sign()); this->refine(x, Interval(int_min, y - one)); } break; case Predicate::LE: { this->refine(x, yic.interval().lower_half_line()); } break; } } void add(Predicate pred, const MachineInt& x, VariableRef y) override { Parent::add(pred, x, y); } void set(VariableRef x, const Interval& value) override { this->_inv.set(x, IntervalCongruence(value)); } void set(VariableRef x, const Congruence& value) override { this->_inv.set(x, IntervalCongruence(value)); } void set(VariableRef x, const IntervalCongruence& value) override { this->_inv.set(x, value); } void refine(VariableRef x, const Interval& value) override { this->_inv.refine(x, IntervalCongruence(value)); } void refine(VariableRef x, const Congruence& value) override { this->_inv.refine(x, IntervalCongruence(value)); } void refine(VariableRef x, const IntervalCongruence& value) override { this->_inv.refine(x, value); } void forget(VariableRef x) override { this->_inv.forget(x); } Interval to_interval(VariableRef x) const override { return this->_inv.get(x).interval(); } Interval to_interval(const LinearExpressionT& e) const override { return this->_inv.project(e).interval(); } Congruence to_congruence(VariableRef x) const override { return this->_inv.get(x).congruence(); } Congruence to_congruence(const LinearExpressionT& e) const override { return this->_inv.project(e).congruence(); } IntervalCongruence to_interval_congruence(VariableRef x) const override { return this->_inv.get(x); } IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const override { return this->_inv.project(e); } void dump(std::ostream& o) const override { return this->_inv.dump(o); } static std::string name() { return "interval congruence domain"; } }; // end class IntervalCongruenceDomain } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/numeric_domain_adapter.hpp000066400000000000000000000735001473507761200320220ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Numerical abstract domain adapter for machine integers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Numerical abstract domain adapter for machine integers /// /// This is a wrapper to use a `numeric::AbstractDomain` as a /// `machine_int::AbstractDomain`. template < typename VariableRef, typename NumDomain > class NumericDomainAdapter final : public machine_int::AbstractDomain< VariableRef, NumericDomainAdapter< VariableRef, NumDomain > > { public: static_assert( numeric::IsAbstractDomain< NumDomain, ZNumber, VariableRef >::value, "NumDomain must implement numeric::AbstractDomain"); private: using Parent = machine_int::AbstractDomain< VariableRef, NumericDomainAdapter< VariableRef, NumDomain > >; using VariableTrait = machine_int::VariableTraits< VariableRef >; public: using MachIntVariableExpression = VariableExpression< MachineInt, VariableRef >; using MachIntLinearExpression = LinearExpression< MachineInt, VariableRef >; using MachIntUnaryOperator = machine_int::UnaryOperator; using MachIntBinaryOperator = machine_int::BinaryOperator; using MachIntPredicate = machine_int::Predicate; using MachIntInterval = machine_int::Interval; using MachIntCongruence = machine_int::Congruence; using MachIntIntervalCongruence = machine_int::IntervalCongruence; using ZBinaryOperator = numeric::BinaryOperator; using ZVariableExpression = VariableExpression< ZNumber, VariableRef >; using ZLinearExpression = LinearExpression< ZNumber, VariableRef >; using ZInterval = numeric::Interval< ZNumber >; using ZCongruence = numeric::Congruence< ZNumber >; using ZIntervalCongruence = numeric::IntervalCongruence< ZNumber >; private: NumDomain _inv; public: /// \brief Create an abstract value from the given numeric abstract domain explicit NumericDomainAdapter(NumDomain inv) : _inv(std::move(inv)) {} /// \brief Copy constructor NumericDomainAdapter(const NumericDomainAdapter&) noexcept( std::is_nothrow_copy_constructible< NumDomain >::value) = default; /// \brief Move constructor NumericDomainAdapter(NumericDomainAdapter&&) noexcept( std::is_nothrow_move_constructible< NumDomain >::value) = default; /// \brief Copy assignment operator NumericDomainAdapter& operator=(const NumericDomainAdapter&) noexcept( std::is_nothrow_copy_assignable< NumDomain >::value) = default; /// \brief Move assignment operator NumericDomainAdapter& operator=(NumericDomainAdapter&&) noexcept( std::is_nothrow_move_assignable< NumDomain >::value) = default; /// \brief Destructor ~NumericDomainAdapter() override = default; void normalize() override { this->_inv.normalize(); } bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const NumericDomainAdapter& other) const override { return this->_inv.leq(other._inv); } bool equals(const NumericDomainAdapter& other) const override { return this->_inv.equals(other._inv); } void join_with(NumericDomainAdapter&& other) override { this->_inv.join_with(std::move(other._inv)); } void join_with(const NumericDomainAdapter& other) override { this->_inv.join_with(other._inv); } void join_loop_with(NumericDomainAdapter&& other) override { this->_inv.join_loop_with(std::move(other._inv)); } void join_loop_with(const NumericDomainAdapter& other) override { this->_inv.join_loop_with(other._inv); } void join_iter_with(NumericDomainAdapter&& other) override { this->_inv.join_iter_with(std::move(other._inv)); } void join_iter_with(const NumericDomainAdapter& other) override { this->_inv.join_iter_with(other._inv); } void widen_with(const NumericDomainAdapter& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const NumericDomainAdapter& other, const MachineInt& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold.to_z_number()); } void meet_with(const NumericDomainAdapter& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const NumericDomainAdapter& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const NumericDomainAdapter& other, const MachineInt& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold.to_z_number()); } NumericDomainAdapter join(const NumericDomainAdapter& other) const override { return NumericDomainAdapter(this->_inv.join(other._inv)); } NumericDomainAdapter join_loop( const NumericDomainAdapter& other) const override { return NumericDomainAdapter(this->_inv.join_loop(other._inv)); } NumericDomainAdapter join_iter( const NumericDomainAdapter& other) const override { return NumericDomainAdapter(this->_inv.join_iter(other._inv)); } NumericDomainAdapter widening( const NumericDomainAdapter& other) const override { return NumericDomainAdapter(this->_inv.widening(other._inv)); } NumericDomainAdapter widening_threshold( const NumericDomainAdapter& other, const MachineInt& threshold) const override { return NumericDomainAdapter( this->_inv.widening_threshold(other._inv, threshold.to_z_number())); } NumericDomainAdapter meet(const NumericDomainAdapter& other) const override { return NumericDomainAdapter(this->_inv.meet(other._inv)); } NumericDomainAdapter narrowing( const NumericDomainAdapter& other) const override { return NumericDomainAdapter(this->_inv.narrowing(other._inv)); } NumericDomainAdapter narrowing_threshold( const NumericDomainAdapter& other, const MachineInt& threshold) const override { return NumericDomainAdapter( this->_inv.narrowing_threshold(other._inv, threshold.to_z_number())); } private: /// \brief Return 2**n static ZNumber power_of_2(uint64_t n) { return ZNumber(1) << n; } /// \brief Return 2**n static ZNumber power_of_2(const ZNumber& n) { return ZNumber(1) << n; } /// \brief Convert a linear expression on machine integers to a linear /// expression on integers static ZLinearExpression to_z_linear_expression( const MachIntLinearExpression& e) { ZLinearExpression r(e.constant().to_z_number()); for (const auto& term : e) { r.add(term.second.to_z_number(), term.first); } return r; } /// \brief Wrap the given variable void wrap(VariableRef x) { this->wrap(x, x, VariableTrait::bit_width(x), VariableTrait::sign(x)); } /// \brief Apply `x = wrap(y, bit-width, sign)` /// /// Apply the wrap-around semantic for machine integers of the given bit-width /// and sign. void wrap(VariableRef x, VariableRef y, uint64_t bit_width, Signedness sign) { if (sign == Signed) { ZNumber n = power_of_2(bit_width); ZNumber m = power_of_2(bit_width - 1); // x = ((y + m) mod n) - m this->_inv.apply(ZBinaryOperator::Add, x, y, m); this->_inv.apply(ZBinaryOperator::Mod, x, x, n); this->_inv.apply(ZBinaryOperator::Sub, x, x, m); } else if (sign == Unsigned) { // x = y mod n ZNumber n = power_of_2(bit_width); this->_inv.apply(ZBinaryOperator::Mod, x, y, n); } else { ikos_unreachable("unreachable"); } } /// \brief Truncate the given variable void trunc(VariableRef x) { this->trunc(x, VariableTrait::bit_width(x), VariableTrait::sign(x)); } /// \brief Apply `x = trunc(x, bit-width, sign)` /// /// This truncate the value of `x`, basically ignoring overflows. void trunc(VariableRef x, uint64_t bit_width, Signedness sign) { this->_inv.refine(x, MachIntInterval::top(bit_width, sign).to_z_interval()); } public: void assign(VariableRef x, const MachineInt& n) override { this->_inv.assign(x, n.to_z_number()); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const MachIntLinearExpression& e) override { this->_inv.assign(x, to_z_linear_expression(e)); this->wrap(x); } void apply(MachIntUnaryOperator op, VariableRef x, VariableRef y) override { this->trunc(y); // add bound information on y switch (op) { case MachIntUnaryOperator::Trunc: { this->wrap(x, y, VariableTrait::bit_width(x), VariableTrait::sign(x)); } break; case MachIntUnaryOperator::Ext: { this->_inv.assign(x, y); } break; case MachIntUnaryOperator::SignCast: { this->wrap(x, y, VariableTrait::bit_width(x), VariableTrait::sign(x)); } break; case MachIntUnaryOperator::Cast: { this->wrap(x, y, VariableTrait::bit_width(x), VariableTrait::sign(x)); } break; default: { ikos_unreachable("unreachable"); } } } void apply(MachIntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { switch (op) { case MachIntBinaryOperator::Add: { this->_inv.apply(ZBinaryOperator::Add, x, y, z); this->wrap(x); } break; case MachIntBinaryOperator::AddNoWrap: { this->_inv.apply(ZBinaryOperator::Add, x, y, z); this->trunc(x); } break; case MachIntBinaryOperator::Sub: { this->_inv.apply(ZBinaryOperator::Sub, x, y, z); this->wrap(x); } break; case MachIntBinaryOperator::SubNoWrap: { this->_inv.apply(ZBinaryOperator::Sub, x, y, z); this->trunc(x); } break; case MachIntBinaryOperator::Mul: { this->_inv.apply(ZBinaryOperator::Mul, x, y, z); this->wrap(x); } break; case MachIntBinaryOperator::MulNoWrap: { this->_inv.apply(ZBinaryOperator::Mul, x, y, z); this->trunc(x); } break; case MachIntBinaryOperator::Div: { this->_inv.apply(ZBinaryOperator::Div, x, y, z); this->trunc(x); // overflow is undefined behavior } break; case MachIntBinaryOperator::DivExact: { this->apply(MachIntBinaryOperator::Div, x, y, z); // sound } break; case MachIntBinaryOperator::Rem: { this->_inv.apply(ZBinaryOperator::Rem, x, y, z); this->trunc(x); } break; case MachIntBinaryOperator::Shl: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); this->_inv.apply(ZBinaryOperator::Shl, x, y, z); this->wrap(x); } break; case MachIntBinaryOperator::ShlNoWrap: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); this->_inv.apply(ZBinaryOperator::Shl, x, y, z); this->trunc(x); } break; case MachIntBinaryOperator::LShr: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); if (VariableTrait::sign(x) == Signed) { if (x == z) { this->forget(x); return; } this->wrap(x, y, bit_width, Unsigned); this->_inv.apply(ZBinaryOperator::Shr, x, x, z); this->wrap(x, x, bit_width, Signed); } else { this->_inv.apply(ZBinaryOperator::Shr, x, y, z); } } break; case MachIntBinaryOperator::LShrExact: { this->apply(MachIntBinaryOperator::LShr, x, y, z); // sound } break; case MachIntBinaryOperator::AShr: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); if (VariableTrait::sign(x) == Signed) { this->_inv.apply(ZBinaryOperator::Shr, x, y, z); } else { if (x == z) { this->forget(x); return; } this->wrap(x, y, bit_width, Signed); this->_inv.apply(ZBinaryOperator::Shr, x, x, z); this->wrap(x, x, bit_width, Unsigned); } } break; case MachIntBinaryOperator::AShrExact: { this->apply(MachIntBinaryOperator::AShr, x, y, z); // sound } break; case MachIntBinaryOperator::And: { this->_inv.apply(ZBinaryOperator::And, x, y, z); this->wrap(x); } break; case MachIntBinaryOperator::Or: { this->_inv.apply(ZBinaryOperator::Or, x, y, z); this->wrap(x); } break; case MachIntBinaryOperator::Xor: { this->_inv.apply(ZBinaryOperator::Xor, x, y, z); this->wrap(x); } break; default: { ikos_unreachable("unreachable"); } } } void apply(MachIntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { switch (op) { case MachIntBinaryOperator::Add: { this->_inv.apply(ZBinaryOperator::Add, x, y, z.to_z_number()); this->wrap(x); } break; case MachIntBinaryOperator::AddNoWrap: { this->_inv.apply(ZBinaryOperator::Add, x, y, z.to_z_number()); this->trunc(x); } break; case MachIntBinaryOperator::Sub: { this->_inv.apply(ZBinaryOperator::Sub, x, y, z.to_z_number()); this->wrap(x); } break; case MachIntBinaryOperator::SubNoWrap: { this->_inv.apply(ZBinaryOperator::Sub, x, y, z.to_z_number()); this->trunc(x); } break; case MachIntBinaryOperator::Mul: { this->_inv.apply(ZBinaryOperator::Mul, x, y, z.to_z_number()); this->wrap(x); } break; case MachIntBinaryOperator::MulNoWrap: { this->_inv.apply(ZBinaryOperator::Mul, x, y, z.to_z_number()); this->trunc(x); } break; case MachIntBinaryOperator::Div: { this->_inv.apply(ZBinaryOperator::Div, x, y, z.to_z_number()); this->trunc(x); // overflow is undefined behavior } break; case MachIntBinaryOperator::DivExact: { this->apply(MachIntBinaryOperator::Div, x, y, z); // sound } break; case MachIntBinaryOperator::Rem: { this->_inv.apply(ZBinaryOperator::Rem, x, y, z.to_z_number()); this->trunc(x); } break; case MachIntBinaryOperator::Shl: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); ZNumber zz = z.to_z_number(); if (!(0 <= zz && zz < bit_width)) { this->set_to_bottom(); return; } this->_inv.apply(ZBinaryOperator::Shl, x, y, zz); this->wrap(x); } break; case MachIntBinaryOperator::ShlNoWrap: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); ZNumber zz = z.to_z_number(); if (!(0 <= zz && zz < bit_width)) { this->set_to_bottom(); return; } this->_inv.apply(ZBinaryOperator::Shl, x, y, zz); this->trunc(x); } break; case MachIntBinaryOperator::LShr: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); ZNumber zz = z.to_z_number(); if (!(0 <= zz && zz < bit_width)) { this->set_to_bottom(); return; } if (VariableTrait::sign(x) == Signed) { this->wrap(x, y, bit_width, Unsigned); this->_inv.apply(ZBinaryOperator::Shr, x, x, zz); this->wrap(x, x, bit_width, Signed); } else { this->_inv.apply(ZBinaryOperator::Shr, x, y, zz); } } break; case MachIntBinaryOperator::LShrExact: { this->apply(MachIntBinaryOperator::LShr, x, y, z); // sound } break; case MachIntBinaryOperator::AShr: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); ZNumber zz = z.to_z_number(); if (!(0 <= zz && zz < bit_width)) { this->set_to_bottom(); return; } if (VariableTrait::sign(x) == Signed) { this->_inv.apply(ZBinaryOperator::Shr, x, y, zz); } else { this->wrap(x, y, bit_width, Signed); this->_inv.apply(ZBinaryOperator::Shr, x, x, zz); this->wrap(x, x, bit_width, Unsigned); } } break; case MachIntBinaryOperator::AShrExact: { this->apply(MachIntBinaryOperator::AShr, x, y, z); // sound } break; case MachIntBinaryOperator::And: { this->_inv.apply(ZBinaryOperator::And, x, y, z.to_z_number()); this->wrap(x); } break; case MachIntBinaryOperator::Or: { this->_inv.apply(ZBinaryOperator::Or, x, y, z.to_z_number()); this->wrap(x); } break; case MachIntBinaryOperator::Xor: { this->_inv.apply(ZBinaryOperator::Xor, x, y, z.to_z_number()); this->wrap(x); } break; default: { ikos_unreachable("unreachable"); } } } void apply(MachIntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { switch (op) { case MachIntBinaryOperator::Add: { this->_inv.apply(ZBinaryOperator::Add, x, y.to_z_number(), z); this->wrap(x); } break; case MachIntBinaryOperator::AddNoWrap: { this->_inv.apply(ZBinaryOperator::Add, x, y.to_z_number(), z); this->trunc(x); } break; case MachIntBinaryOperator::Sub: { this->_inv.apply(ZBinaryOperator::Sub, x, y.to_z_number(), z); this->wrap(x); } break; case MachIntBinaryOperator::SubNoWrap: { this->_inv.apply(ZBinaryOperator::Sub, x, y.to_z_number(), z); this->trunc(x); } break; case MachIntBinaryOperator::Mul: { this->_inv.apply(ZBinaryOperator::Mul, x, y.to_z_number(), z); this->wrap(x); } break; case MachIntBinaryOperator::MulNoWrap: { this->_inv.apply(ZBinaryOperator::Mul, x, y.to_z_number(), z); this->trunc(x); } break; case MachIntBinaryOperator::Div: { this->_inv.apply(ZBinaryOperator::Div, x, y.to_z_number(), z); this->trunc(x); // overflow is undefined behavior } break; case MachIntBinaryOperator::DivExact: { this->apply(MachIntBinaryOperator::Div, x, y, z); // sound } break; case MachIntBinaryOperator::Rem: { this->_inv.apply(ZBinaryOperator::Rem, x, y.to_z_number(), z); this->trunc(x); } break; case MachIntBinaryOperator::Shl: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); this->_inv.apply(ZBinaryOperator::Shl, x, y.to_z_number(), z); this->wrap(x); } break; case MachIntBinaryOperator::ShlNoWrap: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); this->_inv.apply(ZBinaryOperator::Shl, x, y.to_z_number(), z); this->trunc(x); } break; case MachIntBinaryOperator::LShr: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); if (VariableTrait::sign(x) == Signed) { this->_inv.apply(ZBinaryOperator::Shr, x, y.sign_cast(Unsigned).to_z_number(), z); this->wrap(x, x, bit_width, Signed); } else { this->_inv.apply(ZBinaryOperator::Shr, x, y.to_z_number(), z); } } break; case MachIntBinaryOperator::LShrExact: { this->apply(MachIntBinaryOperator::LShr, x, y, z); // sound } break; case MachIntBinaryOperator::AShr: { // z has to be between [0, bit_width - 1] uint64_t bit_width = VariableTrait::bit_width(x); this->_inv.refine(z, ZInterval(ZBound(0), ZBound(ZNumber(bit_width - 1)))); if (VariableTrait::sign(x) == Signed) { this->_inv.apply(ZBinaryOperator::Shr, x, y.to_z_number(), z); } else { this->_inv.apply(ZBinaryOperator::Shr, x, y.sign_cast(Signed).to_z_number(), z); this->wrap(x, x, bit_width, Unsigned); } } break; case MachIntBinaryOperator::AShrExact: { this->apply(MachIntBinaryOperator::AShr, x, y, z); // sound } break; case MachIntBinaryOperator::And: { this->_inv.apply(ZBinaryOperator::And, x, y.to_z_number(), z); this->wrap(x); } break; case MachIntBinaryOperator::Or: { this->_inv.apply(ZBinaryOperator::Or, x, y.to_z_number(), z); this->wrap(x); } break; case MachIntBinaryOperator::Xor: { this->_inv.apply(ZBinaryOperator::Xor, x, y.to_z_number(), z); this->wrap(x); } break; default: { ikos_unreachable("unreachable"); } } } void add(MachIntPredicate pred, VariableRef x, VariableRef y) override { switch (pred) { case MachIntPredicate::EQ: { this->_inv.add(ZVariableExpression(x) == ZVariableExpression(y)); } break; case MachIntPredicate::NE: { this->_inv.add(ZVariableExpression(x) != ZVariableExpression(y)); } break; case MachIntPredicate::GT: { this->_inv.add(ZVariableExpression(x) >= ZVariableExpression(y) + 1); } break; case MachIntPredicate::GE: { this->_inv.add(ZVariableExpression(x) >= ZVariableExpression(y)); } break; case MachIntPredicate::LT: { this->_inv.add(ZVariableExpression(x) <= ZVariableExpression(y) - 1); } break; case MachIntPredicate::LE: { this->_inv.add(ZVariableExpression(x) <= ZVariableExpression(y)); } break; default: { ikos_unreachable("unreachable"); } } } void add(MachIntPredicate pred, VariableRef x, const MachineInt& y) override { switch (pred) { case MachIntPredicate::EQ: { this->_inv.add(ZVariableExpression(x) == y.to_z_number()); } break; case MachIntPredicate::NE: { this->_inv.add(ZVariableExpression(x) != y.to_z_number()); } break; case MachIntPredicate::GT: { this->_inv.add(ZVariableExpression(x) >= y.to_z_number() + 1); } break; case MachIntPredicate::GE: { this->_inv.add(ZVariableExpression(x) >= y.to_z_number()); } break; case MachIntPredicate::LT: { this->_inv.add(ZVariableExpression(x) <= y.to_z_number() - 1); } break; case MachIntPredicate::LE: { this->_inv.add(ZVariableExpression(x) <= y.to_z_number()); } break; default: { ikos_unreachable("unreachable"); } } } void add(MachIntPredicate pred, const MachineInt& x, VariableRef y) override { Parent::add(pred, x, y); } void set(VariableRef x, const MachIntInterval& value) override { this->_inv.set(x, value.to_z_interval()); } void set(VariableRef x, const MachIntCongruence& value) override { this->_inv.set(x, value.to_z_congruence()); } void set(VariableRef x, const MachIntIntervalCongruence& value) override { this->_inv.set(x, value.to_z_interval_congruence()); } void refine(VariableRef x, const MachIntInterval& value) override { this->_inv.refine(x, value.to_z_interval()); } void refine(VariableRef x, const MachIntCongruence& value) override { this->_inv.refine(x, value.to_z_congruence()); } void refine(VariableRef x, const MachIntIntervalCongruence& value) override { this->_inv.refine(x, value.to_z_interval_congruence()); } void forget(VariableRef x) override { this->_inv.forget(x); } MachIntInterval to_interval(VariableRef x) const override { return MachIntInterval::from_z_interval(this->_inv.to_interval(x), VariableTrait::bit_width(x), VariableTrait::sign(x), MachIntInterval::TruncTag{}); } MachIntInterval to_interval(const MachIntLinearExpression& e) const override { return MachIntInterval::from_z_interval(this->_inv.to_interval( to_z_linear_expression(e)), e.constant().bit_width(), e.constant().sign(), MachIntInterval::WrapTag{}); } MachIntCongruence to_congruence(VariableRef x) const override { return MachIntCongruence::from_z_congruence(this->_inv.to_congruence(x), VariableTrait::bit_width(x), VariableTrait::sign(x), MachIntCongruence::TruncTag{}); } MachIntCongruence to_congruence( const MachIntLinearExpression& e) const override { return MachIntCongruence::from_z_congruence(this->_inv.to_congruence( to_z_linear_expression(e)), e.constant().bit_width(), e.constant().sign(), MachIntCongruence::WrapTag{}); } MachIntIntervalCongruence to_interval_congruence( VariableRef x) const override { return MachIntIntervalCongruence:: from_z_interval_congruence(this->_inv.to_interval_congruence(x), VariableTrait::bit_width(x), VariableTrait::sign(x), MachIntIntervalCongruence::TruncTag{}); } MachIntIntervalCongruence to_interval_congruence( const MachIntLinearExpression& e) const override { return MachIntIntervalCongruence:: from_z_interval_congruence(this->_inv.to_interval_congruence( to_z_linear_expression(e)), e.constant().bit_width(), e.constant().sign(), MachIntIntervalCongruence::WrapTag{}); } /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_inv.counter_mark(x); } void counter_unmark(VariableRef x) override { this->_inv.counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { this->_inv.counter_init(x, c.to_z_number()); } void counter_incr(VariableRef x, const MachineInt& k) override { this->_inv.counter_incr(x, k.to_z_number()); } void counter_forget(VariableRef x) override { this->_inv.counter_forget(x); } /// @} void dump(std::ostream& o) const override { return this->_inv.dump(o); } static std::string name() { return "adapter of " + NumDomain::name(); } }; // end class NumericDomainAdapter } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/operator.hpp000066400000000000000000000125121473507761200271600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Operators for machine integer abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Unary machine integer operations enum class UnaryOperator { Trunc, Ext, SignCast, Cast, }; /// \brief Binary machine integer operations enum class BinaryOperator { Add, AddNoWrap, Sub, SubNoWrap, Mul, MulNoWrap, Div, DivExact, Rem, Shl, ShlNoWrap, LShr, LShrExact, AShr, AShrExact, And, Or, Xor, }; /// \brief Predicate on machine integers enum class Predicate { EQ, NE, GT, GE, LT, LE, }; /// \brief Apply a machine integer unary operator on the given operands template < typename T > T apply_unary_operator(UnaryOperator op, const T& operand, uint64_t result_bit_width, Signedness result_sign) { switch (op) { case UnaryOperator::Trunc: return operand.trunc(result_bit_width); case UnaryOperator::Ext: return operand.ext(result_bit_width); case UnaryOperator::SignCast: return operand.sign_cast(result_sign); case UnaryOperator::Cast: return operand.cast(result_bit_width, result_sign); default: ikos_unreachable("unreachable"); } } /// \brief Apply a machine integer binary operator on the given operands template < typename T > T apply_bin_operator(BinaryOperator op, const T& lhs, const T& rhs) { switch (op) { case BinaryOperator::Add: return add(lhs, rhs); case BinaryOperator::AddNoWrap: return add_no_wrap(lhs, rhs); case BinaryOperator::Sub: return sub(lhs, rhs); case BinaryOperator::SubNoWrap: return sub_no_wrap(lhs, rhs); case BinaryOperator::Mul: return mul(lhs, rhs); case BinaryOperator::MulNoWrap: return mul_no_wrap(lhs, rhs); case BinaryOperator::Div: return div(lhs, rhs); case BinaryOperator::DivExact: return div_exact(lhs, rhs); case BinaryOperator::Rem: return rem(lhs, rhs); case BinaryOperator::Shl: return shl(lhs, rhs); case BinaryOperator::ShlNoWrap: return shl_no_wrap(lhs, rhs); case BinaryOperator::LShr: return lshr(lhs, rhs); case BinaryOperator::LShrExact: return lshr_exact(lhs, rhs); case BinaryOperator::AShr: return ashr(lhs, rhs); case BinaryOperator::AShrExact: return ashr_exact(lhs, rhs); case BinaryOperator::And: return and_(lhs, rhs); case BinaryOperator::Or: return or_(lhs, rhs); case BinaryOperator::Xor: return xor_(lhs, rhs); default: ikos_unreachable("unreachable"); } } /// \brief Compare the given operands with the given predicate template < typename T > bool compare(Predicate pred, const T& lhs, const T& rhs) { switch (pred) { case Predicate::EQ: return lhs == rhs; case Predicate::NE: return lhs != rhs; case Predicate::GT: return lhs > rhs; case Predicate::GE: return lhs >= rhs; case Predicate::LT: return lhs < rhs; case Predicate::LE: return lhs <= rhs; default: ikos_unreachable("unreachable"); } } } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/polymorphic_domain.hpp000066400000000000000000000733561473507761200312360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Polymorphic machine integer abstract domain * * The PolymorphicDomain is a machine integer abstract domain whose behavior * depends on the abstract domain it is constructed with. It allows the use of * different abstract domains at runtime. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Polymorphic machine integer abstract domain /// /// The PolymorphicDomain is a machine integer abstract domain whose behavior /// depends on the abstract domain it is constructed with. It allows the use of /// different abstract domains at runtime. template < typename VariableRef > class PolymorphicDomain final : public machine_int::AbstractDomain< VariableRef, PolymorphicDomain< VariableRef > > { public: using LinearExpressionT = LinearExpression< MachineInt, VariableRef >; using VariableTrait = machine_int::VariableTraits< VariableRef >; private: /// Type erasure idiom /// /// This is commonly known as the 'type erasure idiom', used to implement /// std::any. class PolymorphicBase { public: /// \brief Default constructor PolymorphicBase() = default; /// \brief No copy constructor PolymorphicBase(const PolymorphicBase&) = delete; /// \brief No move constructor PolymorphicBase(PolymorphicBase&&) = delete; /// \brief No copy assignment operator PolymorphicBase& operator=(const PolymorphicBase&) = delete; /// \brief No move assignment operator PolymorphicBase& operator=(PolymorphicBase&&) = delete; /// \brief Destructor virtual ~PolymorphicBase() = default; /// \brief Clone the abstract value virtual std::unique_ptr< PolymorphicBase > clone() const = 0; /// \name Core abstract domain methods /// @{ /// \brief Normalize the abstract value virtual void normalize() = 0; /// \brief Check if the abstract value is bottom virtual bool is_bottom() const = 0; /// \brief Check if the abstract value is top virtual bool is_top() const = 0; /// \brief Set the abstract value to bottom virtual void set_to_bottom() = 0; /// \brief Set the abstract value to top virtual void set_to_top() = 0; /// \brief Partial order comparison virtual bool leq(const PolymorphicBase& other) const = 0; /// \brief Equality comparison virtual bool equals(const PolymorphicBase& other) const = 0; /// \brief Perform the union of two abstract values virtual void join_with(PolymorphicBase&& other) = 0; /// \brief Perform the union of two abstract values virtual void join_with(const PolymorphicBase& other) = 0; /// \brief Perform a union on a loop head virtual void join_loop_with(PolymorphicBase&& other) = 0; /// \brief Perform a union on a loop head virtual void join_loop_with(const PolymorphicBase& other) = 0; /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm virtual void join_iter_with(PolymorphicBase&& other) = 0; /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm virtual void join_iter_with(const PolymorphicBase& other) = 0; /// \brief Perform the widening of two abstract values virtual void widen_with(const PolymorphicBase& other) = 0; /// \brief Perform the widening of two abstract values with a threshold virtual void widen_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) = 0; /// \brief Perform the intersection of two abstract values virtual void meet_with(const PolymorphicBase& other) = 0; /// \brief Perform the narrowing of two abstract values virtual void narrow_with(const PolymorphicBase& other) = 0; /// \brief Perform the narrowing of two abstract values with a threshold virtual void narrow_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) = 0; /// \brief Perform the union of two abstract values virtual std::unique_ptr< PolymorphicBase > join( const PolymorphicBase& other) const = 0; /// \brief Perform a union on a loop head virtual std::unique_ptr< PolymorphicBase > join_loop( const PolymorphicBase& other) const = 0; /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm virtual std::unique_ptr< PolymorphicBase > join_iter( const PolymorphicBase& other) const = 0; /// \brief Perform the widening of two abstract values virtual std::unique_ptr< PolymorphicBase > widening( const PolymorphicBase& other) const = 0; /// \brief Perform the widening of two abstract values with a threshold virtual std::unique_ptr< PolymorphicBase > widening_threshold( const PolymorphicBase& other, const MachineInt& threshold) const = 0; /// \brief Perform the intersection of two abstract values virtual std::unique_ptr< PolymorphicBase > meet( const PolymorphicBase& other) const = 0; /// \brief Perform the narrowing of two abstract values virtual std::unique_ptr< PolymorphicBase > narrowing( const PolymorphicBase& other) const = 0; /// \brief Perform the narrowing of two abstract values with a threshold virtual std::unique_ptr< PolymorphicBase > narrowing_threshold( const PolymorphicBase& other, const MachineInt& threshold) const = 0; /// @} /// \name Machine integer abstract domain methods /// @{ /// \brief Assign `x = n` virtual void assign(VariableRef x, const MachineInt& n) = 0; /// \brief Assign `x = y` virtual void assign(VariableRef x, VariableRef y) = 0; /// \brief Assign `x = e` virtual void assign(VariableRef x, const LinearExpressionT& e) = 0; /// \brief Apply `x = op y` virtual void apply(UnaryOperator op, VariableRef x, VariableRef y) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) = 0; // \brief Add the constraint `x pred y` virtual void add(Predicate pred, VariableRef x, VariableRef y) = 0; // \brief Add the constraint `x pred y` virtual void add(Predicate pred, VariableRef x, const MachineInt& y) = 0; // \brief Add the constraint `x pred y` virtual void add(Predicate pred, const MachineInt& x, VariableRef y) = 0; /// \brief Set the interval value of a variable virtual void set(VariableRef x, const Interval& value) = 0; /// \brief Set the congruence value of a variable virtual void set(VariableRef x, const Congruence& value) = 0; /// \brief Set the interval-congruence value of a variable virtual void set(VariableRef x, const IntervalCongruence& value) = 0; /// \brief Refine the value of a variable with an interval virtual void refine(VariableRef x, const Interval& value) = 0; /// \brief Refine the value of a variable with a congruence virtual void refine(VariableRef x, const Congruence& value) = 0; /// \brief Refine the value of a variable with an interval-congruence virtual void refine(VariableRef x, const IntervalCongruence& value) = 0; /// \brief Forget a variable virtual void forget(VariableRef x) = 0; /// \brief Projection to an interval virtual Interval to_interval(VariableRef x) const = 0; /// \brief Projection to an interval virtual Interval to_interval(const LinearExpressionT& e) const = 0; /// \brief Projection to a congruence virtual Congruence to_congruence(VariableRef x) const = 0; /// \brief Projection to a congruence virtual Congruence to_congruence(const LinearExpressionT& e) const = 0; /// \brief Projection to an interval-congruence virtual IntervalCongruence to_interval_congruence(VariableRef x) const = 0; /// \brief Projection to an interval-congruence virtual IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const = 0; /// @} /// \name Non-negative loop counter abstract domain methods /// @{ /// \brief Mark the variable `x` as a non-negative loop counter virtual void counter_mark(VariableRef x) = 0; /// \brief Mark the variable `x` as a normal variable, without losing /// information virtual void counter_unmark(VariableRef x) = 0; /// \brief Initialize a non-negative loop counter: `x = c` virtual void counter_init(VariableRef x, const MachineInt& c) = 0; /// \brief Increment a non-negative loop counter counter: `x += k` virtual void counter_incr(VariableRef x, const MachineInt& k) = 0; /// \brief Forget a non-negative loop counter virtual void counter_forget(VariableRef x) = 0; /// @} /// \brief Dump the abstract value, for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class PolymorphicBase private: template < typename RuntimeDomain > class PolymorphicDerived final : public PolymorphicBase { public: static_assert( machine_int::IsAbstractDomain< RuntimeDomain, VariableRef >::value, "RuntimeDomain must implement machine_int::AbstractDomain"); private: using PolymorphicDerivedT = PolymorphicDerived< RuntimeDomain >; private: RuntimeDomain _inv; public: /// \brief Create an abstract value explicit PolymorphicDerived(RuntimeDomain inv) : _inv(std::move(inv)) {} std::unique_ptr< PolymorphicBase > clone() const override { return std::make_unique< PolymorphicDerivedT >(this->_inv); } /// \name Core abstract domain methods /// @{ void normalize() override { this->_inv.normalize(); } bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } /// \brief Check if the parameter has the same runtime domain bool is_compatible(const PolymorphicBase& other) const { return dynamic_cast< const PolymorphicDerivedT* >(&other) != nullptr; } /// \brief Assert that the parameter has the same runtime domain void assert_compatible(const PolymorphicBase& other) const { ikos_assert_msg(this->is_compatible(other), "incompatible runtime abstract domains"); ikos_ignore(other); } bool leq(const PolymorphicBase& other) const override { this->assert_compatible(other); return this->_inv.leq( static_cast< const PolymorphicDerivedT& >(other)._inv); } bool equals(const PolymorphicBase& other) const override { this->assert_compatible(other); return this->_inv.equals( static_cast< const PolymorphicDerivedT& >(other)._inv); } void join_with(PolymorphicBase&& other) override { this->assert_compatible(other); this->_inv.join_with( std::move(static_cast< PolymorphicDerivedT& >(other)._inv)); } void join_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.join_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void join_loop_with(PolymorphicBase&& other) override { this->assert_compatible(other); this->_inv.join_loop_with( std::move(static_cast< PolymorphicDerivedT& >(other)._inv)); } void join_loop_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.join_loop_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void join_iter_with(PolymorphicBase&& other) override { this->assert_compatible(other); this->_inv.join_iter_with( std::move(static_cast< PolymorphicDerivedT& >(other)._inv)); } void join_iter_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.join_iter_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void widen_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.widen_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void widen_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) override { this->assert_compatible(other); this->_inv.widen_threshold_with(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold); } void meet_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.meet_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void narrow_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.narrow_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void narrow_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) override { this->assert_compatible(other); this->_inv .narrow_threshold_with(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold); } std::unique_ptr< PolymorphicBase > join( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.join( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > join_loop( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.join_loop( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > join_iter( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.join_iter( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > widening( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.widening( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > widening_threshold( const PolymorphicBase& other, const MachineInt& threshold) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >( this->_inv .widening_threshold(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold)); } std::unique_ptr< PolymorphicBase > meet( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.meet( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > narrowing( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.narrowing( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > narrowing_threshold( const PolymorphicBase& other, const MachineInt& threshold) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >( this->_inv .narrowing_threshold(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold)); } /// @} /// \name Machine integer abstract domain methods /// @{ void assign(VariableRef x, const MachineInt& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(UnaryOperator op, VariableRef x, VariableRef y) override { this->_inv.apply(op, x, y); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(Predicate pred, VariableRef x, VariableRef y) override { this->_inv.add(pred, x, y); } void add(Predicate pred, VariableRef x, const MachineInt& y) override { this->_inv.add(pred, x, y); } void add(Predicate pred, const MachineInt& x, VariableRef y) override { this->_inv.add(pred, x, y); } void set(VariableRef x, const Interval& value) override { this->_inv.set(x, value); } void set(VariableRef x, const Congruence& value) override { this->_inv.set(x, value); } void set(VariableRef x, const IntervalCongruence& value) override { this->_inv.set(x, value); } void refine(VariableRef x, const Interval& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const Congruence& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const IntervalCongruence& value) override { this->_inv.refine(x, value); } void forget(VariableRef x) override { this->_inv.forget(x); } Interval to_interval(VariableRef x) const override { return this->_inv.to_interval(x); } Interval to_interval(const LinearExpressionT& e) const override { return this->_inv.to_interval(e); } Congruence to_congruence(VariableRef x) const override { return this->_inv.to_congruence(x); } Congruence to_congruence(const LinearExpressionT& e) const override { return this->_inv.to_congruence(e); } IntervalCongruence to_interval_congruence(VariableRef x) const override { return this->_inv.to_interval_congruence(x); } IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const override { return this->_inv.to_interval_congruence(e); } /// @} /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_inv.counter_mark(x); } void counter_unmark(VariableRef x) override { this->_inv.counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { this->_inv.counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { this->_inv.counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_inv.counter_forget(x); } /// @} void dump(std::ostream& o) const override { this->_inv.dump(o); } }; // end class PolymorphicDerived private: /// \brief Pointer on the polymorphic base class std::unique_ptr< PolymorphicBase > _ptr; private: /// \brief Constructor explicit PolymorphicDomain(std::unique_ptr< PolymorphicBase > ptr) : _ptr(std::move(ptr)) {} public: /// \brief Create a polymorphic domain with the given abstract value template < typename RuntimeDomain > explicit PolymorphicDomain(RuntimeDomain inv) : _ptr(std::make_unique< PolymorphicDerived< remove_cvref_t< RuntimeDomain > > >( std::move(inv))) {} /// \brief Copy constructor PolymorphicDomain(const PolymorphicDomain& other) : _ptr(other._ptr->clone()) {} /// \brief Move constructor PolymorphicDomain(PolymorphicDomain&&) noexcept = default; /// \brief Copy assignment operator PolymorphicDomain& operator=(const PolymorphicDomain& other) { this->_ptr = other._ptr->clone(); return *this; } /// \brief Move assignment operator PolymorphicDomain& operator=(PolymorphicDomain&&) noexcept = default; /// \brief Destructor ~PolymorphicDomain() override = default; /// \name Core abstract domain methods /// @{ void normalize() override { this->_ptr->normalize(); } bool is_bottom() const override { return this->_ptr->is_bottom(); } bool is_top() const override { return this->_ptr->is_top(); } void set_to_bottom() override { this->_ptr->set_to_bottom(); } void set_to_top() override { this->_ptr->set_to_top(); } bool leq(const PolymorphicDomain& other) const override { return this->_ptr->leq(*other._ptr); } bool equals(const PolymorphicDomain& other) const override { return this->_ptr->equals(*other._ptr); } void join_with(PolymorphicDomain&& other) override { this->_ptr->join_with(std::move(*other._ptr)); } void join_with(const PolymorphicDomain& other) override { this->_ptr->join_with(*other._ptr); } void join_loop_with(PolymorphicDomain&& other) override { this->_ptr->join_loop_with(std::move(*other._ptr)); } void join_loop_with(const PolymorphicDomain& other) override { this->_ptr->join_loop_with(*other._ptr); } void join_iter_with(PolymorphicDomain&& other) override { this->_ptr->join_iter_with(std::move(*other._ptr)); } void join_iter_with(const PolymorphicDomain& other) override { this->_ptr->join_iter_with(*other._ptr); } void widen_with(const PolymorphicDomain& other) override { this->_ptr->widen_with(*other._ptr); } void widen_threshold_with(const PolymorphicDomain& other, const MachineInt& threshold) override { this->_ptr->widen_threshold_with(*other._ptr, threshold); } void meet_with(const PolymorphicDomain& other) override { this->_ptr->meet_with(*other._ptr); } void narrow_with(const PolymorphicDomain& other) override { this->_ptr->narrow_with(*other._ptr); } void narrow_threshold_with(const PolymorphicDomain& other, const MachineInt& threshold) override { this->_ptr->narrow_threshold_with(*other._ptr, threshold); } PolymorphicDomain join(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->join(*other._ptr)); } PolymorphicDomain join_loop(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->join_loop(*other._ptr)); } PolymorphicDomain join_iter(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->join_iter(*other._ptr)); } PolymorphicDomain widening(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->widening(*other._ptr)); } PolymorphicDomain widening_threshold( const PolymorphicDomain& other, const MachineInt& threshold) const override { return PolymorphicDomain( this->_ptr->widening_threshold(*other._ptr, threshold)); } PolymorphicDomain meet(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->meet(*other._ptr)); } PolymorphicDomain narrowing(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->narrowing(*other._ptr)); } PolymorphicDomain narrowing_threshold( const PolymorphicDomain& other, const MachineInt& threshold) const override { return PolymorphicDomain( this->_ptr->narrowing_threshold(*other._ptr, threshold)); } /// @} /// \name Machine integer abstract domain methods /// @{ void assign(VariableRef x, const MachineInt& n) override { this->_ptr->assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_ptr->assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_ptr->assign(x, e); } void apply(UnaryOperator op, VariableRef x, VariableRef y) override { this->_ptr->apply(op, x, y); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_ptr->apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_ptr->apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_ptr->apply(op, x, y, z); } void add(Predicate pred, VariableRef x, VariableRef y) override { this->_ptr->add(pred, x, y); } void add(Predicate pred, VariableRef x, const MachineInt& y) override { this->_ptr->add(pred, x, y); } void add(Predicate pred, const MachineInt& x, VariableRef y) override { this->_ptr->add(pred, x, y); } void set(VariableRef x, const Interval& value) override { this->_ptr->set(x, value); } void set(VariableRef x, const Congruence& value) override { this->_ptr->set(x, value); } void set(VariableRef x, const IntervalCongruence& value) override { this->_ptr->set(x, value); } void refine(VariableRef x, const Interval& value) override { this->_ptr->refine(x, value); } void refine(VariableRef x, const Congruence& value) override { this->_ptr->refine(x, value); } void refine(VariableRef x, const IntervalCongruence& value) override { this->_ptr->refine(x, value); } void forget(VariableRef x) override { this->_ptr->forget(x); } Interval to_interval(VariableRef x) const override { return this->_ptr->to_interval(x); } Interval to_interval(const LinearExpressionT& e) const override { return this->_ptr->to_interval(e); } Congruence to_congruence(VariableRef x) const override { return this->_ptr->to_congruence(x); } Congruence to_congruence(const LinearExpressionT& e) const override { return this->_ptr->to_congruence(e); } IntervalCongruence to_interval_congruence(VariableRef x) const override { return this->_ptr->to_interval_congruence(x); } IntervalCongruence to_interval_congruence( const LinearExpressionT& e) const override { return this->_ptr->to_interval_congruence(e); } /// @} /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_ptr->counter_mark(x); } void counter_unmark(VariableRef x) override { this->_ptr->counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { this->_ptr->counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { this->_ptr->counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_ptr->counter_forget(x); } /// @} void dump(std::ostream& o) const override { this->_ptr->dump(o); } static std::string name() { return "polymorphic domain"; } }; // end class PolymorphicDomain } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/machine_int/separate_domain.hpp000066400000000000000000000360451473507761200304670ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic implementation of non-relational domains for machine integers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Generic implementation of non-relational domains for machine integers template < typename VariableRef, typename Value > class SeparateDomain final : public core::AbstractDomain< SeparateDomain< VariableRef, Value > > { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); static_assert(machine_int::IsVariable< VariableRef >::value, "VariableRef must implement machine_int::VariableTraits"); static_assert(core::IsAbstractDomain< Value >::value, "Value must implement AbstractDomain"); private: using VariableTrait = machine_int::VariableTraits< VariableRef >; using PatriciaTreeMapT = PatriciaTreeMap< VariableRef, Value >; public: using LinearExpressionT = LinearExpression< MachineInt, VariableRef >; using Iterator = typename PatriciaTreeMapT::Iterator; private: PatriciaTreeMapT _tree; bool _is_bottom; private: struct TopTag {}; struct BottomTag {}; struct BottomFound {}; /// \brief Create the top abstract value explicit SeparateDomain(TopTag) : _is_bottom(false) {} /// \brief Create the bottom abstract value explicit SeparateDomain(BottomTag) : _is_bottom(true) {} public: /// \brief Create the top abstract value static SeparateDomain top() { return SeparateDomain(TopTag{}); } /// \brief Create the bottom abstract value static SeparateDomain bottom() { return SeparateDomain(BottomTag{}); } /// \brief Copy constructor SeparateDomain(const SeparateDomain&) noexcept = default; /// \brief Move constructor SeparateDomain(SeparateDomain&&) noexcept = default; /// \brief Copy assignment operator SeparateDomain& operator=(const SeparateDomain&) noexcept = default; /// \brief Move assignment operator SeparateDomain& operator=(SeparateDomain&&) noexcept = default; /// \brief Destructor ~SeparateDomain() override = default; /// \brief Begin iterator over the pairs (variable, value) Iterator begin() const { ikos_assert(!this->is_bottom()); return this->_tree.begin(); } /// \brief End iterator over the pairs (variable, value) Iterator end() const { ikos_assert(!this->is_bottom()); return this->_tree.end(); } void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->is_bottom() && this->_tree.empty(); } void set_to_bottom() override { this->_is_bottom = true; this->_tree.clear(); } void set_to_top() override { this->_is_bottom = false; this->_tree.clear(); } bool leq(const SeparateDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_tree.leq(other._tree, [](const Value& x, const Value& y) { return x.leq(y); }); } } bool equals(const SeparateDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_tree.equals(other._tree, [](const Value& x, const Value& y) { return x.equals(y); }); } } void join_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void join_loop_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join_loop(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void join_iter_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join_loop(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void widen_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.widening(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void widen_threshold_with(const SeparateDomain& other, const MachineInt& threshold) { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [threshold](const Value& x, const Value& y) { Value z = x.widening_threshold(y, threshold); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void meet_with(const SeparateDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const Value& x, const Value& y) { Value z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } void narrow_with(const SeparateDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const Value& x, const Value& y) { Value z = x.narrowing(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } void narrow_threshold_with(const SeparateDomain& other, const MachineInt& threshold) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [threshold](const Value& x, const Value& y) { Value z = x.narrowing_threshold(y, threshold); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Get the abstract value for the given variable Value get(VariableRef x) const { if (this->is_bottom()) { return Value::bottom(VariableTrait::bit_width(x), VariableTrait::sign(x)); } else { boost::optional< const Value& > v = this->_tree.at(x); if (v) { return *v; } else { return Value::top(VariableTrait::bit_width(x), VariableTrait::sign(x)); } } } /// \brief Set the abstract value of the given variable void set(VariableRef x, const Value& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { this->_tree.erase(x); } else { this->_tree.insert_or_assign(x, value); } } /// \brief Refine the abstract value of the given variable void refine(VariableRef v, const Value& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { return; } else { try { this->_tree.update_or_insert( [](const Value& x, const Value& y) { Value z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }, v, value); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Projection /// /// Return an overapproximation of the linear expression e as an abstract /// value /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. Value project(const LinearExpressionT& e) const { // Result type uint64_t bit_width = e.constant().bit_width(); Signedness sign = e.constant().sign(); if (this->is_bottom()) { return Value::bottom(bit_width, sign); } Value r(e.constant()); for (const auto& term : e) { r = add(r, mul(Value(term.second), this->get(term.first).cast(bit_width, sign))); } return r; } /// \brief Forget the abstract value of the given variable void forget(VariableRef x) { if (this->is_bottom()) { return; } this->_tree.erase(x); } /// \brief Assign `x = n` void assign(VariableRef x, const MachineInt& n) { this->set(x, Value(n)); } /// \brief Assign `x = n` void assign(VariableRef x, VariableRef y) { this->set(x, this->get(y)); } /// \brief Assign `x = e` /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of `x`. void assign(VariableRef x, const LinearExpressionT& e) { this->set(x, this->project(e)); } /// \brief Apply `x = op y` void apply(UnaryOperator op, VariableRef x, VariableRef y) { this->set(x, apply_unary_operator(op, this->get(y), VariableTrait::bit_width(x), VariableTrait::sign(x))); } /// \brief Apply `x = y op z` void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) { this->set(x, apply_bin_operator(op, this->get(y), this->get(z))); } /// \brief Apply `x = y op z` void apply(BinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) { this->set(x, apply_bin_operator(op, this->get(y), Value(z))); } /// \brief Apply `x = y op z` void apply(BinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) { this->set(x, apply_bin_operator(op, Value(y), this->get(z))); } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { this->_tree.dump(o); } } static std::string name() { return "separate domain of " + Value::name(); } }; // end class SeparateDomain } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/000077500000000000000000000000001473507761200236455ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/abstract_domain.hpp000066400000000000000000000210011473507761200275020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for memory abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace memory { /// \brief Base class for memory abstract domains /// /// A memory abstract domain is a scalar abstract domain with memory operations template < typename VariableRef, typename MemoryLocationRef, typename Derived > class AbstractDomain : public scalar::AbstractDomain< VariableRef, MemoryLocationRef, Derived > { public: using IntInterval = machine_int::Interval; using LiteralT = Literal< VariableRef, MemoryLocationRef >; public: /// \name Memory abstract domain methods /// @{ /// \brief Perform the memory write `*p = v` /// /// \param p The pointer variable /// \param v The stored value /// \param size The stored size, in bytes (for instance, 4 for a int) virtual void mem_write(VariableRef p, const LiteralT& v, const MachineInt& size) = 0; /// \brief Perform the memory read `x = *p` /// /// \param x The result variable /// \param p The pointer variable /// \param size The read size, in bytes (for instance, 4 for a int) virtual void mem_read(const LiteralT& x, VariableRef p, const MachineInt& size) = 0; /// \brief Perform the memory copy `memcpy(dest, src, size)` /// /// \param dest The destination pointer variable /// \param src The source pointer variable /// \param size The number of bytes copied, as a literal /// /// Notes: /// If `dst` and `src` overlap, as the behavior in C is undefined, the /// memory contents is set to top. virtual void mem_copy(VariableRef dest, VariableRef src, const LiteralT& size) = 0; /// \brief Perform the memory set `memset(dest, value, size)` /// /// \param dest The destination pointer variable /// \param value The byte value, as a literal /// \param size The number of written bytes, as a literal virtual void mem_set(VariableRef dest, const LiteralT& value, const LiteralT& size) = 0; /// \brief Forget all memory contents virtual void mem_forget_all() = 0; /// \brief Forget the memory contents at the given memory location virtual void mem_forget(MemoryLocationRef addr) = 0; /// \brief Forget the memory contents in range /// `[addr + offset, addr + offset + size - 1]` /// /// \param addr The memory location /// \param offset The offset as a machine integer interval /// \param size The size in bytes virtual void mem_forget(MemoryLocationRef addr, const IntInterval& offset, const MachineInt& size) = 0; /// \brief Forget the memory contents in range /// `[addr + range.lb(), addr + range.ub()]` /// /// \param addr The memory location /// \param range The byte range as a machine integer interval virtual void mem_forget(MemoryLocationRef addr, const IntInterval& range) = 0; /// \brief Forget the memory contents accessible through pointer `p` virtual void mem_forget_reachable(VariableRef p) = 0; /// \brief Forget the memory contents in range `[p, p + size - 1]` /// /// Forget all memory contents that can be accessible through pointer `p` /// and that overlap with `[p.offset, ..., p.offset + size - 1]` // /// \param p The pointer variable /// \param size The size in bytes virtual void mem_forget_reachable(VariableRef p, const MachineInt& size) = 0; /// \brief Abstract the memory contents reachable through pointer `p` /// /// Abstract all memory contents that can be accessible through pointer `p`. /// Suppose it contains random bytes, and no valid pointers (unlike /// forget_reachable_mem). virtual void mem_abstract_reachable(VariableRef p) = 0; /// \brief Abstract the memory contents in range `[p, p + size - 1]` /// /// Abstract all memory contents that can be accessible through pointer `p` /// and that overlap with `[p.offset, ..., p.offset + size - 1]`. Suppose it /// contains random bytes, and no valid pointers (unlike /// forget_reachable_mem). /// /// \param p The pointer variable /// \param size The size in bytes virtual void mem_abstract_reachable(VariableRef p, const MachineInt& size) = 0; /// \brief Set the memory contents accessible through pointer `p` to zero virtual void mem_zero_reachable(VariableRef p) = 0; /// \brief Set the memory contents accessible through pointer `p` to /// uninitialized virtual void mem_uninitialize_reachable(VariableRef p) = 0; /// @} /// \name Lifetime abstract domain methods /// @{ /// \brief Assign `m = allocated` virtual void lifetime_assign_allocated(MemoryLocationRef m) = 0; /// \brief Assign `m = deallocated` virtual void lifetime_assign_deallocated(MemoryLocationRef m) = 0; /// \brief Add the constraint `m == allocated` virtual void lifetime_assert_allocated(MemoryLocationRef m) = 0; /// \brief Add the constraint `m == deallocated` virtual void lifetime_assert_deallocated(MemoryLocationRef m) = 0; /// \brief Forget the lifetime of a memory location virtual void lifetime_forget(MemoryLocationRef m) = 0; /// \brief Set the lifetime of a memory location virtual void lifetime_set(MemoryLocationRef m, Lifetime value) = 0; /// \brief Get the lifetime value for the given memory location virtual Lifetime lifetime_to_lifetime(MemoryLocationRef m) const = 0; /// @} /// \name Partitioning abstract domain methods /// @{ /// \brief Partition the abstract value according to the given variable virtual void partitioning_set_variable(VariableRef x) = 0; /// \brief Return the current partitioning variable, or boost::none virtual boost::optional< VariableRef > partitioning_variable() const = 0; /// \brief Join the current partitions virtual void partitioning_join() = 0; /// \brief Disable the current partitioning virtual void partitioning_disable() = 0; /// @} }; // end class AbstractDomain /// \brief Check if a type is a memory abstract domain template < typename T, typename VariableRef, typename MemoryLocationRef > struct IsAbstractDomain : std::is_base_of< memory::AbstractDomain< VariableRef, MemoryLocationRef, T >, T > {}; } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/dummy.hpp000066400000000000000000000572671473507761200255320ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief A dummy memory abstract domain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace memory { /// \brief Dummy memory abstract domain /// /// This class implements a memory abstract domain on top of a scalar abstract /// domain, ignoring all memory operations safely. template < typename VariableRef, typename MemoryLocationRef, typename ScalarDomain > class DummyDomain final : public memory::AbstractDomain< VariableRef, MemoryLocationRef, DummyDomain< VariableRef, MemoryLocationRef, ScalarDomain > > { public: static_assert(scalar::IsAbstractDomain< ScalarDomain, VariableRef, MemoryLocationRef >::value, "ScalarDomain must implement scalar::AbstractDomain"); public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; using LiteralT = Literal< VariableRef, MemoryLocationRef >; private: using ScalarVariableTrait = scalar::VariableTraits< VariableRef >; private: ScalarDomain _scalar; public: /// \brief Create an abstract value with the given underlying abstract values DummyDomain(ScalarDomain scalar) : _scalar(std::move(scalar)) {} /// \brief Copy constructor DummyDomain(const DummyDomain&) noexcept( std::is_nothrow_copy_constructible< ScalarDomain >::value) = default; /// \brief Move constructor DummyDomain(DummyDomain&&) noexcept( std::is_nothrow_move_constructible< ScalarDomain >::value) = default; /// \brief Copy assignment operator DummyDomain& operator=(const DummyDomain&) noexcept( std::is_nothrow_copy_assignable< ScalarDomain >::value) = default; /// \brief Move assignment operator DummyDomain& operator=(DummyDomain&&) noexcept( std::is_nothrow_move_assignable< ScalarDomain >::value) = default; /// \brief Destructor ~DummyDomain() override = default; /// \name Implement core abstract domain methods /// @{ void normalize() override { this->_scalar.normalize(); } bool is_bottom() const override { return this->_scalar.is_bottom(); } bool is_top() const override { return this->_scalar.is_top(); } void set_to_bottom() override { this->_scalar.set_to_bottom(); } void set_to_top() override { this->_scalar.set_to_top(); } bool leq(const DummyDomain& other) const override { return this->_scalar.leq(other._scalar); } bool equals(const DummyDomain& other) const override { return this->_scalar.equals(other._scalar); } void join_with(DummyDomain&& other) override { this->_scalar.join_with(std::move(other._scalar)); } void join_with(const DummyDomain& other) override { this->_scalar.join_with(other._scalar); } void join_loop_with(DummyDomain&& other) override { this->_scalar.join_loop_with(std::move(other._scalar)); } void join_loop_with(const DummyDomain& other) override { this->_scalar.join_loop_with(other._scalar); } void join_iter_with(DummyDomain&& other) override { this->_scalar.join_iter_with(std::move(other._scalar)); } void join_iter_with(const DummyDomain& other) override { this->_scalar.join_iter_with(other._scalar); } void widen_with(const DummyDomain& other) override { this->_scalar.widen_with(other._scalar); } void widen_threshold_with(const DummyDomain& other, const MachineInt& threshold) override { this->_scalar.widen_threshold_with(other._scalar, threshold); } void meet_with(const DummyDomain& other) override { this->_scalar.meet_with(other._scalar); } void narrow_with(const DummyDomain& other) override { this->_scalar.narrow_with(other._scalar); } void narrow_threshold_with(const DummyDomain& other, const MachineInt& threshold) override { this->_scalar.narrow_threshold_with(other._scalar, threshold); } DummyDomain join(const DummyDomain& other) const override { return DummyDomain(this->_scalar.join(other._scalar)); } DummyDomain join_loop(const DummyDomain& other) const override { return DummyDomain(this->_scalar.join_loop(other._scalar)); } DummyDomain join_iter(const DummyDomain& other) const override { return DummyDomain(this->_scalar.join_iter(other._scalar)); } DummyDomain widening(const DummyDomain& other) const override { return DummyDomain(this->_scalar.widening(other._scalar)); } DummyDomain widening_threshold(const DummyDomain& other, const MachineInt& threshold) const override { return DummyDomain( this->_scalar.widening_threshold(other._scalar, threshold)); } DummyDomain meet(const DummyDomain& other) const override { return DummyDomain(this->_scalar.meet(other._scalar)); } DummyDomain narrowing(const DummyDomain& other) const override { return DummyDomain(this->_scalar.narrowing(other._scalar)); } DummyDomain narrowing_threshold(const DummyDomain& other, const MachineInt& threshold) const override { return DummyDomain( this->_scalar.narrowing_threshold(other._scalar, threshold)); } /// @} /// \name Implement uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef x) override { this->_scalar.uninit_assert_initialized(x); } bool uninit_is_initialized(VariableRef x) const override { return this->_scalar.uninit_is_initialized(x); } bool uninit_is_uninitialized(VariableRef x) const override { return this->_scalar.uninit_is_uninitialized(x); } void uninit_refine(VariableRef x, Uninitialized value) override { this->_scalar.uninit_refine(x, value); } Uninitialized uninit_to_uninitialized(VariableRef x) const override { return this->_scalar.uninit_to_uninitialized(x); } /// @} /// \name Implement machine integer abstract domain methods /// @{ void int_assign(VariableRef x, const MachineInt& n) override { this->_scalar.int_assign(x, n); } void int_assign_undef(VariableRef x) override { this->_scalar.int_assign_undef(x); } void int_assign_nondet(VariableRef x) override { this->_scalar.int_assign_nondet(x); } void int_assign(VariableRef x, VariableRef y) override { this->_scalar.int_assign(x, y); } void int_assign(VariableRef x, const IntLinearExpression& e) override { this->_scalar.int_assign(x, e); } void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) override { this->_scalar.int_apply(op, x, y); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_scalar.int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_scalar.int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_scalar.int_apply(op, x, y, z); } void int_add(IntPredicate pred, VariableRef x, VariableRef y) override { this->_scalar.int_add(pred, x, y); } void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) override { this->_scalar.int_add(pred, x, y); } void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) override { this->_scalar.int_add(pred, x, y); } void int_set(VariableRef x, const IntInterval& value) override { this->_scalar.int_set(x, value); } void int_set(VariableRef x, const IntCongruence& value) override { this->_scalar.int_set(x, value); } void int_set(VariableRef x, const IntIntervalCongruence& value) override { this->_scalar.int_set(x, value); } void int_refine(VariableRef x, const IntInterval& value) override { this->_scalar.int_refine(x, value); } void int_refine(VariableRef x, const IntCongruence& value) override { this->_scalar.int_refine(x, value); } void int_refine(VariableRef x, const IntIntervalCongruence& value) override { this->_scalar.int_refine(x, value); } void int_forget(VariableRef x) override { this->_scalar.int_forget(x); } IntInterval int_to_interval(VariableRef x) const override { return this->_scalar.int_to_interval(x); } IntInterval int_to_interval(const IntLinearExpression& e) const override { return this->_scalar.int_to_interval(e); } IntCongruence int_to_congruence(VariableRef x) const override { return this->_scalar.int_to_congruence(x); } IntCongruence int_to_congruence(const IntLinearExpression& e) const override { return this->_scalar.int_to_congruence(e); } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { return this->_scalar.int_to_interval_congruence(x); } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { return this->_scalar.int_to_interval_congruence(e); } /// @} /// \name Implement non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_scalar.counter_mark(x); } void counter_unmark(VariableRef x) override { this->_scalar.counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { this->_scalar.counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { this->_scalar.counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_scalar.counter_forget(x); } /// @} /// \name Implement floating point abstract domain methods /// @{ void float_assign_undef(VariableRef x) override { this->_scalar.float_assign_undef(x); } void float_assign_nondet(VariableRef x) override { this->_scalar.float_assign_nondet(x); } void float_assign(VariableRef x, VariableRef y) override { this->_scalar.float_assign(x, y); } void float_forget(VariableRef x) override { this->_scalar.float_forget(x); } /// @} /// \name Implement nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef p) override { this->_scalar.nullity_assert_null(p); } void nullity_assert_non_null(VariableRef p) override { this->_scalar.nullity_assert_non_null(p); } bool nullity_is_null(VariableRef p) const override { return this->_scalar.nullity_is_null(p); } bool nullity_is_non_null(VariableRef p) const override { return this->_scalar.nullity_is_non_null(p); } void nullity_set(VariableRef p, Nullity value) override { this->_scalar.nullity_set(p, value); } void nullity_refine(VariableRef p, Nullity value) override { this->_scalar.nullity_refine(p, value); } Nullity nullity_to_nullity(VariableRef p) const override { return this->_scalar.nullity_to_nullity(p); } /// @} /// \name Implement pointer abstract domain methods /// @{ void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) override { this->_scalar.pointer_assign(p, addr, nullity); } void pointer_assign_null(VariableRef p) override { this->_scalar.pointer_assign_null(p); } void pointer_assign_undef(VariableRef p) override { this->_scalar.pointer_assign_undef(p); } void pointer_assign_nondet(VariableRef p) override { this->_scalar.pointer_assign_nondet(p); } void pointer_assign(VariableRef p, VariableRef q) override { this->_scalar.pointer_assign(p, q); } void pointer_assign(VariableRef p, VariableRef q, VariableRef o) override { this->_scalar.pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) override { this->_scalar.pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) override { this->_scalar.pointer_assign(p, q, o); } void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) override { this->_scalar.pointer_add(pred, p, q); } void pointer_refine(VariableRef p, const PointsToSetT& addrs) override { this->_scalar.pointer_refine(p, addrs); } void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) override { this->_scalar.pointer_refine(p, addrs, offset); } void pointer_refine(VariableRef p, const PointerAbsValueT& value) override { this->_scalar.pointer_refine(p, value); } void pointer_refine(VariableRef p, const PointerSetT& set) override { this->_scalar.pointer_refine(p, set); } void pointer_offset_to_int(VariableRef x, VariableRef p) override { this->_scalar.pointer_offset_to_int(x, p); } IntInterval pointer_offset_to_interval(VariableRef p) const override { return this->_scalar.pointer_offset_to_interval(p); } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { return this->_scalar.pointer_offset_to_congruence(p); } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { return this->_scalar.pointer_offset_to_interval_congruence(p); } PointsToSetT pointer_to_points_to(VariableRef p) const override { return this->_scalar.pointer_to_points_to(p); } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { return this->_scalar.pointer_to_pointer(p); } void pointer_forget_offset(VariableRef p) override { this->_scalar.pointer_forget_offset(p); } void pointer_forget(VariableRef p) override { this->_scalar.pointer_forget(p); } /// @} /// \name Implement dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef x, VariableRef y) override { this->_scalar.dynamic_assign(x, y); } void dynamic_write_undef(VariableRef x) override { this->_scalar.dynamic_write_undef(x); } void dynamic_write_nondet(VariableRef x) override { this->_scalar.dynamic_write_nondet(x); } void dynamic_write_int(VariableRef x, const MachineInt& n) override { this->_scalar.dynamic_write_int(x, n); } void dynamic_write_nondet_int(VariableRef x) override { this->_scalar.dynamic_write_nondet_int(x); } void dynamic_write_int(VariableRef x, VariableRef y) override { this->_scalar.dynamic_write_int(x, y); } void dynamic_write_nondet_float(VariableRef x) override { this->_scalar.dynamic_write_nondet_float(x); } void dynamic_write_null(VariableRef x) override { this->_scalar.dynamic_write_null(x); } void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) override { this->_scalar.dynamic_write_pointer(x, addr, nullity); } void dynamic_write_pointer(VariableRef x, VariableRef y) override { this->_scalar.dynamic_write_pointer(x, y); } void dynamic_read_int(VariableRef x, VariableRef y) override { this->_scalar.dynamic_read_int(x, y); } void dynamic_read_pointer(VariableRef x, VariableRef y) override { this->_scalar.dynamic_read_pointer(x, y); } bool dynamic_is_zero(VariableRef x) const override { return this->_scalar.dynamic_is_zero(x); } bool dynamic_is_null(VariableRef x) const override { return this->_scalar.dynamic_is_null(x); } void dynamic_forget(VariableRef x) override { this->_scalar.dynamic_forget(x); } /// @} /// \name Implement scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef x) override { this->_scalar.scalar_assign_undef(x); } void scalar_assign_nondet(VariableRef x) override { this->_scalar.scalar_assign_nondet(x); } void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) override { this->_scalar.scalar_pointer_to_int(x, p, absolute_zero); } void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) override { this->_scalar.scalar_int_to_pointer(p, x, absolute_zero); } void scalar_forget(VariableRef x) override { this->_scalar.scalar_forget(x); } /// @} /// \name Implement memory abstract domain methods /// @{ void mem_write(VariableRef p, const LiteralT& v, const MachineInt& /*size*/) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->_scalar.is_bottom()) { return; } this->_scalar.nullity_assert_non_null(p); // Writing an uninitialized variable is an error // Note that writing the undefined constant is allowed if (v.is_var()) { this->_scalar.uninit_assert_initialized(v.var()); } } void mem_read(const LiteralT& x, VariableRef p, const MachineInt& /*size*/) override { ikos_assert(x.is_var()); ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->_scalar.is_bottom()) { return; } this->_scalar.nullity_assert_non_null(p); // Assign x to a non deterministic value // Reading uninitialized memory is an error // Therefore, the result of a read is always initialized this->_scalar.scalar_assign_nondet(x.var()); } void mem_copy(VariableRef dest, VariableRef src, const LiteralT& size) override { ikos_assert(ScalarVariableTrait::is_pointer(dest)); ikos_assert(ScalarVariableTrait::is_pointer(src)); if (this->_scalar.is_bottom()) { return; } this->_scalar.nullity_assert_non_null(src); this->_scalar.nullity_assert_non_null(dest); if (size.is_undefined()) { this->_scalar.set_to_bottom(); return; } else if (size.is_var()) { this->_scalar.uninit_assert_initialized(size.var()); } } void mem_set(VariableRef dest, const LiteralT& value, const LiteralT& size) override { ikos_assert(ScalarVariableTrait::is_pointer(dest)); if (this->_scalar.is_bottom()) { return; } this->_scalar.nullity_assert_non_null(dest); if (value.is_undefined()) { this->_scalar.set_to_bottom(); return; } else if (value.is_var()) { this->_scalar.uninit_assert_initialized(value.var()); } if (size.is_undefined()) { this->_scalar.set_to_bottom(); return; } else if (size.is_var()) { this->_scalar.uninit_assert_initialized(size.var()); } } void mem_forget_all() override {} void mem_forget(MemoryLocationRef) override {} void mem_forget(MemoryLocationRef, const IntInterval&, const MachineInt&) override {} void mem_forget(MemoryLocationRef, const IntInterval&) override {} void mem_forget_reachable(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_scalar.uninit_assert_initialized(p); } void mem_forget_reachable(VariableRef p, const MachineInt& /*size*/) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_scalar.uninit_assert_initialized(p); } void mem_abstract_reachable(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_scalar.uninit_assert_initialized(p); } void mem_abstract_reachable(VariableRef p, const MachineInt& /*size*/) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_scalar.uninit_assert_initialized(p); } void mem_zero_reachable(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_scalar.uninit_assert_initialized(p); } void mem_uninitialize_reachable(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_scalar.uninit_assert_initialized(p); } /// @} /// \name Lifetime abstract domain methods /// @{ void lifetime_assign_allocated(MemoryLocationRef) override {} void lifetime_assign_deallocated(MemoryLocationRef) override {} void lifetime_assert_allocated(MemoryLocationRef) override {} void lifetime_assert_deallocated(MemoryLocationRef) override {} void lifetime_set(MemoryLocationRef, Lifetime value) override { if (value.is_bottom()) { this->_scalar.set_to_bottom(); } } void lifetime_forget(MemoryLocationRef) override {} Lifetime lifetime_to_lifetime(MemoryLocationRef) const override { if (this->is_bottom()) { return Lifetime::bottom(); } else { return Lifetime::top(); } } /// @} /// \name Partitioning abstract domain methods /// @{ void partitioning_set_variable(VariableRef) override {} boost::optional< VariableRef > partitioning_variable() const override { return boost::none; } void partitioning_join() override {} void partitioning_disable() override {} /// @} void dump(std::ostream& o) const override { this->_scalar.dump(o); } static std::string name() { return "dummy memory domain using " + ScalarDomain::name(); } }; // end class DummyDomain } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/partitioning.hpp000066400000000000000000001520711473507761200270730ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief A memory abstract domain with partitioning * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace memory { /// \brief Partitioning memory abstract domain /// /// This class implements a memory abstract domain with partitioning. /// /// The partitioning is performed on the valuations of a given integer /// variable. template < typename VariableRef, typename MemoryLocationRef, typename MemoryDomain > class PartitioningDomain final : public memory::AbstractDomain< VariableRef, MemoryLocationRef, PartitioningDomain< VariableRef, MemoryLocationRef, MemoryDomain > > { public: static_assert(memory::IsAbstractDomain< MemoryDomain, VariableRef, MemoryLocationRef >::value, "MemoryDomain must implement memory::AbstractDomain"); public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; using LiteralT = Literal< VariableRef, MemoryLocationRef >; private: using IntVariableTrait = machine_int::VariableTraits< VariableRef >; using ScalarVariableTrait = scalar::VariableTraits< VariableRef >; private: /// \brief Partition struct Partition { /// \brief Interval of the partitioning variable IntInterval interval; /// \brief Memory domain abstract value MemoryDomain memory; }; private: /// \brief Partitioning variable, or boost::none boost::optional< VariableRef > _variable; /// \brief List of partitions, ordered by intervals core::SmallVector< Partition, 1 > _partitions; // Invariants: // * _partitions.size() >= 1 // * ∀i, !_partitions[i].interval.is_bottom() // * ∀i, _partitions[i].interval.ub() < _partitions[i + 1].interval.lb() // * _variable == boost::none => // _partitions.size() == 1 && // _partitions[0].interval == IntInterval::top(1, Signed) // * _variable != boost::none => // ∀i, partition = _partitions[i], // partition.memory.int_to_interval(_variable).leq(partition.interval) // // After normalization: // * ∀i > 1, !_partitions[i].memory.is_bottom() public: /// \brief Create an abstract value with the given underlying memory domain PartitioningDomain(MemoryDomain memory) : _variable(boost::none), _partitions{Partition{IntInterval::top(1, Signed), std::move(memory)}} { } /// \brief Copy constructor PartitioningDomain(const PartitioningDomain&) = default; /// \brief Move constructor PartitioningDomain(PartitioningDomain&&) = default; /// \brief Copy assignment operator PartitioningDomain& operator=(const PartitioningDomain&) = default; /// \brief Move assignment operator PartitioningDomain& operator=(PartitioningDomain&&) = default; /// \brief Destructor ~PartitioningDomain() override = default; /// \name Partitioning abstract domain methods /// @{ void normalize() override { ikos_assert(this->_partitions.size() >= 1); // Remove bottom partitions, but always keep at least one partition. // Start from the end for efficiency. for (auto it = this->_partitions.end(); it != this->_partitions.begin() && this->_partitions.size() > 1;) { --it; it->memory.normalize(); if (it->memory.is_bottom()) { it = this->_partitions.erase(it); } } // Normalize the first partition this->_partitions[0].memory.normalize(); } private: /// \brief Join the partitions and return the merged partition Partition join_partitions() const { Partition p = this->_partitions[0]; for (auto it = std::next(this->_partitions.begin()), et = this->_partitions.end(); it != et; ++it) { p.interval.join_with(it->interval); p.memory.join_with(it->memory); } return p; } /// \brief Update the partitions after a variable update void update_partitions() { if (!this->_variable) { return; } // Update intervals and remove bottom partitions. // Start from the end for efficiency. for (auto it = this->_partitions.end(); it != this->_partitions.begin();) { --it; it->memory.normalize(); IntInterval interval = it->memory.int_to_interval(*this->_variable); if (interval.is_bottom()) { if (this->_partitions.size() > 1) { it = this->_partitions.erase(it); } else { it->interval.set_to_top(); return; } } else { it->interval = std::move(interval); } } // Sort partitions by interval lower bounds std::sort(this->_partitions.begin(), this->_partitions.end(), [](const Partition& a, const Partition& b) { return a.interval.lb() < b.interval.lb(); }); // Merge partitions if necessary. // Start from the end for efficiency. for (auto it = std::prev(this->_partitions.end()); it != this->_partitions.begin() && this->_partitions.size() > 1;) { --it; if (it->interval.ub() >= std::next(it)->interval.lb()) { it->interval.join_with(std::next(it)->interval); it->memory.join_with(std::move(std::next(it)->memory)); it = std::prev(this->_partitions.erase(std::next(it))); } } } /// \brief Return True if both abstract values have the same partitioning bool is_same_partitioning(const PartitioningDomain& other) const { return this->_variable == other._variable && this->_partitions.size() == other._partitions.size() && std::equal(this->_partitions.begin(), this->_partitions.end(), other._partitions.begin(), other._partitions.end(), [](const Partition& a, const Partition& b) { return a.interval == b.interval; }); } public: void partitioning_set_variable(VariableRef x) override { if (!ScalarVariableTrait::is_int(x)) { this->partitioning_disable(); } else if (this->_variable && *this->_variable == x) { return; } else { this->_variable = x; this->update_partitions(); } } boost::optional< VariableRef > partitioning_variable() const override { return this->_variable; } void partitioning_join() override { for (auto it = std::next(this->_partitions.begin()), et = this->_partitions.end(); it != et; ++it) { this->_partitions[0].interval.join_with(it->interval); this->_partitions[0].memory.join_with(std::move(it->memory)); } this->_partitions.erase(std::next(this->_partitions.begin()), this->_partitions.end()); } void partitioning_disable() override { if (!this->_variable) { // Already done ikos_assert(this->_partitions.size() == 1); return; } this->partitioning_join(); this->_variable = boost::none; this->_partitions[0].interval = IntInterval::top(1, Signed); } /// @} /// \name Implement core abstract domain methods /// @{ bool is_bottom() const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [](const Partition& partition) { return partition.memory.is_bottom(); }); } bool is_top() const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [](const Partition& partition) { return partition.memory.is_top(); }); } void set_to_bottom() override { // Remove all partitions except the first one this->_partitions.erase(std::next(this->_partitions.begin()), this->_partitions.end()); // Set the first partition to bottom this->_partitions[0].interval.set_to_top(); this->_partitions[0].memory.set_to_bottom(); } void set_to_top() override { // Remove all partitions except the first one this->_partitions.erase(std::next(this->_partitions.begin()), this->_partitions.end()); // Set the first partition to top this->_partitions[0].interval.set_to_top(); this->_partitions[0].memory.set_to_top(); } bool leq(const PartitioningDomain& other) const override { if (this->_variable != other._variable) { return this->join_partitions().memory.leq(other.join_partitions().memory); } else { for (auto this_it = this->_partitions.begin(), this_et = this->_partitions.end(), other_it = other._partitions.begin(), other_et = other._partitions.end(); this_it != this_et;) { if (other_it == other_et || this_it->interval.ub() < other_it->interval.lb()) { // The partition in `this` does not match any partition in `other` if (!this_it->memory.is_bottom()) { return false; } ++this_it; } else if (other_it->interval.ub() < this_it->interval.lb()) { // The partition in `other` does not match any partition in `this` ++other_it; } else if (this_it->interval.ub() <= other_it->interval.ub()) { // The partition in `this` matches a partition in `other` if (!this_it->memory.leq(other_it->memory)) { return false; } ++this_it; } else { // The partition in `this` overlaps one or more partitions in `other` MemoryDomain other_memory = other_it->memory; for (auto it = std::next(other_it); it != other_et && this_it->interval.ub() >= it->interval.lb(); ++it) { other_memory.join_with(it->memory); } if (!this_it->memory.leq(other_memory)) { return false; } ++this_it; } } return true; } } bool equals(const PartitioningDomain& other) const override { if (this->_variable != other._variable) { return this->join_partitions().memory.equals( other.join_partitions().memory); } else { return this->leq(other) && other.leq(*this); } } void join_with(const PartitioningDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_variable != other._variable) { this->partitioning_disable(); for (const Partition& partition : other._partitions) { this->_partitions[0].memory.join_with(partition.memory); } } else { auto this_it = this->_partitions.begin(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); while (other_it != other_et) { if (this_it == this->_partitions.end()) { // All the remaining partitions in `other` do not match any partition // in `this` this->_partitions.insert(this->_partitions.end(), other_it, other_et); break; } else if (this_it->interval.ub() < other_it->interval.lb()) { // The partition in `other` is on the right of the partition in `this` ++this_it; } else if (other_it->interval.ub() < this_it->interval.lb()) { // The partition in `other` is on the left of the partition in `this` this_it = std::next(this->_partitions.insert(this_it, *other_it)); ++other_it; } else { // The partition in `other` overlaps the partition in `this` this_it->interval.join_with(other_it->interval); // The partition `this` could be bigger now. // Join with the following partitions if necessary. for (auto it = std::next(this_it); it != this->_partitions.end() && this_it->interval.ub() >= it->interval.lb();) { this_it->interval.join_with(it->interval); this_it->memory.join_with(it->memory); it = this->_partitions.erase(it); this_it = std::prev(it); // might be invalidated by erase() } // Join with the partition in `other` this_it->memory.join_with(other_it->memory); ++other_it; } } } } void join_loop_with(const PartitioningDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_variable != other._variable) { this->partitioning_disable(); this->_partitions[0].memory.join_loop_with( other.join_partitions().memory); } else if (this->is_same_partitioning(other)) { auto this_it = this->_partitions.begin(); auto this_et = this->_partitions.end(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); for (; this_it != this_et && other_it != other_et; ++this_it, ++other_it) { ikos_assert(this_it->interval == other_it->interval); this_it->memory.join_loop_with(other_it->memory); } } else if (other._partitions.size() == 1) { this->partitioning_join(); this->_partitions[0].interval.join_loop_with( other._partitions[0].interval); this->_partitions[0].memory.join_loop_with(other._partitions[0].memory); } else { this->partitioning_join(); Partition other_partition = other.join_partitions(); this->_partitions[0].interval.join_loop_with(other_partition.interval); this->_partitions[0].memory.join_loop_with(other_partition.memory); } } void join_iter_with(const PartitioningDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_variable != other._variable) { this->partitioning_disable(); this->_partitions[0].memory.join_iter_with( other.join_partitions().memory); } else if (this->is_same_partitioning(other)) { auto this_it = this->_partitions.begin(); auto this_et = this->_partitions.end(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); for (; this_it != this_et && other_it != other_et; ++this_it, ++other_it) { ikos_assert(this_it->interval == other_it->interval); this_it->memory.join_iter_with(other_it->memory); } } else if (other._partitions.size() == 1) { this->partitioning_join(); this->_partitions[0].interval.join_iter_with( other._partitions[0].interval); this->_partitions[0].memory.join_iter_with(other._partitions[0].memory); } else { this->partitioning_join(); Partition other_partition = other.join_partitions(); this->_partitions[0].interval.join_iter_with(other_partition.interval); this->_partitions[0].memory.join_iter_with(other_partition.memory); } } void widen_with(const PartitioningDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_variable != other._variable) { this->partitioning_disable(); this->_partitions[0].memory.widen_with(other.join_partitions().memory); } else if (this->is_same_partitioning(other)) { auto this_it = this->_partitions.begin(); auto this_et = this->_partitions.end(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); for (; this_it != this_et && other_it != other_et; ++this_it, ++other_it) { ikos_assert(this_it->interval == other_it->interval); this_it->memory.widen_with(other_it->memory); } } else if (other._partitions.size() == 1) { this->partitioning_join(); this->_partitions[0].interval.widen_with(other._partitions[0].interval); this->_partitions[0].memory.widen_with(other._partitions[0].memory); } else { this->partitioning_join(); Partition other_partition = other.join_partitions(); this->_partitions[0].interval.widen_with(other_partition.interval); this->_partitions[0].memory.widen_with(other_partition.memory); } } void widen_threshold_with(const PartitioningDomain& other, const MachineInt& threshold) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_variable != other._variable) { this->partitioning_disable(); this->_partitions[0] .memory.widen_threshold_with(other.join_partitions().memory, threshold); } else if (this->is_same_partitioning(other)) { auto this_it = this->_partitions.begin(); auto this_et = this->_partitions.end(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); for (; this_it != this_et && other_it != other_et; ++this_it, ++other_it) { ikos_assert(this_it->interval == other_it->interval); this_it->memory.widen_threshold_with(other_it->memory, threshold); } } else if (other._partitions.size() == 1) { this->partitioning_join(); this->_partitions[0] .interval.widen_threshold_with(other._partitions[0].interval, threshold); this->_partitions[0] .memory.widen_threshold_with(other._partitions[0].memory, threshold); } else { this->partitioning_join(); Partition other_partition = other.join_partitions(); this->_partitions[0] .interval.widen_threshold_with(other_partition.interval, threshold); this->_partitions[0].memory.widen_threshold_with(other_partition.memory, threshold); } } void meet_with(const PartitioningDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->_variable != other._variable) { this->partitioning_disable(); this->_partitions[0].memory.meet_with(other.join_partitions().memory); } else if (this->is_same_partitioning(other)) { auto this_it = this->_partitions.begin(); auto this_et = this->_partitions.end(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); for (; this_it != this_et && other_it != other_et; ++this_it, ++other_it) { ikos_assert(this_it->interval == other_it->interval); this_it->memory.meet_with(other_it->memory); } } else if (other._partitions.size() == 1) { this->partitioning_join(); this->_partitions[0].interval.meet_with(other._partitions[0].interval); if (this->_partitions[0].interval.is_bottom()) { this->set_to_bottom(); } else { this->_partitions[0].memory.meet_with(other._partitions[0].memory); } } else { this->partitioning_join(); Partition other_partition = other.join_partitions(); this->_partitions[0].interval.meet_with(other_partition.interval); if (this->_partitions[0].interval.is_bottom()) { this->set_to_bottom(); } else { this->_partitions[0].memory.meet_with(other_partition.memory); } } } void narrow_with(const PartitioningDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->_variable != other._variable) { this->partitioning_disable(); this->_partitions[0].memory.narrow_with(other.join_partitions().memory); } else if (this->is_same_partitioning(other)) { auto this_it = this->_partitions.begin(); auto this_et = this->_partitions.end(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); for (; this_it != this_et && other_it != other_et; ++this_it, ++other_it) { ikos_assert(this_it->interval == other_it->interval); this_it->memory.narrow_with(other_it->memory); } } else if (other._partitions.size() == 1) { this->partitioning_join(); this->_partitions[0].interval.narrow_with(other._partitions[0].interval); if (this->_partitions[0].interval.is_bottom()) { this->set_to_bottom(); } else { this->_partitions[0].memory.narrow_with(other._partitions[0].memory); } } else { this->partitioning_join(); Partition other_partition = other.join_partitions(); this->_partitions[0].interval.narrow_with(other_partition.interval); if (this->_partitions[0].interval.is_bottom()) { this->set_to_bottom(); } else { this->_partitions[0].memory.narrow_with(other_partition.memory); } } } void narrow_threshold_with(const PartitioningDomain& other, const MachineInt& threshold) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->_variable != other._variable) { this->partitioning_disable(); this->_partitions[0] .memory.narrow_threshold_with(other.join_partitions().memory, threshold); } else if (this->is_same_partitioning(other)) { auto this_it = this->_partitions.begin(); auto this_et = this->_partitions.end(); auto other_it = other._partitions.begin(); auto other_et = other._partitions.end(); for (; this_it != this_et && other_it != other_et; ++this_it, ++other_it) { ikos_assert(this_it->interval == other_it->interval); this_it->memory.narrow_threshold_with(other_it->memory, threshold); } } else if (other._partitions.size() == 1) { this->partitioning_join(); this->_partitions[0] .interval.narrow_threshold_with(other._partitions[0].interval, threshold); if (this->_partitions[0].interval.is_bottom()) { this->set_to_bottom(); } else { this->_partitions[0] .memory.narrow_threshold_with(other._partitions[0].memory, threshold); } } else { this->partitioning_join(); Partition other_partition = other.join_partitions(); this->_partitions[0] .interval.narrow_threshold_with(other_partition.interval, threshold); if (this->_partitions[0].interval.is_bottom()) { this->set_to_bottom(); } else { this->_partitions[0] .memory.narrow_threshold_with(other_partition.memory, threshold); } } } /// @} /// \name Implement uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.uninit_assert_initialized(x); } } bool uninit_is_initialized(VariableRef x) const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [=](const Partition& partition) { return partition.memory.uninit_is_initialized(x); }); } bool uninit_is_uninitialized(VariableRef x) const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [=](const Partition& partition) { return partition.memory.uninit_is_uninitialized(x); }); } void uninit_refine(VariableRef x, Uninitialized value) override { for (Partition& partition : this->_partitions) { partition.memory.uninit_refine(x, value); } } Uninitialized uninit_to_uninitialized(VariableRef x) const override { auto result = Uninitialized::bottom(); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.uninit_to_uninitialized(x)); } return result; } /// @} /// \name Implement machine integer abstract domain methods /// @{ void int_assign(VariableRef x, const MachineInt& n) override { if (this->_variable && *this->_variable == x) { this->partitioning_join(); this->_partitions[0].interval = IntInterval(n); } for (Partition& partition : this->_partitions) { partition.memory.int_assign(x, n); } } void int_assign_undef(VariableRef x) override { if (this->_variable && *this->_variable == x) { this->partitioning_join(); this->_partitions[0].interval.set_to_top(); } for (Partition& partition : this->_partitions) { partition.memory.int_assign_undef(x); } } void int_assign_nondet(VariableRef x) override { if (this->_variable && *this->_variable == x) { this->partitioning_join(); this->_partitions[0].interval.set_to_top(); } for (Partition& partition : this->_partitions) { partition.memory.int_assign_nondet(x); } } void int_assign(VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.int_assign(x, y); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void int_assign(VariableRef x, const IntLinearExpression& e) override { for (Partition& partition : this->_partitions) { partition.memory.int_assign(x, e); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.int_apply(op, x, y); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { for (Partition& partition : this->_partitions) { partition.memory.int_apply(op, x, y, z); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { for (Partition& partition : this->_partitions) { partition.memory.int_apply(op, x, y, z); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { for (Partition& partition : this->_partitions) { partition.memory.int_apply(op, x, y, z); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void int_add(IntPredicate pred, VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.int_add(pred, x, y); } } void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) override { for (Partition& partition : this->_partitions) { partition.memory.int_add(pred, x, y); } } void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.int_add(pred, x, y); } } void int_set(VariableRef x, const IntInterval& value) override { if (this->_variable && *this->_variable == x) { this->partitioning_join(); if (value.is_bottom()) { this->_partitions[0].interval.set_to_top(); } else { this->_partitions[0].interval = value; } } for (Partition& partition : this->_partitions) { partition.memory.int_set(x, value); } } void int_set(VariableRef x, const IntCongruence& value) override { if (this->_variable && *this->_variable == x) { this->partitioning_join(); if (value.is_bottom()) { this->_partitions[0].interval.set_to_top(); } else if (value.singleton()) { this->_partitions[0].interval = IntInterval(*value.singleton()); } else { this->_partitions[0].interval.set_to_top(); } } for (Partition& partition : this->_partitions) { partition.memory.int_set(x, value); } } void int_set(VariableRef x, const IntIntervalCongruence& value) override { if (this->_variable && *this->_variable == x) { this->partitioning_join(); if (value.is_bottom()) { this->_partitions[0].interval.set_to_top(); } else { this->_partitions[0].interval = value.interval(); } } for (Partition& partition : this->_partitions) { partition.memory.int_set(x, value); } } void int_refine(VariableRef x, const IntInterval& value) override { for (Partition& partition : this->_partitions) { partition.memory.int_refine(x, value); } } void int_refine(VariableRef x, const IntCongruence& value) override { for (Partition& partition : this->_partitions) { partition.memory.int_refine(x, value); } } void int_refine(VariableRef x, const IntIntervalCongruence& value) override { for (Partition& partition : this->_partitions) { partition.memory.int_refine(x, value); } } void int_forget(VariableRef x) override { if (this->_variable && *this->_variable == x) { this->partitioning_join(); this->_partitions[0].interval.set_to_top(); } for (Partition& partition : this->_partitions) { partition.memory.int_forget(x); } } IntInterval int_to_interval(VariableRef x) const override { auto result = IntInterval::bottom(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.int_to_interval(x)); } return result; } IntInterval int_to_interval(const IntLinearExpression& e) const override { auto result = IntInterval::bottom(e.constant().bit_width(), e.constant().sign()); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.int_to_interval(e)); } return result; } IntCongruence int_to_congruence(VariableRef x) const override { auto result = IntCongruence::bottom(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.int_to_congruence(x)); } return result; } IntCongruence int_to_congruence(const IntLinearExpression& e) const override { auto result = IntCongruence::bottom(e.constant().bit_width(), e.constant().sign()); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.int_to_congruence(e)); } return result; } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { auto result = IntIntervalCongruence::bottom(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.int_to_interval_congruence(x)); } return result; } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { auto result = IntIntervalCongruence::bottom(e.constant().bit_width(), e.constant().sign()); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.int_to_interval_congruence(e)); } return result; } /// @} /// \name Implement non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { ikos_assert(!this->_variable || *this->_variable != x); for (Partition& partition : this->_partitions) { partition.memory.counter_mark(x); } } void counter_unmark(VariableRef x) override { ikos_assert(!this->_variable || *this->_variable != x); for (Partition& partition : this->_partitions) { partition.memory.counter_unmark(x); } } void counter_init(VariableRef x, const MachineInt& c) override { ikos_assert(!this->_variable || *this->_variable != x); for (Partition& partition : this->_partitions) { partition.memory.counter_init(x, c); } } void counter_incr(VariableRef x, const MachineInt& k) override { ikos_assert(!this->_variable || *this->_variable != x); for (Partition& partition : this->_partitions) { partition.memory.counter_incr(x, k); } } void counter_forget(VariableRef x) override { ikos_assert(!this->_variable || *this->_variable != x); for (Partition& partition : this->_partitions) { partition.memory.counter_forget(x); } } /// @} /// \name Implement floating point abstract domain methods /// @{ void float_assign_undef(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.float_assign_undef(x); } } void float_assign_nondet(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.float_assign_nondet(x); } } void float_assign(VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.float_assign(x, y); } } void float_forget(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.float_forget(x); } } /// @} /// \name Implement nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.nullity_assert_null(p); } } void nullity_assert_non_null(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.nullity_assert_non_null(p); } } bool nullity_is_null(VariableRef p) const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [=](const Partition& partition) { return partition.memory.nullity_is_null(p); }); } bool nullity_is_non_null(VariableRef p) const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [=](const Partition& partition) { return partition.memory.nullity_is_non_null(p); }); } void nullity_set(VariableRef p, Nullity value) override { for (Partition& partition : this->_partitions) { partition.memory.nullity_set(p, value); } } void nullity_refine(VariableRef p, Nullity value) override { for (Partition& partition : this->_partitions) { partition.memory.nullity_refine(p, value); } } Nullity nullity_to_nullity(VariableRef p) const override { auto result = Nullity::bottom(); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.nullity_to_nullity(p)); } return result; } /// @} /// \name Implement pointer abstract domain methods /// @{ void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign(p, addr, nullity); } } void pointer_assign_null(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign_null(p); } } void pointer_assign_undef(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign_undef(p); } } void pointer_assign_nondet(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign_nondet(p); } } void pointer_assign(VariableRef p, VariableRef q) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign(p, q); } } void pointer_assign(VariableRef p, VariableRef q, VariableRef o) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign(p, q, o); } } void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign(p, q, o); } } void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_assign(p, q, o); } } void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_add(pred, p, q); } } void pointer_refine(VariableRef p, const PointsToSetT& addrs) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_refine(p, addrs); } } void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_refine(p, addrs, offset); } } void pointer_refine(VariableRef p, const PointerAbsValueT& value) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_refine(p, value); } } void pointer_refine(VariableRef p, const PointerSetT& set) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_refine(p, set); } } void pointer_offset_to_int(VariableRef x, VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_offset_to_int(x, p); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } IntInterval pointer_offset_to_interval(VariableRef p) const override { auto result = this->_partitions[0].memory.pointer_offset_to_interval(p); for (auto it = std::next(this->_partitions.begin()), et = this->_partitions.end(); it != et; ++it) { result.join_with(it->memory.pointer_offset_to_interval(p)); } return result; } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { auto result = this->_partitions[0].memory.pointer_offset_to_congruence(p); for (auto it = std::next(this->_partitions.begin()), et = this->_partitions.end(); it != et; ++it) { result.join_with(it->memory.pointer_offset_to_congruence(p)); } return result; } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { auto result = this->_partitions[0].memory.pointer_offset_to_interval_congruence(p); for (auto it = std::next(this->_partitions.begin()), et = this->_partitions.end(); it != et; ++it) { result.join_with(it->memory.pointer_offset_to_interval_congruence(p)); } return result; } PointsToSetT pointer_to_points_to(VariableRef p) const override { auto result = this->_partitions[0].memory.pointer_to_points_to(p); for (auto it = std::next(this->_partitions.begin()), et = this->_partitions.end(); it != et; ++it) { result.join_with(it->memory.pointer_to_points_to(p)); } return result; } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { auto result = this->_partitions[0].memory.pointer_to_pointer(p); for (auto it = std::next(this->_partitions.begin()), et = this->_partitions.end(); it != et; ++it) { result.join_with(it->memory.pointer_to_pointer(p)); } return result; } void pointer_forget_offset(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_forget_offset(p); } } void pointer_forget(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.pointer_forget(p); } } /// @} /// \name Implement dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_assign(x, y); } } void dynamic_write_undef(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_undef(x); } } void dynamic_write_nondet(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_nondet(x); } } void dynamic_write_int(VariableRef x, const MachineInt& n) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_int(x, n); } } void dynamic_write_nondet_int(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_nondet_int(x); } } void dynamic_write_int(VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_int(x, y); } } void dynamic_write_nondet_float(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_nondet_float(x); } } void dynamic_write_null(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_null(x); } } void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_pointer(x, addr, nullity); } } void dynamic_write_pointer(VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_write_pointer(x, y); } } void dynamic_read_int(VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_read_int(x, y); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void dynamic_read_pointer(VariableRef x, VariableRef y) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_read_pointer(x, y); } } bool dynamic_is_zero(VariableRef x) const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [=](const Partition& partition) { return partition.memory.dynamic_is_zero(x); }); } bool dynamic_is_null(VariableRef x) const override { return std::all_of(this->_partitions.begin(), this->_partitions.end(), [=](const Partition& partition) { return partition.memory.dynamic_is_null(x); }); } void dynamic_forget(VariableRef x) override { for (Partition& partition : this->_partitions) { partition.memory.dynamic_forget(x); } } /// @} /// \name Implement scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef x) override { if (ScalarVariableTrait::is_int(x)) { this->int_assign_undef(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_assign_undef(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_assign_undef(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_write_undef(x); } else { ikos_unreachable("unexpected type"); } } void scalar_assign_nondet(VariableRef x) override { if (ScalarVariableTrait::is_int(x)) { this->int_assign_nondet(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_assign_nondet(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_assign_nondet(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_write_nondet(x); } else { ikos_unreachable("unexpected type"); } } void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) override { for (Partition& partition : this->_partitions) { partition.memory.scalar_pointer_to_int(x, p, absolute_zero); } if (this->_variable && *this->_variable == x) { this->update_partitions(); } } void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) override { for (Partition& partition : this->_partitions) { partition.memory.scalar_int_to_pointer(p, x, absolute_zero); } } void scalar_forget(VariableRef x) override { if (ScalarVariableTrait::is_int(x)) { this->int_forget(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_forget(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_forget(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_forget(x); } else { ikos_unreachable("unexpected type"); } } /// @} /// \name Implement memory abstract domain methods /// @{ void mem_write(VariableRef p, const LiteralT& v, const MachineInt& size) override { for (Partition& partition : this->_partitions) { partition.memory.mem_write(p, v, size); } } void mem_read(const LiteralT& x, VariableRef p, const MachineInt& size) override { for (Partition& partition : this->_partitions) { partition.memory.mem_read(x, p, size); } if (this->_variable && x.is_machine_int_var() && *this->_variable == x.var()) { this->update_partitions(); } } void mem_copy(VariableRef dest, VariableRef src, const LiteralT& size) override { for (Partition& partition : this->_partitions) { partition.memory.mem_copy(dest, src, size); } } void mem_set(VariableRef dest, const LiteralT& value, const LiteralT& size) override { for (Partition& partition : this->_partitions) { partition.memory.mem_set(dest, value, size); } } void mem_forget_all() override { for (Partition& partition : this->_partitions) { partition.memory.mem_forget_all(); } } void mem_forget(MemoryLocationRef addr) override { for (Partition& partition : this->_partitions) { partition.memory.mem_forget(addr); } } void mem_forget(MemoryLocationRef addr, const IntInterval& offset, const MachineInt& size) override { for (Partition& partition : this->_partitions) { partition.memory.mem_forget(addr, offset, size); } } void mem_forget(MemoryLocationRef addr, const IntInterval& range) override { for (Partition& partition : this->_partitions) { partition.memory.mem_forget(addr, range); } } void mem_forget_reachable(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.mem_forget_reachable(p); } } void mem_forget_reachable(VariableRef p, const MachineInt& size) override { for (Partition& partition : this->_partitions) { partition.memory.mem_forget_reachable(p, size); } } void mem_abstract_reachable(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.mem_abstract_reachable(p); } } void mem_abstract_reachable(VariableRef p, const MachineInt& size) override { for (Partition& partition : this->_partitions) { partition.memory.mem_abstract_reachable(p, size); } } void mem_zero_reachable(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.mem_zero_reachable(p); } } void mem_uninitialize_reachable(VariableRef p) override { for (Partition& partition : this->_partitions) { partition.memory.mem_uninitialize_reachable(p); } } /// @} /// \name Lifetime abstract domain methods /// @{ void lifetime_assign_allocated(MemoryLocationRef m) override { for (Partition& partition : this->_partitions) { partition.memory.lifetime_assign_allocated(m); } } void lifetime_assign_deallocated(MemoryLocationRef m) override { for (Partition& partition : this->_partitions) { partition.memory.lifetime_assign_deallocated(m); } } void lifetime_assert_allocated(MemoryLocationRef m) override { for (Partition& partition : this->_partitions) { partition.memory.lifetime_assert_allocated(m); } } void lifetime_assert_deallocated(MemoryLocationRef m) override { for (Partition& partition : this->_partitions) { partition.memory.lifetime_assert_deallocated(m); } } void lifetime_set(MemoryLocationRef m, Lifetime value) override { for (Partition& partition : this->_partitions) { partition.memory.lifetime_set(m, value); } } void lifetime_forget(MemoryLocationRef m) override { for (Partition& partition : this->_partitions) { partition.memory.lifetime_forget(m); } } Lifetime lifetime_to_lifetime(MemoryLocationRef m) const override { auto result = Lifetime::bottom(); for (const Partition& partition : this->_partitions) { result.join_with(partition.memory.lifetime_to_lifetime(m)); } return result; } /// @} void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else if (!this->_variable) { ikos_assert(this->_partitions.size() == 1); this->_partitions[0].memory.dump(o); } else { ikos_assert(this->_partitions.size() >= 1); o << "{"; for (auto it = this->_partitions.begin(), et = this->_partitions.end(); it != et;) { core::DumpableTraits< VariableRef >::dump(o, *this->_variable); o << " ∈ "; it->interval.dump(o); o << " -> "; it->memory.dump(o); ++it; if (it != et) { o << ", "; } } o << "}"; } } static std::string name() { return "partitioning domain using " + MemoryDomain::name(); } }; // end class PartitioningDomain } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/polymorphic_domain.hpp000066400000000000000000002103651473507761200302610ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Polymorphic memory abstract domain * * The PolymorphicDomain is a memory abstract domain whose behavior depends on * the abstract domain it is constructed with. It allows the use of different * abstract domains at runtime. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace memory { /// \brief Polymorphic memory abstract domain /// /// The PolymorphicDomain is a memory abstract domain whose behavior depends on /// the abstract domain it is constructed with. It allows the use of different /// abstract domains at runtime. template < typename VariableRef, typename MemoryLocationRef > class PolymorphicDomain final : public memory::AbstractDomain< VariableRef, MemoryLocationRef, PolymorphicDomain< VariableRef, MemoryLocationRef > > { public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; using LiteralT = Literal< VariableRef, MemoryLocationRef >; private: /// Type erasure idiom /// /// This is commonly known as the 'type erasure idiom', used to implement /// std::any. class PolymorphicBase { public: /// \brief Default constructor PolymorphicBase() = default; /// \brief No copy constructor PolymorphicBase(const PolymorphicBase&) = delete; /// \brief No move constructor PolymorphicBase(PolymorphicBase&&) = delete; /// \brief No copy assignment operator PolymorphicBase& operator=(const PolymorphicBase&) = delete; /// \brief No move assignment operator PolymorphicBase& operator=(PolymorphicBase&&) = delete; /// \brief Destructor virtual ~PolymorphicBase() = default; /// \brief Clone the abstract value virtual std::unique_ptr< PolymorphicBase > clone() const = 0; /// \name Core abstract domain methods /// @{ /// \brief Normalize the abstract value virtual void normalize() = 0; /// \brief Check if the abstract value is bottom virtual bool is_bottom() const = 0; /// \brief Check if the abstract value is top virtual bool is_top() const = 0; /// \brief Set the abstract value to bottom virtual void set_to_bottom() = 0; /// \brief Set the abstract value to top virtual void set_to_top() = 0; /// \brief Partial order comparison virtual bool leq(const PolymorphicBase& other) const = 0; /// \brief Equality comparison virtual bool equals(const PolymorphicBase& other) const = 0; /// \brief Perform the union of two abstract values virtual void join_with(PolymorphicBase&& other) = 0; /// \brief Perform the union of two abstract values virtual void join_with(const PolymorphicBase& other) = 0; /// \brief Perform a union on a loop head virtual void join_loop_with(PolymorphicBase&& other) = 0; /// \brief Perform a union on a loop head virtual void join_loop_with(const PolymorphicBase& other) = 0; /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm virtual void join_iter_with(PolymorphicBase&& other) = 0; /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm virtual void join_iter_with(const PolymorphicBase& other) = 0; /// \brief Perform the widening of two abstract values virtual void widen_with(const PolymorphicBase& other) = 0; /// \brief Perform the widening of two abstract values with a threshold virtual void widen_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) = 0; /// \brief Perform the intersection of two abstract values virtual void meet_with(const PolymorphicBase& other) = 0; /// \brief Perform the narrowing of two abstract values virtual void narrow_with(const PolymorphicBase& other) = 0; /// \brief Perform the narrowing of two abstract values with a threshold virtual void narrow_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) = 0; /// \brief Perform the union of two abstract values virtual std::unique_ptr< PolymorphicBase > join( const PolymorphicBase& other) const = 0; /// \brief Perform a union on a loop head virtual std::unique_ptr< PolymorphicBase > join_loop( const PolymorphicBase& other) const = 0; /// \brief Perform a union on two consecutive iterations of a fix-point /// algorithm virtual std::unique_ptr< PolymorphicBase > join_iter( const PolymorphicBase& other) const = 0; /// \brief Perform the widening of two abstract values virtual std::unique_ptr< PolymorphicBase > widening( const PolymorphicBase& other) const = 0; /// \brief Perform the widening of two abstract values with a threshold virtual std::unique_ptr< PolymorphicBase > widening_threshold( const PolymorphicBase& other, const MachineInt& threshold) const = 0; /// \brief Perform the intersection of two abstract values virtual std::unique_ptr< PolymorphicBase > meet( const PolymorphicBase& other) const = 0; /// \brief Perform the narrowing of two abstract values virtual std::unique_ptr< PolymorphicBase > narrowing( const PolymorphicBase& other) const = 0; /// \brief Perform the narrowing of two abstract values with a threshold virtual std::unique_ptr< PolymorphicBase > narrowing_threshold( const PolymorphicBase& other, const MachineInt& threshold) const = 0; /// @} /// \name Uninitialized abstract domain methods /// @{ /// \brief Add the constraint `x == initialized` virtual void uninit_assert_initialized(VariableRef x) = 0; /// \brief Return true if `x` is initialized, otherwise false virtual bool uninit_is_initialized(VariableRef x) const = 0; /// \brief Return true if `x` is uninitialized, otherwise false virtual bool uninit_is_uninitialized(VariableRef x) const = 0; /// \brief Refine the uninitialized value of a variable virtual void uninit_refine(VariableRef x, Uninitialized value) = 0; /// \brief Get the uninitialized value for the given variable virtual Uninitialized uninit_to_uninitialized(VariableRef x) const = 0; /// @} /// \name Machine integer abstract domain methods /// @{ /// \brief Assign `x = n` virtual void int_assign(VariableRef x, const MachineInt& n) = 0; /// \brief Assign `x = undefined` virtual void int_assign_undef(VariableRef x) = 0; /// \brief Assign `x` to a non deterministic integer virtual void int_assign_nondet(VariableRef x) = 0; /// \brief Assign `x = y` virtual void int_assign(VariableRef x, VariableRef y) = 0; /// \brief Assign `x = e` /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of `x`. virtual void int_assign(VariableRef x, const IntLinearExpression& e) = 0; /// \brief Apply `x = op y` virtual void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) = 0; /// \brief Apply `x = y op z` virtual void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) = 0; /// \brief Apply `x = y op z` virtual void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) = 0; /// \brief Apply `x = y op z` virtual void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) = 0; // \brief Add the constraint `x pred y` virtual void int_add(IntPredicate pred, VariableRef x, VariableRef y) = 0; // \brief Add the constraint `x pred y` virtual void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) = 0; // \brief Add the constraint `x pred y` virtual void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) = 0; /// \brief Set the interval value of a variable virtual void int_set(VariableRef x, const IntInterval& value) = 0; /// \brief Set the congruence value of a variable virtual void int_set(VariableRef x, const IntCongruence& value) = 0; /// \brief Set the interval-congruence value of a variable virtual void int_set(VariableRef x, const IntIntervalCongruence& value) = 0; /// \brief Refine the value of a variable with an interval virtual void int_refine(VariableRef x, const IntInterval& value) = 0; /// \brief Refine the value of a variable with a congruence virtual void int_refine(VariableRef x, const IntCongruence& value) = 0; /// \brief Refine the value of a variable with an interval-congruence virtual void int_refine(VariableRef x, const IntIntervalCongruence& value) = 0; /// \brief Forget an integer variable virtual void int_forget(VariableRef x) = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the value of `x` as an interval virtual IntInterval int_to_interval(VariableRef x) const = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the linear expression `e` as an interval /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual IntInterval int_to_interval(const IntLinearExpression& e) const = 0; /// \brief Projection to a congruence /// /// Return an overapproximation of the value of `x` as a congruence virtual IntCongruence int_to_congruence(VariableRef x) const = 0; /// \brief Projection to a congruence /// /// Return an overapproximation of the linear expression `e` as a congruence /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual IntCongruence int_to_congruence( const IntLinearExpression& e) const = 0; /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the value of `x` as an /// interval-congruence virtual IntIntervalCongruence int_to_interval_congruence( VariableRef x) const = 0; /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the linear expression `e` as an /// interval-congruence /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const = 0; /// @} /// \name Non-negative loop counter abstract domain methods /// @{ /// \brief Mark the variable `x` as a non-negative loop counter virtual void counter_mark(VariableRef x) = 0; /// \brief Mark the variable `x` as a normal variable, without losing /// information virtual void counter_unmark(VariableRef x) = 0; /// \brief Initialize a non-negative loop counter: `x = c` /// /// Precondition: `c >= 0` virtual void counter_init(VariableRef x, const MachineInt& c) = 0; /// \brief Increment a non-negative loop counter counter: `x += k` /// /// Precondition: `k >= 0` virtual void counter_incr(VariableRef x, const MachineInt& k) = 0; /// \brief Forget a non-negative loop counter virtual void counter_forget(VariableRef x) = 0; /// @} /// \name Floating point abstract domain methods /// @{ /// \brief Assign `x = undefined` virtual void float_assign_undef(VariableRef x) = 0; /// \brief Assign `x` to a non deterministic floating point virtual void float_assign_nondet(VariableRef x) = 0; /// \brief Assign `x = y` virtual void float_assign(VariableRef x, VariableRef y) = 0; /// \brief Forget a floating point variable virtual void float_forget(VariableRef x) = 0; /// @} /// \name Nullity abstract domain methods /// @{ /// \brief Add the constraint `p == null` virtual void nullity_assert_null(VariableRef p) = 0; /// \brief Add the constraint `p != null` virtual void nullity_assert_non_null(VariableRef p) = 0; /// \brief Return true if `p` is null, otherwise false virtual bool nullity_is_null(VariableRef p) const = 0; /// \brief Return true if `p` is non null, otherwise false virtual bool nullity_is_non_null(VariableRef p) const = 0; /// \brief Set the nullity of the pointer `p` to the given value virtual void nullity_set(VariableRef p, Nullity value) = 0; /// \brief Refine the pointer `p` with the given nullity value virtual void nullity_refine(VariableRef p, Nullity value) = 0; /// \brief Get the nullity value for the given variable virtual Nullity nullity_to_nullity(VariableRef p) const = 0; /// @} /// \name Pointer abstract domain methods /// @{ /// \brief Assign `p` to an address (i.e, memory location) /// /// This is equivalent to `p = &x` or `p = malloc()` virtual void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) = 0; /// \brief Assign `p = null` virtual void pointer_assign_null(VariableRef p) = 0; /// \brief Assign `p = undefined` virtual void pointer_assign_undef(VariableRef p) = 0; /// \brief Assign `p` to a non deterministic pointer virtual void pointer_assign_nondet(VariableRef p) = 0; /// \brief Assign `p = q` virtual void pointer_assign(VariableRef p, VariableRef q) = 0; /// \brief Assign `p = q + o` virtual void pointer_assign(VariableRef p, VariableRef q, VariableRef o) = 0; /// \brief Assign `p = q + o` virtual void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) = 0; /// \brief Assign `p = q + o` virtual void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) = 0; // \brief Add the constraint `p pred q` virtual void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) = 0; /// \brief Refine the pointer `p` with the given set of addresses virtual void pointer_refine(VariableRef p, const PointsToSetT& addrs) = 0; /// \brief Refine the pointer `p` with the given set of addresses and /// offsets virtual void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) = 0; /// \brief Refine the pointer `p` with the given pointer abstract value virtual void pointer_refine(VariableRef p, const PointerAbsValueT& value) = 0; /// \brief Refine the pointer `p` with the given pointer set virtual void pointer_refine(VariableRef p, const PointerSetT& set) = 0; /// \brief Assign `x = offset-of p` virtual void pointer_offset_to_int(VariableRef x, VariableRef p) = 0; /// \brief Project the offset of the pointer `p` to an interval virtual IntInterval pointer_offset_to_interval(VariableRef p) const = 0; /// \brief Project the offset of the pointer `p` to a congruence virtual IntCongruence pointer_offset_to_congruence(VariableRef p) const = 0; /// \brief Project the offset of the pointer `p` to an interval-congruence virtual IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const = 0; /// \brief Return the points-to set of `p` virtual PointsToSetT pointer_to_points_to(VariableRef p) const = 0; /// \brief Return the pointer abstract value of `p` virtual PointerAbsValueT pointer_to_pointer(VariableRef p) const = 0; /// \brief Forget the offset of a pointer variable virtual void pointer_forget_offset(VariableRef p) = 0; /// \brief Forget a pointer variable virtual void pointer_forget(VariableRef p) = 0; /// @} /// \name Dynamically typed variables abstract domain methods /// @{ /// \brief Assign a dynamically typed variable to a dynamically typed /// variable virtual void dynamic_assign(VariableRef x, VariableRef y) = 0; /// \brief Write undefined to a dynamically typed variable virtual void dynamic_write_undef(VariableRef x) = 0; /// \brief Write a non deterministic value to a dynamically typed variable virtual void dynamic_write_nondet(VariableRef x) = 0; /// \brief Write an integer to a dynamically typed variable virtual void dynamic_write_int(VariableRef x, const MachineInt& n) = 0; /// \brief Write a non deterministic integer to a dynamically typed variable virtual void dynamic_write_nondet_int(VariableRef x) = 0; /// \brief Write an integer variable to a dynamically typed variable virtual void dynamic_write_int(VariableRef x, VariableRef y) = 0; /// \brief Write a non deterministic float to a dynamically typed variable virtual void dynamic_write_nondet_float(VariableRef x) = 0; /// \brief Write null to a dynamically typed variable virtual void dynamic_write_null(VariableRef x) = 0; /// \brief Write a pointer to a dynamically typed variable virtual void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) = 0; /// \brief Write a pointer variable to a dynamically typed variable virtual void dynamic_write_pointer(VariableRef x, VariableRef y) = 0; /// \brief Read an integer variable from a dynamically typed variable virtual void dynamic_read_int(VariableRef x, VariableRef y) = 0; /// \brief Read a pointer variable from a dynamically typed variable virtual void dynamic_read_pointer(VariableRef x, VariableRef y) = 0; /// \brief Return true if `x` is the integer zero virtual bool dynamic_is_zero(VariableRef x) const = 0; /// \brief Return true if `x` is the null pointer virtual bool dynamic_is_null(VariableRef x) const = 0; /// \brief Forget a dynamically typed variable virtual void dynamic_forget(VariableRef x) = 0; /// @} /// \name Scalar abstract domain methods /// @{ /// \brief Assign `x = undefined` virtual void scalar_assign_undef(VariableRef x) = 0; /// \brief Assign `x` to a non deterministic value virtual void scalar_assign_nondet(VariableRef x) = 0; /// \brief Assign `x = ptr-to-int p` virtual void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) = 0; /// \brief Assign `p = int-to-ptr x` virtual void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) = 0; /// \brief Forget a scalar variable virtual void scalar_forget(VariableRef x) = 0; /// @} /// \name Memory abstract domain methods /// @{ /// \brief Perform the memory write `*p = v` /// /// \param p The pointer variable /// \param v The stored value /// \param size The stored size, in bytes (for instance, 4 for a int) virtual void mem_write(VariableRef p, const LiteralT& v, const MachineInt& size) = 0; /// \brief Perform the memory read `x = *p` /// /// \param x The result variable /// \param p The pointer variable /// \param size The read size, in bytes (for instance, 4 for a int) virtual void mem_read(const LiteralT& x, VariableRef p, const MachineInt& size) = 0; /// \brief Perform the memory copy `memcpy(dest, src, size)` /// /// \param dest The destination pointer variable /// \param src The source pointer variable /// \param size The number of bytes copied, as a literal /// /// Notes: /// If `dst` and `src` overlap, as the behavior in C is undefined, the /// memory contents is set to top. virtual void mem_copy(VariableRef dest, VariableRef src, const LiteralT& size) = 0; /// \brief Perform the memory set `memset(dest, value, size)` /// /// \param dest The destination pointer variable /// \param value The byte value, as a literal /// \param size The number of written bytes, as a literal virtual void mem_set(VariableRef dest, const LiteralT& value, const LiteralT& size) = 0; /// \brief Forget all memory contents virtual void mem_forget_all() = 0; /// \brief Forget the memory contents at the given memory location virtual void mem_forget(MemoryLocationRef addr) = 0; /// \brief Forget the memory contents in range /// `[addr + offset, addr + offset + size - 1]` /// /// \param addr The memory location /// \param offset The offset as a machine integer interval /// \param size The size in bytes virtual void mem_forget(MemoryLocationRef addr, const IntInterval& offset, const MachineInt& size) = 0; /// \brief Forget the memory contents in range /// `[addr + range.lb(), addr + range.ub()]` /// /// \param addr The memory location /// \param range The byte range as a machine integer interval virtual void mem_forget(MemoryLocationRef addr, const IntInterval& range) = 0; /// \brief Forget the memory contents accessible through pointer `p` virtual void mem_forget_reachable(VariableRef p) = 0; /// \brief Forget the memory contents in range `[p, p + size - 1]` /// /// Forget all memory contents that can be accessible through pointer `p` /// and that overlap with `[p.offset, ..., p.offset + size - 1]` // /// \param p The pointer variable /// \param size The size in bytes virtual void mem_forget_reachable(VariableRef p, const MachineInt& size) = 0; /// \brief Abstract the memory contents reachable through pointer `p` /// /// Abstract all memory contents that can be accessible through pointer `p`. /// Suppose it contains random bytes, and no valid pointers (unlike /// forget_reachable_mem). virtual void mem_abstract_reachable(VariableRef p) = 0; /// \brief Abstract the memory contents in range `[p, p + size - 1]` /// /// Abstract all memory contents that can be accessible through pointer `p` /// and that overlap with `[p.offset, ..., p.offset + size - 1]`. Suppose it /// contains random bytes, and no valid pointers (unlike /// forget_reachable_mem). /// /// \param p The pointer variable /// \param size The size in bytes virtual void mem_abstract_reachable(VariableRef p, const MachineInt& size) = 0; /// \brief Set the memory contents accessible through pointer `p` to zero virtual void mem_zero_reachable(VariableRef p) = 0; /// \brief Set the memory contents accessible through pointer `p` to /// uninitialized virtual void mem_uninitialize_reachable(VariableRef p) = 0; /// @} /// \name Lifetime abstract domain methods /// @{ /// \brief Assign `m = allocated` virtual void lifetime_assign_allocated(MemoryLocationRef m) = 0; /// \brief Assign `m = deallocated` virtual void lifetime_assign_deallocated(MemoryLocationRef m) = 0; /// \brief Add the constraint `m == allocated` virtual void lifetime_assert_allocated(MemoryLocationRef m) = 0; /// \brief Add the constraint `m == deallocated` virtual void lifetime_assert_deallocated(MemoryLocationRef m) = 0; /// \brief Forget the lifetime of a memory location virtual void lifetime_forget(MemoryLocationRef m) = 0; /// \brief Set the lifetime of a memory location virtual void lifetime_set(MemoryLocationRef m, Lifetime value) = 0; /// \brief Get the lifetime value for the given memory location virtual Lifetime lifetime_to_lifetime(MemoryLocationRef m) const = 0; /// @} /// \name Partitioning abstract domain methods /// @{ /// \brief Partition the abstract value according to the given variable virtual void partitioning_set_variable(VariableRef x) = 0; /// \brief Return the current partitioning variable, or boost::none virtual boost::optional< VariableRef > partitioning_variable() const = 0; /// \brief Join the current partitions virtual void partitioning_join() = 0; /// \brief Disable the current partitioning virtual void partitioning_disable() = 0; /// @} /// \brief Dump the abstract value, for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class PolymorphicBase private: template < typename RuntimeDomain > class PolymorphicDerived final : public PolymorphicBase { public: static_assert(memory::IsAbstractDomain< RuntimeDomain, VariableRef, MemoryLocationRef >::value, "RuntimeDomain must implement memory::AbstractDomain"); private: using PolymorphicDerivedT = PolymorphicDerived< RuntimeDomain >; private: RuntimeDomain _inv; public: /// \brief Create an abstract value explicit PolymorphicDerived(RuntimeDomain inv) : _inv(std::move(inv)) {} std::unique_ptr< PolymorphicBase > clone() const override { return std::make_unique< PolymorphicDerivedT >(this->_inv); } /// \name Core abstract domain methods /// @{ void normalize() override { return this->_inv.normalize(); } bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } /// \brief Check if the parameter has the same runtime domain bool is_compatible(const PolymorphicBase& other) const { return dynamic_cast< const PolymorphicDerivedT* >(&other) != nullptr; } /// \brief Assert that the parameter has the same runtime domain void assert_compatible(const PolymorphicBase& other) const { ikos_assert_msg(this->is_compatible(other), "incompatible runtime abstract domains"); ikos_ignore(other); } bool leq(const PolymorphicBase& other) const override { this->assert_compatible(other); return this->_inv.leq( static_cast< const PolymorphicDerivedT& >(other)._inv); } bool equals(const PolymorphicBase& other) const override { this->assert_compatible(other); return this->_inv.equals( static_cast< const PolymorphicDerivedT& >(other)._inv); } void join_with(PolymorphicBase&& other) override { this->assert_compatible(other); this->_inv.join_with( std::move(static_cast< PolymorphicDerivedT& >(other)._inv)); } void join_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.join_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void join_loop_with(PolymorphicBase&& other) override { this->assert_compatible(other); this->_inv.join_loop_with( std::move(static_cast< PolymorphicDerivedT& >(other)._inv)); } void join_loop_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.join_loop_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void join_iter_with(PolymorphicBase&& other) override { this->assert_compatible(other); this->_inv.join_iter_with( std::move(static_cast< PolymorphicDerivedT& >(other)._inv)); } void join_iter_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.join_iter_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void widen_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.widen_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void widen_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) override { this->assert_compatible(other); this->_inv.widen_threshold_with(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold); } void meet_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.meet_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void narrow_with(const PolymorphicBase& other) override { this->assert_compatible(other); this->_inv.narrow_with( static_cast< const PolymorphicDerivedT& >(other)._inv); } void narrow_threshold_with(const PolymorphicBase& other, const MachineInt& threshold) override { this->assert_compatible(other); this->_inv .narrow_threshold_with(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold); } std::unique_ptr< PolymorphicBase > join( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.join( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > join_loop( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.join_loop( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > join_iter( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.join_iter( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > widening( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.widening( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > widening_threshold( const PolymorphicBase& other, const MachineInt& threshold) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >( this->_inv .widening_threshold(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold)); } std::unique_ptr< PolymorphicBase > meet( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.meet( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > narrowing( const PolymorphicBase& other) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >(this->_inv.narrowing( static_cast< const PolymorphicDerivedT& >(other)._inv)); } std::unique_ptr< PolymorphicBase > narrowing_threshold( const PolymorphicBase& other, const MachineInt& threshold) const override { this->assert_compatible(other); return std::make_unique< PolymorphicDerivedT >( this->_inv .narrowing_threshold(static_cast< const PolymorphicDerivedT& >( other) ._inv, threshold)); } /// @} /// \name Uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef x) override { this->_inv.uninit_assert_initialized(x); } bool uninit_is_initialized(VariableRef x) const override { return this->_inv.uninit_is_initialized(x); } bool uninit_is_uninitialized(VariableRef x) const override { return this->_inv.uninit_is_uninitialized(x); } void uninit_refine(VariableRef x, Uninitialized value) override { this->_inv.uninit_refine(x, value); } Uninitialized uninit_to_uninitialized(VariableRef x) const override { return this->_inv.uninit_to_uninitialized(x); } /// @} /// \name Machine integer abstract domain methods /// @{ void int_assign(VariableRef x, const MachineInt& n) override { this->_inv.int_assign(x, n); } void int_assign_undef(VariableRef x) override { this->_inv.int_assign_undef(x); } void int_assign_nondet(VariableRef x) override { this->_inv.int_assign_nondet(x); } void int_assign(VariableRef x, VariableRef y) override { this->_inv.int_assign(x, y); } void int_assign(VariableRef x, const IntLinearExpression& e) override { this->_inv.int_assign(x, e); } void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) override { this->_inv.int_apply(op, x, y); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_inv.int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_inv.int_apply(op, x, y, z); } void int_add(IntPredicate pred, VariableRef x, VariableRef y) override { this->_inv.int_add(pred, x, y); } void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) override { this->_inv.int_add(pred, x, y); } void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) override { this->_inv.int_add(pred, x, y); } void int_set(VariableRef x, const IntInterval& value) override { this->_inv.int_set(x, value); } void int_set(VariableRef x, const IntCongruence& value) override { this->_inv.int_set(x, value); } void int_set(VariableRef x, const IntIntervalCongruence& value) override { this->_inv.int_set(x, value); } void int_refine(VariableRef x, const IntInterval& value) override { this->_inv.int_refine(x, value); } void int_refine(VariableRef x, const IntCongruence& value) override { this->_inv.int_refine(x, value); } void int_refine(VariableRef x, const IntIntervalCongruence& value) override { this->_inv.int_refine(x, value); } void int_forget(VariableRef x) override { this->_inv.int_forget(x); } IntInterval int_to_interval(VariableRef x) const override { return this->_inv.int_to_interval(x); } IntInterval int_to_interval(const IntLinearExpression& e) const override { return this->_inv.int_to_interval(e); } IntCongruence int_to_congruence(VariableRef x) const override { return this->_inv.int_to_congruence(x); } IntCongruence int_to_congruence( const IntLinearExpression& e) const override { return this->_inv.int_to_congruence(e); } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { return this->_inv.int_to_interval_congruence(x); } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { return this->_inv.int_to_interval_congruence(e); } /// @} /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_inv.counter_mark(x); } void counter_unmark(VariableRef x) override { this->_inv.counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { this->_inv.counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { this->_inv.counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_inv.counter_forget(x); } /// @} /// \name Floating point abstract domain methods /// @{ void float_assign_undef(VariableRef x) override { this->_inv.float_assign_undef(x); } void float_assign_nondet(VariableRef x) override { this->_inv.float_assign_nondet(x); } void float_assign(VariableRef x, VariableRef y) override { this->_inv.float_assign(x, y); } void float_forget(VariableRef x) override { this->_inv.float_forget(x); } /// @} /// \name Nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef p) override { this->_inv.nullity_assert_null(p); } void nullity_assert_non_null(VariableRef p) override { this->_inv.nullity_assert_non_null(p); } bool nullity_is_null(VariableRef p) const override { return this->_inv.nullity_is_null(p); } bool nullity_is_non_null(VariableRef p) const override { return this->_inv.nullity_is_non_null(p); } void nullity_set(VariableRef p, Nullity value) override { this->_inv.nullity_set(p, value); } void nullity_refine(VariableRef p, Nullity value) override { this->_inv.nullity_refine(p, value); } Nullity nullity_to_nullity(VariableRef p) const override { return this->_inv.nullity_to_nullity(p); } /// @} /// \name Pointer abstract domain methods /// @{ void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) override { this->_inv.pointer_assign(p, addr, nullity); } void pointer_assign_null(VariableRef p) override { this->_inv.pointer_assign_null(p); } void pointer_assign_undef(VariableRef p) override { this->_inv.pointer_assign_undef(p); } void pointer_assign_nondet(VariableRef p) override { this->_inv.pointer_assign_nondet(p); } void pointer_assign(VariableRef p, VariableRef q) override { this->_inv.pointer_assign(p, q); } void pointer_assign(VariableRef p, VariableRef q, VariableRef o) override { this->_inv.pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) override { this->_inv.pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) override { this->_inv.pointer_assign(p, q, o); } void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) override { this->_inv.pointer_add(pred, p, q); } void pointer_refine(VariableRef p, const PointsToSetT& addrs) override { this->_inv.pointer_refine(p, addrs); } void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) override { this->_inv.pointer_refine(p, addrs, offset); } void pointer_refine(VariableRef p, const PointerAbsValueT& value) override { this->_inv.pointer_refine(p, value); } void pointer_refine(VariableRef p, const PointerSetT& set) override { this->_inv.pointer_refine(p, set); } void pointer_offset_to_int(VariableRef x, VariableRef p) override { this->_inv.pointer_offset_to_int(x, p); } IntInterval pointer_offset_to_interval(VariableRef p) const override { return this->_inv.pointer_offset_to_interval(p); } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { return this->_inv.pointer_offset_to_congruence(p); } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { return this->_inv.pointer_offset_to_interval_congruence(p); } PointsToSetT pointer_to_points_to(VariableRef p) const override { return this->_inv.pointer_to_points_to(p); } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { return this->_inv.pointer_to_pointer(p); } void pointer_forget_offset(VariableRef p) override { this->_inv.pointer_forget_offset(p); } void pointer_forget(VariableRef p) override { this->_inv.pointer_forget(p); } /// @} /// \name Dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef x, VariableRef y) override { this->_inv.dynamic_assign(x, y); } void dynamic_write_undef(VariableRef x) override { this->_inv.dynamic_write_undef(x); } void dynamic_write_nondet(VariableRef x) override { this->_inv.dynamic_write_nondet(x); } void dynamic_write_int(VariableRef x, const MachineInt& n) override { this->_inv.dynamic_write_int(x, n); } void dynamic_write_nondet_int(VariableRef x) override { this->_inv.dynamic_write_nondet_int(x); } void dynamic_write_int(VariableRef x, VariableRef y) override { this->_inv.dynamic_write_int(x, y); } void dynamic_write_nondet_float(VariableRef x) override { this->_inv.dynamic_write_nondet_float(x); } void dynamic_write_null(VariableRef x) override { this->_inv.dynamic_write_null(x); } void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) override { this->_inv.dynamic_write_pointer(x, addr, nullity); } void dynamic_write_pointer(VariableRef x, VariableRef y) override { this->_inv.dynamic_write_pointer(x, y); } void dynamic_read_int(VariableRef x, VariableRef y) override { this->_inv.dynamic_read_int(x, y); } void dynamic_read_pointer(VariableRef x, VariableRef y) override { this->_inv.dynamic_read_pointer(x, y); } bool dynamic_is_zero(VariableRef x) const override { return this->_inv.dynamic_is_zero(x); } bool dynamic_is_null(VariableRef x) const override { return this->_inv.dynamic_is_null(x); } void dynamic_forget(VariableRef x) override { this->_inv.dynamic_forget(x); } /// @} /// \name Scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef x) override { this->_inv.scalar_assign_undef(x); } void scalar_assign_nondet(VariableRef x) override { this->_inv.scalar_assign_nondet(x); } void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) override { this->_inv.scalar_pointer_to_int(x, p, absolute_zero); } void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) override { this->_inv.scalar_int_to_pointer(p, x, absolute_zero); } void scalar_forget(VariableRef x) override { this->_inv.scalar_forget(x); } /// @} /// \name Memory abstract domain methods /// @{ void mem_write(VariableRef p, const LiteralT& v, const MachineInt& size) override { this->_inv.mem_write(p, v, size); } void mem_read(const LiteralT& x, VariableRef p, const MachineInt& size) override { this->_inv.mem_read(x, p, size); } void mem_copy(VariableRef dest, VariableRef src, const LiteralT& size) override { this->_inv.mem_copy(dest, src, size); } void mem_set(VariableRef dest, const LiteralT& value, const LiteralT& size) override { this->_inv.mem_set(dest, value, size); } void mem_forget_all() override { this->_inv.mem_forget_all(); } void mem_forget(MemoryLocationRef addr) override { this->_inv.mem_forget(addr); } void mem_forget(MemoryLocationRef addr, const IntInterval& offset, const MachineInt& size) override { this->_inv.mem_forget(addr, offset, size); } void mem_forget(MemoryLocationRef addr, const IntInterval& range) override { this->_inv.mem_forget(addr, range); } void mem_forget_reachable(VariableRef p) override { this->_inv.mem_forget_reachable(p); } void mem_forget_reachable(VariableRef p, const MachineInt& size) override { this->_inv.mem_forget_reachable(p, size); } void mem_abstract_reachable(VariableRef p) override { this->_inv.mem_abstract_reachable(p); } void mem_abstract_reachable(VariableRef p, const MachineInt& size) override { this->_inv.mem_abstract_reachable(p, size); } void mem_zero_reachable(VariableRef p) override { this->_inv.mem_zero_reachable(p); } void mem_uninitialize_reachable(VariableRef p) override { this->_inv.mem_uninitialize_reachable(p); } /// @} /// \name Lifetime abstract domain methods /// @{ void lifetime_assign_allocated(MemoryLocationRef m) override { this->_inv.lifetime_assign_allocated(m); } void lifetime_assign_deallocated(MemoryLocationRef m) override { this->_inv.lifetime_assign_deallocated(m); } void lifetime_assert_allocated(MemoryLocationRef m) override { this->_inv.lifetime_assert_allocated(m); } void lifetime_assert_deallocated(MemoryLocationRef m) override { this->_inv.lifetime_assert_deallocated(m); } void lifetime_forget(MemoryLocationRef m) override { this->_inv.lifetime_forget(m); } void lifetime_set(MemoryLocationRef m, Lifetime value) override { this->_inv.lifetime_set(m, value); } Lifetime lifetime_to_lifetime(MemoryLocationRef m) const override { return this->_inv.lifetime_to_lifetime(m); } /// @} /// \name Partitioning abstract domain methods /// @{ void partitioning_set_variable(VariableRef x) override { this->_inv.partitioning_set_variable(x); } boost::optional< VariableRef > partitioning_variable() const override { return this->_inv.partitioning_variable(); } void partitioning_join() override { this->_inv.partitioning_join(); } void partitioning_disable() override { this->_inv.partitioning_disable(); } /// @} void dump(std::ostream& o) const override { this->_inv.dump(o); } }; // end class PolymorphicDerived private: /// \brief Pointer on the polymorphic base class std::unique_ptr< PolymorphicBase > _ptr; private: /// \brief Constructor explicit PolymorphicDomain(std::unique_ptr< PolymorphicBase > ptr) : _ptr(std::move(ptr)) {} public: /// \brief Create a polymorphic domain with the given abstract value template < typename RuntimeDomain > explicit PolymorphicDomain(RuntimeDomain inv) : _ptr(std::make_unique< PolymorphicDerived< remove_cvref_t< RuntimeDomain > > >( std::move(inv))) {} /// \brief Copy constructor PolymorphicDomain(const PolymorphicDomain& other) : _ptr(other._ptr->clone()) {} /// \brief Move constructor PolymorphicDomain(PolymorphicDomain&&) noexcept = default; /// \brief Copy assignment operator PolymorphicDomain& operator=(const PolymorphicDomain& other) { this->_ptr = other._ptr->clone(); return *this; } /// \brief Move assignment operator PolymorphicDomain& operator=(PolymorphicDomain&&) noexcept = default; /// \brief Destructor ~PolymorphicDomain() override = default; /// \name Core abstract domain methods /// @{ void normalize() override { this->_ptr->normalize(); } bool is_bottom() const override { return this->_ptr->is_bottom(); } bool is_top() const override { return this->_ptr->is_top(); } void set_to_bottom() override { this->_ptr->set_to_bottom(); } void set_to_top() override { this->_ptr->set_to_top(); } bool leq(const PolymorphicDomain& other) const override { return this->_ptr->leq(*other._ptr); } bool equals(const PolymorphicDomain& other) const override { return this->_ptr->equals(*other._ptr); } void join_with(PolymorphicDomain&& other) override { this->_ptr->join_with(std::move(*other._ptr)); } void join_with(const PolymorphicDomain& other) override { this->_ptr->join_with(*other._ptr); } void join_loop_with(PolymorphicDomain&& other) override { this->_ptr->join_loop_with(std::move(*other._ptr)); } void join_loop_with(const PolymorphicDomain& other) override { this->_ptr->join_loop_with(*other._ptr); } void join_iter_with(PolymorphicDomain&& other) override { this->_ptr->join_iter_with(std::move(*other._ptr)); } void join_iter_with(const PolymorphicDomain& other) override { this->_ptr->join_iter_with(*other._ptr); } void widen_with(const PolymorphicDomain& other) override { this->_ptr->widen_with(*other._ptr); } void widen_threshold_with(const PolymorphicDomain& other, const MachineInt& threshold) override { this->_ptr->widen_threshold_with(*other._ptr, threshold); } void meet_with(const PolymorphicDomain& other) override { this->_ptr->meet_with(*other._ptr); } void narrow_with(const PolymorphicDomain& other) override { this->_ptr->narrow_with(*other._ptr); } void narrow_threshold_with(const PolymorphicDomain& other, const MachineInt& threshold) override { this->_ptr->narrow_threshold_with(*other._ptr, threshold); } PolymorphicDomain join(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->join(*other._ptr)); } PolymorphicDomain join_loop(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->join_loop(*other._ptr)); } PolymorphicDomain join_iter(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->join_iter(*other._ptr)); } PolymorphicDomain widening(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->widening(*other._ptr)); } PolymorphicDomain widening_threshold( const PolymorphicDomain& other, const MachineInt& threshold) const override { return PolymorphicDomain( this->_ptr->widening_threshold(*other._ptr, threshold)); } PolymorphicDomain meet(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->meet(*other._ptr)); } PolymorphicDomain narrowing(const PolymorphicDomain& other) const override { return PolymorphicDomain(this->_ptr->narrowing(*other._ptr)); } PolymorphicDomain narrowing_threshold( const PolymorphicDomain& other, const MachineInt& threshold) const override { return PolymorphicDomain( this->_ptr->narrowing_threshold(*other._ptr, threshold)); } /// @} /// \name Uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef x) override { this->_ptr->uninit_assert_initialized(x); } bool uninit_is_initialized(VariableRef x) const override { return this->_ptr->uninit_is_initialized(x); } bool uninit_is_uninitialized(VariableRef x) const override { return this->_ptr->uninit_is_uninitialized(x); } void uninit_refine(VariableRef x, Uninitialized value) override { this->_ptr->uninit_refine(x, value); } Uninitialized uninit_to_uninitialized(VariableRef x) const override { return this->_ptr->uninit_to_uninitialized(x); } /// @} /// \name Machine integer abstract domain methods /// @{ void int_assign(VariableRef x, const MachineInt& n) override { this->_ptr->int_assign(x, n); } void int_assign_undef(VariableRef x) override { this->_ptr->int_assign_undef(x); } void int_assign_nondet(VariableRef x) override { this->_ptr->int_assign_nondet(x); } void int_assign(VariableRef x, VariableRef y) override { this->_ptr->int_assign(x, y); } void int_assign(VariableRef x, const IntLinearExpression& e) override { this->_ptr->int_assign(x, e); } void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) override { this->_ptr->int_apply(op, x, y); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_ptr->int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_ptr->int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_ptr->int_apply(op, x, y, z); } void int_add(IntPredicate pred, VariableRef x, VariableRef y) override { this->_ptr->int_add(pred, x, y); } void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) override { this->_ptr->int_add(pred, x, y); } void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) override { this->_ptr->int_add(pred, x, y); } void int_set(VariableRef x, const IntInterval& value) override { this->_ptr->int_set(x, value); } void int_set(VariableRef x, const IntCongruence& value) override { this->_ptr->int_set(x, value); } void int_set(VariableRef x, const IntIntervalCongruence& value) override { this->_ptr->int_set(x, value); } void int_refine(VariableRef x, const IntInterval& value) override { this->_ptr->int_refine(x, value); } void int_refine(VariableRef x, const IntCongruence& value) override { this->_ptr->int_refine(x, value); } void int_refine(VariableRef x, const IntIntervalCongruence& value) override { this->_ptr->int_refine(x, value); } void int_forget(VariableRef x) override { this->_ptr->int_forget(x); } IntInterval int_to_interval(VariableRef x) const override { return this->_ptr->int_to_interval(x); } IntInterval int_to_interval(const IntLinearExpression& e) const override { return this->_ptr->int_to_interval(e); } IntCongruence int_to_congruence(VariableRef x) const override { return this->_ptr->int_to_congruence(x); } IntCongruence int_to_congruence(const IntLinearExpression& e) const override { return this->_ptr->int_to_congruence(e); } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { return this->_ptr->int_to_interval_congruence(x); } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { return this->_ptr->int_to_interval_congruence(e); } /// @} /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_ptr->counter_mark(x); } void counter_unmark(VariableRef x) override { this->_ptr->counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { this->_ptr->counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { this->_ptr->counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_ptr->counter_forget(x); } /// @} /// \name Floating point abstract domain methods /// @{ void float_assign_undef(VariableRef x) override { this->_ptr->float_assign_undef(x); } void float_assign_nondet(VariableRef x) override { this->_ptr->float_assign_nondet(x); } void float_assign(VariableRef x, VariableRef y) override { this->_ptr->float_assign(x, y); } void float_forget(VariableRef x) override { this->_ptr->float_forget(x); } /// @} /// \name Nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef p) override { this->_ptr->nullity_assert_null(p); } void nullity_assert_non_null(VariableRef p) override { this->_ptr->nullity_assert_non_null(p); } bool nullity_is_null(VariableRef p) const override { return this->_ptr->nullity_is_null(p); } bool nullity_is_non_null(VariableRef p) const override { return this->_ptr->nullity_is_non_null(p); } void nullity_set(VariableRef p, Nullity value) override { this->_ptr->nullity_set(p, value); } void nullity_refine(VariableRef p, Nullity value) override { this->_ptr->nullity_refine(p, value); } Nullity nullity_to_nullity(VariableRef p) const override { return this->_ptr->nullity_to_nullity(p); } /// @} /// \name Pointer abstract domain methods /// @{ void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) override { this->_ptr->pointer_assign(p, addr, nullity); } void pointer_assign_null(VariableRef p) override { this->_ptr->pointer_assign_null(p); } void pointer_assign_undef(VariableRef p) override { this->_ptr->pointer_assign_undef(p); } void pointer_assign_nondet(VariableRef p) override { this->_ptr->pointer_assign_nondet(p); } void pointer_assign(VariableRef p, VariableRef q) override { this->_ptr->pointer_assign(p, q); } void pointer_assign(VariableRef p, VariableRef q, VariableRef o) override { this->_ptr->pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) override { this->_ptr->pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) override { this->_ptr->pointer_assign(p, q, o); } void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) override { this->_ptr->pointer_add(pred, p, q); } void pointer_refine(VariableRef p, const PointsToSetT& addrs) override { this->_ptr->pointer_refine(p, addrs); } void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) override { this->_ptr->pointer_refine(p, addrs, offset); } void pointer_refine(VariableRef p, const PointerAbsValueT& value) override { this->_ptr->pointer_refine(p, value); } void pointer_refine(VariableRef p, const PointerSetT& set) override { this->_ptr->pointer_refine(p, set); } void pointer_offset_to_int(VariableRef x, VariableRef p) override { this->_ptr->pointer_offset_to_int(x, p); } IntInterval pointer_offset_to_interval(VariableRef p) const override { return this->_ptr->pointer_offset_to_interval(p); } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { return this->_ptr->pointer_offset_to_congruence(p); } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { return this->_ptr->pointer_offset_to_interval_congruence(p); } PointsToSetT pointer_to_points_to(VariableRef p) const override { return this->_ptr->pointer_to_points_to(p); } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { return this->_ptr->pointer_to_pointer(p); } void pointer_forget_offset(VariableRef p) override { this->_ptr->pointer_forget_offset(p); } void pointer_forget(VariableRef p) override { this->_ptr->pointer_forget(p); } /// @} /// \name Dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef x, VariableRef y) override { this->_ptr->dynamic_assign(x, y); } void dynamic_write_undef(VariableRef x) override { this->_ptr->dynamic_write_undef(x); } void dynamic_write_nondet(VariableRef x) override { this->_ptr->dynamic_write_nondet(x); } void dynamic_write_int(VariableRef x, const MachineInt& n) override { this->_ptr->dynamic_write_int(x, n); } void dynamic_write_nondet_int(VariableRef x) override { this->_ptr->dynamic_write_nondet_int(x); } void dynamic_write_int(VariableRef x, VariableRef y) override { this->_ptr->dynamic_write_int(x, y); } void dynamic_write_nondet_float(VariableRef x) override { this->_ptr->dynamic_write_nondet_float(x); } void dynamic_write_null(VariableRef x) override { this->_ptr->dynamic_write_null(x); } void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) override { this->_ptr->dynamic_write_pointer(x, addr, nullity); } void dynamic_write_pointer(VariableRef x, VariableRef y) override { this->_ptr->dynamic_write_pointer(x, y); } void dynamic_read_int(VariableRef x, VariableRef y) override { this->_ptr->dynamic_read_int(x, y); } void dynamic_read_pointer(VariableRef x, VariableRef y) override { this->_ptr->dynamic_read_pointer(x, y); } bool dynamic_is_zero(VariableRef x) const override { return this->_ptr->dynamic_is_zero(x); } bool dynamic_is_null(VariableRef x) const override { return this->_ptr->dynamic_is_null(x); } void dynamic_forget(VariableRef x) override { this->_ptr->dynamic_forget(x); } /// @} /// \name Scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef x) override { this->_ptr->scalar_assign_undef(x); } void scalar_assign_nondet(VariableRef x) override { this->_ptr->scalar_assign_nondet(x); } void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) override { this->_ptr->scalar_pointer_to_int(x, p, absolute_zero); } void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) override { this->_ptr->scalar_int_to_pointer(p, x, absolute_zero); } void scalar_forget(VariableRef x) override { this->_ptr->scalar_forget(x); } /// @} /// \name Memory abstract domain methods /// @{ void mem_write(VariableRef p, const LiteralT& v, const MachineInt& size) override { this->_ptr->mem_write(p, v, size); } void mem_read(const LiteralT& x, VariableRef p, const MachineInt& size) override { this->_ptr->mem_read(x, p, size); } void mem_copy(VariableRef dest, VariableRef src, const LiteralT& size) override { this->_ptr->mem_copy(dest, src, size); } void mem_set(VariableRef dest, const LiteralT& value, const LiteralT& size) override { this->_ptr->mem_set(dest, value, size); } void mem_forget_all() override { this->_ptr->mem_forget_all(); } void mem_forget(MemoryLocationRef addr) override { this->_ptr->mem_forget(addr); } void mem_forget(MemoryLocationRef addr, const IntInterval& offset, const MachineInt& size) override { this->_ptr->mem_forget(addr, offset, size); } void mem_forget(MemoryLocationRef addr, const IntInterval& range) override { this->_ptr->mem_forget(addr, range); } void mem_forget_reachable(VariableRef p) override { this->_ptr->mem_forget_reachable(p); } void mem_forget_reachable(VariableRef p, const MachineInt& size) override { this->_ptr->mem_forget_reachable(p, size); } void mem_abstract_reachable(VariableRef p) override { this->_ptr->mem_abstract_reachable(p); } void mem_abstract_reachable(VariableRef p, const MachineInt& size) override { this->_ptr->mem_abstract_reachable(p, size); } void mem_zero_reachable(VariableRef p) override { this->_ptr->mem_zero_reachable(p); } void mem_uninitialize_reachable(VariableRef p) override { this->_ptr->mem_uninitialize_reachable(p); } /// @} /// \name Lifetime abstract domain methods /// @{ void lifetime_assign_allocated(MemoryLocationRef m) override { this->_ptr->lifetime_assign_allocated(m); } void lifetime_assign_deallocated(MemoryLocationRef m) override { this->_ptr->lifetime_assign_deallocated(m); } void lifetime_assert_allocated(MemoryLocationRef m) override { this->_ptr->lifetime_assert_allocated(m); } void lifetime_assert_deallocated(MemoryLocationRef m) override { this->_ptr->lifetime_assert_deallocated(m); } void lifetime_forget(MemoryLocationRef m) override { this->_ptr->lifetime_forget(m); } void lifetime_set(MemoryLocationRef m, Lifetime value) override { this->_ptr->lifetime_set(m, value); } Lifetime lifetime_to_lifetime(MemoryLocationRef m) const override { return this->_ptr->lifetime_to_lifetime(m); } /// @} /// \name Partitioning abstract domain methods /// @{ void partitioning_set_variable(VariableRef x) override { this->_ptr->partitioning_set_variable(x); } boost::optional< VariableRef > partitioning_variable() const override { return this->_ptr->partitioning_variable(); } void partitioning_join() override { this->_ptr->partitioning_join(); } void partitioning_disable() override { this->_ptr->partitioning_disable(); } /// @} void dump(std::ostream& o) const override { this->_ptr->dump(o); } static std::string name() { return "polymorphic domain"; } }; // end class PolymorphicDomain } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/value.hpp000066400000000000000000002126221473507761200254770ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief A value abstract domain 'a la' Mine parameterized by a numerical * abstract domain. * * Based on the paper "Field-Sensitive Value Analysis of Embedded C * Programs with Union Types and Pointer Arithmetics" by A. Mine * (LCTES'06) * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * Clement Decoodt * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace memory { /// \brief Value abstract domain /// /// Memory abstraction consisting of cells and a scalar abstract domain. /// /// This domain abstracts memory into a set of memory cells with /// integer, float or pointer type following Mine's paper. If a cell is /// of type integer this domain can model its value and whether it is /// initialized or not. If the cell is of type float, the domain keeps /// track of whether it is initialized or not. If the cell is of pointer /// type this domain keeps track of its address, its offset, whether it is /// null or not and whether it is initialized or not. /// /// A memory cell is a triple `(base, offset, size)` modelling all bytes at /// address `base`, starting at offset `offset` up to `offset + size - 1`. A /// memory cell is represented by a variable implementing /// `memory::CellVariableTraits`. The variable has a dynamic type. It is /// either an integer of 8*size bits, a floating point of 8*size bits or a /// pointer. /// /// Note that offset variables should be unsigned. template < typename VariableRef, typename MemoryLocationRef, typename CellFactoryRef, typename ScalarDomain, typename LifetimeDomain > class ValueDomain final : public memory::AbstractDomain< VariableRef, MemoryLocationRef, ValueDomain< VariableRef, MemoryLocationRef, CellFactoryRef, ScalarDomain, LifetimeDomain > > { public: static_assert(memory::IsCellVariable< VariableRef, MemoryLocationRef >::value, "VariableRef must implement memory::CellVariableTraits"); static_assert(memory::IsCellFactory< VariableRef, MemoryLocationRef, CellFactoryRef >::value, "CellFactoryRef must implement memory::CellFactoryTraits"); static_assert(scalar::IsAbstractDomain< ScalarDomain, VariableRef, MemoryLocationRef >::value, "ScalarDomain must implement scalar::AbstractDomain"); static_assert( lifetime::IsAbstractDomain< LifetimeDomain, MemoryLocationRef >::value, "LifetimeDomain must implement lifetime::AbstractDomain"); public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; using LiteralT = Literal< VariableRef, MemoryLocationRef >; private: using CellSetT = CellSet< VariableRef >; using MemLocToCellSetT = MemLocToCellSet< MemoryLocationRef, VariableRef >; using MemLocToPointerSetT = MemLocToPointerSet< MemoryLocationRef >; using MachIntVariableTrait = machine_int::VariableTraits< VariableRef >; using ScalarVariableTrait = scalar::VariableTraits< VariableRef >; using CellVariableTrait = memory::CellVariableTraits< VariableRef, MemoryLocationRef >; using CellFactoryTrait = memory:: CellFactoryTraits< VariableRef, MemoryLocationRef, CellFactoryRef >; private: /// \brief Cell factory CellFactoryRef _cell_factory; /// \brief Underlying scalar domain ScalarDomain _scalar; /// \brief Map from memory location to set of cells MemLocToCellSetT _cells; /// \brief Map from memory location to set of pointers MemLocToPointerSetT _pointer_sets; /// \brief Underlying lifetime abstract domain LifetimeDomain _lifetime; private: /// \brief Constructor ValueDomain(CellFactoryRef cell_factory, ScalarDomain scalar, MemLocToCellSetT cells, MemLocToPointerSetT pointer_sets, LifetimeDomain lifetime) : _cell_factory(std::move(cell_factory)), _scalar(std::move(scalar)), _cells(std::move(cells)), _pointer_sets(std::move(pointer_sets)), _lifetime(std::move(lifetime)) { this->normalize(); } public: /// \brief Create an abstract value with the given underlying abstract values /// /// \param cell_factory The cell factory /// \param scalar The scalar abstract value /// \param lifetime The lifetime abstract value ValueDomain(CellFactoryRef cell_factory, ScalarDomain scalar, LifetimeDomain lifetime) : _cell_factory(std::move(cell_factory)), _scalar(std::move(scalar)), _cells(MemLocToCellSetT::top()), _pointer_sets(MemLocToPointerSetT::top()), _lifetime(std::move(lifetime)) { this->normalize(); } /// \brief Copy constructor ValueDomain(const ValueDomain&) noexcept( (std::is_nothrow_copy_constructible< ScalarDomain >::value) && (std::is_nothrow_copy_constructible< LifetimeDomain >::value)) = default; /// \brief Move constructor ValueDomain(ValueDomain&&) noexcept( (std::is_nothrow_move_constructible< ScalarDomain >::value) && (std::is_nothrow_move_constructible< LifetimeDomain >::value)) = default; /// \brief Copy assignment operator ValueDomain& operator=(const ValueDomain&) noexcept( (std::is_nothrow_copy_assignable< ScalarDomain >::value) && (std::is_nothrow_copy_assignable< LifetimeDomain >::value)) = default; /// \brief Move assignment operator ValueDomain& operator=(ValueDomain&&) noexcept( (std::is_nothrow_move_assignable< ScalarDomain >::value) && (std::is_nothrow_move_assignable< LifetimeDomain >::value)) = default; /// \brief Destructor ~ValueDomain() override = default; /// \name Implement core abstract domain methods /// @{ void normalize() override { this->_lifetime.normalize(); if (this->_lifetime.is_bottom()) { this->set_to_bottom(); return; } this->_pointer_sets.normalize(); if (this->_pointer_sets.is_bottom()) { this->set_to_bottom(); return; } this->_cells.normalize(); if (this->_cells.is_bottom()) { this->set_to_bottom(); return; } this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } } private: /// \brief Return true if the abstract value is bottom /// /// This is not always correct since it doesn't check this->_scalar bool is_bottom_fast() const { return this->_cells.is_bottom(); } public: bool is_bottom() const override { return this->_lifetime.is_bottom() || this->_pointer_sets.is_bottom() || this->_cells.is_bottom() || this->_scalar.is_bottom(); } bool is_top() const override { return this->_lifetime.is_top() && this->_pointer_sets.is_top() && this->_cells.is_top() && this->_scalar.is_top(); } void set_to_bottom() override { this->_scalar.set_to_bottom(); this->_cells.set_to_bottom(); this->_pointer_sets.set_to_bottom(); this->_lifetime.set_to_bottom(); } void set_to_top() override { this->_scalar.set_to_top(); this->_cells.set_to_top(); this->_pointer_sets.set_to_top(); this->_lifetime.set_to_top(); } bool leq(const ValueDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_scalar.leq(other._scalar) && this->_cells.leq(other._cells) && this->_pointer_sets.leq(other._pointer_sets) && this->_lifetime.leq(other._lifetime); } } bool equals(const ValueDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_scalar.equals(other._scalar) && this->_cells.equals(other._cells) && this->_pointer_sets.equals(other._pointer_sets) && this->_lifetime.equals(other._lifetime); } } void join_with(ValueDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_scalar.join_with(std::move(other._scalar)); this->_cells.join_with(std::move(other._cells)); this->_pointer_sets.join_with(std::move(other._pointer_sets)); this->_lifetime.join_with(std::move(other._lifetime)); } } void join_with(const ValueDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_scalar.join_with(other._scalar); this->_cells.join_with(other._cells); this->_pointer_sets.join_with(other._pointer_sets); this->_lifetime.join_with(other._lifetime); } } void join_loop_with(ValueDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_scalar.join_loop_with(std::move(other._scalar)); this->_cells.join_loop_with(std::move(other._cells)); this->_pointer_sets.join_loop_with(std::move(other._pointer_sets)); this->_lifetime.join_loop_with(std::move(other._lifetime)); } } void join_loop_with(const ValueDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_scalar.join_loop_with(other._scalar); this->_cells.join_loop_with(other._cells); this->_pointer_sets.join_loop_with(other._pointer_sets); this->_lifetime.join_loop_with(other._lifetime); } } void join_iter_with(ValueDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_scalar.join_iter_with(std::move(other._scalar)); this->_cells.join_iter_with(std::move(other._cells)); this->_pointer_sets.join_iter_with(std::move(other._pointer_sets)); this->_lifetime.join_iter_with(std::move(other._lifetime)); } } void join_iter_with(const ValueDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_scalar.join_iter_with(other._scalar); this->_cells.join_iter_with(other._cells); this->_pointer_sets.join_iter_with(other._pointer_sets); this->_lifetime.join_iter_with(other._lifetime); } } void widen_with(const ValueDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_scalar.widen_with(other._scalar); this->_cells.widen_with(other._cells); this->_pointer_sets.widen_with(other._pointer_sets); this->_lifetime.widen_with(other._lifetime); } } void widen_threshold_with(const ValueDomain& other, const MachineInt& threshold) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_scalar.widen_threshold_with(other._scalar, threshold); this->_cells.widen_with(other._cells); this->_pointer_sets.join_with(other._pointer_sets); this->_lifetime.widen_with(other._lifetime); } } void meet_with(const ValueDomain& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_scalar.meet_with(other._scalar); this->_cells.meet_with(other._cells); this->_pointer_sets.meet_with(other._pointer_sets); this->_lifetime.meet_with(other._lifetime); } } void narrow_with(const ValueDomain& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_scalar.narrow_with(other._scalar); this->_cells.narrow_with(other._cells); this->_pointer_sets.narrow_with(other._pointer_sets); this->_lifetime.narrow_with(other._lifetime); } } void narrow_threshold_with(const ValueDomain& other, const MachineInt& threshold) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_scalar.narrow_threshold_with(other._scalar, threshold); this->_cells.narrow_with(other._cells); this->_pointer_sets.narrow_with(other._pointer_sets); this->_lifetime.narrow_with(other._lifetime); } } ValueDomain join(const ValueDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return ValueDomain(this->_cell_factory, this->_scalar.join(other._scalar), this->_cells.join(other._cells), this->_pointer_sets.join(other._pointer_sets), this->_lifetime.join(other._lifetime)); } } ValueDomain join_loop(const ValueDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return ValueDomain(this->_cell_factory, this->_scalar.join_loop(other._scalar), this->_cells.join_loop(other._cells), this->_pointer_sets.join_loop(other._pointer_sets), this->_lifetime.join_loop(other._lifetime)); } } ValueDomain join_iter(const ValueDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return ValueDomain(this->_cell_factory, this->_scalar.join_iter(other._scalar), this->_cells.join_iter(other._cells), this->_pointer_sets.join_iter(other._pointer_sets), this->_lifetime.join_iter(other._lifetime)); } } ValueDomain widening(const ValueDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return ValueDomain(this->_cell_factory, this->_scalar.widening(other._scalar), this->_cells.widening(other._cells), this->_pointer_sets.widening(other._pointer_sets), this->_lifetime.widening(other._lifetime)); } } ValueDomain widening_threshold(const ValueDomain& other, const MachineInt& threshold) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return ValueDomain(this->_cell_factory, this->_scalar.widening_threshold(other._scalar, threshold), this->_cells.widening(other._cells), this->_pointer_sets.join(other._pointer_sets), this->_lifetime.widening(other._lifetime)); } } ValueDomain meet(const ValueDomain& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return ValueDomain(this->_cell_factory, this->_scalar.meet(other._scalar), this->_cells.meet(other._cells), this->_pointer_sets.meet(other._pointer_sets), this->_lifetime.meet(other._lifetime)); } } ValueDomain narrowing(const ValueDomain& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return ValueDomain(this->_cell_factory, this->_scalar.narrowing(other._scalar), this->_cells.narrowing(other._cells), this->_pointer_sets.narrowing(other._pointer_sets), this->_lifetime.narrowing(other._lifetime)); } } ValueDomain narrowing_threshold(const ValueDomain& other, const MachineInt& threshold) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return ValueDomain(this->_cell_factory, this->_scalar.narrowing_threshold(other._scalar, threshold), this->_cells.narrowing(other._cells), this->_pointer_sets.narrowing(other._pointer_sets), this->_lifetime.narrowing(other._lifetime)); } } /// @} /// \name Implement uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef x) override { this->_scalar.uninit_assert_initialized(x); } bool uninit_is_initialized(VariableRef x) const override { return this->_scalar.uninit_is_initialized(x); } bool uninit_is_uninitialized(VariableRef x) const override { return this->_scalar.uninit_is_uninitialized(x); } void uninit_refine(VariableRef x, Uninitialized value) override { this->_scalar.uninit_refine(x, value); } Uninitialized uninit_to_uninitialized(VariableRef x) const override { return this->_scalar.uninit_to_uninitialized(x); } /// @} /// \name Implement machine integer abstract domain methods /// @{ void int_assign(VariableRef x, const MachineInt& n) override { this->_scalar.int_assign(x, n); } void int_assign_undef(VariableRef x) override { this->_scalar.int_assign_undef(x); } void int_assign_nondet(VariableRef x) override { this->_scalar.int_assign_nondet(x); } void int_assign(VariableRef x, VariableRef y) override { this->_scalar.int_assign(x, y); } void int_assign(VariableRef x, const IntLinearExpression& e) override { this->_scalar.int_assign(x, e); } void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) override { this->_scalar.int_apply(op, x, y); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_scalar.int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { this->_scalar.int_apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { this->_scalar.int_apply(op, x, y, z); } void int_add(IntPredicate pred, VariableRef x, VariableRef y) override { this->_scalar.int_add(pred, x, y); } void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) override { this->_scalar.int_add(pred, x, y); } void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) override { this->_scalar.int_add(pred, x, y); } void int_set(VariableRef x, const IntInterval& value) override { this->_scalar.int_set(x, value); } void int_set(VariableRef x, const IntCongruence& value) override { this->_scalar.int_set(x, value); } void int_set(VariableRef x, const IntIntervalCongruence& value) override { this->_scalar.int_set(x, value); } void int_refine(VariableRef x, const IntInterval& value) override { this->_scalar.int_refine(x, value); } void int_refine(VariableRef x, const IntCongruence& value) override { this->_scalar.int_refine(x, value); } void int_refine(VariableRef x, const IntIntervalCongruence& value) override { this->_scalar.int_refine(x, value); } void int_forget(VariableRef x) override { this->_scalar.int_forget(x); } IntInterval int_to_interval(VariableRef x) const override { return this->_scalar.int_to_interval(x); } IntInterval int_to_interval(const IntLinearExpression& e) const override { return this->_scalar.int_to_interval(e); } IntCongruence int_to_congruence(VariableRef x) const override { return this->_scalar.int_to_congruence(x); } IntCongruence int_to_congruence(const IntLinearExpression& e) const override { return this->_scalar.int_to_congruence(e); } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { return this->_scalar.int_to_interval_congruence(x); } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { return this->_scalar.int_to_interval_congruence(e); } /// @} /// \name Implement non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_scalar.counter_mark(x); } void counter_unmark(VariableRef x) override { this->_scalar.counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { this->_scalar.counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { this->_scalar.counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_scalar.counter_forget(x); } /// @} /// \name Implement floating point abstract domain methods /// @{ void float_assign_undef(VariableRef x) override { this->_scalar.float_assign_undef(x); } void float_assign_nondet(VariableRef x) override { this->_scalar.float_assign_nondet(x); } void float_assign(VariableRef x, VariableRef y) override { this->_scalar.float_assign(x, y); } void float_forget(VariableRef x) override { this->_scalar.float_forget(x); } /// @} /// \name Implement nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef p) override { this->_scalar.nullity_assert_null(p); } void nullity_assert_non_null(VariableRef p) override { this->_scalar.nullity_assert_non_null(p); } bool nullity_is_null(VariableRef p) const override { return this->_scalar.nullity_is_null(p); } bool nullity_is_non_null(VariableRef p) const override { return this->_scalar.nullity_is_non_null(p); } void nullity_set(VariableRef p, Nullity value) override { this->_scalar.nullity_set(p, value); } void nullity_refine(VariableRef p, Nullity value) override { this->_scalar.nullity_refine(p, value); } Nullity nullity_to_nullity(VariableRef p) const override { return this->_scalar.nullity_to_nullity(p); } /// @} /// \name Implement pointer abstract domain methods /// @{ void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) override { this->_scalar.pointer_assign(p, addr, nullity); } void pointer_assign_null(VariableRef p) override { this->_scalar.pointer_assign_null(p); } void pointer_assign_undef(VariableRef p) override { this->_scalar.pointer_assign_undef(p); } void pointer_assign_nondet(VariableRef p) override { this->_scalar.pointer_assign_nondet(p); } void pointer_assign(VariableRef p, VariableRef q) override { this->_scalar.pointer_assign(p, q); } void pointer_assign(VariableRef p, VariableRef q, VariableRef o) override { this->_scalar.pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) override { this->_scalar.pointer_assign(p, q, o); } void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) override { this->_scalar.pointer_assign(p, q, o); } void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) override { this->_scalar.pointer_add(pred, p, q); } void pointer_refine(VariableRef p, const PointsToSetT& addrs) override { this->_scalar.pointer_refine(p, addrs); } void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) override { this->_scalar.pointer_refine(p, addrs, offset); } void pointer_refine(VariableRef p, const PointerAbsValueT& value) override { this->_scalar.pointer_refine(p, value); } void pointer_refine(VariableRef p, const PointerSetT& set) override { this->_scalar.pointer_refine(p, set); } void pointer_offset_to_int(VariableRef x, VariableRef p) override { this->_scalar.pointer_offset_to_int(x, p); } IntInterval pointer_offset_to_interval(VariableRef p) const override { return this->_scalar.pointer_offset_to_interval(p); } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { return this->_scalar.pointer_offset_to_congruence(p); } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { return this->_scalar.pointer_offset_to_interval_congruence(p); } PointsToSetT pointer_to_points_to(VariableRef p) const override { return this->_scalar.pointer_to_points_to(p); } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { return this->_scalar.pointer_to_pointer(p); } void pointer_forget_offset(VariableRef p) override { this->_scalar.pointer_forget_offset(p); } void pointer_forget(VariableRef p) override { this->_scalar.pointer_forget(p); } /// @} /// \name Implement dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef x, VariableRef y) override { this->_scalar.dynamic_assign(x, y); } void dynamic_write_undef(VariableRef x) override { this->_scalar.dynamic_write_undef(x); } void dynamic_write_nondet(VariableRef x) override { this->_scalar.dynamic_write_nondet(x); } void dynamic_write_int(VariableRef x, const MachineInt& n) override { this->_scalar.dynamic_write_int(x, n); } void dynamic_write_nondet_int(VariableRef x) override { this->_scalar.dynamic_write_nondet_int(x); } void dynamic_write_int(VariableRef x, VariableRef y) override { this->_scalar.dynamic_write_int(x, y); } void dynamic_write_nondet_float(VariableRef x) override { this->_scalar.dynamic_write_nondet_float(x); } void dynamic_write_null(VariableRef x) override { this->_scalar.dynamic_write_null(x); } void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) override { this->_scalar.dynamic_write_pointer(x, addr, nullity); } void dynamic_write_pointer(VariableRef x, VariableRef y) override { this->_scalar.dynamic_write_pointer(x, y); } void dynamic_read_int(VariableRef x, VariableRef y) override { this->_scalar.dynamic_read_int(x, y); } void dynamic_read_pointer(VariableRef x, VariableRef y) override { this->_scalar.dynamic_read_pointer(x, y); } bool dynamic_is_zero(VariableRef x) const override { return this->_scalar.dynamic_is_zero(x); } bool dynamic_is_null(VariableRef x) const override { return this->_scalar.dynamic_is_null(x); } void dynamic_forget(VariableRef x) override { this->_scalar.dynamic_forget(x); } /// @} /// \name Implement scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef x) override { this->_scalar.scalar_assign_undef(x); } void scalar_assign_nondet(VariableRef x) override { this->_scalar.scalar_assign_nondet(x); } void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) override { this->_scalar.scalar_pointer_to_int(x, p, absolute_zero); } void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) override { this->_scalar.scalar_int_to_pointer(p, x, absolute_zero); } void scalar_forget(VariableRef x) override { this->_scalar.scalar_forget(x); } /// @} /// \name Implement memory abstract domain methods /// @{ private: /// \brief Preferred signedness for a cell created from a literal /// /// For machine integers, return the integer sign /// For floating points, return Signed /// For pointers, return Unsigned class LiteralPreferredSignedness : public LiteralT::template Visitor< Signedness > { public: LiteralPreferredSignedness() = default; Signedness machine_int(const MachineInt& i) const { return i.sign(); } Signedness floating_point(const DummyNumber&) const { return Signed; } Signedness memory_location(MemoryLocationRef) const { return Unsigned; } Signedness null() const { return Unsigned; } Signedness undefined() const { return Signed; } Signedness machine_int_var(VariableRef var) const { return MachIntVariableTrait::sign(var); } Signedness floating_point_var(VariableRef) const { return Signed; } Signedness pointer_var(VariableRef) const { return Unsigned; } }; // end class LiteralPreferredSignedness /// \brief Return the preferred signedness for a cell creating from the given /// literal Signedness preferred_cell_sign(const LiteralT& lit) const { return lit.apply_visitor(LiteralPreferredSignedness()); } /// \brief Get or create the cell with the given base address, offset and size /// /// If a new cell is created, it will have the given signedness VariableRef make_cell(MemoryLocationRef base, const MachineInt& offset, const MachineInt& size, Signedness sign) { ikos_assert(offset.sign() == Unsigned); ikos_assert(size.sign() == Unsigned); ikos_assert(size.is_strictly_positive()); VariableRef c = CellFactoryTrait::cell(this->_cell_factory, base, offset, size, sign); ikos_assert(CellVariableTrait::is_cell(c)); ikos_assert(MachIntVariableTrait::bit_width(c) == size.to< uint64_t >() * 8); return c; } /// \brief Return the byte range for a given cell IntInterval cell_range(VariableRef cell) const { const MachineInt& offset = CellVariableTrait::offset(cell); const MachineInt& size = CellVariableTrait::size(cell); auto one = MachineInt(1, offset.bit_width(), Unsigned); return IntInterval(offset, offset + (size - one)); } /// \brief Return true if the given cell overlaps with the given byte range bool cell_overlap(VariableRef cell, const IntInterval& range) const { IntInterval meet = this->cell_range(cell).meet(range); return !meet.is_bottom(); } /// \brief Return true if the given cells overlap bool cell_overlap(VariableRef a, VariableRef b) const { return this->cell_overlap(a, this->cell_range(b)); } /// \brief Return true if the memory write at `offset` of size `size` /// can update the given cell. Return false if the number of overlaps between /// the cell and the memory write is not exactly 1. /// /// For instance: /// * If Cell{o,4,4}, offset=[0, 8], size=4: returns false /// * If Cell{o,4,4}, offset=[4, 4], size=2: returns false /// * If Cell{o,4,4}, offset=[0, 8], offset=4Z+0, size=4, returns true /// * If Cell{o,4,4}, offset=[0, 8], offset=4Z+1, size=4, returns false bool cell_realizes_once(VariableRef cell, IntIntervalCongruence offset, const MachineInt& size) const { const MachineInt& cell_offset = CellVariableTrait::offset(cell); const MachineInt& cell_size = CellVariableTrait::size(cell); auto one = MachineInt(1, size.bit_width(), Unsigned); if (size != cell_size) { return false; } // Keep offsets that could 'touch' the cell bool overflow = false; // offset <= cell_offset + cell_size - 1 MachineInt ub = add(cell_offset, cell_size - one, overflow); if (overflow) { ub.set_max(); } // offset + size - 1 >= cell_offset MachineInt lb = sub(cell_offset, size - one, overflow); if (overflow) { lb.set_min(); } offset.meet_with(IntIntervalCongruence(IntInterval(lb, ub))); return offset == IntIntervalCongruence(cell_offset); } /// \brief Create a new cell for a write, performing reduction if possible VariableRef write_realize_single_cell(MemoryLocationRef base, const MachineInt& offset, const MachineInt& size, Signedness sign) { VariableRef new_cell = this->make_cell(base, offset, size, sign); const CellSetT& cells = this->_cells.get(base); if (cells.is_empty()) { // No cell found for the base address this->_cells.set(base, CellSetT{new_cell}); return new_cell; } CellSetT new_cells = cells; bool found = false; // Remove overlapping cells for (VariableRef cell : cells) { if (cell == new_cell) { found = true; } else if (this->cell_overlap(cell, new_cell)) { if (this->_scalar.uninit_is_uninitialized(cell)) { // Make new uninitialized cells for the parts not covered // by the new_cell. IntInterval new_interval = this->cell_range(new_cell); MachineInt new_lb = new_interval.lb(); MachineInt new_ub = new_interval.ub(); IntInterval un_interval = this->cell_range(cell); MachineInt un_lb = un_interval.lb(); MachineInt un_ub = un_interval.ub(); if (un_lb < new_lb) { MachineInt low_size = new_lb - un_lb; VariableRef low_cell = this->make_cell(base, un_lb, low_size, sign); this->_scalar.uninit_refine(low_cell, Uninitialized::uninitialized()); new_cells.add(low_cell); } if (new_ub < un_ub) { MachineInt high_size = un_ub - new_ub; auto one = MachineInt(1, high_size.bit_width(), Unsigned); MachineInt high_lb = new_ub + one; VariableRef high_cell = this->make_cell(base, high_lb, high_size, sign); this->_scalar.uninit_refine(high_cell, Uninitialized::uninitialized()); new_cells.add(high_cell); } } this->_scalar.dynamic_forget(cell); new_cells.remove(cell); } } if (!found) { new_cells.add(new_cell); } this->_cells.set(base, new_cells); return new_cell; } /// \brief Perform a write with an approximated offset. /// /// Returns a list of cells on which we should perform a weak update. std::vector< VariableRef > write_realize_range_cells( MemoryLocationRef base, const IntIntervalCongruence& offset, const MachineInt& size) { // Write byte range auto zero = MachineInt::zero(size.bit_width(), Unsigned); auto one = MachineInt(1, size.bit_width(), Unsigned); IntInterval range = add(offset.interval(), IntInterval(zero, size - one)); // Current list of cells const CellSetT& cells = this->_cells.get(base); if (cells.is_empty()) { // no cell found for the base address return {}; } CellSetT new_cells = cells; std::vector< VariableRef > updated_cells; for (VariableRef cell : cells) { if (this->cell_overlap(cell, range)) { if (this->cell_realizes_once(cell, offset, size)) { // This cell has only one way to be affected by the write statement updated_cells.push_back(cell); } else { this->_scalar.dynamic_forget(cell); new_cells.remove(cell); } } } this->_cells.set(base, new_cells); return updated_cells; } /// \brief Detect whether the read bits are initialized, uninitialized, /// for possibly uninitialized. ikos::core::Uninitialized is_read_uninitialized(MemoryLocationRef base, const MachineInt& offset, const MachineInt& size) { if (!size.fits< uint32_t >()) { // The ZNumber infrastructure cannot handle shifts by // more than the max 32-bit number, so give up in that case. // and assume possibly uninitialized. return ikos::core::Uninitialized::top(); } // Use ZNumbers as bitvectors for bits [0,size) relative to the // low bound of the read (i.e. offset). ZNumber zoffset = offset.to_z_number(); ZNumber zsize = size.to_z_number(); ZNumber zupper = zoffset + zsize; ZNumber read_mask = make_clipped_mask(zoffset, zsize, zoffset, zsize); CellSetT cells = this->_cells.get(base); ZNumber initialized_coverage = ZNumber(0); ZNumber uninitialized_coverage = ZNumber(0); for (VariableRef cell : cells) { ZNumber other_offset = CellVariableTrait::offset(cell).to_z_number(); ZNumber other_size = CellVariableTrait::size(cell).to_z_number(); ZNumber cell_mask = make_clipped_mask(other_offset, other_size, zoffset, zsize); Uninitialized cell_uninit = this->uninit_to_uninitialized(cell); if (cell_uninit == ikos::core::Uninitialized::initialized()) { initialized_coverage |= cell_mask; } else if (cell_uninit == ikos::core::Uninitialized::uninitialized()) { uninitialized_coverage |= cell_mask; } } if (read_mask == initialized_coverage) { // The read bits are completely initialized return ikos::core::Uninitialized::initialized(); } else if (read_mask == uninitialized_coverage) { // The read bits are all uninitialized return ikos::core::Uninitialized::uninitialized(); } // The bits may or may not be initialized, so top. return ikos::core::Uninitialized::top(); } /// \brief Create a new cell for a read VariableRef read_realize_single_cell(MemoryLocationRef base, const MachineInt& offset, const MachineInt& size, Signedness sign) { ikos::core::Uninitialized addr_uninit = is_read_uninitialized(base, offset, size); VariableRef new_cell = this->make_cell(base, offset, size, sign); this->_scalar.uninit_refine(new_cell, addr_uninit); CellSetT cells = this->_cells.get(base); cells.add(new_cell); this->_cells.set(base, cells); return new_cell; } /// \brief Assignment `var = literal` class LiteralWriter : public LiteralT::template Visitor<> { private: /// \brief Cell variable VariableRef _lhs; /// \brief Scalar abstract value ScalarDomain& _scalar; public: LiteralWriter(VariableRef lhs, ScalarDomain& scalar) : _lhs(lhs), _scalar(scalar) {} void machine_int(const MachineInt& rhs) { if (MachIntVariableTrait::bit_width(this->_lhs) == rhs.bit_width()) { this->_scalar.dynamic_write_int(this->_lhs, rhs); } else { this->_scalar.dynamic_write_nondet_int(this->_lhs); } } void floating_point(const DummyNumber&) { this->_scalar.dynamic_write_nondet_float(this->_lhs); } void memory_location(MemoryLocationRef addr) { this->_scalar.dynamic_write_pointer(this->_lhs, addr, Nullity::non_null()); } void null() { this->_scalar.dynamic_write_null(this->_lhs); } void undefined() { this->_scalar.dynamic_write_undef(this->_lhs); } void machine_int_var(VariableRef rhs) { if (MachIntVariableTrait::bit_width(_lhs) == MachIntVariableTrait::bit_width(rhs)) { this->_scalar.dynamic_write_int(this->_lhs, rhs); } else { this->_scalar.dynamic_write_nondet_int(this->_lhs); } } void floating_point_var(VariableRef /*rhs*/) { this->_scalar.dynamic_write_nondet_float(this->_lhs); } void pointer_var(VariableRef rhs) { this->_scalar.dynamic_write_pointer(this->_lhs, rhs); } }; // end class LiteralWriter /// \brief Assignment `literal = var` class LiteralReader : public LiteralT::template Visitor<> { private: /// \brief Cell variable VariableRef _rhs; /// \brief Scalar abstract value ScalarDomain& _scalar; public: LiteralReader(VariableRef rhs, ScalarDomain& scalar) : _rhs(rhs), _scalar(scalar) {} void machine_int(const MachineInt&) { ikos_unreachable("trying to assign a machine integer"); } void floating_point(const DummyNumber&) { ikos_unreachable("trying to assign a floating point"); } void memory_location(MemoryLocationRef) { ikos_unreachable("trying to assign a memory location"); } void null() { ikos_unreachable("trying to assign to null"); } void undefined() { ikos_unreachable("trying to assign to undefined"); } void machine_int_var(VariableRef lhs) { // If the right hand side is a null pointer, assign the integer to zero // (implicit cast from pointer to int) if (this->_scalar.dynamic_is_null(this->_rhs)) { auto zero = MachineInt::zero(MachIntVariableTrait::bit_width(lhs), MachIntVariableTrait::sign(lhs)); this->_scalar.int_assign(lhs, zero); } else if (MachIntVariableTrait::bit_width(lhs) == MachIntVariableTrait::bit_width(this->_rhs)) { this->_scalar.dynamic_read_int(lhs, this->_rhs); } else { this->_scalar.int_assign_nondet(lhs); } } void floating_point_var(VariableRef lhs) { this->_scalar.float_assign_nondet(lhs); } void pointer_var(VariableRef lhs) { // If the right hand side is the integer zero, assign the pointer to null // (implicit cast from int to pointer) if (this->_scalar.dynamic_is_zero(this->_rhs)) { this->_scalar.pointer_assign_null(lhs); } else { this->_scalar.dynamic_read_pointer(lhs, this->_rhs); } } }; // end class LiteralReader /// \brief Perform a strong update `lhs = rhs` void strong_update(VariableRef lhs, const LiteralT& rhs) { LiteralWriter v(lhs, this->_scalar); rhs.apply_visitor(v); } /// \brief Perform a weak update `lhs = rhs` void weak_update(VariableRef lhs, const LiteralT& rhs) { ScalarDomain scalar = this->_scalar; LiteralWriter v(lhs, scalar); rhs.apply_visitor(v); this->_scalar.join_with(std::move(scalar)); } /// \brief Perform a strong update `lhs = rhs` void strong_update(const LiteralT& lhs, VariableRef rhs) { LiteralReader v(rhs, this->_scalar); lhs.apply_visitor(v); } /// \brief Perform a weak update `lhs = rhs` void weak_update(const LiteralT& lhs, VariableRef rhs) { ScalarDomain scalar = this->_scalar; LiteralReader v(rhs, scalar); lhs.apply_visitor(v); this->_scalar.join_with(std::move(scalar)); } public: void mem_write(VariableRef ptr, const LiteralT& rhs, const MachineInt& size) override { ikos_assert(ScalarVariableTrait::is_pointer(ptr)); if (this->is_bottom_fast()) { return; } // Null/undefined pointer dereference this->_scalar.nullity_assert_non_null(ptr); // Writing an uninitialized variable is an error // Note that writing the undefined constant is allowed if (rhs.is_var()) { this->_scalar.uninit_assert_initialized(rhs.var()); } this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } // Memory locations pointed by the pointer PointsToSetT addrs = this->_scalar.pointer_to_points_to(ptr); if (addrs.is_empty()) { // Invalid dereference this->set_to_bottom(); return; } if (size.is_zero()) { // Does nothing return; } if (addrs.is_top()) { this->mem_forget_all(); // Very conservative, but sound return; } // // Update memory cells // // Offset interval-congruence IntIntervalCongruence offset_ic = this->_scalar.pointer_offset_to_interval_congruence(ptr); ikos_assert(offset_ic.sign() == Unsigned); if (offset_ic.singleton()) { // The offset has one possible value. // // We can perform the usual reduction and update. MachineInt offset = *offset_ic.singleton(); Signedness sign = this->preferred_cell_sign(rhs); for (MemoryLocationRef addr : addrs) { VariableRef cell = this->write_realize_single_cell(addr, offset, size, sign); if (addrs.size() == 1) { this->strong_update(cell, rhs); } else { this->weak_update(cell, rhs); } } } else { // The offset is a range. // // We check for all overlapping cells. If there is only one way to // write on that cell, we perform a weak update, otherwise we just // kill the cell. // // For instance, let's say offset=[0, 10], size=4 and we have a cell // C{o, 4, 4}. // // There are 7 ways to write on the cell: // C{o,1,4}, C{o,2,4}, ..., C{o,6,4} and C{o,7,4}. // Thus, we need to kill the cell. // // If we also have offset=4Z+0 from the underlying abstract domain, then // there is only one way: C{o,4,4} and thus we can perform a weak // update. for (MemoryLocationRef addr : addrs) { std::vector< VariableRef > cells = this->write_realize_range_cells(addr, offset_ic, size); for (VariableRef cell : cells) { this->weak_update(cell, rhs); } } } // // Update pointer sets // auto rhs_ptr = PointerAbsValueT::bottom(1, Unsigned); if (rhs.is_memory_location()) { rhs_ptr = PointerAbsValueT(Uninitialized::initialized(), Nullity::non_null(), PointsToSetT{rhs.memory_location()}, IntInterval(MachineInt::zero(offset_ic.bit_width(), Unsigned))); } else if (rhs.is_pointer_var()) { rhs_ptr = this->_scalar.pointer_to_pointer(rhs.var()); } else { // Right hand side is not a pointer, nothing else to do return; } for (MemoryLocationRef addr : addrs) { PointerSetT pointer_set = this->_pointer_sets.get(addr, offset_ic.bit_width(), Unsigned); pointer_set.add(rhs_ptr); this->_pointer_sets.set(addr, pointer_set); } } void mem_read(const LiteralT& lhs, VariableRef ptr, const MachineInt& size) override { ikos_assert(lhs.is_var()); ikos_assert(ScalarVariableTrait::is_pointer(ptr)); ikos_assert(size.is_strictly_positive()); if (this->is_bottom_fast()) { return; } // Null/undefined pointer dereference this->_scalar.nullity_assert_non_null(ptr); this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } // Memory locations pointed by the pointer PointsToSetT addrs = this->_scalar.pointer_to_points_to(ptr); if (addrs.is_empty()) { // Invalid dereference this->set_to_bottom(); return; } if (addrs.is_top()) { this->_scalar.scalar_assign_nondet(lhs.var()); return; } // // Handle memory cells // // Offset interval IntInterval offset_intv = this->_scalar.pointer_offset_to_interval(ptr); ikos_assert(offset_intv.sign() == Unsigned); if (offset_intv.singleton()) { // The offset has one possible value. // // We can perform the usual reduction and update. MachineInt offset = *offset_intv.singleton(); Signedness sign = this->preferred_cell_sign(lhs); bool first = true; for (MemoryLocationRef addr : addrs) { VariableRef cell = this->read_realize_single_cell(addr, offset, size, sign); if (first) { this->strong_update(lhs, cell); first = false; } else { this->weak_update(lhs, cell); } } } else { // The offset is a range. // // If we try to read a summarized region of the heap we just // return top. Note that we do not keep track of writes into // summarized cells that's why if we read a summarized cell // the only sound result we can return is top. // // TODO(jnavas): note that we could have a bounded array for which we // have the complete set of cells and thus we could be more // precise in that case. // // To deal with this situation in a more systematic way // we should combine anyway the value domain with some // summarization array-based domain (e.g.,some array domain // such as a trivial array smashing or something more // expressive like Cousot&Logozzo's POPL'11). this->_scalar.scalar_assign_nondet(lhs.var()); } // // Handle pointer sets // if (lhs.is_pointer_var()) { PointerSetT pointer_set = PointerSetT::bottom(offset_intv.bit_width(), Unsigned); for (MemoryLocationRef addr : addrs) { pointer_set.join_with( this->_pointer_sets.get(addr, offset_intv.bit_width(), Unsigned)); } this->_scalar.pointer_refine(lhs.var(), pointer_set); } } void mem_copy(VariableRef dest, VariableRef src, const LiteralT& size) override { ikos_assert(ScalarVariableTrait::is_pointer(dest)); ikos_assert(ScalarVariableTrait::is_pointer(src)); if (this->is_bottom_fast()) { return; } // Null/undefined pointer dereference this->_scalar.nullity_assert_non_null(src); this->_scalar.nullity_assert_non_null(dest); if (size.is_undefined()) { this->_scalar.set_to_bottom(); return; } else if (size.is_var()) { this->_scalar.uninit_assert_initialized(size.var()); } this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } // Memory locations pointed by dest and src PointsToSetT src_addrs = this->_scalar.pointer_to_points_to(src); PointsToSetT dest_addrs = this->_scalar.pointer_to_points_to(dest); if (src_addrs.is_empty() || dest_addrs.is_empty()) { // Invalid dereference this->set_to_bottom(); return; } if (dest_addrs.is_top()) { this->mem_forget_all(); // Very conservative, but sound return; } // // Update memory cells // // Offsets and size intervals IntInterval src_intv = this->_scalar.pointer_offset_to_interval(src); IntInterval dest_intv = this->_scalar.pointer_offset_to_interval(dest); auto size_intv = IntInterval::bottom(1, Unsigned); if (size.is_machine_int()) { size_intv = IntInterval(size.machine_int()); } else if (size.is_machine_int_var()) { size_intv = this->_scalar.int_to_interval(size.var()); } else { ikos_unreachable("unexpected literal for size"); } assert_compatible(size_intv, src_intv); if (size_intv.ub().is_zero()) { return; // Does nothing } // To be sound, remove all reachable cells for (MemoryLocationRef addr : dest_addrs) { this->mem_forget_cells(addr, dest_intv, size_intv.ub()); } if (dest_addrs.singleton() && dest_intv.singleton() && !src_addrs.is_top() && src_intv.singleton() && !size_intv.lb().is_zero()) { // In this case, we can be more precise MemoryLocationRef dest_addr = *dest_addrs.singleton(); MachineInt dest_offset = *dest_intv.singleton(); MachineInt src_offset = *src_intv.singleton(); const MachineInt& size_lb = size_intv.lb(); auto one = MachineInt(1, dest_intv.bit_width(), Unsigned); auto src_range = IntInterval(src_offset, src_offset + (size_lb - one)); boost::optional< ScalarDomain > new_scalar; CellSetT dest_cells = this->_cells.get(dest_addr); for (MemoryLocationRef src_addr : src_addrs) { // Copy from src_addr/src_offset to dest_addr/dest_offset ScalarDomain scalar = this->_scalar; const CellSetT& src_cells = this->_cells.get(src_addr); for (VariableRef cell : src_cells) { if (this->cell_range(cell).leq(src_range)) { VariableRef new_cell = this->make_cell(dest_addr, dest_offset + (CellVariableTrait::offset(cell) - src_offset), CellVariableTrait::size(cell), MachIntVariableTrait::sign(cell)); dest_cells.add(new_cell); scalar.dynamic_assign(new_cell, cell); } } if (!new_scalar) { new_scalar = std::move(scalar); } else { new_scalar->join_with(std::move(scalar)); } } ikos_assert(new_scalar); this->_scalar = std::move(*new_scalar); this->_cells.set(dest_addr, dest_cells); } // // Update pointer sets // // Collect source pointer sets auto src_pointer_set = PointerSetT::bottom(src_intv.bit_width(), Unsigned); if (src_addrs.is_top()) { src_pointer_set.set_to_top(); // Be sound } else { for (MemoryLocationRef addr : src_addrs) { src_pointer_set.join_with( this->_pointer_sets.get(addr, src_intv.bit_width(), Unsigned)); } } // Update destination pointer sets for (MemoryLocationRef addr : dest_addrs) { PointerSetT dest_pointer_set = this->_pointer_sets.get(addr, src_intv.bit_width(), Unsigned); dest_pointer_set.join_with(src_pointer_set); this->_pointer_sets.set(addr, dest_pointer_set); } } void mem_set(VariableRef dest, const LiteralT& value, const LiteralT& size) override { ikos_assert(ScalarVariableTrait::is_pointer(dest)); if (this->is_bottom_fast()) { return; } // Null/undefined pointer dereference this->_scalar.nullity_assert_non_null(dest); if (value.is_undefined()) { this->_scalar.set_to_bottom(); return; } else if (value.is_var()) { this->_scalar.uninit_assert_initialized(value.var()); } if (size.is_undefined()) { this->_scalar.set_to_bottom(); return; } else if (size.is_var()) { this->_scalar.uninit_assert_initialized(size.var()); } this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } // Memory locations pointed by dest PointsToSetT addrs = this->_scalar.pointer_to_points_to(dest); if (addrs.is_empty()) { // Invalid dereference this->set_to_bottom(); return; } if (addrs.is_top()) { this->mem_forget_cells(); // Very conservative, but sound return; } // // Update memory cells // // Offset, size and value intervals IntInterval dest_intv = this->_scalar.pointer_offset_to_interval(dest); auto size_intv = IntInterval::bottom(1, Unsigned); auto value_intv = IntInterval::bottom(1, Unsigned); if (size.is_machine_int()) { size_intv = IntInterval(size.machine_int()); } else if (size.is_machine_int_var()) { size_intv = this->_scalar.int_to_interval(size.var()); } else { ikos_unreachable("unexpected literal for size"); } assert_compatible(size_intv, dest_intv); if (value.is_machine_int()) { value_intv = IntInterval(value.machine_int()); } else if (size.is_machine_int_var()) { value_intv = this->_scalar.int_to_interval(value.var()); } else { ikos_unreachable("unexpected literal for value"); } if (size_intv.ub().is_zero()) { return; // Does nothing } if (value_intv.is_zero()) { // Memory set to zero const MachineInt& size_lb = size_intv.lb(); auto zero = MachineInt::zero(size_lb.bit_width(), Unsigned); auto one = MachineInt(1, size_lb.bit_width(), Unsigned); // Offsets that are updated auto safe_range_lb = IntInterval(dest_intv.lb(), dest_intv.lb() + (size_lb - one)); auto safe_range_ub = IntInterval(dest_intv.ub(), dest_intv.ub() + (size_lb - one)); IntInterval safe_range = safe_range_lb.meet(safe_range_ub); // Possibly updated offsets IntInterval unsafe_range = add(dest_intv, IntInterval(zero, size_intv.ub() - one)); for (MemoryLocationRef addr : addrs) { const CellSetT& cells = this->_cells.get(addr); if (!cells.is_empty()) { CellSetT new_cells = cells; for (VariableRef cell : cells) { IntInterval range = this->cell_range(cell); if (range.leq(safe_range)) { LiteralT zero_lit = LiteralT::machine_int( MachineInt::zero(MachIntVariableTrait::bit_width(cell), MachIntVariableTrait::sign(cell))); if (addrs.singleton()) { this->strong_update(cell, zero_lit); } else { this->weak_update(cell, zero_lit); } } else if (!range.meet(unsafe_range).is_bottom()) { this->_scalar.dynamic_forget(cell); new_cells.remove(cell); } } this->_cells.set(addr, new_cells); } } } else { // To be sound, remove all reachable cells for (MemoryLocationRef addr : addrs) { this->mem_forget_cells(addr, dest_intv, size_intv.ub()); } } // Nothing to do for pointer sets } private: /// \brief Forget all memory cells void mem_forget_cells() { if (this->_cells.is_bottom()) { return; } for (auto it = this->_cells.begin(), et = this->_cells.end(); it != et; ++it) { const CellSetT& cells = it->second; if (cells.is_empty()) { continue; } for (VariableRef cell : cells) { this->_scalar.dynamic_forget(cell); } } this->_cells.set_to_top(); } /// \brief Forget the memory cells for the given memory location void mem_forget_cells(MemoryLocationRef addr) { const CellSetT& cells = this->_cells.get(addr); if (cells.is_bottom()) { return; } for (VariableRef cell : cells) { this->_scalar.dynamic_forget(cell); } this->_cells.forget(addr); } /// \brief Forget the memory cells in range /// `[addr + offset, addr + offset + size - 1]` void mem_forget_cells(MemoryLocationRef addr, const IntInterval& offset, const MachineInt& size) { if (size.is_zero()) { return; } auto zero = MachineInt::zero(size.bit_width(), Unsigned); auto one = MachineInt(1, size.bit_width(), Unsigned); this->mem_forget_cells(addr, add(offset, IntInterval(zero, size - one))); } /// \brief Forget the memory cells in /// `[addr + range.lb(), addr + range.ub()]` void mem_forget_cells(MemoryLocationRef addr, const IntInterval& range) { const CellSetT& cells = this->_cells.get(addr); if (cells.is_bottom() || cells.is_empty()) { return; } CellSetT new_cells = cells; for (VariableRef cell : cells) { if (this->cell_overlap(cell, range)) { this->_scalar.dynamic_forget(cell); new_cells.remove(cell); } } this->_cells.set(addr, new_cells); } /// \brief Forget all pointer sets void mem_forget_pointer_sets() { this->_pointer_sets.set_to_top(); } /// \brief Forget the pointer set for the given memory location void mem_forget_pointer_set(MemoryLocationRef addr) { this->_pointer_sets.forget(addr); } public: void mem_forget_all() override { this->mem_forget_cells(); this->mem_forget_pointer_sets(); } void mem_forget(MemoryLocationRef addr) override { this->mem_forget_cells(addr); this->mem_forget_pointer_set(addr); } void mem_forget(MemoryLocationRef addr, const IntInterval& offset, const MachineInt& size) override { if (size.is_zero()) { return; } this->mem_forget_cells(addr, offset, size); this->mem_forget_pointer_set(addr); } void mem_forget(MemoryLocationRef addr, const IntInterval& range) override { this->mem_forget_cells(addr, range); this->mem_forget_pointer_set(addr); } void mem_forget_reachable(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_scalar.uninit_assert_initialized(p); this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } if (this->_scalar.nullity_is_null(p)) { return; // Does nothing } // Memory locations pointed by the pointer PointsToSetT addrs = this->_scalar.pointer_to_points_to(p); if (addrs.is_top()) { this->mem_forget_all(); // Very conservative, but sound return; } for (MemoryLocationRef addr : addrs) { this->mem_forget(addr); } } void mem_forget_reachable(VariableRef p, const MachineInt& size) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_scalar.uninit_assert_initialized(p); this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } if (this->_scalar.nullity_is_null(p)) { return; // Does nothing } if (size.is_zero()) { return; // Does nothing } // Memory locations pointed by the pointer PointsToSetT addrs = this->_scalar.pointer_to_points_to(p); if (addrs.is_top()) { this->mem_forget_all(); // very conservative, but sound return; } // Offset interval IntInterval offset_intv = this->_scalar.pointer_offset_to_interval(p); for (MemoryLocationRef addr : addrs) { this->mem_forget(addr, offset_intv, size); } } void mem_abstract_reachable(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_scalar.uninit_assert_initialized(p); this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } if (this->_scalar.nullity_is_null(p)) { return; // Does nothing } // Memory locations pointed by the pointer PointsToSetT addrs = this->_scalar.pointer_to_points_to(p); if (addrs.is_top()) { this->mem_forget_cells(); // Very conservative, but sound return; } for (MemoryLocationRef addr : addrs) { this->mem_forget_cells(addr); } } void mem_abstract_reachable(VariableRef p, const MachineInt& size) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_scalar.uninit_assert_initialized(p); this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } if (this->_scalar.nullity_is_null(p)) { return; // Does nothing } if (size.is_zero()) { return; // Does nothing } // Memory locations pointed by the pointer PointsToSetT addrs = this->_scalar.pointer_to_points_to(p); if (addrs.is_top()) { this->mem_forget_cells(); // Very conservative, but sound return; } // Offset interval IntInterval offset_intv = this->_scalar.pointer_offset_to_interval(p); for (MemoryLocationRef addr : addrs) { this->mem_forget_cells(addr, offset_intv, size); } } void mem_zero_reachable(VariableRef p) override { this->mem_uninitialize_reachable(p); } void mem_uninitialize_reachable(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_scalar.uninit_assert_initialized(p); this->_scalar.normalize(); if (this->_scalar.is_bottom()) { this->set_to_bottom(); return; } if (this->_scalar.nullity_is_null(p)) { return; // Does nothing } // Memory locations pointed by the pointer PointsToSetT addrs = this->_scalar.pointer_to_points_to(p); if (addrs.is_top()) { this->mem_forget_all(); // Very conservative, but sound return; } for (MemoryLocationRef addr : addrs) { this->mem_forget(addr); } if (auto addr = addrs.singleton()) { uint64_t bit_width = MachIntVariableTrait::bit_width(ScalarVariableTrait::offset_var(p)); this->_pointer_sets.set(*addr, PointerSetT::empty(bit_width, Unsigned)); } } /// @} /// \name Lifetime abstract domain methods /// @{ void lifetime_assign_allocated(MemoryLocationRef m) override { this->_lifetime.assign_allocated(m); } void lifetime_assign_deallocated(MemoryLocationRef m) override { this->_lifetime.assign_deallocated(m); } void lifetime_assert_allocated(MemoryLocationRef m) override { this->_lifetime.assert_allocated(m); } void lifetime_assert_deallocated(MemoryLocationRef m) override { this->_lifetime.assert_deallocated(m); } void lifetime_forget(MemoryLocationRef m) override { this->_lifetime.forget(m); } void lifetime_set(MemoryLocationRef m, Lifetime value) override { this->_lifetime.set(m, value); } Lifetime lifetime_to_lifetime(MemoryLocationRef m) const override { return this->_lifetime.get(m); } /// @} /// \name Partitioning abstract domain methods /// @{ void partitioning_set_variable(VariableRef) override {} boost::optional< VariableRef > partitioning_variable() const override { return boost::none; } void partitioning_join() override {} void partitioning_disable() override {} /// @} void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else if (this->is_top()) { o << "T"; } else { o << "("; this->_scalar.dump(o); o << ", "; this->_cells.dump(o); o << ", "; this->_pointer_sets.dump(o); o << ", "; this->_lifetime.dump(o); o << ")"; } } static std::string name() { return "value domain using " + ScalarDomain::name() + " and " + LifetimeDomain::name(); } }; // end class ValueDomain } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/value/000077500000000000000000000000001473507761200247615ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/value/cell_set.hpp000066400000000000000000000146461473507761200272770ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Abstract domain for a set of cells, based on Patricia trees * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace memory { /// \brief Cell set abstract domain /// /// It is similar to the DiscreteDomain but has a different semantic. /// /// The empty cell set represents top. /// The bottom value is represented as top. /// /// Note that this is not a lattice. template < typename VariableRef > class CellSet final : public core::AbstractDomain< CellSet< VariableRef > > { private: using PatriciaTreeSetT = PatriciaTreeSet< VariableRef >; public: using Iterator = typename PatriciaTreeSetT::Iterator; private: PatriciaTreeSetT _set; private: struct EmptyTag {}; /// \brief Create the empty cell set explicit CellSet(EmptyTag) {} public: /// \brief Create the top cell set static CellSet top() { return CellSet(EmptyTag{}); } /// \brief Create the bottom cell set static CellSet bottom() { return CellSet(EmptyTag{}); } /// \brief Create the empty cell set static CellSet empty() { return CellSet(EmptyTag{}); } /// \brief Create the cell set with the given cells CellSet(std::initializer_list< VariableRef > cells) : _set(cells) {} /// \brief Copy constructor CellSet(const CellSet&) noexcept = default; /// \brief Move constructor CellSet(CellSet&&) noexcept = default; /// \brief Copy assignment operator CellSet& operator=(const CellSet&) noexcept = default; /// \brief Move assignment operator CellSet& operator=(CellSet&&) noexcept = default; /// \brief Destructor ~CellSet() override = default; /// \brief Return the number of cells std::size_t size() const { return this->_set.size(); } /// \brief Begin iterator over the cells Iterator begin() const { return this->_set.begin(); } /// \brief End iterator over the cells Iterator end() const { return this->_set.end(); } void normalize() override {} bool is_bottom() const override { return false; } bool is_top() const override { return this->_set.empty(); } /// \brief Return true if the set is empty bool is_empty() const { return this->_set.empty(); } void set_to_bottom() override { this->_set.clear(); } void set_to_top() override { this->_set.clear(); } bool leq(const CellSet& other) const override { if (other.is_top()) { return true; } else if (this->is_top()) { return false; } else { return this->_set.is_subset_of(other._set); } } bool equals(const CellSet& other) const override { if (this->is_top()) { return other.is_top(); } else if (other.is_top()) { return false; } else { return this->_set.equals(other._set); } } void join_with(const CellSet& other) override { // only keep cells present on both sides this->_set.intersect_with(other._set); } void widen_with(const CellSet& other) override { this->join_with(other); } void meet_with(const CellSet& other) override { // keep all the cells this->_set.join_with(other._set); } void narrow_with(const CellSet& other) override { this->meet_with(other); } /// \brief Perform the set difference void difference_with(const CellSet& other) { this->_set.difference_with(other._set); } /// \brief Perform the set difference CellSet difference(const CellSet& other) const { CellSet tmp(*this); tmp.difference_with(other); return tmp; } /// \brief Add a cell in the set void add(VariableRef cell) { this->_set.insert(cell); } /// \brief Remove a cell from the set void remove(VariableRef cell) { this->_set.erase(cell); } /// \brief If the cell set is a singleton {c}, return c, otherwise return /// boost::none boost::optional< VariableRef > singleton() const { if (this->_set.size() == 1) { return *this->_set.begin(); } else { return boost::none; } } /// \brief Return true if the cell set contains the given cell bool contains(VariableRef cell) const { return this->is_top() || this->_set.contains(cell); } void dump(std::ostream& o) const override { if (this->is_top()) { o << "⊤"; } else { this->_set.dump(o); } } static std::string name() { return "cell set domain"; } }; // end class CellSet } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/value/mem_loc_to_cell_set.hpp000066400000000000000000000051071473507761200314640ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Map from memory locations to set of synthetic cells * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace memory { /// \brief Map from memory locations to set of synthetic cells template < typename MemoryLocationRef, typename VariableRef > using MemLocToCellSet = SeparateDomain< MemoryLocationRef, CellSet< VariableRef > >; } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/memory/value/mem_loc_to_pointer_set.hpp000066400000000000000000000332531473507761200322300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Map from memory locations to set of pointers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace memory { /// \brief Map from memory locations to set of pointers template < typename MemoryLocationRef > class MemLocToPointerSet final : public core::AbstractDomain< MemLocToPointerSet< MemoryLocationRef > > { public: static_assert(IsMemoryLocation< MemoryLocationRef >::value, "MemoryLocationRef does not meet the requirements for memory " "location types"); private: using PointerSetT = PointerSet< MemoryLocationRef >; using PatriciaTreeMapT = PatriciaTreeMap< MemoryLocationRef, PointerSetT >; public: using Iterator = typename PatriciaTreeMapT::Iterator; private: PatriciaTreeMapT _tree; bool _is_bottom; private: struct TopTag {}; struct BottomTag {}; struct BottomFound {}; /// \brief Create the top abstract value explicit MemLocToPointerSet(TopTag) : _is_bottom(false) {} /// \brief Create the bottom abstract value explicit MemLocToPointerSet(BottomTag) : _is_bottom(true) {} public: /// \brief Create the top abstract value static MemLocToPointerSet top() { return MemLocToPointerSet(TopTag{}); } /// \brief Create the bottom abstract value static MemLocToPointerSet bottom() { return MemLocToPointerSet(BottomTag{}); } /// \brief Copy constructor MemLocToPointerSet(const MemLocToPointerSet&) noexcept = default; /// \brief Move constructor MemLocToPointerSet(MemLocToPointerSet&&) noexcept = default; /// \brief Copy assignment operator MemLocToPointerSet& operator=(const MemLocToPointerSet&) noexcept = default; /// \brief Move assignment operator MemLocToPointerSet& operator=(MemLocToPointerSet&&) noexcept = default; /// \brief Destructor ~MemLocToPointerSet() override = default; /// \brief Begin iterator over the pairs (variable, value) Iterator begin() const { ikos_assert(!this->is_bottom()); return this->_tree.begin(); } /// \brief End iterator over the pairs (variable, value) Iterator end() const { ikos_assert(!this->is_bottom()); return this->_tree.end(); } void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->is_bottom() && this->_tree.empty(); } void set_to_bottom() override { this->_is_bottom = true; this->_tree.clear(); } void set_to_top() override { this->_is_bottom = false; this->_tree.clear(); } bool leq(const MemLocToPointerSet& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_tree.leq(other._tree, [](const PointerSetT& x, const PointerSetT& y) { return x.leq(y); }); } } bool equals(const MemLocToPointerSet& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_tree.equals(other._tree, [](const PointerSetT& x, const PointerSetT& y) { return x.equals(y); }); } } void join_with(const MemLocToPointerSet& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.join(y); if (z.is_top()) { return boost::optional< PointerSetT >( boost::none); } return boost::optional< PointerSetT >(z); }); } } void join_loop_with(const MemLocToPointerSet& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.join_loop(y); if (z.is_top()) { return boost::optional< PointerSetT >( boost::none); } return boost::optional< PointerSetT >(z); }); } } void join_iter_with(const MemLocToPointerSet& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.join_iter(y); if (z.is_top()) { return boost::optional< PointerSetT >( boost::none); } return boost::optional< PointerSetT >(z); }); } } void widen_with(const MemLocToPointerSet& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.widening(y); if (z.is_top()) { return boost::optional< PointerSetT >( boost::none); } return boost::optional< PointerSetT >(z); }); } } void widen_threshold_with(const MemLocToPointerSet& other, const MachineInt& threshold) { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [threshold](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.widening_threshold(y, threshold); if (z.is_top()) { return boost::optional< PointerSetT >( boost::none); } return boost::optional< PointerSetT >(z); }); } } void meet_with(const MemLocToPointerSet& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< PointerSetT >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } void narrow_with(const MemLocToPointerSet& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.narrowing(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< PointerSetT >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } void narrow_threshold_with(const MemLocToPointerSet& other, const MachineInt& threshold) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [threshold](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.narrowing_threshold(y, threshold); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< PointerSetT >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Get the pointer set for the given memory location PointerSetT get(MemoryLocationRef addr, uint64_t bit_width, Signedness sign) const { if (this->is_bottom()) { return PointerSetT::bottom(bit_width, sign); } else { boost::optional< const PointerSetT& > v = this->_tree.at(addr); if (v) { return *v; } else { return PointerSetT::top(bit_width, sign); } } } /// \brief Set the pointer set of the given memory location void set(MemoryLocationRef addr, const PointerSetT& pointer_set) { if (this->is_bottom()) { return; } else if (pointer_set.is_bottom()) { this->set_to_bottom(); } else if (pointer_set.is_top()) { this->_tree.erase(addr); } else { this->_tree.insert_or_assign(addr, pointer_set); } } /// \brief Refine the pointer set of the given memory location void refine(MemoryLocationRef addr, const PointerSetT& pointer_set) { if (this->is_bottom()) { return; } else if (pointer_set.is_bottom()) { this->set_to_bottom(); } else if (pointer_set.is_top()) { return; } else { try { this->_tree.update_or_insert( [](const PointerSetT& x, const PointerSetT& y) { PointerSetT z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< PointerSetT >(z); }, addr, pointer_set); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Forget the pointer set of the given memory location void forget(MemoryLocationRef addr) { if (this->is_bottom()) { return; } this->_tree.erase(addr); } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { this->_tree.dump(o); } } static std::string name() { return "memory location to pointer set"; } }; // end class MemLocToPointerSet } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/nullity/000077500000000000000000000000001473507761200240355ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/nullity/abstract_domain.hpp000066400000000000000000000104031473507761200276760ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for abstract domains keeping track of null variables * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace nullity { /// \brief Predicate on pointers using Predicate = pointer::Predicate; /// \brief Base class for abstract domains keeping track of null variables template < typename VariableRef, typename Derived > class AbstractDomain : public core::AbstractDomain< Derived > { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); public: /// \brief Assign `x = null` virtual void assign_null(VariableRef x) = 0; /// \brief Assign `x = non-null` virtual void assign_non_null(VariableRef x) = 0; /// \brief Assign `x = y` virtual void assign(VariableRef x, VariableRef y) = 0; /// \brief Add the constraint `x == null` virtual void assert_null(VariableRef x) = 0; /// \brief Add the constraint `x != null` virtual void assert_non_null(VariableRef x) = 0; // \brief Add the constraint `x pred y` virtual void add(Predicate pred, VariableRef x, VariableRef y) = 0; /// \brief Return true if `x` is null, otherwise false virtual bool is_null(VariableRef x) const = 0; /// \brief Return true if `x` is non null, otherwise false virtual bool is_non_null(VariableRef x) const = 0; /// \brief Set the nullity value of a variable virtual void set(VariableRef x, const Nullity& value) = 0; /// \brief Refine the nullity value of a variable virtual void refine(VariableRef x, const Nullity& value) = 0; /// \brief Forget the nullity of a variable virtual void forget(VariableRef x) = 0; /// \brief Get the nullity value for the given variable virtual Nullity get(VariableRef x) const = 0; }; // end class AbstractDomain /// \brief Check if a type is a nullity abstract domain template < typename T, typename VariableRef > struct IsAbstractDomain : std::is_base_of< nullity::AbstractDomain< VariableRef, T >, T > {}; } // end namespace nullity } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/nullity/dummy.hpp000066400000000000000000000127331473507761200257070ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief A dummy nullity abstract domain that is either top or bottom * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { namespace nullity { /// \brief Dummy nullity abstract domain that is either top or bottom /// /// This can be used to disable a nullity analysis in a generic implementation template < typename VariableRef > class DummyDomain final : public nullity::AbstractDomain< VariableRef, DummyDomain< VariableRef > > { private: bool _is_bottom; private: /// \brief Private constructor explicit DummyDomain(bool is_bottom) : _is_bottom(is_bottom) {} public: /// \brief Create the top abstract value static DummyDomain top() { return DummyDomain(false); } /// \brief Create the bottom abstract value static DummyDomain bottom() { return DummyDomain(true); } /// \brief Copy constructor DummyDomain(const DummyDomain&) noexcept = default; /// \brief Move constructor DummyDomain(DummyDomain&&) noexcept = default; /// \brief Copy assignment operator DummyDomain& operator=(const DummyDomain&) noexcept = default; /// \brief Move assignment operator DummyDomain& operator=(DummyDomain&&) noexcept = default; /// \brief Destructor ~DummyDomain() override = default; void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->_is_bottom; } void set_to_bottom() override { this->_is_bottom = true; } void set_to_top() override { this->_is_bottom = false; } bool leq(const DummyDomain& other) const override { return static_cast< int >(this->_is_bottom) >= static_cast< int >(other._is_bottom); } bool equals(const DummyDomain& other) const override { return this->_is_bottom == other._is_bottom; } void join_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom && other._is_bottom); } void widen_with(const DummyDomain& other) override { this->join_with(other); } void meet_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom || other._is_bottom); } void narrow_with(const DummyDomain& other) override { this->meet_with(other); } void assign_null(VariableRef) override {} void assign_non_null(VariableRef) override {} void assign(VariableRef, VariableRef) override {} void assert_null(VariableRef) override {} void assert_non_null(VariableRef) override {} void add(Predicate, VariableRef, VariableRef) override {} bool is_null(VariableRef) const override { return this->_is_bottom; } bool is_non_null(VariableRef) const override { return this->_is_bottom; } void set(VariableRef, const Nullity& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void refine(VariableRef, const Nullity& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void forget(VariableRef) override {} Nullity get(VariableRef) const override { if (this->_is_bottom) { return Nullity::bottom(); } else { return Nullity::top(); } } void dump(std::ostream& o) const override { if (this->_is_bottom) { o << "⊥"; } else { o << "T"; } } static std::string name() { return "dummy nullity domain"; } }; // end class DummyDomain } // end namespace nullity } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/nullity/separate_domain.hpp000066400000000000000000000161261473507761200277070ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of an abstract domain keeping track of null variables * using a separate domain. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace nullity { /// \brief Nullity abstract domain /// /// Implementation of the nullity abstract domain interface using a separate /// domain. template < typename VariableRef > class SeparateDomain final : public nullity::AbstractDomain< VariableRef, SeparateDomain< VariableRef > > { private: using SeparateDomainT = core::SeparateDomain< VariableRef, Nullity >; public: using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit SeparateDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static SeparateDomain top() { return SeparateDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static SeparateDomain bottom() { return SeparateDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor SeparateDomain(const SeparateDomain&) noexcept = default; /// \brief Move constructor SeparateDomain(SeparateDomain&&) noexcept = default; /// \brief Copy assignment operator SeparateDomain& operator=(const SeparateDomain&) noexcept = default; /// \brief Move assignment operator SeparateDomain& operator=(SeparateDomain&&) noexcept = default; /// \brief Destructor ~SeparateDomain() override = default; /// \brief Begin iterator over the pairs (variable, nullity) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, nullity) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const SeparateDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const SeparateDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const SeparateDomain& other) override { this->_inv.join_with(other._inv); } void widen_with(const SeparateDomain& other) override { this->_inv.widen_with(other._inv); } void meet_with(const SeparateDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const SeparateDomain& other) override { this->_inv.narrow_with(other._inv); } void assign_null(VariableRef x) override { this->_inv.set(x, Nullity::null()); } void assign_non_null(VariableRef x) override { this->_inv.set(x, Nullity::non_null()); } void assign(VariableRef x, VariableRef y) override { this->_inv.set(x, this->_inv.get(y)); } void assert_null(VariableRef x) override { this->_inv.refine(x, Nullity::null()); } void assert_non_null(VariableRef x) override { this->_inv.refine(x, Nullity::non_null()); } void add(Predicate pred, VariableRef x, VariableRef y) override { if (this->is_bottom()) { return; } Nullity xn = this->_inv.get(x); Nullity yn = this->_inv.get(y); switch (pred) { case Predicate::EQ: { // x == y Nullity z = xn.meet(yn); this->_inv.set(x, z); this->_inv.set(y, z); } break; case Predicate::NE: { // x != y if (xn.is_null() && yn.is_null()) { this->_inv.set_to_bottom(); } else if (xn.is_top() && yn.is_null()) { this->_inv.set(x, Nullity::non_null()); } else if (xn.is_null() && yn.is_top()) { this->_inv.set(y, Nullity::non_null()); } } break; case Predicate::GT: { this->add(Predicate::NE, x, y); } break; case Predicate::GE: { // nothing we can do. } break; case Predicate::LT: { this->add(Predicate::NE, x, y); } break; case Predicate::LE: { // nothing we can do. } break; } } bool is_null(VariableRef x) const override { Nullity value = this->_inv.get(x); return value.is_bottom() || value.is_null(); } bool is_non_null(VariableRef x) const override { Nullity value = this->_inv.get(x); return value.is_bottom() || value.is_non_null(); } void set(VariableRef x, const Nullity& value) override { this->_inv.set(x, value); } void refine(VariableRef x, const Nullity& value) override { this->_inv.refine(x, value); } void forget(VariableRef x) override { this->_inv.forget(x); } Nullity get(VariableRef x) const override { return this->_inv.get(x); } void dump(std::ostream& o) const override { return this->_inv.dump(o); } static std::string name() { return "nullity domain"; } }; // end class SeparateDomain } // end namespace nullity } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/000077500000000000000000000000001473507761200237775ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/abstract_domain.hpp000066400000000000000000000226511473507761200276500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for numerical abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Base class for numerical abstract domains template < typename Number, typename VariableRef, typename Derived > class AbstractDomain : public core::AbstractDomain< Derived > { public: static_assert( IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; public: /// \brief Perform the widening of two abstract values with a threshold virtual void widen_threshold_with(const Derived& other, const Number& threshold) = 0; /// \brief Perform the widening of two abstract values with a threshold virtual Derived widening_threshold(const Derived& other, const Number& threshold) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.widen_threshold_with(other, threshold); return tmp; } /// \brief Perform the narrowing of two abstract values with a threshold virtual void narrow_threshold_with(const Derived& other, const Number& threshold) = 0; /// \brief Perform the narrowing of two abstract values with a threshold virtual Derived narrowing_threshold(const Derived& other, const Number& threshold) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.narrow_threshold_with(other, threshold); return tmp; } /// \brief Assign `x = n` virtual void assign(VariableRef x, int n) = 0; /// \brief Assign `x = n` virtual void assign(VariableRef x, const Number& n) = 0; /// \brief Assign `x = y` virtual void assign(VariableRef x, VariableRef y) = 0; /// \brief Assign `x = e` virtual void assign(VariableRef x, const LinearExpressionT& e) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) = 0; /// \brief Apply `x = y op z` virtual void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) = 0; /// \brief Add a linear constraint virtual void add(const LinearConstraintT& cst) = 0; /// \brief Add a linear constraint system virtual void add(const LinearConstraintSystemT& csts) = 0; /// \brief Set the interval value of a variable virtual void set(VariableRef x, const IntervalT& value) = 0; /// \brief Set the congruence value of a variable virtual void set(VariableRef x, const CongruenceT& value) = 0; /// \brief Set the interval-congruence value of a variable virtual void set(VariableRef x, const IntervalCongruenceT& value) = 0; /// \brief Refine the value of a variable with an interval virtual void refine(VariableRef x, const IntervalT& value) = 0; /// \brief Refine the value of a variable with a congruence virtual void refine(VariableRef x, const CongruenceT& value) = 0; /// \brief Refine the value of a variable with an interval-congruence virtual void refine(VariableRef x, const IntervalCongruenceT& value) = 0; /// \brief Forget a numerical variable virtual void forget(VariableRef x) = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the value of `x` as an interval virtual IntervalT to_interval(VariableRef x) const = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the linear expression `e` as an interval virtual IntervalT to_interval(const LinearExpressionT& e) const { if (this->is_bottom()) { return IntervalT::bottom(); } IntervalT r(e.constant()); for (const auto& term : e) { r += IntervalT(term.second) * this->to_interval(term.first); } return r; } /// \brief Projection to a congruence /// /// Return an overapproximation of the value of `x` as a congruence virtual CongruenceT to_congruence(VariableRef x) const = 0; /// \brief Projection to a congruence /// /// Return an overapproximation of the linear expression `e` as a congruence virtual CongruenceT to_congruence(const LinearExpressionT& e) const { if (this->is_bottom()) { return CongruenceT::bottom(); } CongruenceT r(e.constant()); for (const auto& term : e) { r += CongruenceT(term.second) * this->to_congruence(term.first); } return r; } /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the value of `x` as an interval-congruence virtual IntervalCongruenceT to_interval_congruence(VariableRef x) const = 0; /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the linear expression `e` as an /// interval-congruence virtual IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const { if (this->is_bottom()) { return IntervalCongruenceT::bottom(); } IntervalCongruenceT r(e.constant()); for (const auto& term : e) { r += IntervalCongruenceT(term.second) * this->to_interval_congruence(term.first); } return r; } /// \brief Return a set of linear constraints representing the abstract value virtual LinearConstraintSystemT to_linear_constraint_system() const = 0; /// \name Non-negative loop counter abstract domain methods /// @{ /// \brief Mark the variable `x` as a non-negative loop counter virtual void counter_mark(VariableRef /*x*/) {} /// \brief Mark the variable `x` as a normal variable, without losing /// information virtual void counter_unmark(VariableRef /*x*/) {} /// \brief Initialize a non-negative loop counter: `x = c` /// /// Precondition: `c >= 0` virtual void counter_init(VariableRef x, const Number& c) { this->assign(x, c); } /// \brief Increment a non-negative loop counter counter: `x += k` /// /// Precondition: `k >= 0` virtual void counter_incr(VariableRef x, const Number& k) { this->apply(BinaryOperator::Add, x, x, k); } /// \brief Forget a non-negative loop counter virtual void counter_forget(VariableRef x) { this->forget(x); } /// @} }; // end class AbstractDomain /// \brief Check if a type is a numeric abstract domain template < typename T, typename Number, typename VariableRef > struct IsAbstractDomain : std::is_base_of< numeric::AbstractDomain< Number, VariableRef, T >, T > { }; } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/apron.hpp000066400000000000000000001241401473507761200256310ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Wrapper for the APRON library * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { namespace apron { /// \brief Create a binary expression template < typename Number > inline ap_texpr0_t* binop_expr(ap_texpr_op_t, ap_texpr0_t*, ap_texpr0_t*); template <> inline ap_texpr0_t* binop_expr< ZNumber >(ap_texpr_op_t op, ap_texpr0_t* l, ap_texpr0_t* r) { return ap_texpr0_binop(op, l, r, AP_RTYPE_INT, AP_RDIR_ZERO); } template <> inline ap_texpr0_t* binop_expr< QNumber >(ap_texpr_op_t op, ap_texpr0_t* l, ap_texpr0_t* r) { return ap_texpr0_binop(op, l, r, AP_RTYPE_REAL, AP_RDIR_NEAREST); } /// \brief Conversion from ikos::ZNumber to ap_scalar_t* inline ap_scalar_t* to_ap_scalar(const ZNumber& n) { mpq_class e(n.mpz()); return ap_scalar_alloc_set_mpq(e.get_mpq_t()); } /// \brief Conversion from ikos::QNumber to ap_scalar_t* inline ap_scalar_t* to_ap_scalar(const QNumber& n) { mpq_class e(n.mpq()); return ap_scalar_alloc_set_mpq(e.get_mpq_t()); } /// \brief Conversion from ikos::ZNumber to ap_texpr0_t* inline ap_texpr0_t* to_ap_expr(const ZNumber& n) { mpq_class e(n.mpz()); return ap_texpr0_cst_scalar_mpq(e.get_mpq_t()); } /// \brief Conversion from ikos::QNumber to ap_texpr0_t* inline ap_texpr0_t* to_ap_expr(const QNumber& q) { mpq_class e(q.mpq()); return ap_texpr0_cst_scalar_mpq(e.get_mpq_t()); } /// \brief Conversion from ap_scalar_t* to ikos::ZNumber/QNumber template < typename Number > inline Number to_ikos_number(ap_scalar_t*, bool round_upper); template <> inline ZNumber to_ikos_number(ap_scalar_t* scalar, bool round_upper) { ikos_assert(ap_scalar_infty(scalar) == 0); ikos_assert(scalar->discr == AP_SCALAR_MPQ); QNumber q(mpq_class(scalar->val.mpq)); if (round_upper) { return q.round_to_upper(); } else { return q.round_to_lower(); } } template <> inline QNumber to_ikos_number(ap_scalar_t* scalar, bool /*round_upper*/) { ikos_assert(ap_scalar_infty(scalar) == 0); ikos_assert(scalar->discr == AP_SCALAR_MPQ); return QNumber(mpq_class(scalar->val.mpq)); } /// \brief Conversion from ap_coeff_t* to ikos::ZNumber/QNumber template < typename Number > inline Number to_ikos_number(ap_coeff_t* coeff, bool round_upper) { ikos_assert(coeff->discr == AP_COEFF_SCALAR); return to_ikos_number< Number >(coeff->val.scalar, round_upper); } /// \brief Conversion from ap_scalar_t* to ikos::bound< Number > template < typename Number > inline Bound< Number > to_ikos_bound(ap_scalar_t* scalar, bool round_upper) { using BoundT = Bound< Number >; if (ap_scalar_infty(scalar) == -1) { return BoundT::minus_infinity(); } else if (ap_scalar_infty(scalar) == 1) { return BoundT::plus_infinity(); } else { return BoundT(to_ikos_number< Number >(scalar, round_upper)); } } /// \brief Conversion from ap_interval_t* to ikos::interval< Number > template < typename Number > inline Interval< Number > to_ikos_interval(ap_interval_t* intv) { using IntervalT = Interval< Number >; if (ap_interval_is_top(intv)) { return IntervalT::top(); } if (ap_interval_is_bottom(intv)) { return IntervalT::bottom(); } return IntervalT(to_ikos_bound< Number >(intv->inf, true), to_ikos_bound< Number >(intv->sup, false)); } /// \brief Available abstract domains enum Domain { Interval, Octagon, PolkaPolyhedra, PolkaLinearEqualities, PplPolyhedra, PplLinearCongruences, PkgridPolyhedraLinCongruences, }; inline const char* domain_name(Domain d) { switch (d) { case Interval: return "APRON Intervals"; case Octagon: return "APRON Octagons"; case PolkaPolyhedra: return "APRON NewPolka Convex Polyhedra"; case PolkaLinearEqualities: return "APRON NewPolka Linear Equalities"; case PplPolyhedra: return "APRON PPL Convex Polyhedra"; case PplLinearCongruences: return "APRON PPL Linear Congruences"; case PkgridPolyhedraLinCongruences: return "APRON Reduced Product of NewPolka Convex Polyhedra and PPL " "Linear Congruences"; default: ikos_unreachable("unexpected domain"); } } inline ap_manager_t* alloc_domain_manager(Domain d) { switch (d) { case Interval: return box_manager_alloc(); case Octagon: return oct_manager_alloc(); case PolkaPolyhedra: return pk_manager_alloc(false); case PolkaLinearEqualities: return pkeq_manager_alloc(); case PplPolyhedra: return ap_ppl_poly_manager_alloc(false); case PplLinearCongruences: return ap_ppl_grid_manager_alloc(); case PkgridPolyhedraLinCongruences: return ap_pkgrid_manager_alloc(pk_manager_alloc(false), ap_ppl_grid_manager_alloc()); default: ikos_unreachable("unexpected domain"); } } } // end namespace apron /// \brief Wrapper for APRON abstract domains template < apron::Domain Domain, typename Number, typename VariableRef > class ApronDomain final : public numeric::AbstractDomain< Number, VariableRef, ApronDomain< Domain, Number, VariableRef > > { public: using BoundT = Bound< Number >; using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using VariableExprT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using VariableMap = PatriciaTreeMap< VariableRef, ap_dim_t >; using Parent = numeric::AbstractDomain< Number, VariableRef, ApronDomain >; /// \brief Deleter for ap_abstract0_t* struct InvDeleter { void operator()(ap_abstract0_t* inv) { ap_abstract0_free(manager(), inv); } }; /// \brief Wrapper for ap_abstract0_t using InvPtr = std::unique_ptr< ap_abstract0_t, InvDeleter >; private: mutable std::mutex _mutex; InvPtr _inv; VariableMap _var_map; private: /// \brief Get the manager for the given apron domain static ap_manager_t* manager() { // Initialized at first call static ap_manager_t* Man = apron::alloc_domain_manager(Domain); return Man; } /* * Dimension utils */ /// \brief Return the size of an ap_abstract0_t static std::size_t dimension(ap_abstract0_t* inv) { return ap_abstract0_dimension(manager(), inv).intdim; } /// \brief Return a dimension change that adds a number of dimensions static ap_dimchange_t* add_dimensions(ap_abstract0_t* inv, std::size_t dims) { ikos_assert(dims > 0); ap_dimchange_t* dimchange = ap_dimchange_alloc(dims, 0); for (std::size_t i = 0; i < dims; i++) { // Add dimension at the end dimchange->dim[i] = static_cast< ap_dim_t >(dimension(inv)); } return dimchange; } /// \brief Return a dimension change that removes the given dimensions of an /// ap_abstract0_t static ap_dimchange_t* remove_dimensions( ap_abstract0_t* /*inv*/, const std::vector< ap_dim_t >& dims) { ikos_assert(!dims.empty()); ikos_assert(std::is_sorted(dims.begin(), dims.end())); // Make sure that the removed dimensions are in ascending order ap_dimchange_t* dimchange = ap_dimchange_alloc(dims.size(), 0); for (std::size_t i = 0; i < dims.size(); i++) { // Remove dimension dims[i] and shift to the left all the dimensions // greater than dims[i] dimchange->dim[i] = dims[i]; } return dimchange; } /* * Variable dimension utils */ /// \brief Get the dimension associated to a variable boost::optional< const ap_dim_t& > var_dim(VariableRef v) const { return this->_var_map.at(v); } /// \brief Get the dimension associated to a variable, or create one ap_dim_t var_dim_insert(VariableRef v) { boost::optional< const ap_dim_t& > dim = this->_var_map.at(v); if (dim) { return *dim; } auto new_dim = static_cast< ap_dim_t >(this->_var_map.size()); this->_var_map.insert_or_assign(v, new_dim); ap_dimchange_t* dimchange = add_dimensions(this->_inv.get(), 1); ap_abstract0_add_dimensions(manager(), true, this->_inv.get(), dimchange, false); ap_dimchange_free(dimchange); return new_dim; } /* * Abstract operator utils */ /// \brief Merge two variable maps, updating the associated abstract values static VariableMap merge_var_maps(const VariableMap& lhs_var_map, ap_abstract0_t* lhs_inv, const VariableMap& rhs_var_map, ap_abstract0_t* rhs_inv) { ikos_assert(lhs_var_map.size() == dimension(lhs_inv)); ikos_assert(rhs_var_map.size() == dimension(rhs_inv)); // Build a result variable map, based on lhs_var_map VariableMap result = lhs_var_map; // Add variables from rhs_var_map to the result variable map for (auto it = rhs_var_map.begin(), et = rhs_var_map.end(); it != et; ++it) { VariableRef rhs_v = it->first; boost::optional< const ap_dim_t& > lhs_dim = lhs_var_map.at(rhs_v); if (!lhs_dim) { auto dim = static_cast< ap_dim_t >(result.size()); result.insert_or_assign(rhs_v, dim); } } // Add the necessary dimensions to lhs_inv and rhs_inv if (result.size() > lhs_var_map.size()) { ap_dimchange_t* dimchange = add_dimensions(lhs_inv, result.size() - lhs_var_map.size()); ap_abstract0_add_dimensions(manager(), true, lhs_inv, dimchange, false); ap_dimchange_free(dimchange); } if (result.size() > rhs_var_map.size()) { ap_dimchange_t* dimchange = add_dimensions(rhs_inv, result.size() - rhs_var_map.size()); ap_abstract0_add_dimensions(manager(), true, rhs_inv, dimchange, false); ap_dimchange_free(dimchange); } ikos_assert(result.size() == dimension(lhs_inv)); ikos_assert(result.size() == dimension(rhs_inv)); // Build and apply the permutation map for rhs_inv ap_dimperm_t* rhs_perm = build_perm_map(rhs_var_map, result); ap_abstract0_permute_dimensions(manager(), true, rhs_inv, rhs_perm); ap_dimperm_free(rhs_perm); ikos_assert(result.size() == dimension(lhs_inv)); ikos_assert(result.size() == dimension(rhs_inv)); return result; } /// \brief Return a permutation map from the old to the new map static ap_dimperm_t* build_perm_map(const VariableMap& old_map, const VariableMap& new_map) { std::size_t n = new_map.size(); ap_dimperm_t* perm = ap_dimperm_alloc(n); std::vector< bool > index_assigned(n, false); std::vector< bool > value_assigned(n, false); for (auto it = old_map.begin(), et = old_map.end(); it != et; ++it) { boost::optional< const ap_dim_t& > dim = new_map.at(it->first); ikos_assert(dim); perm->dim[it->second] = *dim; index_assigned[it->second] = true; value_assigned[*dim] = true; } ap_dim_t counter = 0; for (std::size_t i = 0; i < n; i++) { if (index_assigned[i]) { continue; } while (value_assigned[counter]) { counter++; } perm->dim[i] = counter; counter++; } return perm; } /// \brief Return the narrowing of the given invariants static ap_abstract0_t* apron_narrowing(ap_abstract0_t* a, ap_abstract0_t* b) { if (Domain == apron::Octagon) { return ap_abstract0_oct_narrowing(manager(), a, b); } else { // by default, use meet return ap_abstract0_meet(manager(), false, a, b); } } /// \brief Conversion from VariableRef to ap_texpr0_t* ap_texpr0_t* to_ap_expr(VariableRef v) { return ap_texpr0_dim(this->var_dim_insert(v)); } /// \brief Conversion from LinearExpression to ap_texpr0_t* ap_texpr0_t* to_ap_expr(const LinearExpressionT& e) { ap_texpr0_t* r = apron::to_ap_expr(e.constant()); for (auto it = e.begin(), et = e.end(); it != et; ++it) { ap_texpr0_t* term = apron::binop_expr< Number >(AP_TEXPR_MUL, apron::to_ap_expr(it->second), this->to_ap_expr(it->first)); r = apron::binop_expr< Number >(AP_TEXPR_ADD, r, term); } return r; } /// \brief Conversion from LinearConstraint to ap_tcons0_t ap_tcons0_t to_ap_constraint(const LinearConstraintT& cst) { const LinearExpressionT& exp = cst.expression(); if (cst.is_equality()) { return ap_tcons0_make(AP_CONS_EQ, this->to_ap_expr(exp), nullptr); } else if (cst.is_inequality()) { return ap_tcons0_make(AP_CONS_SUPEQ, this->to_ap_expr(-exp), nullptr); } else { return ap_tcons0_make(AP_CONS_DISEQ, this->to_ap_expr(exp), nullptr); } } /// \brief Conversion from ap_linexpr0_t* to LinearExpression LinearExpressionT to_ikos_linear_expression(ap_linexpr0_t* expr) const { ikos_assert(ap_linexpr0_is_linear(expr)); ap_coeff_t* coeff = ap_linexpr0_cstref(expr); LinearExpressionT e(apron::to_ikos_number< Number >(coeff, false)); for (auto it = _var_map.begin(), et = _var_map.end(); it != et; ++it) { coeff = ap_linexpr0_coeffref(expr, it->second); if (ap_coeff_zero(coeff)) { continue; } e.add(apron::to_ikos_number< Number >(coeff, false), it->first); } return e; } /// \brief Conversion from ap_lincons0_t to LinearConstraint LinearConstraintT to_ikos_linear_constraint(const ap_lincons0_t& cst) const { ikos_assert(cst.scalar == nullptr); LinearExpressionT e = this->to_ikos_linear_expression(cst.linexpr0); switch (cst.constyp) { case AP_CONS_EQ: return LinearConstraintT(std::move(e), LinearConstraintT::Equality); case AP_CONS_SUPEQ: return LinearConstraintT(-std::move(e), LinearConstraintT::Inequality); case AP_CONS_SUP: return LinearConstraintT(-std::move(e) + 1, LinearConstraintT::Inequality); case AP_CONS_DISEQ: return LinearConstraintT(std::move(e), LinearConstraintT::Disequation); case AP_CONS_EQMOD: default: ikos_unreachable("unexpected linear constraint"); } } /// \brief Return true if the variable mapping is the same bool same_var_map(const ApronDomain& other) const { return dimension(this->_inv.get()) == dimension(other._inv.get()) && this->_var_map.size() == other._var_map.size() && this->_var_map.equals(other._var_map, [](ap_dim_t x, ap_dim_t y) { return x == y; }); } private: struct TopTag {}; struct BottomTag {}; /// \brief Private constructor ApronDomain(InvPtr inv, VariableMap var_map) : _inv(std::move(inv)), _var_map(std::move(var_map)) {} /// \brief Create the top abstract value explicit ApronDomain(TopTag) : _inv(ap_abstract0_top(manager(), 0, 0)) {} /// \brief Create the bottom abstract value explicit ApronDomain(BottomTag) : _inv(ap_abstract0_bottom(manager(), 0, 0)) {} public: /// \brief Create the top abstract value static ApronDomain top() { return ApronDomain(TopTag{}); } /// \brief Create the bottom abstract value static ApronDomain bottom() { return ApronDomain(BottomTag{}); } /// \brief Copy constructor ApronDomain(const ApronDomain& other) { std::lock_guard< std::mutex > lock(other._mutex); this->_inv = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); this->_var_map = other._var_map; } /// \brief Move constructor ApronDomain(ApronDomain&& other) noexcept : _inv(std::move(other._inv)), _var_map(std::move(other._var_map)) {} /// \brief Copy assignment operator ApronDomain& operator=(const ApronDomain& other) { std::lock_guard< std::mutex > lock(other._mutex); this->_inv = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); this->_var_map = other._var_map; return *this; } /// \brief Move assignment operator ApronDomain& operator=(ApronDomain&& other) noexcept { this->_inv = std::move(other._inv); this->_var_map = std::move(other._var_map); return *this; } /// \brief Destructor ~ApronDomain() override = default; void normalize() override { std::lock_guard< std::mutex > lock(this->_mutex); ap_abstract0_canonicalize(manager(), this->_inv.get()); } bool is_bottom() const override { std::lock_guard< std::mutex > lock(this->_mutex); return ap_abstract0_is_bottom(manager(), this->_inv.get()); } bool is_top() const override { std::lock_guard< std::mutex > lock(this->_mutex); return ap_abstract0_is_top(manager(), this->_inv.get()); } void set_to_bottom() override { this->_inv = InvPtr(ap_abstract0_bottom(manager(), 0, 0)); this->_var_map.clear(); } void set_to_top() override { this->_inv = InvPtr(ap_abstract0_top(manager(), 0, 0)); this->_var_map.clear(); } bool leq(const ApronDomain& other) const override { if (this == &other) { return true; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return true; } else if (ap_abstract0_is_bottom(manager(), other._inv.get())) { return false; } else if (this->same_var_map(other)) { return ap_abstract0_is_leq(manager(), this->_inv.get(), other._inv.get()); } else { InvPtr lhs = InvPtr(ap_abstract0_copy(manager(), this->_inv.get())); InvPtr rhs = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); merge_var_maps(this->_var_map, lhs.get(), other._var_map, rhs.get()); return ap_abstract0_is_leq(manager(), lhs.get(), rhs.get()); } } bool equals(const ApronDomain& other) const override { if (this == &other) { return true; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return ap_abstract0_is_bottom(manager(), other._inv.get()); } else if (ap_abstract0_is_bottom(manager(), other._inv.get())) { return false; } else if (this->same_var_map(other)) { return ap_abstract0_is_eq(manager(), this->_inv.get(), other._inv.get()); } else { InvPtr lhs = InvPtr(ap_abstract0_copy(manager(), this->_inv.get())); InvPtr rhs = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); merge_var_maps(this->_var_map, lhs.get(), other._var_map, rhs.get()); return ap_abstract0_is_eq(manager(), lhs.get(), rhs.get()); } } void join_with(ApronDomain&& other) override { if (this == &other) { return; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { this->_inv = std::move(other._inv); this->_var_map = std::move(other._var_map); } else if (ap_abstract0_is_bottom(manager(), other._inv.get())) { return; } else if (this->same_var_map(other)) { ap_abstract0_join(manager(), true, this->_inv.get(), other._inv.get()); } else { this->_var_map = merge_var_maps(this->_var_map, this->_inv.get(), other._var_map, other._inv.get()); ap_abstract0_join(manager(), true, this->_inv.get(), other._inv.get()); } } void join_with(const ApronDomain& other) override { if (this == &other) { return; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { this->_inv = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); this->_var_map = other._var_map; } else if (ap_abstract0_is_bottom(manager(), other._inv.get())) { return; } else if (this->same_var_map(other)) { ap_abstract0_join(manager(), true, this->_inv.get(), other._inv.get()); } else { InvPtr rhs = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); this->_var_map = merge_var_maps(this->_var_map, this->_inv.get(), other._var_map, rhs.get()); ap_abstract0_join(manager(), true, this->_inv.get(), rhs.get()); } } ApronDomain join(const ApronDomain& other) const override { if (this == &other) { return *this; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return ApronDomain(InvPtr(ap_abstract0_copy(manager(), other._inv.get())), other._var_map); } else if (ap_abstract0_is_bottom(manager(), other._inv.get())) { return ApronDomain(InvPtr(ap_abstract0_copy(manager(), this->_inv.get())), this->_var_map); } else if (this->same_var_map(other)) { return ApronDomain(InvPtr(ap_abstract0_join(manager(), false, this->_inv.get(), other._inv.get())), this->_var_map); } else { InvPtr lhs = InvPtr(ap_abstract0_copy(manager(), this->_inv.get())); InvPtr rhs = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); VariableMap var_map = merge_var_maps(this->_var_map, lhs.get(), other._var_map, rhs.get()); ap_abstract0_join(manager(), true, lhs.get(), rhs.get()); return ApronDomain(std::move(lhs), var_map); } } ApronDomain widening(const ApronDomain& other) const override { if (this == &other) { return *this; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return ApronDomain(InvPtr(ap_abstract0_copy(manager(), other._inv.get())), other._var_map); } else if (ap_abstract0_is_bottom(manager(), other._inv.get())) { return ApronDomain(InvPtr(ap_abstract0_copy(manager(), this->_inv.get())), this->_var_map); } else if (this->same_var_map(other)) { return ApronDomain(InvPtr(ap_abstract0_widening(manager(), this->_inv.get(), other._inv.get())), this->_var_map); } else { InvPtr lhs = InvPtr(ap_abstract0_copy(manager(), this->_inv.get())); InvPtr rhs = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); VariableMap var_map = merge_var_maps(this->_var_map, lhs.get(), other._var_map, rhs.get()); return ApronDomain(InvPtr(ap_abstract0_widening(manager(), lhs.get(), rhs.get())), var_map); } } void widen_with(const ApronDomain& other) override { this->operator=(this->widening(other)); } ApronDomain widening_threshold(const ApronDomain& other, const Number& /*threshold*/) const override { return this->widening(other); } void widen_threshold_with(const ApronDomain& other, const Number& /*threshold*/) override { this->widen_with(other); } ApronDomain meet(const ApronDomain& other) const override { if (this == &other) { return *this; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get()) || ap_abstract0_is_bottom(manager(), other._inv.get())) { return bottom(); } else if (this->same_var_map(other)) { return ApronDomain(InvPtr(ap_abstract0_meet(manager(), false, this->_inv.get(), other._inv.get())), this->_var_map); } else { InvPtr lhs = InvPtr(ap_abstract0_copy(manager(), this->_inv.get())); InvPtr rhs = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); VariableMap var_map = merge_var_maps(this->_var_map, lhs.get(), other._var_map, rhs.get()); ap_abstract0_meet(manager(), true, lhs.get(), rhs.get()); return ApronDomain(std::move(lhs), var_map); } } void meet_with(const ApronDomain& other) override { this->operator=(this->meet(other)); } ApronDomain narrowing(const ApronDomain& other) const override { if (this == &other) { return *this; } std::lock(this->_mutex, other._mutex); std::lock_guard< std::mutex > lock_this(this->_mutex, std::adopt_lock); std::lock_guard< std::mutex > lock_other(other._mutex, std::adopt_lock); if (ap_abstract0_is_bottom(manager(), this->_inv.get()) || ap_abstract0_is_bottom(manager(), other._inv.get())) { return bottom(); } else if (this->same_var_map(other)) { return ApronDomain(InvPtr(apron_narrowing(this->_inv.get(), other._inv.get())), this->_var_map); } else { InvPtr lhs = InvPtr(ap_abstract0_copy(manager(), this->_inv.get())); InvPtr rhs = InvPtr(ap_abstract0_copy(manager(), other._inv.get())); VariableMap var_map = merge_var_maps(this->_var_map, lhs.get(), other._var_map, rhs.get()); return ApronDomain(InvPtr(apron_narrowing(lhs.get(), rhs.get())), var_map); } } void narrow_with(const ApronDomain& other) override { this->operator=(this->narrowing(other)); } ApronDomain narrowing_threshold(const ApronDomain& other, const Number& /*threshold*/) const override { return this->narrowing(other); } void narrow_threshold_with(const ApronDomain& other, const Number& /*threshold*/) override { this->narrow_with(other); } void assign(VariableRef x, int n) override { this->assign(x, LinearExpressionT(n)); } void assign(VariableRef x, const Number& n) override { this->assign(x, LinearExpressionT(n)); } void assign(VariableRef x, VariableRef y) override { this->assign(x, LinearExpressionT(y)); } void assign(VariableRef x, const LinearExpressionT& e) override { std::lock_guard< std::mutex > lock(this->_mutex); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return; } ap_texpr0_t* t = this->to_ap_expr(e); ap_dim_t v_dim = this->var_dim_insert(x); ap_abstract0_assign_texpr(manager(), true, this->_inv.get(), v_dim, t, nullptr); ap_texpr0_free(t); } private: /// \brief Return true if the operator is supported static bool is_supported(BinaryOperator op) { switch (op) { case BinaryOperator::Add: case BinaryOperator::Sub: case BinaryOperator::Mul: case BinaryOperator::Div: case BinaryOperator::Rem: return true; default: return false; } } /// \brief Apply `x = left op right` void apply(BinaryOperator op, VariableRef x, ap_texpr0_t* left, ap_texpr0_t* right) { ap_texpr0_t* t; switch (op) { case BinaryOperator::Add: { t = apron::binop_expr< Number >(AP_TEXPR_ADD, left, right); } break; case BinaryOperator::Sub: { t = apron::binop_expr< Number >(AP_TEXPR_SUB, left, right); } break; case BinaryOperator::Mul: { t = apron::binop_expr< Number >(AP_TEXPR_MUL, left, right); } break; case BinaryOperator::Div: { t = apron::binop_expr< Number >(AP_TEXPR_DIV, left, right); } break; case BinaryOperator::Rem: { // XXX(marthaud): AP_TEXPR_MOD is actually a signed remainder.. t = apron::binop_expr< Number >(AP_TEXPR_MOD, left, right); } break; default: { ikos_unreachable("unsupported operator"); } } ap_dim_t x_dim = this->var_dim_insert(x); ap_abstract0_assign_texpr(manager(), true, this->_inv.get(), x_dim, t, nullptr); ap_texpr0_free(t); } public: void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { if (this->is_bottom()) { return; } if (is_supported(op)) { std::lock_guard< std::mutex > lock(this->_mutex); this->apply(op, x, this->to_ap_expr(y), this->to_ap_expr(z)); } else { this->set(x, apply_bin_operator(op, this->to_interval(y), this->to_interval(z))); } } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { if (this->is_bottom()) { return; } if (is_supported(op)) { std::lock_guard< std::mutex > lock(this->_mutex); this->apply(op, x, this->to_ap_expr(y), apron::to_ap_expr(z)); } else if (op == BinaryOperator::Mod) { // Optimized version, because mod is heavily used on machine integers if (z == 0) { this->set_to_bottom(); return; } IntervalT v_y = this->to_interval(y); boost::optional< Number > n = v_y.mod_to_sub(z); if (n) { // Equivalent to x = y - n this->apply(BinaryOperator::Sub, x, y, *n); } else { this->set(x, IntervalT(BoundT(0), BoundT(abs(z) - 1))); } } else { this->set(x, apply_bin_operator(op, this->to_interval(y), IntervalT(z))); } } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { if (this->is_bottom()) { return; } if (is_supported(op)) { std::lock_guard< std::mutex > lock(this->_mutex); this->apply(op, x, apron::to_ap_expr(y), this->to_ap_expr(z)); } else { this->set(x, apply_bin_operator(op, IntervalT(y), this->to_interval(z))); } } void add(const LinearConstraintT& cst) override { this->add(LinearConstraintSystemT{cst}); } void add(const LinearConstraintSystemT& csts) override { std::lock_guard< std::mutex > lock(this->_mutex); if (csts.empty()) { return; } if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return; } ap_tcons0_array_t ap_csts = ap_tcons0_array_make(csts.size()); std::size_t i = 0; for (const LinearConstraintT& cst : csts) { ap_csts.p[i++] = this->to_ap_constraint(cst); } ap_abstract0_meet_tcons_array(manager(), true, this->_inv.get(), &ap_csts); // Improve the precision for (i = 0; i < csts.size() && !ap_abstract0_is_bottom(manager(), this->_inv.get()); i++) { // Check satisfiability of ap_csts.p[i] ap_tcons0_t& cst = ap_csts.p[i]; ap_interval_t* ap_intv = ap_abstract0_bound_texpr(manager(), this->_inv.get(), cst.texpr0); IntervalT intv = apron::to_ikos_interval< Number >(ap_intv); if (intv.is_bottom() || (cst.constyp == AP_CONS_EQ && !intv.contains(0)) || (cst.constyp == AP_CONS_SUPEQ && intv.ub() < BoundT(0)) || (cst.constyp == AP_CONS_DISEQ && intv == IntervalT(0))) { // Cst is not satisfiable this->set_to_bottom(); } ap_interval_free(ap_intv); } ap_tcons0_array_clear(&ap_csts); } void set(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->forget(x); this->refine(x, value); } } void set(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->forget(x); this->refine(x, value); } } void set(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->forget(x); this->refine(x, value.interval()); this->refine(x, value.congruence()); } } void refine(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { return; } else { this->add(within_interval(x, value)); } } void refine(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { return; } else if (value.singleton()) { this->add(VariableExprT(x) == *value.singleton()); } else { std::lock_guard< std::mutex > lock(this->_mutex); ap_tcons0_array_t csts = ap_tcons0_array_make(1); csts.p[0] = ap_tcons0_make(AP_CONS_EQMOD, this->to_ap_expr(VariableExprT(x) - value.residue()), apron::to_ap_scalar(value.modulus())); ap_abstract0_meet_tcons_array(manager(), true, this->_inv.get(), &csts); ap_tcons0_array_clear(&csts); } } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->refine(x, value.interval()); this->refine(x, value.congruence()); } } void forget(VariableRef x) override { std::lock_guard< std::mutex > lock(this->_mutex); boost::optional< const ap_dim_t& > has_dim = this->var_dim(x); if (!has_dim) { return; } ap_dim_t dim = *has_dim; std::vector< ap_dim_t > vector_dims{dim}; ap_abstract0_forget_array(manager(), true, this->_inv.get(), &vector_dims[0], vector_dims.size(), false); ap_dimchange_t* dimchange = remove_dimensions(this->_inv.get(), vector_dims); ap_abstract0_remove_dimensions(manager(), true, this->_inv.get(), dimchange); ap_dimchange_free(dimchange); this->_var_map.transform([dim](VariableRef, ap_dim_t d) { if (d < dim) { return boost::optional< ap_dim_t >(d); } else if (d == dim) { return boost::optional< ap_dim_t >(boost::none); } else { // d > dim return boost::optional< ap_dim_t >(d - 1); } }); ikos_assert(this->_var_map.size() == dimension(this->_inv.get())); } IntervalT to_interval(VariableRef x) const override { std::lock_guard< std::mutex > lock(this->_mutex); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return IntervalT::bottom(); } boost::optional< const ap_dim_t& > dim = this->var_dim(x); if (!dim) { return IntervalT::top(); } ap_interval_t* intv = ap_abstract0_bound_dimension(manager(), this->_inv.get(), *dim); IntervalT r = apron::to_ikos_interval< Number >(intv); ap_interval_free(intv); return r; } IntervalT to_interval(const LinearExpressionT& e) const override { return Parent::to_interval(e); } CongruenceT to_congruence(VariableRef) const override { if (this->is_bottom()) { return CongruenceT::bottom(); } return CongruenceT::top(); } CongruenceT to_congruence(const LinearExpressionT& e) const override { return Parent::to_congruence(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { if (this->is_bottom()) { return IntervalCongruenceT::bottom(); } return IntervalCongruenceT(this->to_interval(x), this->to_congruence(x)); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { if (this->is_bottom()) { return IntervalCongruenceT::bottom(); } return IntervalCongruenceT(this->to_interval(e), this->to_congruence(e)); } LinearConstraintSystemT to_linear_constraint_system() const override { std::lock_guard< std::mutex > lock(this->_mutex); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; ap_lincons0_array_t ap_csts = ap_abstract0_to_lincons_array(manager(), this->_inv.get()); for (std::size_t i = 0; i < ap_csts.size; i++) { ap_lincons0_t& ap_cst = ap_csts.p[i]; if (ap_cst.constyp == AP_CONS_EQMOD) { // ikos::LinearConstraint does not support modular equality continue; } csts.add(this->to_ikos_linear_constraint(ap_cst)); } ap_lincons0_array_clear(&ap_csts); return csts; } void dump(std::ostream& o) const override { std::lock_guard< std::mutex > lock(this->_mutex); if (ap_abstract0_is_bottom(manager(), this->_inv.get())) { o << "⊥"; return; } #if 1 o << "{"; ap_lincons0_array_t ap_csts = ap_abstract0_to_lincons_array(manager(), this->_inv.get()); for (unsigned i = 0; i < ap_csts.size;) { ap_lincons0_t& ap_cst = ap_csts.p[i]; if (ap_cst.constyp == AP_CONS_EQMOD) { // ikos::LinearConstraint does not support modular equality ikos_assert(ap_cst.scalar != nullptr); LinearExpressionT expr = this->to_ikos_linear_expression(ap_cst.linexpr0); Number mod = apron::to_ikos_number< Number >(ap_cst.scalar, false); o << expr << " = 0 mod " << mod; } else { LinearConstraintT cst = this->to_ikos_linear_constraint(ap_cst); o << cst; } i++; if (i < ap_csts.size) { o << "; "; } } ap_lincons0_array_clear(&ap_csts); o << "}"; #else // Only for debugging purpose // This is less generic since it needs a FILE* (here, we use stdout) o << "("; this->_var_map.dump(o); o << ",{\n" << std::flush; fflush(stdout); ap_abstract0_fprint(stdout, manager(), this->_inv.get(), nullptr); fflush(stdout); o << "})"; #endif } static std::string name() { return apron::domain_name(Domain); } }; // end class ApronDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/congruence.hpp000066400000000000000000000246321473507761200266470ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Standard domain of numerical congruences * * Author: Alexandre C. D. Wimmers * * Contributors: * * Jorge A. Navas * * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Congruence abstract domain template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class CongruenceDomain final : public numeric::AbstractDomain< Number, VariableRef, CongruenceDomain< Number, VariableRef, MaxReductionCycles > > { public: using CongruenceT = Congruence< Number >; using IntervalT = Interval< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using VariableExprT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using SeparateDomainT = SeparateDomain< Number, VariableRef, CongruenceT >; using EqualityCongruenceSolverT = EqualityCongruenceSolver< Number, VariableRef, CongruenceDomain >; using Parent = numeric::AbstractDomain< Number, VariableRef, CongruenceDomain >; public: using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit CongruenceDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static CongruenceDomain top() { return CongruenceDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static CongruenceDomain bottom() { return CongruenceDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor CongruenceDomain(const CongruenceDomain&) noexcept = default; /// \brief Move constructor CongruenceDomain(CongruenceDomain&&) noexcept = default; /// \brief Copy assignment operator CongruenceDomain& operator=(const CongruenceDomain&) noexcept = default; /// \brief Move assignment operator CongruenceDomain& operator=(CongruenceDomain&&) noexcept = default; /// \brief Destructor ~CongruenceDomain() override = default; /// \brief Begin iterator over the pairs (variable, congruence) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, congruence) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const CongruenceDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const CongruenceDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const CongruenceDomain& other) override { this->_inv.join_with(other._inv); } void join_loop_with(const CongruenceDomain& other) override { this->_inv.join_loop_with(other._inv); } void join_iter_with(const CongruenceDomain& other) override { this->_inv.join_iter_with(other._inv); } void widen_with(const CongruenceDomain& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const CongruenceDomain& other, const Number& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const CongruenceDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const CongruenceDomain& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const CongruenceDomain& other, const Number& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } void assign(VariableRef x, int n) override { this->_inv.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(const LinearConstraintT& cst) override { if (this->is_bottom()) { return; } EqualityCongruenceSolverT solver(MaxReductionCycles); solver.add(cst); solver.run(*this); } void add(const LinearConstraintSystemT& csts) override { if (this->is_bottom()) { return; } EqualityCongruenceSolverT solver(MaxReductionCycles); solver.add(csts); solver.run(*this); } void set(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< Number > n = value.singleton(); if (n) { this->_inv.set(x, CongruenceT(*n)); } else { this->forget(x); } } } void set(VariableRef x, const CongruenceT& value) override { this->_inv.set(x, value); } void set(VariableRef x, const IntervalCongruenceT& value) override { this->_inv.set(x, value.congruence()); } void refine(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruenceT iv(value, this->_inv.get(x)); this->_inv.set(x, iv.congruence()); } } void refine(VariableRef x, const CongruenceT& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruenceT iv(this->_inv.get(x)); iv.meet_with(value); this->_inv.set(x, iv.congruence()); } } void forget(VariableRef x) override { this->_inv.forget(x); } IntervalT to_interval(VariableRef x) const override { if (this->is_bottom()) { return IntervalT::bottom(); } boost::optional< Number > n = this->_inv.get(x).singleton(); if (n) { return IntervalT(*n); } else { return IntervalT::top(); } } IntervalT to_interval(const LinearExpressionT& e) const override { return Parent::to_interval(e); } CongruenceT to_congruence(VariableRef x) const override { return this->_inv.get(x); } CongruenceT to_congruence(const LinearExpressionT& e) const override { return this->_inv.project(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return IntervalCongruenceT(this->_inv.get(x)); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return Parent::to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; for (auto it = this->begin(), et = this->end(); it != et; ++it) { boost::optional< Number > n = it->second.singleton(); if (n) { csts.add(VariableExprT(it->first) == *n); } } return csts; } void dump(std::ostream& o) const override { this->_inv.dump(o); } static std::string name() { return "congruence domain"; } }; // end class CongruenceDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/constant.hpp000066400000000000000000000314731473507761200263510ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Standard domain of constants * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Constant abstract domain template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class ConstantDomain final : public numeric::AbstractDomain< Number, VariableRef, ConstantDomain< Number, VariableRef, MaxReductionCycles > > { public: using ConstantT = Constant< Number >; using IntervalT = Interval< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using CongruenceT = Congruence< Number >; using VariableExprT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using SeparateDomainT = SeparateDomain< Number, VariableRef, ConstantT >; using Parent = numeric::AbstractDomain< Number, VariableRef, ConstantDomain >; public: using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit ConstantDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static ConstantDomain top() { return ConstantDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static ConstantDomain bottom() { return ConstantDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor ConstantDomain(const ConstantDomain&) noexcept = default; /// \brief Move constructor ConstantDomain(ConstantDomain&&) noexcept = default; /// \brief Copy assignment operator ConstantDomain& operator=(const ConstantDomain&) noexcept = default; /// \brief Move assignment operator ConstantDomain& operator=(ConstantDomain&&) noexcept = default; /// \brief Destructor ~ConstantDomain() override = default; /// \brief Begin iterator over the pairs (variable, constant) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, constant) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const ConstantDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const ConstantDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const ConstantDomain& other) override { this->_inv.join_with(other._inv); } void join_loop_with(const ConstantDomain& other) override { this->_inv.join_loop_with(other._inv); } void join_iter_with(const ConstantDomain& other) override { this->_inv.join_iter_with(other._inv); } void widen_with(const ConstantDomain& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const ConstantDomain& other, const Number& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const ConstantDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const ConstantDomain& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const ConstantDomain& other, const Number& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } void assign(VariableRef x, int n) override { this->_inv.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(const LinearConstraintT& cst) override { if (this->is_bottom()) { return; } auto e = IntervalDomain< Number, VariableRef, MaxReductionCycles >::top(); for (const auto& term : cst) { VariableRef x = term.first; boost::optional< Number > n = this->_inv.get(x).number(); if (n) { e.assign(x, *n); } } e.add(cst); if (e.is_bottom()) { this->set_to_bottom(); return; } for (auto it = e.begin(), et = e.end(); it != et; ++it) { boost::optional< Number > n = it->second.singleton(); if (n) { this->_inv.set(it->first, ConstantT(*n)); } } } void add(const LinearConstraintSystemT& csts) override { if (this->is_bottom()) { return; } auto e = IntervalDomain< Number, VariableRef, MaxReductionCycles >::top(); for (VariableRef x : csts.variables()) { boost::optional< Number > n = this->_inv.get(x).number(); if (n) { e.assign(x, *n); } } e.add(csts); if (e.is_bottom()) { this->set_to_bottom(); return; } for (auto it = e.begin(), et = e.end(); it != et; ++it) { boost::optional< Number > n = it->second.singleton(); if (n) { this->_inv.set(it->first, ConstantT(*n)); } } } void set(VariableRef x, const ConstantT& value) { this->_inv.set(x, value); } void set(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< Number > n = value.singleton(); if (n) { this->_inv.set(x, ConstantT(*n)); } else { this->_inv.forget(x); } } } void set(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< Number > n = value.singleton(); if (n) { this->_inv.set(x, ConstantT(*n)); } else { this->_inv.forget(x); } } } void set(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< Number > n = value.singleton(); if (n) { this->_inv.set(x, ConstantT(*n)); } else { this->_inv.forget(x); } } } void refine(VariableRef x, const ConstantT& value) { this->_inv.refine(x, value); } void refine(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalT i(this->to_interval(x).meet(value)); if (i.is_bottom()) { this->set_to_bottom(); } else if (i.singleton()) { this->_inv.set(x, ConstantT(*i.singleton())); } } } void refine(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { CongruenceT c(this->to_congruence(x).meet(value)); if (c.is_bottom()) { this->set_to_bottom(); } else if (c.singleton()) { this->_inv.set(x, ConstantT(*c.singleton())); } } } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruenceT ic(this->to_interval_congruence(x).meet(value)); if (ic.is_bottom()) { this->set_to_bottom(); } else if (ic.singleton()) { this->_inv.set(x, ConstantT(*ic.singleton())); } } } void forget(VariableRef x) override { this->_inv.forget(x); } ConstantT to_constant(VariableRef x) const { return this->_inv.get(x); } ConstantT to_constant(const LinearExpressionT& e) const { return this->_inv.project(e); } IntervalT to_interval(VariableRef x) const override { if (this->is_bottom()) { return IntervalT::bottom(); } boost::optional< Number > n = this->_inv.get(x).singleton(); if (n) { return IntervalT(*n); } else { return IntervalT::top(); } } IntervalT to_interval(const LinearExpressionT& e) const override { return Parent::to_interval(e); } CongruenceT to_congruence(VariableRef x) const override { if (this->is_bottom()) { return CongruenceT::bottom(); } boost::optional< Number > n = this->_inv.get(x).singleton(); if (n) { return CongruenceT(*n); } else { return CongruenceT::top(); } } CongruenceT to_congruence(const LinearExpressionT& e) const override { return Parent::to_congruence(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { if (this->is_bottom()) { return IntervalCongruenceT::bottom(); } boost::optional< Number > n = this->_inv.get(x).singleton(); if (n) { return IntervalCongruenceT(*n); } else { return IntervalCongruenceT::top(); } } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return Parent::to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; for (auto it = this->begin(), et = this->end(); it != et; ++it) { boost::optional< Number > n = it->second.number(); if (n) { csts.add(VariableExprT(it->first) == *n); } } return csts; } void dump(std::ostream& o) const override { this->_inv.dump(o); } static std::string name() { return "constant domain"; } }; // end class ConstantDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/dbm.hpp000066400000000000000000001257171473507761200252670ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Standard domain of Difference-Bound Matrices * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Based on Antoine Mine's paper: A New Numerical Abstract Domain Based on * Difference-Bound Matrices, in PADO, 155-172, 2001. * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Difference-Bound Matrices abstract domain template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class DBM final : public numeric::AbstractDomain< Number, VariableRef, DBM< Number, VariableRef, MaxReductionCycles > > { public: using BoundT = Bound< Number >; using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using VariableExprT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: /// \brief Index of a variable in the matrix using MatrixIndex = unsigned; // \brief Map from variable to index using VarIndexMap = boost::container::flat_map< VariableRef, MatrixIndex >; /// \brief Solver using LinearIntervalSolverT = LinearIntervalSolver< Number, VariableRef, DBM >; /// \brief Parent using Parent = numeric::AbstractDomain< Number, VariableRef, DBM >; class Matrix { private: std::vector< BoundT > _matrix; MatrixIndex _num_vars = 0; // size of the matrix public: /// \brief Create an empty matrix Matrix() = default; /// \brief Copy constructor Matrix(const Matrix&) = default; /// \brief Move constructor Matrix(Matrix&&) = default; /// \brief Copy assignment operator Matrix& operator=(const Matrix&) = default; /// \brief Move assignment operator Matrix& operator=(Matrix&&) = default; /// \brief Destructor ~Matrix() = default; /// \brief Return the number of variables in the matrix MatrixIndex num_vars() const { return this->_num_vars; } /// \brief Return the element (i, j) const BoundT& operator()(MatrixIndex i, MatrixIndex j) const { ikos_assert_msg(i < this->_num_vars && j < this->_num_vars, "ouf of bounds matrix access"); return this->_matrix[this->_num_vars * i + j]; } /// \brief Return the element (i, j) BoundT& operator()(MatrixIndex i, MatrixIndex j) { ikos_assert_msg(i < this->_num_vars && j < this->_num_vars, "ouf of bounds matrix access"); return this->_matrix[this->_num_vars * i + j]; } /// \brief Clear the matrix void clear() { this->_num_vars = 0; this->_matrix.clear(); } /// \brief Clear and resize the matrix void clear_resize(MatrixIndex num_vars) { this->_num_vars = num_vars; this->_matrix.clear(); this->_matrix.resize(num_vars * num_vars, BoundT::plus_infinity()); } /// \brief Resize the matrix to handle a new variable /// /// \returns the index of the new variable MatrixIndex add_variable() { if (this->_num_vars == 0) { this->_num_vars = 2; this->_matrix.resize(this->_num_vars * this->_num_vars, BoundT::plus_infinity()); } else { std::vector< BoundT > new_matrix((this->_num_vars + 1) * (this->_num_vars + 1), BoundT::plus_infinity()); for (MatrixIndex i = 0; i < this->_num_vars; i++) { for (MatrixIndex j = 0; j < this->_num_vars; j++) { new_matrix[(this->_num_vars + 1) * i + j] = std::move(this->_matrix[this->_num_vars * i + j]); } } std::swap(this->_matrix, new_matrix); this->_num_vars++; } return this->_num_vars - 1; } /// \brief Apply Floyd-Warshall algorithm to normalize the matrix void normalize() { const MatrixIndex n = this->_num_vars; for (MatrixIndex i = 0; i < n; i++) { this->_matrix[n * i + i] = BoundT(0); } for (MatrixIndex k = 0; k < n; k++) { for (MatrixIndex i = 0; i < n; i++) { for (MatrixIndex j = 0; j < n; j++) { this->_matrix[n * i + j] = min(this->_matrix[n * i + j], this->_matrix[n * i + k] + this->_matrix[n * k + j]); } } } } /// \brief Return true if the matrix has a negative cycle /// /// Precondition: matrix is normalized bool has_negative_cycle() const { for (MatrixIndex i = 0; i < this->_num_vars; i++) { if (this->operator()(i, i) < BoundT(0)) { return true; } } return false; } /// \brief Return true if the matrix only contains +oo bool all_plus_infinity() const { for (MatrixIndex i = 0; i < this->_num_vars; i++) { for (MatrixIndex j = 0; j < this->_num_vars; j++) { if (i != j && !this->operator()(i, j).is_plus_infinity()) { return false; } } } return true; } /// \brief Return true if all M[i, j] and M[j, i] are +oo, for all j bool all_plus_infinity(MatrixIndex i) const { for (MatrixIndex j = 0; j < this->_num_vars; j++) { if (i == j) { continue; } if (!this->operator()(i, j).is_plus_infinity() || !this->operator()(j, i).is_plus_infinity()) { return false; } } return true; } /// \brief Print the matrix, for debugging purpose void dump(std::ostream& o) const { for (MatrixIndex i = 0; i < this->_num_vars; i++) { for (MatrixIndex j = 0; j < this->_num_vars; j++) { o << "M[" << i << ", " << j << "] = " << this->operator()(i, j) << "; "; } o << "\n"; } } }; // end class Matrix private: bool _is_bottom; bool _is_normalized; Matrix _matrix; VarIndexMap _var_index_map; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top abstract value explicit DBM(TopTag) : _is_bottom(false), _is_normalized(true) {} /// \brief Create the bottom abstract value explicit DBM(BottomTag) : _is_bottom(true), _is_normalized(true) {} public: /// \brief Create the top abstract value static DBM top() { return DBM(TopTag{}); } /// \brief Create the bottom abstract value static DBM bottom() { return DBM(BottomTag{}); } /// \brief Copy constructor DBM(const DBM&) = default; /// \brief Move constructor DBM(DBM&&) = default; /// \brief Copy assignment operator DBM& operator=(const DBM&) = default; /// \brief Move assignment operator DBM& operator=(DBM&&) = default; /// \brief Destructor ~DBM() override = default; void normalize() override { if (this->_is_normalized) { return; } if (this->_is_bottom) { this->set_to_bottom(); return; } // Floyd-Warshall algorithm this->_matrix.normalize(); // Check for negative cycle if (this->_matrix.has_negative_cycle()) { this->set_to_bottom(); return; } this->_is_normalized = true; } bool is_bottom() const override { if (this->_is_normalized) { return this->_is_bottom; } else if (this->_is_bottom) { return true; } else { // Very inefficient, make sure this is not in a hot path Matrix tmp = this->_matrix; tmp.normalize(); return tmp.has_negative_cycle(); } } bool is_top() const override { return !this->_is_bottom && this->_matrix.all_plus_infinity(); } void set_to_bottom() override { this->_is_bottom = true; this->_is_normalized = true; this->_matrix.clear(); this->_var_index_map.clear(); } void set_to_top() override { this->_is_bottom = false; this->_is_normalized = true; this->_matrix.clear(); this->_var_index_map.clear(); } private: /// \brief Return a normalized copy DBM normalize_copy() const { // Very inefficient, make sure this is not in a hot path DBM tmp = *this; tmp.normalize(); return tmp; } public: bool leq(const DBM& other) const override { // Requires normalization if (!this->_is_normalized) { return this->normalize_copy().leq(other); } if (!other._is_normalized) { return this->leq(other.normalize_copy()); } ikos_assert(this->_is_normalized); ikos_assert(other._is_normalized); if (this->_is_bottom) { return true; } else if (other._is_bottom) { return false; } std::vector< std::pair< MatrixIndex, MatrixIndex > > vars; vars.reserve(this->_var_index_map.size()); // Iterate over this->_var_index_map and other._var_index_map in parallel // This is possible because var_index_map is sorted. for (auto l = this->_var_index_map.begin(), r = other._var_index_map.begin(); r != other._var_index_map.end();) { if (l == this->_var_index_map.end() || r->first < l->first) { // Variable in `other` but not in `this` if (!other._matrix.all_plus_infinity(r->second)) { return false; } ++r; } else if (l->first < r->first) { // Variable in `this` but not in `other`, this is fine. ++l; } else { vars.emplace_back(l->second, r->second); ++l; ++r; } } // Check if this->_matrix(i, j) <= other._matrix(i, j) for (const auto& i : vars) { // special variable 0 if (!(this->_matrix(i.first, 0) <= other._matrix(i.second, 0)) || !(this->_matrix(0, i.first) <= other._matrix(0, i.second))) { return false; } for (const auto& j : vars) { if (!(this->_matrix(i.first, j.first) <= other._matrix(i.second, j.second))) { return false; } } } return true; } bool equals(const DBM& other) const override { return this->leq(other) && other.leq(*this); } private: /// \brief Apply a pointwise binary operator template < typename BinaryOperator > DBM pointwise_binary_op(const DBM& other, const BinaryOperator& op) const { // Result dbm auto dbm = DBM::top(); // Marker for an invalid index const MatrixIndex none = std::numeric_limits< MatrixIndex >::max(); // Build index map MatrixIndex next_index = 1; std::vector< std::pair< MatrixIndex, MatrixIndex > > vars; vars.reserve(this->_var_index_map.size()); for (auto l = this->_var_index_map.begin(), r = other._var_index_map.begin(); l != this->_var_index_map.end() || r != other._var_index_map.end();) { if (l == this->_var_index_map.end() || (r != other._var_index_map.end() && r->first < l->first)) { // Variable in `other` but not in `this` if (op.meet_semantic()) { dbm._var_index_map.emplace_hint(dbm._var_index_map.end(), r->first, next_index++); vars.emplace_back(none, r->second); } ++r; } else if (r == other._var_index_map.end() || (l != this->_var_index_map.end() && l->first < r->first)) { // Variable in `this` but not in `other` if (op.meet_semantic()) { dbm._var_index_map.emplace_hint(dbm._var_index_map.end(), l->first, next_index++); vars.emplace_back(l->second, none); } l++; } else { ikos_assert(l->first == r->first); dbm._var_index_map.emplace_hint(dbm._var_index_map.end(), l->first, next_index++); vars.emplace_back(l->second, r->second); l++; r++; } } // Allocate memory for the result matrix dbm._matrix.clear_resize(static_cast< MatrixIndex >(vars.size() + 1)); // Compute the result matrix for (std::size_t i_index = 0; i_index < vars.size(); ++i_index) { const auto& i = vars[i_index]; const auto i_res = static_cast< MatrixIndex >(i_index + 1); if (op.meet_semantic() && i.second == none) { dbm._matrix(i_res, 0) = op(this->_matrix(i.first, 0)); dbm._matrix(0, i_res) = op(this->_matrix(0, i.first)); } else if (op.meet_semantic() && i.first == none) { dbm._matrix(i_res, 0) = op(other._matrix(i.second, 0)); dbm._matrix(0, i_res) = op(other._matrix(0, i.second)); } else { dbm._matrix(i_res, 0) = op(this->_matrix(i.first, 0), other._matrix(i.second, 0)); dbm._matrix(0, i_res) = op(this->_matrix(0, i.first), other._matrix(0, i.second)); } for (std::size_t j_index = 0; j_index < vars.size(); ++j_index) { const auto& j = vars[j_index]; const auto j_res = static_cast< MatrixIndex >(j_index + 1); if (i_res == j_res) { dbm._matrix(i_res, i_res) = BoundT(0); } else if (op.meet_semantic() && (i.first == none || j.first == none) && (i.second == none || j.second == none)) { dbm._matrix(i_res, j_res) = op(); } else if (op.meet_semantic() && (i.second == none || j.second == none)) { dbm._matrix(i_res, j_res) = op(this->_matrix(i.first, j.first)); } else if (op.meet_semantic() && (i.first == none || j.first == none)) { dbm._matrix(i_res, j_res) = op(other._matrix(i.second, j.second)); } else { dbm._matrix(i_res, j_res) = op(this->_matrix(i.first, j.first), other._matrix(i.second, j.second)); } } } dbm._is_normalized = false; return dbm; } struct JoinOperator { bool meet_semantic() const { return false; } BoundT operator()() const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT&) const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT& x, const BoundT& y) const { return max(x, y); } }; struct WideningOperator { bool meet_semantic() const { return false; } BoundT operator()() const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT&) const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT& x, const BoundT& y) const { if (y <= x) { return x; } else { return BoundT::plus_infinity(); } } }; struct WideningThresholdOperator { BoundT threshold; explicit WideningThresholdOperator(const Number& threshold_) : threshold(threshold_) {} bool meet_semantic() const { return false; } BoundT operator()() const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT&) const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT& x, const BoundT& y) const { if (y <= x) { return x; } else if (threshold >= y) { return threshold; } else { return BoundT::plus_infinity(); } } }; struct MeetOperator { bool meet_semantic() const { return true; } BoundT operator()() const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT& x) const { return x; } BoundT operator()(const BoundT& x, const BoundT& y) const { return min(x, y); } }; struct NarrowingOperator { bool meet_semantic() const { return true; } BoundT operator()() const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT& x) const { return x; } BoundT operator()(const BoundT& x, const BoundT& y) const { if (x.is_plus_infinity()) { return y; } else { return x; } } }; struct NarrowingThresholdOperator { BoundT threshold; explicit NarrowingThresholdOperator(const Number& threshold_) : threshold(threshold_) {} bool meet_semantic() const { return true; } BoundT operator()() const { return BoundT::plus_infinity(); } BoundT operator()(const BoundT& x) const { return x; } BoundT operator()(const BoundT& x, const BoundT& y) const { if (x.is_plus_infinity() || x == threshold) { return y; } else { return x; } } }; public: void join_with(DBM&& other) override { // Requires normalization this->normalize(); other.normalize(); ikos_assert(this->_is_normalized); ikos_assert(other._is_normalized); if (this->_is_bottom) { this->operator=(std::move(other)); } else if (other._is_bottom) { return; } else { DBM dbm = this->pointwise_binary_op(other, JoinOperator{}); dbm._is_normalized = true; // The join is normalized by construction this->operator=(std::move(dbm)); } } void join_with(const DBM& other) override { // Requires normalization this->normalize(); if (!other._is_normalized) { this->join_with(other.normalize_copy()); return; } ikos_assert(this->_is_normalized); ikos_assert(other._is_normalized); if (this->_is_bottom) { this->operator=(other); } else if (other._is_bottom) { return; } else { DBM dbm = this->pointwise_binary_op(other, JoinOperator{}); dbm._is_normalized = true; // The join is normalized by construction this->operator=(std::move(dbm)); } } DBM join(const DBM& other) const override { // Requires normalization if (!this->_is_normalized) { return this->normalize_copy().join(other); } else if (!other._is_normalized) { return this->join(other.normalize_copy()); } ikos_assert(this->_is_normalized); ikos_assert(other._is_normalized); if (this->_is_bottom) { return other; } else if (other._is_bottom) { return *this; } else { DBM dbm = this->pointwise_binary_op(other, JoinOperator{}); dbm._is_normalized = true; // The join is normalized by construction return dbm; } } void widen_with(const DBM& other) override { this->operator=(this->widening(other)); } DBM widening(const DBM& other) const override { // Requires the normalization of the right hand side. // The left hand side should not be normalized. if (!other._is_normalized) { return this->widening(other.normalize_copy()); } ikos_assert(other._is_normalized); if (this->_is_bottom) { return other; } else if (other._is_bottom) { return *this; } else { return this->pointwise_binary_op(other, WideningOperator{}); } } DBM widening_threshold(const DBM& other, const Number& threshold) const override { // Requires the normalization of the right hand side. // The left hand side should not be normalized. if (!other._is_normalized) { return this->widening_threshold(other.normalize_copy(), threshold); } ikos_assert(other._is_normalized); if (this->_is_bottom) { return other; } else if (other._is_bottom) { return *this; } else { return this->pointwise_binary_op(other, WideningThresholdOperator{threshold}); } } void widen_threshold_with(const DBM& other, const Number& threshold) override { this->operator=(this->widening_threshold(other, threshold)); } DBM meet(const DBM& other) const override { // Requires normalization if (!this->_is_normalized) { return this->normalize_copy().meet(other); } else if (!other._is_normalized) { return this->meet(other.normalize_copy()); } ikos_assert(this->_is_normalized); ikos_assert(other._is_normalized); if (this->_is_bottom || other._is_bottom) { return bottom(); } else { return this->pointwise_binary_op(other, MeetOperator{}); } } void meet_with(const DBM& other) override { this->operator=(this->meet(other)); } DBM narrowing(const DBM& other) const override { // Requires normalization if (!this->_is_normalized) { return this->normalize_copy().narrowing(other); } else if (!other._is_normalized) { return this->narrowing(other.normalize_copy()); } ikos_assert(this->_is_normalized); ikos_assert(other._is_normalized); if (this->_is_bottom || other._is_bottom) { return bottom(); } else { return this->pointwise_binary_op(other, NarrowingOperator{}); } } void narrow_with(const DBM& other) override { this->operator=(this->narrowing(other)); } DBM narrowing_threshold(const DBM& other, const Number& threshold) const override { // Requires normalization if (!this->_is_normalized) { return this->normalize_copy().narrowing_threshold(other, threshold); } else if (!other._is_normalized) { return this->narrowing_threshold(other.normalize_copy(), threshold); } ikos_assert(this->_is_normalized); ikos_assert(other._is_normalized); if (this->_is_bottom || other._is_bottom) { return bottom(); } else { return this->pointwise_binary_op(other, NarrowingThresholdOperator{threshold}); } } void narrow_threshold_with(const DBM& other, const Number& threshold) override { this->operator=(this->narrowing_threshold(other, threshold)); } private: /// \brief Get the index of variable x in _matrix /// /// Create a new one if not found MatrixIndex var_index(VariableRef x) { if (this->_matrix.num_vars() == 0) { MatrixIndex i = this->_matrix.add_variable(); this->_var_index_map.emplace(x, i); return i; } auto it = this->_var_index_map.find(x); if (it != this->_var_index_map.end()) { return it->second; } // Look for an unused index in _matrix std::vector< bool > is_used(this->_matrix.num_vars(), false); is_used[0] = true; for (const auto& p : this->_var_index_map) { is_used[p.second] = true; } auto unused_index = std::find(is_used.begin(), is_used.end(), false); if (unused_index == is_used.end()) { // No unused index found, we resize the matrix MatrixIndex i = this->_matrix.add_variable(); this->_var_index_map.emplace(x, i); return i; } else { MatrixIndex i = static_cast< MatrixIndex >( std::distance(is_used.begin(), unused_index)); this->_var_index_map.emplace(x, i); return i; } } /// \brief Add constraint v_i - v_j <= c void add_constraint(MatrixIndex i, MatrixIndex j, const BoundT& c) { const BoundT& w = this->_matrix(j, i); if (c < w) { this->_matrix(j, i) = c; this->_is_normalized = false; } } /// \brief Add constraint v_i - v_j <= c void add_constraint(MatrixIndex i, MatrixIndex j, const Number& c) { this->add_constraint(i, j, BoundT(c)); } /// \brief Add constraint v_i - v_j <= c void add_constraint(MatrixIndex i, MatrixIndex j, int c) { this->add_constraint(i, j, BoundT(c)); } /// \brief Apply v_i = v_i + c void increment(MatrixIndex i, const BoundT& c) { if (c == BoundT(0)) { return; } for (MatrixIndex j = 0; j < this->_matrix.num_vars(); j++) { if (i != j) { this->_matrix(i, j) -= c; this->_matrix(j, i) += c; } } this->_is_normalized = false; } /// \brief Apply v_i = v_i + c void increment(MatrixIndex i, const Number& c) { this->increment(i, BoundT(c)); } public: void assign(VariableRef x, int n) override { this->assign(x, Number(n)); } void assign(VariableRef x, const Number& n) override { if (this->_is_bottom) { return; } MatrixIndex i = this->var_index(x); this->forget(i); this->add_constraint(i, 0, n); this->add_constraint(0, i, -n); } void assign(VariableRef x, VariableRef y) override { if (this->_is_bottom) { return; } if (x == y) { return; } MatrixIndex i = this->var_index(x); MatrixIndex j = this->var_index(y); this->forget(i); this->add_constraint(i, j, 0); this->add_constraint(j, i, 0); } void assign(VariableRef x, const LinearExpressionT& e) override { // Does not require normalization if (this->_is_bottom) { return; } if (e.is_constant()) { // x = c MatrixIndex i = this->var_index(x); this->forget(i); this->add_constraint(i, 0, e.constant()); this->add_constraint(0, i, -e.constant()); return; } if (e.num_terms() == 1 && e.begin()->second == 1) { // x = y + c MatrixIndex i = this->var_index(x); VariableRef y = e.begin()->first; const Number& c = e.constant(); if (x == y) { // x = x + c this->increment(i, c); } else { MatrixIndex j = this->var_index(y); this->forget(i); this->add_constraint(i, j, c); this->add_constraint(j, i, -c); } return; } // Projection using intervals, requires normalization this->normalize(); if (this->_is_bottom) { return; } this->set(x, this->to_interval(e)); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { // Requires normalization this->normalize(); if (this->_is_bottom) { return; } IntervalT v_y = this->to_interval(y); IntervalT v_z = this->to_interval(z); if (v_z.singleton()) { this->apply(op, x, y, *v_z.singleton()); } else if (v_y.singleton()) { this->apply(op, x, *v_y.singleton(), z); } else { this->set(x, apply_bin_operator(op, v_y, v_z)); } } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { // Does not require normalization if (this->_is_bottom) { return; } switch (op) { case BinaryOperator::Add: { MatrixIndex i = this->var_index(x); if (x == y) { // x = x + z this->increment(i, z); } else { // x = y + z MatrixIndex j = this->var_index(y); this->forget(i); this->add_constraint(i, j, z); this->add_constraint(j, i, -z); } } break; case BinaryOperator::Sub: { MatrixIndex i = this->var_index(x); if (x == y) { // x = x - z this->increment(i, -z); } else { // x = y - z MatrixIndex j = this->var_index(y); this->forget(i); this->add_constraint(i, j, -z); this->add_constraint(j, i, z); } } break; case BinaryOperator::Mul: { if (z == 1) { // x = y if (x == y) { return; } MatrixIndex i = this->var_index(x); MatrixIndex j = this->var_index(y); this->forget(i); this->add_constraint(i, j, 0); this->add_constraint(j, i, 0); } else { // Requires normalization this->normalize(); if (this->_is_bottom) { return; } this->set(x, this->to_interval(y) * IntervalT(z)); } } break; case BinaryOperator::Div: { if (z == 1) { // x = y if (x == y) { return; } MatrixIndex i = this->var_index(x); MatrixIndex j = this->var_index(y); this->forget(i); this->add_constraint(i, j, 0); this->add_constraint(j, i, 0); } else { // Requires normalization this->normalize(); if (this->_is_bottom) { return; } this->set(x, this->to_interval(y) / IntervalT(z)); } } break; case BinaryOperator::Mod: { if (z == 0) { this->set_to_bottom(); return; } // Requires normalization this->normalize(); if (this->_is_bottom) { return; } IntervalT v_y = this->to_interval(y); boost::optional< Number > n = v_y.mod_to_sub(z); if (n) { // Equivalent to x = y - n MatrixIndex i = this->var_index(x); if (x == y) { // x = x - n this->increment(i, -(*n)); } else { // x = y - n MatrixIndex j = this->var_index(y); this->forget(i); this->add_constraint(i, j, -(*n)); this->add_constraint(j, i, *n); } } else { this->set(x, IntervalT(BoundT(0), BoundT(abs(z) - 1))); // If y < abs(z) then x >= y if (v_y.ub() < BoundT(abs(z))) { MatrixIndex i = this->var_index(x); MatrixIndex j = this->var_index(y); this->add_constraint(j, i, BoundT(0)); } // If y >= -abs(z) then x <= y + abs(z) if (v_y.lb() >= BoundT(-abs(z))) { MatrixIndex i = this->var_index(x); MatrixIndex j = this->var_index(y); this->add_constraint(i, j, BoundT(abs(z))); } } } break; case BinaryOperator::Rem: case BinaryOperator::Shl: case BinaryOperator::Shr: case BinaryOperator::And: case BinaryOperator::Or: case BinaryOperator::Xor: { // Requires normalization this->normalize(); if (this->_is_bottom) { return; } this->set(x, apply_bin_operator(op, this->to_interval(y), IntervalT(z))); } break; } } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { // Does not require normalization if (this->_is_bottom) { return; } switch (op) { case BinaryOperator::Add: { MatrixIndex i = this->var_index(x); if (x == z) { // x = y + x this->increment(i, y); } else { // x = y + z MatrixIndex j = this->var_index(z); this->forget(i); this->add_constraint(i, j, y); this->add_constraint(j, i, -y); } } break; case BinaryOperator::Sub: { // Requires normalization this->normalize(); if (this->_is_bottom) { return; } this->set(x, IntervalT(y) - this->to_interval(z)); } break; case BinaryOperator::Mul: { if (y == 1) { // x = z if (x == z) { return; } MatrixIndex i = this->var_index(x); MatrixIndex j = this->var_index(z); this->forget(i); this->add_constraint(i, j, 0); this->add_constraint(j, i, 0); } else { // Requires normalization this->normalize(); if (this->_is_bottom) { return; } this->set(x, IntervalT(y) * this->to_interval(z)); } } break; case BinaryOperator::Div: case BinaryOperator::Rem: case BinaryOperator::Mod: case BinaryOperator::Shl: case BinaryOperator::Shr: case BinaryOperator::And: case BinaryOperator::Or: case BinaryOperator::Xor: { // Requires normalization this->normalize(); if (this->_is_bottom) { return; } this->set(x, apply_bin_operator(op, IntervalT(y), this->to_interval(z))); } break; } } void add(const LinearConstraintT& cst) override { // Does not require normalization if (this->_is_bottom) { return; } if (cst.num_terms() == 0) { if (cst.is_contradiction()) { this->set_to_bottom(); } return; } auto it = cst.begin(); auto it2 = ++cst.begin(); MatrixIndex i; MatrixIndex j; const Number& c = cst.constant(); if (cst.num_terms() == 1 && it->second == 1) { i = this->var_index(it->first); j = 0; } else if (cst.num_terms() == 1 && it->second == -1) { i = 0; j = this->var_index(it->first); } else if (cst.num_terms() == 2 && it->second == 1 && it2->second == -1) { i = this->var_index(it->first); j = this->var_index(it2->first); } else if (cst.num_terms() == 2 && it->second == -1 && it2->second == 1) { i = this->var_index(it2->first); j = this->var_index(it->first); } else { // Use the linear interval solver this->normalize(); if (this->_is_bottom) { return; } LinearIntervalSolverT solver(MaxReductionCycles); solver.add(cst); solver.run(*this); return; } if (cst.is_inequality()) { this->add_constraint(i, j, c); } else if (cst.is_equality()) { this->add_constraint(i, j, c); this->add_constraint(j, i, -c); } else { // Use the linear interval solver this->normalize(); if (this->_is_bottom) { return; } LinearIntervalSolverT solver(MaxReductionCycles); solver.add(cst); solver.run(*this); } } void add(const LinearConstraintSystemT& csts) override { if (this->_is_bottom) { return; } LinearIntervalSolverT solver(MaxReductionCycles); for (const LinearConstraintT& cst : csts) { // Process each constraint if (cst.num_terms() == 0) { if (cst.is_contradiction()) { this->set_to_bottom(); return; } } else if (cst.is_inequality() || cst.is_equality()) { auto it = cst.begin(); auto it2 = ++cst.begin(); MatrixIndex i; MatrixIndex j; const Number& c = cst.constant(); if (cst.num_terms() == 1 && it->second == 1) { i = this->var_index(it->first); j = 0; } else if (cst.num_terms() == 1 && it->second == -1) { i = 0; j = this->var_index(it->first); } else if (cst.num_terms() == 2 && it->second == 1 && it2->second == -1) { i = this->var_index(it->first); j = this->var_index(it2->first); } else if (cst.num_terms() == 2 && it->second == -1 && it2->second == 1) { i = this->var_index(it2->first); j = this->var_index(it->first); } else { solver.add(cst); continue; } if (cst.is_inequality()) { this->add_constraint(i, j, c); } else { this->add_constraint(i, j, c); this->add_constraint(j, i, -c); } } else { solver.add(cst); } } if (!solver.empty()) { // Use the linear interval solver this->normalize(); if (this->_is_bottom) { return; } solver.run(*this); } } void set(VariableRef x, const IntervalT& value) override { if (this->_is_bottom) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { MatrixIndex i = this->var_index(x); this->forget(i); this->add_constraint(i, 0, value.ub()); this->add_constraint(0, i, -value.lb()); } } void set(VariableRef x, const CongruenceT& value) override { if (this->_is_bottom) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { MatrixIndex i = this->var_index(x); this->forget(i); boost::optional< Number > n = value.singleton(); if (n) { this->add_constraint(i, 0, *n); this->add_constraint(0, i, -*n); } } } void set(VariableRef x, const IntervalCongruenceT& value) override { this->set(x, value.interval()); } void refine(VariableRef x, const IntervalT& value) override { if (this->_is_bottom) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { MatrixIndex i = this->var_index(x); this->add_constraint(i, 0, value.ub()); this->add_constraint(0, i, -value.lb()); } } void refine(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruenceT iv(this->to_interval(x), value); this->refine(x, iv.interval()); } } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruenceT iv(this->to_interval(x)); iv.meet_with(value); this->refine(x, iv.interval()); } } private: /// \brief Forget all informations about variable k void forget(MatrixIndex k) { // Use informations about k to improve all constraints // Not necessary if already normalized if (!this->_is_normalized) { for (MatrixIndex i = 0; i < this->_matrix.num_vars(); i++) { const BoundT& w_i_k = this->_matrix(i, k); if (w_i_k + this->_matrix(k, i) < BoundT(0)) { this->_is_bottom = true; return; } for (MatrixIndex j = 0; j < this->_matrix.num_vars(); j++) { if (i != k && j != k && i != j) { this->_matrix(i, j) = min(this->_matrix(i, j), w_i_k + this->_matrix(k, j)); } } } } for (MatrixIndex i = 0; i < this->_matrix.num_vars(); i++) { this->_matrix(i, k) = BoundT::plus_infinity(); this->_matrix(k, i) = BoundT::plus_infinity(); } this->_matrix(k, k) = BoundT(0); this->_is_normalized = false; } public: void forget(VariableRef x) override { if (this->_is_bottom) { return; } auto it = this->_var_index_map.find(x); if (it != this->_var_index_map.end()) { this->forget(it->second); this->_var_index_map.erase(it); } } private: struct GetVar { const VariableRef& operator()( const std::pair< VariableRef, MatrixIndex >& p) const { return p.first; } }; public: /// \brief Iterator over a list of variables using VariableIterator = boost::transform_iterator< GetVar, typename VarIndexMap::const_iterator >; /// \brief Begin iterator over the list of variables VariableIterator var_begin() const { return boost::make_transform_iterator(this->_var_index_map.cbegin(), GetVar()); } /// \brief End iterator over the list of variables VariableIterator var_end() const { return boost::make_transform_iterator(this->_var_index_map.cend(), GetVar()); } IntervalT to_interval(VariableRef x) const override { if (this->_is_bottom) { return IntervalT::bottom(); } else { auto it = this->_var_index_map.find(x); if (it == this->_var_index_map.cend()) { return IntervalT::top(); } else { return IntervalT(-this->_matrix(it->second, 0), this->_matrix(0, it->second)); } } } IntervalT to_interval(const LinearExpressionT& e) const override { // TODO(marthaud): provide a better result for e = x - y return Parent::to_interval(e); } CongruenceT to_congruence(VariableRef x) const override { if (this->_is_bottom) { return CongruenceT::bottom(); } else { boost::optional< Number > n = this->to_interval(x).singleton(); if (n) { return CongruenceT(*n); } else { return CongruenceT::top(); } } } CongruenceT to_congruence(const LinearExpressionT& e) const override { return Parent::to_congruence(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return IntervalCongruenceT(this->to_interval(x)); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { // TODO(marthaud): provide a better result for e = x - y return Parent::to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->_is_bottom) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; for (auto it = this->_var_index_map.begin(), et = this->_var_index_map.end(); it != et; ++it) { csts.add(within_interval(it->first, IntervalT(-this->_matrix(it->second, 0), this->_matrix(0, it->second)))); for (auto it2 = it + 1; it2 != et; ++it2) { csts.add( within_interval(VariableExprT(it->first) - VariableExprT(it2->first), IntervalT(-this->_matrix(it->second, it2->second), this->_matrix(it2->second, it->second)))); } } return csts; } void dump(std::ostream& o) const override { this->to_linear_constraint_system().dump(o); } static std::string name() { return "dbm"; } }; // end class DBM } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/domain_product.hpp000066400000000000000000000636611473507761200275330ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Products of numerical abstract domains * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Domain product of 2 numerical abstract domains template < typename Number, typename VariableRef, typename Domain1, typename Domain2 > class DomainProduct2 final : public numeric::AbstractDomain< Number, VariableRef, DomainProduct2< Number, VariableRef, Domain1, Domain2 > > { public: static_assert( numeric::IsAbstractDomain< Domain1, Number, VariableRef >::value, "Domain1 must implement numeric::AbstractDomain"); static_assert( numeric::IsAbstractDomain< Domain2, Number, VariableRef >::value, "Domain2 must implement numeric::AbstractDomain"); public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using Product = core::DomainProduct2< Domain1, Domain2 >; private: Product _product; private: /// \brief Private constructor explicit DomainProduct2(Product product) : _product(std::move(product)) {} public: /// \brief Create the abstract value with the given abstract values DomainProduct2(Domain1 first, Domain2 second) : _product(std::move(first), std::move(second)) {} /// \brief Copy constructor DomainProduct2(const DomainProduct2&) noexcept( (std::is_nothrow_copy_constructible< Domain1 >::value) && (std::is_nothrow_copy_constructible< Domain2 >::value)) = default; /// \brief Move constructor DomainProduct2(DomainProduct2&&) noexcept( (std::is_nothrow_move_constructible< Domain1 >::value) && (std::is_nothrow_move_constructible< Domain2 >::value)) = default; /// \brief Copy assignment operator DomainProduct2& operator=(const DomainProduct2&) noexcept( (std::is_nothrow_copy_assignable< Domain1 >::value) && (std::is_nothrow_copy_assignable< Domain2 >::value)) = default; /// \brief Move assignment operator DomainProduct2& operator=(DomainProduct2&&) noexcept( (std::is_nothrow_move_assignable< Domain1 >::value) && (std::is_nothrow_move_assignable< Domain2 >::value)) = default; /// \brief Destructor ~DomainProduct2() override = default; /// \brief Return the first abstract value /// /// Note: does not normalize. const Domain1& first() const { return this->_product.first(); } /// \brief Return the first abstract value /// /// Note: does not normalize. Domain1& first() { return this->_product.first(); } /// \brief Return the second abstract value /// /// Note: does not normalize. const Domain2& second() const { return this->_product.second(); } /// \brief Return the second abstract value /// /// Note: does not normalize. Domain2& second() { return this->_product.second(); } void normalize() override { this->_product.normalize(); } bool is_bottom() const override { return this->_product.is_bottom(); } bool is_top() const override { return this->_product.is_top(); } void set_to_bottom() override { this->_product.set_to_bottom(); } void set_to_top() override { this->_product.set_to_top(); } bool leq(const DomainProduct2& other) const override { return this->_product.leq(other._product); } bool equals(const DomainProduct2& other) const override { return this->_product.equals(other._product); } void join_with(DomainProduct2&& other) override { this->_product.join_with(std::move(other._product)); } void join_with(const DomainProduct2& other) override { this->_product.join_with(other._product); } void join_loop_with(DomainProduct2&& other) override { this->_product.join_loop_with(std::move(other._product)); } void join_loop_with(const DomainProduct2& other) override { this->_product.join_loop_with(other._product); } void join_iter_with(DomainProduct2&& other) override { this->_product.join_iter_with(std::move(other._product)); } void join_iter_with(const DomainProduct2& other) override { this->_product.join_iter_with(other._product); } void widen_with(const DomainProduct2& other) override { this->_product.widen_with(other._product); } void widen_threshold_with(const DomainProduct2& other, const Number& threshold) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->first().widen_threshold_with(other.first(), threshold); this->second().widen_threshold_with(other.second(), threshold); } } void meet_with(const DomainProduct2& other) override { this->_product.meet_with(other._product); } void narrow_with(const DomainProduct2& other) override { this->_product.narrow_with(other._product); } void narrow_threshold_with(const DomainProduct2& other, const Number& threshold) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->first().narrow_threshold_with(other.first(), threshold); this->second().narrow_threshold_with(other.second(), threshold); } } DomainProduct2 join(const DomainProduct2& other) const override { return DomainProduct2(this->_product.join(other._product)); } DomainProduct2 join_loop(const DomainProduct2& other) const override { return DomainProduct2(this->_product.join_loop(other._product)); } DomainProduct2 join_iter(const DomainProduct2& other) const override { return DomainProduct2(this->_product.join_iter(other._product)); } DomainProduct2 widening(const DomainProduct2& other) const override { return DomainProduct2(this->_product.widening(other._product)); } DomainProduct2 widening_threshold(const DomainProduct2& other, const Number& threshold) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return DomainProduct2(this->first().widening_threshold(other.first(), threshold), this->second().widening_threshold(other.second(), threshold)); } } DomainProduct2 meet(const DomainProduct2& other) const override { return DomainProduct2(this->_product.meet(other._product)); } DomainProduct2 narrowing(const DomainProduct2& other) const override { return DomainProduct2(this->_product.narrowing(other._product)); } DomainProduct2 narrowing_threshold(const DomainProduct2& other, const Number& threshold) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return DomainProduct2(this->first().narrowing_threshold(other.first(), threshold), this->second().narrowing_threshold(other.second(), threshold)); } } void assign(VariableRef x, int n) override { this->_product.first().assign(x, n); this->_product.second().assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_product.first().assign(x, n); this->_product.second().assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_product.first().assign(x, y); this->_product.second().assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_product.first().assign(x, e); this->_product.second().assign(x, e); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_product.first().apply(op, x, y, z); this->_product.second().apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_product.first().apply(op, x, y, z); this->_product.second().apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_product.first().apply(op, x, y, z); this->_product.second().apply(op, x, y, z); } void add(const LinearConstraintT& cst) override { this->_product.first().add(cst); this->_product.second().add(cst); } void add(const LinearConstraintSystemT& csts) override { this->_product.first().add(csts); this->_product.second().add(csts); } void set(VariableRef x, const IntervalT& value) override { this->_product.first().set(x, value); this->_product.second().set(x, value); } void set(VariableRef x, const CongruenceT& value) override { this->_product.first().set(x, value); this->_product.second().set(x, value); } void set(VariableRef x, const IntervalCongruenceT& value) override { this->_product.first().set(x, value); this->_product.second().set(x, value); } void refine(VariableRef x, const IntervalT& value) override { this->_product.first().refine(x, value); this->_product.second().refine(x, value); } void refine(VariableRef x, const CongruenceT& value) override { this->_product.first().refine(x, value); this->_product.second().refine(x, value); } void refine(VariableRef x, const IntervalCongruenceT& value) override { this->_product.first().refine(x, value); this->_product.second().refine(x, value); } void forget(VariableRef x) override { this->_product.first().forget(x); this->_product.second().forget(x); } IntervalT to_interval(VariableRef x) const override { IntervalT a = this->_product.first().to_interval(x); IntervalT b = this->_product.second().to_interval(x); return a.meet(b); } IntervalT to_interval(const LinearExpressionT& e) const override { IntervalT a = this->_product.first().to_interval(e); IntervalT b = this->_product.second().to_interval(e); return a.meet(b); } CongruenceT to_congruence(VariableRef x) const override { CongruenceT a = this->_product.first().to_congruence(x); CongruenceT b = this->_product.second().to_congruence(x); return a.meet(b); } CongruenceT to_congruence(const LinearExpressionT& e) const override { CongruenceT a = this->_product.first().to_congruence(e); CongruenceT b = this->_product.second().to_congruence(e); return a.meet(b); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { IntervalCongruenceT a = this->_product.first().to_interval_congruence(x); IntervalCongruenceT b = this->_product.second().to_interval_congruence(x); return a.meet(b); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { IntervalCongruenceT a = this->_product.first().to_interval_congruence(e); IntervalCongruenceT b = this->_product.second().to_interval_congruence(e); return a.meet(b); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; csts = this->_product.first().to_linear_constraint_system(); csts.add(this->_product.second().to_linear_constraint_system()); return csts; } /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_product.first().counter_mark(x); this->_product.second().counter_mark(x); } void counter_unmark(VariableRef x) override { this->_product.first().counter_unmark(x); this->_product.second().counter_unmark(x); } void counter_init(VariableRef x, const Number& c) override { this->_product.first().counter_init(x, c); this->_product.second().counter_init(x, c); } void counter_incr(VariableRef x, const Number& k) override { this->_product.first().counter_incr(x, k); this->_product.second().counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_product.first().counter_forget(x); this->_product.second().counter_forget(x); } /// @} void dump(std::ostream& o) const override { this->_product.dump(o); } static std::string name() { return "numerical product " + Domain1::name() + " x " + Domain2::name(); } }; // end class DomainProduct2 /// \brief Domain product of 3 numerical abstract domains template < typename Number, typename VariableRef, typename Domain1, typename Domain2, typename Domain3 > class DomainProduct3 final : public numeric::AbstractDomain< Number, VariableRef, DomainProduct3< Number, VariableRef, Domain1, Domain2, Domain3 > > { public: static_assert( numeric::IsAbstractDomain< Domain1, Number, VariableRef >::value, "Domain1 must implement numeric::AbstractDomain"); static_assert( numeric::IsAbstractDomain< Domain2, Number, VariableRef >::value, "Domain2 must implement numeric::AbstractDomain"); static_assert( numeric::IsAbstractDomain< Domain3, Number, VariableRef >::value, "Domain3 must implement numeric::AbstractDomain"); public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using Product12 = DomainProduct2< Number, VariableRef, Domain1, Domain2 >; using Product123 = DomainProduct2< Number, VariableRef, Product12, Domain3 >; private: Product123 _product; private: /// \brief Private constructor explicit DomainProduct3(Product123 product) : _product(std::move(product)) {} public: /// \brief Create the top abstract value DomainProduct3() = default; /// \brief Create the abstract value with the given abstract values DomainProduct3(Domain1 first, Domain2 second, Domain3 third) : _product(Product12(std::move(first), std::move(second)), std::move(third)) {} /// \brief Copy constructor DomainProduct3(const DomainProduct3&) noexcept( (std::is_nothrow_copy_constructible< Domain1 >::value) && (std::is_nothrow_copy_constructible< Domain2 >::value) && (std::is_nothrow_copy_constructible< Domain3 >::value)) = default; /// \brief Move constructor DomainProduct3(DomainProduct3&&) noexcept( (std::is_nothrow_move_constructible< Domain1 >::value) && (std::is_nothrow_move_constructible< Domain2 >::value) && (std::is_nothrow_move_constructible< Domain3 >::value)) = default; /// \brief Copy assignment operator DomainProduct3& operator=(const DomainProduct3&) noexcept( (std::is_nothrow_copy_assignable< Domain1 >::value) && (std::is_nothrow_copy_assignable< Domain2 >::value) && (std::is_nothrow_copy_assignable< Domain3 >::value)) = default; /// \brief Move assignment operator DomainProduct3& operator=(DomainProduct3&&) noexcept( (std::is_nothrow_move_assignable< Domain1 >::value) && (std::is_nothrow_move_assignable< Domain2 >::value) && (std::is_nothrow_move_assignable< Domain3 >::value)) = default; /// \brief Destructor ~DomainProduct3() override = default; /// \brief Create the top abstract value static DomainProduct3 top() { return DomainProduct3(Product123::top()); } /// \brief Create the bottom abstract value static DomainProduct3 bottom() { return DomainProduct3(Product123::bottom()); } /// \brief Return the first abstract value /// /// Note: does not normalize. const Domain1& first() const { return this->_product.first().first(); } /// \brief Return the first abstract value /// /// Note: does not normalize. Domain1& first() { return this->_product.first().first(); } /// \brief Return the second abstract value /// /// Note: does not normalize. const Domain2& second() const { return this->_product.first().second(); } /// \brief Return the second abstract value /// /// Note: does not normalize. Domain2& second() { return this->_product.first().second(); } /// \brief Return the third abstract value /// /// Note: does not normalize. const Domain3& third() const { return this->_product.second(); } /// \brief Return the third abstract value /// /// Note: does not normalize. Domain3& third() { return this->_product.second(); } void normalize() override { this->_product.normalize(); } bool is_bottom() const override { return this->_product.is_bottom(); } bool is_top() const override { return this->_product.is_top(); } void set_to_bottom() override { this->_product.set_to_bottom(); } void set_to_top() override { this->_product.set_to_top(); } bool leq(const DomainProduct3& other) const override { return this->_product.leq(other._product); } bool equals(const DomainProduct3& other) const override { return this->_product.equals(other._product); } void join_with(DomainProduct3&& other) override { this->_product.join_with(std::move(other._product)); } void join_with(const DomainProduct3& other) override { this->_product.join_with(other._product); } void join_loop_with(DomainProduct3&& other) override { this->_product.join_loop_with(std::move(other._product)); } void join_loop_with(const DomainProduct3& other) override { this->_product.join_loop_with(other._product); } void join_iter_with(DomainProduct3&& other) override { this->_product.join_iter_with(std::move(other._product)); } void join_iter_with(const DomainProduct3& other) override { this->_product.join_iter_with(other._product); } void widen_with(const DomainProduct3& other) override { this->_product.widen_with(other._product); } void widen_threshold_with(const DomainProduct3& other, const Number& threshold) override { this->_product.widen_threshold_with(other._product, threshold); } void meet_with(const DomainProduct3& other) override { this->_product.meet_with(other._product); } void narrow_with(const DomainProduct3& other) override { this->_product.narrow_with(other._product); } void narrow_threshold_with(const DomainProduct3& other, const Number& threshold) override { this->_product.narrow_threshold_with(other._product, threshold); } DomainProduct3 join(const DomainProduct3& other) const override { return DomainProduct3(this->_product.join(other._product)); } DomainProduct3 join_loop(const DomainProduct3& other) const override { return DomainProduct3(this->_product.join_loop(other._product)); } DomainProduct3 join_iter(const DomainProduct3& other) const override { return DomainProduct3(this->_product.join_iter(other._product)); } DomainProduct3 widening(const DomainProduct3& other) const override { return DomainProduct3(this->_product.widening(other._product)); } DomainProduct3 widening_threshold(const DomainProduct3& other, const Number& threshold) const override { return DomainProduct3( this->_product.widening_threshold(other._product, threshold)); } DomainProduct3 meet(const DomainProduct3& other) const override { return DomainProduct3(this->_product.meet(other._product)); } DomainProduct3 narrowing(const DomainProduct3& other) const override { return DomainProduct3(this->_product.narrowing(other._product)); } DomainProduct3 narrowing_threshold(const DomainProduct3& other, const Number& threshold) const override { return DomainProduct3( this->_product.narrowing_threshold(other._product, threshold)); } void assign(VariableRef x, int n) override { this->_product.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_product.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_product.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_product.assign(x, e); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_product.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_product.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_product.apply(op, x, y, z); } void add(const LinearConstraintT& cst) override { this->_product.add(cst); } void add(const LinearConstraintSystemT& csts) override { this->_product.add(csts); } void set(VariableRef x, const IntervalT& value) override { this->_product.set(x, value); } void set(VariableRef x, const CongruenceT& value) override { this->_product.set(x, value); } void set(VariableRef x, const IntervalCongruenceT& value) override { this->_product.set(x, value); } void refine(VariableRef x, const IntervalT& value) override { this->_product.refine(x, value); } void refine(VariableRef x, const CongruenceT& value) override { this->_product.refine(x, value); } void refine(VariableRef x, const IntervalCongruenceT& value) override { this->_product.refine(x, value); } void forget(VariableRef x) override { this->_product.forget(x); } IntervalT to_interval(VariableRef x) const override { return this->_product.to_interval(x); } IntervalT to_interval(const LinearExpressionT& e) const override { return this->_product.to_interval(e); } CongruenceT to_congruence(VariableRef x) const override { return this->_product.to_congruence(x); } CongruenceT to_congruence(const LinearExpressionT& e) const override { return this->_product.to_congruence(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return this->_product.to_interval_congruence(x); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return this->_product.to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { return this->_product.to_linear_constraint_system(); } /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_product.counter_mark(x); } void counter_unmark(VariableRef x) override { this->_product.counter_unmark(x); } void counter_init(VariableRef x, const Number& c) override { this->_product.counter_init(x, c); } void counter_incr(VariableRef x, const Number& k) override { this->_product.counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_product.counter_forget(x); } /// @} void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "("; this->first().dump(o); o << ", "; this->second().dump(o); o << ", "; this->third().dump(o); o << ")"; } } static std::string name() { return "numerical product " + Domain1::name() + " x " + Domain2::name() + " x " + Domain3::name(); } }; // end class DomainProduct3 } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/equality_congruence_solver.hpp000066400000000000000000000161371473507761200321570ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Congruence solver for linear constraints equalities * * Author: Alexandre C. D. Wimmers * * Contributors: * * Jorge A. Navas * * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Equality congruence solver /// /// Note that the solver does not own the linear constraints. /// /// TODO(awimmers): Check correctness of the solver. Granger provides a sound /// and more precise solver for equality linear congruences (see Theorem 4.4). template < typename Number, typename VariableRef, typename NumAbstractDomain > class EqualityCongruenceSolver { private: using CongruenceT = Congruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; using LinearConstraintRef = std::reference_wrapper< const LinearConstraintT >; using LinearConstraintSystemRef = std::reference_wrapper< const LinearConstraintSystemT >; private: using ConstraintSet = std::vector< LinearConstraintRef >; using VariableSet = boost::container::flat_set< VariableRef >; private: std::size_t _max_cycles; std::size_t _op_count = 0; bool _is_contradiction = false; ConstraintSet _csts; VariableSet _refined_variables; private: struct BottomFound {}; /// \brief Refine the abstract value for the given variable v void refine(VariableRef v, const CongruenceT& c, NumAbstractDomain& inv) { CongruenceT old_c = inv.to_congruence(v); CongruenceT new_c = old_c.meet(c); if (new_c.is_bottom()) { throw BottomFound(); } if (old_c != new_c) { inv.refine(v, new_c); this->_refined_variables.insert(v); ++this->_op_count; } } /// \brief Compute the residual of a linear constraint CongruenceT compute_residual(const LinearConstraintT& cst, VariableRef pivot, const NumAbstractDomain& inv) { CongruenceT residual(cst.constant()); for (const auto& term : cst) { if (term.first != pivot) { residual -= CongruenceT(term.second) * inv.to_congruence(term.first); ++this->_op_count; } } return residual; } void propagate(const LinearConstraintT& cst, NumAbstractDomain& inv) { // Inequations (>=, <=, >, and <) do not work well with // congruences because for any number n there is always x and y // \in gamma(aZ+b) such that n < x and n > y. // // The only cases we can catch is when all the expressions // are constants. We do not bother because any product // with intervals or constants should get those cases. if (!cst.is_equality()) { return; } for (const auto& term : cst) { const Number& c = term.second; VariableRef pivot = term.first; CongruenceT rhs = this->compute_residual(cst, pivot, inv) / CongruenceT(c); this->refine(pivot, rhs, inv); } } /// \brief Solve a linear constraint system void solve_system(NumAbstractDomain& inv) { std::size_t cycle = 0; do { ++cycle; this->_refined_variables.clear(); for (const LinearConstraintT& cst : this->_csts) { this->propagate(cst, inv); } } while (!this->_refined_variables.empty() && cycle <= this->_max_cycles); } public: /// \brief Constructor explicit EqualityCongruenceSolver(std::size_t max_cycles) : _max_cycles(max_cycles) {} /// \brief Add a constraint /// /// Warning: the linear constraint should outlive the solver void add(LinearConstraintRef cst) { if (cst.get().is_contradiction()) { this->_is_contradiction = true; } else if (cst.get().is_tautology()) { return; } else { this->_csts.push_back(cst); } } /// \brief Add a system of constraint /// /// Warning: the linear constrainst system should outlive the solver void add(LinearConstraintSystemRef csts) { for (const LinearConstraintT& cst : csts.get()) { if (cst.is_contradiction()) { this->_is_contradiction = true; return; } else if (cst.is_tautology()) { continue; } else { this->_csts.push_back(cst); } } } /// \brief Return the number of linear constraints std::size_t size() const { return this->_csts.size(); } /// \brief Return true if the solver is empty bool empty() const { return this->_csts.empty(); } /// \brief Solve the system and refine the given invariant void run(NumAbstractDomain& inv) { if (this->_is_contradiction) { inv.set_to_bottom(); return; } if (this->empty()) { return; } try { this->solve_system(inv); } catch (BottomFound&) { inv.set_to_bottom(); } } }; // end class EqualityCongruenceSolver } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/gauge.hpp000066400000000000000000001170721473507761200256100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the Gauge Domain * * Based on Arnaud Venet's paper: The Gauge Domain: Scalable Analysis of * Linear Inequality Invariants, in CAV, 129-154, 2012. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Gauge semilattice template < typename Number, typename VariableRef > class GaugeSemiLattice final : public core::AbstractDomain< GaugeSemiLattice< Number, VariableRef > > { public: using GaugeBoundT = GaugeBound< Number, VariableRef >; using GaugeT = Gauge< Number, VariableRef >; using BoundT = Bound< Number >; using ConstantT = Constant< Number >; using IntervalT = Interval< Number >; using VariableExpressionT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using PatriciaTreeMapT = PatriciaTreeMap< VariableRef, GaugeT >; private: PatriciaTreeMapT _tree; bool _is_bottom; /* Invariants: * _is_bottom => _tree.empty() * for v in _tree: _tree.at(v) != GaugeT::top() * for v in _tree: _tree.at(v) != GaugeT::bottom() */ private: struct TopTag {}; struct BottomTag {}; struct BottomFound {}; /// \brief Create the top abstract value explicit GaugeSemiLattice(TopTag) : _is_bottom(false) {} /// \brief Create the bottom abstract value explicit GaugeSemiLattice(BottomTag) : _is_bottom(true) {} public: /// \brief Create the top abstract value static GaugeSemiLattice top() { return GaugeSemiLattice(TopTag{}); } /// \brief Create the bottom abstract value static GaugeSemiLattice bottom() { return GaugeSemiLattice(BottomTag{}); } /// \brief Copy constructor GaugeSemiLattice(const GaugeSemiLattice&) noexcept = default; /// \brief Move constructor GaugeSemiLattice(GaugeSemiLattice&&) noexcept = default; /// \brief Copy assignment operator GaugeSemiLattice& operator=(const GaugeSemiLattice&) noexcept = default; /// \brief Move assignment operator GaugeSemiLattice& operator=(GaugeSemiLattice&&) noexcept = default; /// \brief Destructor ~GaugeSemiLattice() override = default; void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->_is_bottom && this->_tree.empty(); } void set_to_bottom() override { this->_is_bottom = true; this->_tree.clear(); } void set_to_top() override { this->_is_bottom = false; this->_tree.clear(); } bool leq(const GaugeSemiLattice& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_tree.leq(other._tree, [](const GaugeT& x, const GaugeT& y) { return x.leq(y); }); } } bool equals(const GaugeSemiLattice& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_tree.equals(other._tree, [](const GaugeT& x, const GaugeT& y) { return x.equals(y); }); } } void join_with(const GaugeSemiLattice& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const GaugeT& x, const GaugeT& y) { GaugeT z = x.join(y); if (z.is_top()) { return boost::optional< GaugeT >( boost::none); } return boost::optional< GaugeT >(z); }); } } void meet_with(const GaugeSemiLattice& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const GaugeT& x, const GaugeT& y) { GaugeT z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< GaugeT >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } // \brief Widening interval-like void widen_interval_with(const GaugeSemiLattice& other) { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const GaugeT& x, const GaugeT& y) { GaugeT z = x.widening_interval(y); if (z.is_top()) { return boost::optional< GaugeT >( boost::none); } return boost::optional< GaugeT >(z); }); } } // \brief Widening interval-like with a threshold void widen_interval_threshold_with(const GaugeSemiLattice& other, const Number& threshold) { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [threshold](const GaugeT& x, const GaugeT& y) { GaugeT z = x.widening_interval_threshold(y, threshold); if (z.is_top()) { return boost::optional< GaugeT >( boost::none); } return boost::optional< GaugeT >(z); }); } } /// \brief Widening with interpolation void widen_interpol_with(const GaugeSemiLattice& other, VariableRef k, const Number& u, const ConstantT& v) { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [k, u, v](const GaugeT& x, const GaugeT& y) { GaugeT z = x.widening_interpol(y, k, u, v); if (z.is_top()) { return boost::optional< GaugeT >( boost::none); } return boost::optional< GaugeT >(z); }); } } void widen_with(const GaugeSemiLattice& other) override { this->widen_interval_with(other); } void narrow_with(const GaugeSemiLattice& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const GaugeT& x, const GaugeT& y) { GaugeT z = x.narrowing(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< GaugeT >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } // \brief Narrowing interval-like with a threshold void narrow_interval_threshold_with(const GaugeSemiLattice& other, const Number& threshold) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [threshold](const GaugeT& x, const GaugeT& y) { GaugeT z = x.narrowing_interval_threshold(y, threshold); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< GaugeT >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Increment counter `v` by `k` void counter_incr(VariableRef v, const Number& k) { if (this->is_bottom()) { return; } this->_tree.transform([v, k](VariableRef, const GaugeT& x) { GaugeT y = x.counter_incr(v, k); if (y.is_top()) { return boost::optional< GaugeT >(boost::none); } else { return boost::optional< GaugeT >(y); } }); } /// \brief Forget counter `v` /// /// \param value Interval for `v` void counter_forget(VariableRef v, IntervalT value = IntervalT::top()) { if (this->is_bottom()) { return; } value.meet_with(IntervalT(BoundT(0), BoundT::plus_infinity())); ikos_assert(!value.is_bottom()); ikos_assert(value.lb().is_finite()); Number l = *value.lb().number(); const BoundT& u = value.ub(); this->_tree.transform([v, l, u](VariableRef, const GaugeT& x) { GaugeT y = x.coalesce(v, l, u); if (y.is_top()) { return boost::optional< GaugeT >(boost::none); } else { return boost::optional< GaugeT >(y); } }); } /// \brief Forget variable `v` void forget(VariableRef v) { if (this->is_bottom()) { return; } this->_tree.erase(v); } /// \brief Set the gauge for the given variable void set(VariableRef v, const GaugeT& g) { if (this->is_bottom()) { return; } else if (g.is_bottom()) { this->set_to_bottom(); } else if (g.is_top()) { this->_tree.erase(v); } else { this->_tree.insert_or_assign(v, g); } } /// \brief Refine the gauge for the given variable void refine(VariableRef v, const GaugeT& g) { if (this->is_bottom()) { return; } else if (g.is_bottom()) { this->set_to_bottom(); } else if (g.is_top()) { return; } else { try { this->_tree.update_or_insert( [](const GaugeT& x, const GaugeT& y) { GaugeT z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< GaugeT >(z); }, v, g); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Get the gauge for the given variable GaugeT get(VariableRef v) const { if (this->is_bottom()) { return GaugeT::bottom(); } else { boost::optional< const GaugeT& > g = this->_tree.at(v); if (g) { return *g; } else { return GaugeT::top(); } } } LinearConstraintSystemT to_linear_constraint_system() const { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; for (auto it = this->_tree.begin(); it != this->_tree.end(); ++it) { const GaugeBoundT& lb = it->second.lb(); const GaugeBoundT& ub = it->second.ub(); if (lb.is_finite()) { csts.add(lb.lin_expr() <= VariableExpressionT(it->first)); } if (ub.is_finite()) { csts.add(VariableExpressionT(it->first) <= ub.lin_expr()); } } return csts; } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { this->_tree.dump(o); } } static std::string name() { return "gauge semilattice"; } }; // end class GaugeSemiLattice /// \brief Gauge abstract domain template < typename Number, typename VariableRef > class GaugeDomain final : public numeric::AbstractDomain< Number, VariableRef, GaugeDomain< Number, VariableRef > > { public: using GaugeBoundT = GaugeBound< Number, VariableRef >; using GaugeT = Gauge< Number, VariableRef >; using BoundT = Bound< Number >; using ConstantT = Constant< Number >; using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using VariableExpressionT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; public: using SectionDomainT = ConstantDomain< Number, VariableRef >; using GaugeSemiLatticeT = GaugeSemiLattice< Number, VariableRef >; using CounterSetT = PatriciaTreeSet< VariableRef >; using IntervalDomainT = IntervalDomain< Number, VariableRef >; private: SectionDomainT _sections; GaugeSemiLatticeT _gauges; CounterSetT _counters; IntervalDomainT _intervals; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top abstract value explicit GaugeDomain(TopTag) : _sections(SectionDomainT::top()), _gauges(GaugeSemiLatticeT::top()), _counters(), _intervals(IntervalDomainT::top()) {} /// \brief Create the bottom abstract value explicit GaugeDomain(BottomTag) : _sections(SectionDomainT::bottom()), _gauges(GaugeSemiLatticeT::bottom()), _counters(), _intervals(IntervalDomainT::bottom()) {} public: /// \brief Create the top abstract value static GaugeDomain top() { return GaugeDomain(TopTag{}); } /// \brief Create the bottom abstract value static GaugeDomain bottom() { return GaugeDomain(BottomTag{}); } /// \brief Copy constructor GaugeDomain(const GaugeDomain&) noexcept = default; /// \brief Move constructor GaugeDomain(GaugeDomain&&) noexcept = default; /// \brief Copy assignment operator GaugeDomain& operator=(const GaugeDomain&) noexcept = default; /// \brief Move assignment operator GaugeDomain& operator=(GaugeDomain&&) noexcept = default; /// \brief Destructor ~GaugeDomain() override = default; void normalize() override { if (this->_sections.is_bottom() || this->_gauges.is_bottom() || this->_intervals.is_bottom()) { this->set_to_bottom(); } } bool is_bottom() const override { return this->_sections.is_bottom() || this->_gauges.is_bottom() || this->_intervals.is_bottom(); } bool is_top() const override { return this->_sections.is_top() && this->_gauges.is_top() && this->_counters.empty() && this->_intervals.is_top(); } void set_to_bottom() override { this->_sections.set_to_bottom(); this->_gauges.set_to_bottom(); this->_counters.clear(); this->_intervals.set_to_bottom(); } void set_to_top() override { this->_sections.set_to_top(); this->_gauges.set_to_top(); this->_counters.clear(); this->_intervals.set_to_top(); } bool leq(const GaugeDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_sections.leq(other._sections) && this->_gauges.leq(other._gauges) && other._counters.is_subset_of(this->_counters) && this->_intervals.leq(other._intervals); } } bool equals(const GaugeDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_sections.equals(other._sections) && this->_gauges.equals(other._gauges) && this->_counters.equals(other._counters) && this->_intervals.equals(other._intervals); } } private: /// \brief Make sure `l` and `r` have the same set of counters static void uniformize_counters(GaugeDomain& l, GaugeDomain& r) { for (VariableRef v : l._counters.difference(r._counters)) { l.counter_unmark(v); } for (VariableRef v : r._counters.difference(l._counters)) { r.counter_unmark(v); } ikos_assert(l._counters == r._counters); } public: void join_with(const GaugeDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_counters.equals(other._counters)) { this->_sections.join_with(other._sections); this->_gauges.join_with(other._gauges); this->_counters.intersect_with(other._counters); this->_intervals.join_with(other._intervals); } else { GaugeDomain other_copy = other; uniformize_counters(*this, other_copy); this->join_with(other_copy); } } void join_loop_with(const GaugeDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_counters.equals(other._counters)) { SectionDomainT sections = this->_sections.join(other._sections); if (this->_sections.equals(sections)) { this->_gauges.join_with(other._gauges); this->_counters.intersect_with(other._counters); this->_intervals.join_with(other._intervals); } else { GaugeSemiLatticeT gauges = this->_gauges; for (auto it = this->_sections.begin(), et = this->_sections.end(); it != et; ++it) { VariableRef k = it->first; const ConstantT& u = it->second; ConstantT v = other._sections.to_constant(k); if (u != v) { ikos_assert(u.is_number()); gauges.widen_interpol_with(other._gauges, k, *u.number(), v); } } this->_sections = sections; this->_gauges = gauges; this->_counters.intersect_with(other._counters); this->_intervals.join_with(other._intervals); } } else { GaugeDomain other_copy = other; uniformize_counters(*this, other_copy); this->join_loop_with(other_copy); } } void join_iter_with(const GaugeDomain& other) override { this->join_loop_with(other); } void widen_with(const GaugeDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_counters.equals(other._counters)) { SectionDomainT sections = this->_sections.widening(other._sections); if (this->_sections.equals(sections)) { this->_gauges.widen_interval_with(other._gauges); this->_counters.intersect_with(other._counters); this->_intervals.widen_with(other._intervals); } else { GaugeSemiLatticeT gauges = this->_gauges; for (auto it = this->_sections.begin(), et = this->_sections.end(); it != et; ++it) { VariableRef k = it->first; const ConstantT& u = it->second; ConstantT v = other._sections.to_constant(k); if (u != v) { ikos_assert(u.is_number()); gauges.widen_interpol_with(other._gauges, k, *u.number(), v); } } this->_sections = sections; this->_gauges = gauges; this->_counters.intersect_with(other._counters); this->_intervals.widen_with(other._intervals); } } else { GaugeDomain other_copy = other; uniformize_counters(*this, other_copy); this->widen_with(other_copy); } } void widen_threshold_with(const GaugeDomain& other, const Number& threshold) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else if (this->_counters.equals(other._counters)) { SectionDomainT sections = this->_sections.widening(other._sections); if (this->_sections.equals(sections)) { this->_gauges.widen_interval_threshold_with(other._gauges, threshold); this->_counters.intersect_with(other._counters); this->_intervals.widen_threshold_with(other._intervals, threshold); } else { GaugeSemiLatticeT gauges = this->_gauges; for (auto it = this->_sections.begin(), et = this->_sections.end(); it != et; ++it) { VariableRef k = it->first; const ConstantT& u = it->second; ConstantT v = other._sections.to_constant(k); if (u != v) { ikos_assert(u.is_number()); gauges.widen_interpol_with(other._gauges, k, *u.number(), v); } } this->_sections = sections; this->_gauges = gauges; this->_counters.intersect_with(other._counters); this->_intervals.widen_threshold_with(other._intervals, threshold); } } else { GaugeDomain other_copy = other; uniformize_counters(*this, other_copy); this->widen_threshold_with(other_copy, threshold); } } void meet_with(const GaugeDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->_counters.equals(other._counters)) { this->_sections.meet_with(other._sections); this->_gauges.meet_with(other._gauges); this->_counters.join_with(other._counters); this->_intervals.meet_with(other._intervals); } else { GaugeDomain other_copy = other; uniformize_counters(*this, other_copy); this->meet_with(other_copy); } } void narrow_with(const GaugeDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->_counters.equals(other._counters)) { this->_sections.narrow_with(other._sections); this->_gauges.narrow_with(other._gauges); this->_counters.join_with(other._counters); this->_intervals.narrow_with(other._intervals); } else { GaugeDomain other_copy = other; uniformize_counters(*this, other_copy); this->narrow_with(other_copy); } } void narrow_threshold_with(const GaugeDomain& other, const Number& threshold) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->_counters.equals(other._counters)) { this->_sections.narrow_threshold_with(other._sections, threshold); this->_gauges.narrow_interval_threshold_with(other._gauges, threshold); this->_counters.join_with(other._counters); this->_intervals.narrow_threshold_with(other._intervals, threshold); } else { GaugeDomain other_copy = other; uniformize_counters(*this, other_copy); this->narrow_threshold_with(other_copy, threshold); } } private: /// \brief Return true if the given variable is a counter bool is_counter(VariableRef x) const { return this->_counters.contains(x); } public: void assign(VariableRef x, int n) override { ikos_assert(!this->is_counter(x)); this->set(x, GaugeT(n)); } void assign(VariableRef x, const Number& n) override { ikos_assert(!this->is_counter(x)); this->set(x, GaugeT(n)); } void assign(VariableRef x, VariableRef y) override { ikos_assert(!this->is_counter(x)); this->set(x, this->to_gauge(y)); } void assign(VariableRef x, const LinearExpressionT& e) override { ikos_assert(!this->is_counter(x)); this->set(x, this->to_gauge(e)); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { if (this->is_bottom()) { return; } ikos_assert(!this->is_counter(x)); switch (op) { case BinaryOperator::Add: { this->set(x, this->to_gauge(y) + this->to_gauge(z)); } break; case BinaryOperator::Sub: { this->set(x, this->to_gauge(y) - this->to_gauge(z)); } break; case BinaryOperator::Mul: { GaugeT yg = this->to_gauge(y); GaugeT zg = this->to_gauge(z); boost::optional< IntervalT > yi = yg.interval(); boost::optional< IntervalT > zi = zg.interval(); if (yi) { this->set(x, zg * (*yi)); } else if (zi) { this->set(x, yg * (*zi)); } else { // use interval representation this->set(x, this->to_interval(y) * this->to_interval(z)); } } break; case BinaryOperator::Div: case BinaryOperator::Rem: case BinaryOperator::Mod: case BinaryOperator::Shl: case BinaryOperator::Shr: case BinaryOperator::And: case BinaryOperator::Or: case BinaryOperator::Xor: { IntervalT yi = this->to_interval(y); IntervalT zi = this->to_interval(z); if (zi.singleton()) { this->apply(op, x, y, *zi.singleton()); } else if (yi.singleton()) { this->apply(op, x, *yi.singleton(), z); } else { // use interval representation this->set(x, apply_bin_operator(op, yi, zi)); } } break; default: { ikos_unreachable("unreachable"); } } } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { if (this->is_bottom()) { return; } ikos_assert(!this->is_counter(x)); switch (op) { case BinaryOperator::Add: { this->set(x, this->to_gauge(y) + GaugeT(z)); } break; case BinaryOperator::Sub: { this->set(x, this->to_gauge(y) - GaugeT(z)); } break; case BinaryOperator::Mul: { this->set(x, this->to_gauge(y) * z); } break; case BinaryOperator::Mod: { if (z == 0) { this->set_to_bottom(); return; } IntervalT yi = this->to_interval(y); boost::optional< Number > n = yi.mod_to_sub(z); if (n) { // Equivalent to x = y - n this->set(x, this->to_gauge(y) - GaugeT(*n)); } else { this->set(x, GaugeT(GaugeBoundT(0), GaugeBoundT(abs(z) - 1))); } } break; case BinaryOperator::Div: case BinaryOperator::Rem: case BinaryOperator::Shl: case BinaryOperator::Shr: case BinaryOperator::And: case BinaryOperator::Or: case BinaryOperator::Xor: { // use interval representation this->set(x, apply_bin_operator(op, this->to_interval(y), IntervalT(z))); } break; default: { ikos_unreachable("unreachable"); } } } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { if (this->is_bottom()) { return; } ikos_assert(!this->is_counter(x)); switch (op) { case BinaryOperator::Add: { this->set(x, GaugeT(y) + this->to_gauge(z)); } break; case BinaryOperator::Sub: { this->set(x, GaugeT(y) - this->to_gauge(z)); } break; case BinaryOperator::Mul: { this->set(x, this->to_gauge(z) * y); } break; case BinaryOperator::Div: case BinaryOperator::Rem: case BinaryOperator::Mod: case BinaryOperator::Shl: case BinaryOperator::Shr: case BinaryOperator::And: case BinaryOperator::Or: case BinaryOperator::Xor: { // use interval representation this->set(x, apply_bin_operator(op, IntervalT(y), this->to_interval(z))); } break; default: { ikos_unreachable("unreachable"); } } } void add(const LinearConstraintT& cst) override { this->add(LinearConstraintSystemT{cst}); } void add(const LinearConstraintSystemT& csts) override { if (this->is_bottom()) { return; } LinearConstraintSystemT counters_csts; for (const LinearConstraintT& cst : csts) { if (cst.is_contradiction()) { this->set_to_bottom(); return; } GaugeT g = this->to_gauge(cst.expression()); if (cst.is_inequality()) { // e <= 0 if (g.lb().is_finite()) { counters_csts.add(g.lb().lin_expr() <= 0); } } else if (cst.is_equality()) { // e == 0 if (g.lb().is_finite()) { counters_csts.add(g.lb().lin_expr() <= 0); } if (g.ub().is_finite()) { counters_csts.add(g.ub().lin_expr() >= 0); } } else if (cst.is_disequation()) { // e != 0 if (g.singleton()) { counters_csts.add(g.lb().lin_expr() != 0); } } else { ikos_unreachable("unreachable"); } } this->_intervals.add(counters_csts); } /// \brief Set the gauge for the variable `x` void set(VariableRef x, const GaugeT& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { ikos_assert(!this->is_counter(x)); this->_gauges.set(x, value); } } void set(VariableRef x, const IntervalT& value) override { this->set(x, GaugeT(value)); } void set(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { ikos_assert(!this->is_counter(x)); boost::optional< Number > n = value.singleton(); if (n) { this->_gauges.set(x, GaugeT(*n)); } else { this->_gauges.forget(x); } } } void set(VariableRef x, const IntervalCongruenceT& value) override { this->set(x, GaugeT(value.interval())); } /// \brief Refine the gauge for the variable `x` void refine(VariableRef x, const GaugeT& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { ikos_assert(!this->is_counter(x)); this->_gauges.refine(x, value); } } void refine(VariableRef x, const IntervalT& value) override { this->refine(x, GaugeT(value)); } void refine(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { ikos_assert(!this->is_counter(x)); IntervalCongruenceT iv(this->to_interval(x), value); this->refine(x, GaugeT(iv.interval())); } } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { ikos_assert(!this->is_counter(x)); IntervalCongruenceT iv(this->to_interval(x)); iv.meet_with(value); this->refine(x, GaugeT(iv.interval())); } } void forget(VariableRef x) override { if (this->is_bottom()) { return; } else if (this->is_counter(x)) { this->counter_forget(x); } else { this->_gauges.forget(x); } } /// \brief Projection to a gauge /// /// Return an overapproximation of the value of `x` as an interval GaugeT to_gauge(VariableRef x) const { if (this->is_bottom()) { return GaugeT::bottom(); } else if (this->is_counter(x)) { return GaugeT(GaugeBoundT(x)); } else { return this->_gauges.get(x); } } /// \brief Projection to a gauge /// /// Return an overapproximation of the linear expression `e` as a gauge GaugeT to_gauge(const LinearExpressionT& e) const { if (this->is_bottom()) { return GaugeT::bottom(); } GaugeT r(e.constant()); for (const auto& term : e) { if (this->is_counter(term.first)) { r += GaugeT(GaugeBoundT(term.second, term.first)); } else { r += this->_gauges.get(term.first) * term.second; } } return r; } /// \brief Projection to an interval /// /// Return an overapproximation of the gauge `g` as an interval IntervalT to_interval(const GaugeT& g) const { if (this->is_bottom() || g.is_bottom()) { return IntervalT::bottom(); } else { BoundT lb = g.lb().is_finite() ? this->_intervals.to_interval(g.lb().lin_expr()).lb() : BoundT::minus_infinity(); BoundT ub = g.ub().is_finite() ? this->_intervals.to_interval(g.ub().lin_expr()).ub() : BoundT::plus_infinity(); return IntervalT(lb, ub); } } IntervalT to_interval(VariableRef x) const override { if (this->is_bottom()) { return IntervalT::bottom(); } else if (this->is_counter(x)) { return this->_intervals.to_interval(x); } else { return this->to_interval(this->_gauges.get(x)); } } IntervalT to_interval(const LinearExpressionT& e) const override { if (this->is_bottom()) { return IntervalT::bottom(); } else { return this->to_interval(this->to_gauge(e)); } } CongruenceT to_congruence(VariableRef x) const override { if (this->is_bottom()) { return CongruenceT::bottom(); } boost::optional< Number > n = this->to_interval(x).singleton(); if (n) { return CongruenceT(*n); } else { return CongruenceT::top(); } } CongruenceT to_congruence(const LinearExpressionT& e) const override { if (this->is_bottom()) { return CongruenceT::bottom(); } boost::optional< Number > n = this->to_interval(e).singleton(); if (n) { return CongruenceT(*n); } else { return CongruenceT::top(); } } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return IntervalCongruenceT(this->to_interval(x)); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return IntervalCongruenceT(this->to_interval(e)); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; csts = this->_gauges.to_linear_constraint_system(); csts.add(this->_intervals.to_linear_constraint_system()); return csts; } /// \name Non-negative loop counter abstract domain methods /// @{ /// \brief Mark the variable `x` as a non-negative loop counter void counter_mark(VariableRef x) override { if (this->is_bottom()) { return; } if (this->_counters.contains(x)) { return; } IntervalT itv = this->to_interval(x); itv.meet_with(IntervalT(BoundT(0), BoundT::plus_infinity())); if (itv.is_bottom()) { this->set_to_bottom(); return; } if (itv.singleton()) { this->_sections.set(x, ConstantT(*itv.singleton())); } this->_gauges.forget(x); this->_counters.insert(x); this->_intervals.set(x, itv); } /// \brief Mark the variable `x` as a normal variable, without losing /// information void counter_unmark(VariableRef x) override { if (this->is_bottom()) { return; } if (!this->_counters.contains(x)) { return; } IntervalT itv = this->_intervals.to_interval(x); this->_sections.forget(x); this->_gauges.counter_forget(x, itv); this->_gauges.set(x, GaugeT(itv)); this->_counters.erase(x); this->_intervals.forget(x); } /// \brief Initialize a non-negative loop counter: `x = c` /// /// Precondition: `c >= 0` void counter_init(VariableRef x, const Number& c) override { ikos_assert(c >= 0); if (this->is_bottom()) { return; } if (this->_counters.contains(x)) { this->_gauges.counter_forget(x, this->_intervals.to_interval(x)); } else { this->_gauges.forget(x); } this->_sections.assign(x, c); this->_counters.insert(x); this->_intervals.assign(x, c); } /// \brief Increment a non-negative loop counter counter: `x += k` /// /// Precondition: `k >= 0` void counter_incr(VariableRef x, const Number& k) override { ikos_assert(k >= 0); if (this->is_bottom()) { return; } this->_sections.apply(BinaryOperator::Add, x, x, k); this->_gauges.counter_incr(x, k); this->_intervals.apply(BinaryOperator::Add, x, x, k); } /// \brief Forget a non-negative loop counter void counter_forget(VariableRef x) override { if (this->is_bottom()) { return; } IntervalT itv = this->_intervals.to_interval(x); this->_sections.forget(x); this->_gauges.counter_forget(x, itv); this->_counters.erase(x); this->_intervals.forget(x); } /// @} void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "(sections="; this->_sections.dump(o); o << ", gauges="; this->_gauges.dump(o); o << ", counters="; this->_counters.dump(o); o << ", intervals="; this->_intervals.dump(o); o << ")"; } } static std::string name() { return "gauge domain"; } }; // end class GaugeDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/gauge_interval_congruence.hpp000066400000000000000000000372731473507761200317300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Reduced product of gauges, intervals and congruences * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Reduced product of gauges, intervals and congruences template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class GaugeIntervalCongruenceDomain final : public numeric::AbstractDomain< Number, VariableRef, GaugeIntervalCongruenceDomain< Number, VariableRef, MaxReductionCycles > > { public: using GaugeT = Gauge< Number, VariableRef >; using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using GaugeDomainT = GaugeDomain< Number, VariableRef >; using IntervalDomainT = IntervalDomain< Number, VariableRef, MaxReductionCycles >; using CongruenceDomainT = CongruenceDomain< Number, VariableRef, MaxReductionCycles >; using DomainProduct = numeric::DomainProduct3< Number, VariableRef, GaugeDomainT, IntervalDomainT, CongruenceDomainT >; private: DomainProduct _product; private: /// \brief Private constructor explicit GaugeIntervalCongruenceDomain(DomainProduct product) : _product(std::move(product)) {} /// \brief Reduce the information on variable `v` void reduce_variable(VariableRef v) { if (this->is_bottom()) { return; } IntervalT i = this->_product.first().to_interval(v); IntervalT j = this->_product.second().to_interval(v); CongruenceT c = this->_product.third().to_congruence(v); IntervalCongruenceT val(i.meet(j), c); if (val.is_bottom()) { this->set_to_bottom(); } else { if (val.interval() != j) { this->_product.second().set(v, val.interval()); } if (val.congruence() != c) { this->_product.third().set(v, val.congruence()); } } } public: /// \brief Create the top abstract value static GaugeIntervalCongruenceDomain top() { return GaugeIntervalCongruenceDomain( DomainProduct(GaugeDomainT::top(), IntervalDomainT::top(), CongruenceDomainT::top())); } /// \brief Create the bottom abstract value static GaugeIntervalCongruenceDomain bottom() { return GaugeIntervalCongruenceDomain( DomainProduct(GaugeDomainT::bottom(), IntervalDomainT::bottom(), CongruenceDomainT::bottom())); } /// \brief Copy constructor GaugeIntervalCongruenceDomain(const GaugeIntervalCongruenceDomain&) noexcept = default; /// \brief Move constructor GaugeIntervalCongruenceDomain(GaugeIntervalCongruenceDomain&&) noexcept = default; /// \brief Copy assignment operator GaugeIntervalCongruenceDomain& operator=( const GaugeIntervalCongruenceDomain&) noexcept = default; /// \brief Move assignment operator GaugeIntervalCongruenceDomain& operator=( GaugeIntervalCongruenceDomain&&) noexcept = default; /// \brief Destructor ~GaugeIntervalCongruenceDomain() override = default; /// \brief Return the first abstract value /// /// Note: does not normalize. const GaugeDomainT& first() const { return this->_product.first(); } /// \brief Return the first abstract value /// /// Note: does not normalize. GaugeDomainT& first() { return this->_product.first(); } /// \brief Return the second abstract value /// /// Note: does not normalize. const IntervalDomainT& second() const { return this->_product.second(); } /// \brief Return the second abstract value /// /// Note: does not normalize. IntervalDomainT& second() { return this->_product.second(); } /// \brief Return the third abstract value /// /// Note: does not normalize. const CongruenceDomainT& third() const { return this->_product.third(); } /// \brief Return the third abstract value /// /// Note: does not normalize. CongruenceDomainT& third() { return this->_product.third(); } void normalize() override { this->_product.normalize(); } bool is_bottom() const override { return this->_product.is_bottom(); } bool is_top() const override { return this->_product.is_top(); } void set_to_bottom() override { this->_product.set_to_bottom(); } void set_to_top() override { this->_product.set_to_top(); } bool leq(const GaugeIntervalCongruenceDomain& other) const override { return this->_product.leq(other._product); } bool equals(const GaugeIntervalCongruenceDomain& other) const override { return this->_product.equals(other._product); } void join_with(GaugeIntervalCongruenceDomain&& other) override { this->_product.join_with(std::move(other._product)); } void join_with(const GaugeIntervalCongruenceDomain& other) override { this->_product.join_with(other._product); } void join_loop_with(GaugeIntervalCongruenceDomain&& other) override { this->_product.join_loop_with(std::move(other._product)); } void join_loop_with(const GaugeIntervalCongruenceDomain& other) override { this->_product.join_loop_with(other._product); } void join_iter_with(GaugeIntervalCongruenceDomain&& other) override { this->_product.join_iter_with(std::move(other._product)); } void join_iter_with(const GaugeIntervalCongruenceDomain& other) override { this->_product.join_iter_with(other._product); } void widen_with(const GaugeIntervalCongruenceDomain& other) override { this->_product.widen_with(other._product); } void widen_threshold_with(const GaugeIntervalCongruenceDomain& other, const Number& threshold) override { this->_product.widen_threshold_with(other._product, threshold); } void meet_with(const GaugeIntervalCongruenceDomain& other) override { this->_product.meet_with(other._product); } void narrow_with(const GaugeIntervalCongruenceDomain& other) override { this->_product.narrow_with(other._product); } void narrow_threshold_with(const GaugeIntervalCongruenceDomain& other, const Number& threshold) override { this->_product.narrow_threshold_with(other._product, threshold); } GaugeIntervalCongruenceDomain join( const GaugeIntervalCongruenceDomain& other) const override { return GaugeIntervalCongruenceDomain(this->_product.join(other._product)); } GaugeIntervalCongruenceDomain join_loop( const GaugeIntervalCongruenceDomain& other) const override { return GaugeIntervalCongruenceDomain( this->_product.join_loop(other._product)); } GaugeIntervalCongruenceDomain join_iter( const GaugeIntervalCongruenceDomain& other) const override { return GaugeIntervalCongruenceDomain( this->_product.join_iter(other._product)); } GaugeIntervalCongruenceDomain widening( const GaugeIntervalCongruenceDomain& other) const override { return GaugeIntervalCongruenceDomain( this->_product.widening(other._product)); } GaugeIntervalCongruenceDomain widening_threshold( const GaugeIntervalCongruenceDomain& other, const Number& threshold) const override { return GaugeIntervalCongruenceDomain( this->_product.widening_threshold(other._product, threshold)); } GaugeIntervalCongruenceDomain meet( const GaugeIntervalCongruenceDomain& other) const override { return GaugeIntervalCongruenceDomain(this->_product.meet(other._product)); } GaugeIntervalCongruenceDomain narrowing( const GaugeIntervalCongruenceDomain& other) const override { return GaugeIntervalCongruenceDomain( this->_product.narrowing(other._product)); } GaugeIntervalCongruenceDomain narrowing_threshold( const GaugeIntervalCongruenceDomain& other, const Number& threshold) const override { return GaugeIntervalCongruenceDomain( this->_product.narrowing_threshold(other._product, threshold)); } void assign(VariableRef x, int n) override { this->_product.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_product.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_product.assign(x, y); this->reduce_variable(x); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_product.assign(x, e); this->reduce_variable(x); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_product.apply(op, x, y, z); this->reduce_variable(x); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_product.apply(op, x, y, z); this->reduce_variable(x); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_product.apply(op, x, y, z); this->reduce_variable(x); } void add(const LinearConstraintT& cst) override { this->_product.add(cst); for (const auto& term : cst) { this->reduce_variable(term.first); } } void add(const LinearConstraintSystemT& csts) override { this->_product.add(csts); for (const LinearConstraintT& cst : csts) { for (const auto& term : cst) { this->reduce_variable(term.first); } } } void set(VariableRef x, const IntervalT& value) override { this->set(x, IntervalCongruenceT(value)); } void set(VariableRef x, const CongruenceT& value) override { this->set(x, IntervalCongruenceT(value)); } void set(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_product.first().set(x, value.interval()); this->_product.second().set(x, value.interval()); this->_product.third().set(x, value.congruence()); } } void refine(VariableRef x, const IntervalT& value) override { this->refine(x, IntervalCongruenceT(value)); } void refine(VariableRef x, const CongruenceT& value) override { this->refine(x, IntervalCongruenceT(value)); } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_product.second().refine(x, value.interval()); this->_product.third().refine(x, value.congruence()); this->reduce_variable(x); } } void forget(VariableRef x) override { this->_product.forget(x); } GaugeT to_gauge(VariableRef x) const { return this->_product.first().to_gauge(x); } GaugeT to_gauge(const LinearExpressionT& e) const { return this->_product.first().to_gauge(e); } IntervalT to_interval(VariableRef x) const override { return this->to_interval_congruence(x).interval(); } IntervalT to_interval(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).interval(); } CongruenceT to_congruence(VariableRef x) const override { return this->to_interval_congruence(x).congruence(); } CongruenceT to_congruence(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).congruence(); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { if (this->is_bottom()) { return IntervalCongruenceT::bottom(); } else { IntervalT i = this->_product.first().to_interval(x); i.meet_with(this->_product.second().to_interval(x)); CongruenceT c = this->_product.third().to_congruence(x); return IntervalCongruenceT(i, c); } } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { if (this->is_bottom()) { return IntervalCongruenceT::bottom(); } else { IntervalT i = this->_product.first().to_interval(e); i.meet_with(this->_product.second().to_interval(e)); CongruenceT c = this->_product.third().to_congruence(e); return IntervalCongruenceT(i, c); } } LinearConstraintSystemT to_linear_constraint_system() const override { return this->_product.to_linear_constraint_system(); } /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_product.counter_mark(x); } void counter_unmark(VariableRef x) override { this->_product.counter_unmark(x); } void counter_init(VariableRef x, const Number& c) override { this->_product.counter_init(x, c); } void counter_incr(VariableRef x, const Number& k) override { this->_product.counter_incr(x, k); } void counter_forget(VariableRef x) override { this->_product.counter_forget(x); } /// @} void dump(std::ostream& o) const override { this->_product.dump(o); } static std::string name() { return "gauge + interval + congruence domain"; } }; // end class GaugeIntervalCongruenceDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/interval.hpp000066400000000000000000000243061473507761200263410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Standard domain of intervals * * Author: Arnaud J. Venet * * Contributors: * * Alexandre C. D. Wimmers * * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Interval abstract domain template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class IntervalDomain final : public numeric::AbstractDomain< Number, VariableRef, IntervalDomain< Number, VariableRef, MaxReductionCycles > > { public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using SeparateDomainT = SeparateDomain< Number, VariableRef, IntervalT >; using LinearIntervalSolverT = LinearIntervalSolver< Number, VariableRef, IntervalDomain >; using Parent = numeric::AbstractDomain< Number, VariableRef, IntervalDomain >; public: using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit IntervalDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static IntervalDomain top() { return IntervalDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static IntervalDomain bottom() { return IntervalDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor IntervalDomain(const IntervalDomain&) noexcept = default; /// \brief Move constructor IntervalDomain(IntervalDomain&&) noexcept = default; /// \brief Copy assignment operator IntervalDomain& operator=(const IntervalDomain&) noexcept = default; /// \brief Move assignment operator IntervalDomain& operator=(IntervalDomain&&) noexcept = default; /// \brief Destructor ~IntervalDomain() override = default; /// \brief Begin iterator over the pairs (variable, interval) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, interval) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const IntervalDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const IntervalDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const IntervalDomain& other) override { this->_inv.join_with(other._inv); } void join_loop_with(const IntervalDomain& other) override { this->_inv.join_loop_with(other._inv); } void join_iter_with(const IntervalDomain& other) override { this->_inv.join_iter_with(other._inv); } void widen_with(const IntervalDomain& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const IntervalDomain& other, const Number& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const IntervalDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const IntervalDomain& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const IntervalDomain& other, const Number& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } void assign(VariableRef x, int n) override { this->_inv.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(const LinearConstraintT& cst) override { if (this->is_bottom()) { return; } LinearIntervalSolverT solver(MaxReductionCycles); solver.add(cst); solver.run(*this); } void add(const LinearConstraintSystemT& csts) override { if (this->is_bottom()) { return; } LinearIntervalSolverT solver(MaxReductionCycles); solver.add(csts); solver.run(*this); } void set(VariableRef x, const IntervalT& value) override { this->_inv.set(x, value); } void set(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< Number > n = value.singleton(); if (n) { this->_inv.set(x, IntervalT(*n)); } else { this->_inv.forget(x); } } } void set(VariableRef x, const IntervalCongruenceT& value) override { this->_inv.set(x, value.interval()); } void refine(VariableRef x, const IntervalT& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruenceT iv(this->_inv.get(x), value); this->_inv.set(x, iv.interval()); } } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { IntervalCongruenceT iv(this->_inv.get(x)); iv.meet_with(value); this->_inv.set(x, iv.interval()); } } void forget(VariableRef x) override { this->_inv.forget(x); } IntervalT to_interval(VariableRef x) const override { return this->_inv.get(x); } IntervalT to_interval(const LinearExpressionT& e) const override { return this->_inv.project(e); } CongruenceT to_congruence(VariableRef x) const override { if (this->is_bottom()) { return CongruenceT::bottom(); } boost::optional< Number > n = this->_inv.get(x).singleton(); if (n) { return CongruenceT(*n); } else { return CongruenceT::top(); } } CongruenceT to_congruence(const LinearExpressionT& e) const override { return Parent::to_congruence(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return IntervalCongruenceT(this->_inv.get(x)); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return Parent::to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; for (auto it = this->begin(), et = this->end(); it != et; ++it) { csts.add(within_interval(it->first, it->second)); } return csts; } void dump(std::ostream& o) const override { this->_inv.dump(o); } static std::string name() { return "interval domain"; } }; // end class IntervalDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/interval_congruence.hpp000066400000000000000000000244641473507761200305560ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Reduced product of intervals and congruences * * The reduce operator based on "Static Analysis of Arithmetical * Congruences" by P. Granger published in International Journal of * Computer Mathematics, 1989. * * Author: Jorge A. Navas Laserna * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Reduced product of intervals and congruences template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class IntervalCongruenceDomain final : public numeric::AbstractDomain< Number, VariableRef, IntervalCongruenceDomain< Number, VariableRef, MaxReductionCycles > > { public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using SeparateDomainT = SeparateDomain< Number, VariableRef, IntervalCongruenceT >; using LinearIntervalSolverT = LinearIntervalSolver< Number, VariableRef, IntervalCongruenceDomain >; using EqualityCongruenceSolverT = EqualityCongruenceSolver< Number, VariableRef, IntervalCongruenceDomain >; public: using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit IntervalCongruenceDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static IntervalCongruenceDomain top() { return IntervalCongruenceDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static IntervalCongruenceDomain bottom() { return IntervalCongruenceDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor IntervalCongruenceDomain(const IntervalCongruenceDomain&) noexcept = default; /// \brief Move constructor IntervalCongruenceDomain(IntervalCongruenceDomain&&) noexcept = default; /// \brief Copy assignment operator IntervalCongruenceDomain& operator=( const IntervalCongruenceDomain&) noexcept = default; /// \brief Move assignment operator IntervalCongruenceDomain& operator=(IntervalCongruenceDomain&&) noexcept = default; /// \brief Destructor ~IntervalCongruenceDomain() override = default; /// \brief Begin iterator over the pairs (variable, interval_congruence) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, interval_congruence) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const IntervalCongruenceDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const IntervalCongruenceDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const IntervalCongruenceDomain& other) override { this->_inv.join_with(other._inv); } void join_loop_with(const IntervalCongruenceDomain& other) override { this->_inv.join_loop_with(other._inv); } void join_iter_with(const IntervalCongruenceDomain& other) override { this->_inv.join_iter_with(other._inv); } void widen_with(const IntervalCongruenceDomain& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const IntervalCongruenceDomain& other, const Number& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const IntervalCongruenceDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const IntervalCongruenceDomain& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const IntervalCongruenceDomain& other, const Number& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } void assign(VariableRef x, int n) override { this->_inv.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_inv.assign(x, e); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_inv.apply(op, x, y, z); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_inv.apply(op, x, y, z); } void add(const LinearConstraintT& cst) override { if (this->is_bottom()) { return; } LinearIntervalSolverT int_solver(MaxReductionCycles); int_solver.add(cst); int_solver.run(*this); EqualityCongruenceSolverT cong_solver(MaxReductionCycles); cong_solver.add(cst); cong_solver.run(*this); } void add(const LinearConstraintSystemT& csts) override { if (this->is_bottom()) { return; } LinearIntervalSolverT int_solver(MaxReductionCycles); int_solver.add(csts); int_solver.run(*this); EqualityCongruenceSolverT cong_solver(MaxReductionCycles); cong_solver.add(csts); cong_solver.run(*this); } void set(VariableRef x, const IntervalCongruenceT& value) override { this->_inv.set(x, value); } void set(VariableRef x, const IntervalT& value) override { this->set(x, IntervalCongruenceT(value)); } void set(VariableRef x, const CongruenceT& value) override { this->set(x, IntervalCongruenceT(value)); } void refine(VariableRef x, const IntervalCongruenceT& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const IntervalT& value) override { this->refine(x, IntervalCongruenceT(value)); } void refine(VariableRef x, const CongruenceT& value) override { this->refine(x, IntervalCongruenceT(value)); } void forget(VariableRef x) override { this->_inv.forget(x); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return this->_inv.get(x); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return this->_inv.project(e); } IntervalT to_interval(VariableRef x) const override { return this->to_interval_congruence(x).interval(); } IntervalT to_interval(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).interval(); } CongruenceT to_congruence(VariableRef x) const override { return this->to_interval_congruence(x).congruence(); } CongruenceT to_congruence(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).congruence(); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; for (auto it = this->begin(), et = this->end(); it != et; ++it) { csts.add(within_interval(it->first, it->second.interval())); } return csts; } void dump(std::ostream& o) const override { this->_inv.dump(o); } static std::string name() { return "reduced product of intervals and congruences"; } }; // end class IntervalCongruenceDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/linear_interval_solver.hpp000066400000000000000000000240251473507761200312630ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Interval solver for linear constraints * * The resolution of a system of linear constraints over the domain of intervals * is based on W. Harvey & P. J. Stuckey's paper: Improving linear constraint * propagation by changing constraint representation, in Constraints, * 8(2):173–207, 2003. * * Author: Arnaud J. Venet * * Contributors: * * Alexandre C. D. Wimmers * * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Trim the bounds of the given interval inline ZInterval trim_bound(const ZInterval& i, const ZBound& b) { ikos_assert(!i.is_bottom()); if (i.lb() == b) { return ZInterval(b + ZBound(1), i.ub()); } else if (i.ub() == b) { return ZInterval(i.lb(), b - ZBound(1)); } else { return i; } } /// \brief Trim the bounds of the given interval inline QInterval trim_bound(const QInterval& i, const QBound&) { // No refinement possible for disequations over rational numbers return i; } /// \brief Linear interval solver /// /// Note that the solver does not own the linear constraints. template < typename Number, typename VariableRef, typename NumAbstractDomain > class LinearIntervalSolver { private: static const std::size_t LargeSystemCstThreshold = 3; /// \brief Cost of one propagation cycle for a dense 3x3 system of constraints static const std::size_t LargeSystemOpThreshold = 27; private: using BoundT = Bound< Number >; using IntervalT = Interval< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; using LinearConstraintRef = std::reference_wrapper< const LinearConstraintT >; using LinearConstraintSystemRef = std::reference_wrapper< const LinearConstraintSystemT >; private: using ConstraintSet = std::vector< LinearConstraintRef >; using TriggerTable = boost::container::flat_map< VariableRef, ConstraintSet >; using VariableSet = boost::container::flat_set< VariableRef >; private: std::size_t _max_cycles; std::size_t _op_per_cycle = 0; std::size_t _max_op = 0; std::size_t _op_count = 0; bool _is_contradiction = false; bool _is_large_system = false; ConstraintSet _csts; TriggerTable _trigger_table; VariableSet _refined_variables; private: struct BottomFound {}; /// \brief Refine the abstract value for the given variable v void refine(VariableRef v, const IntervalT& i, NumAbstractDomain& inv) { IntervalT old_i = inv.to_interval(v); IntervalT new_i = old_i.meet(i); if (new_i.is_bottom()) { throw BottomFound(); } if (old_i != new_i) { inv.refine(v, new_i); this->_refined_variables.insert(v); ++this->_op_count; } } /// \brief Compute the residual of a linear constraint IntervalT compute_residual(const LinearConstraintT& cst, VariableRef pivot, const NumAbstractDomain& inv) { IntervalT residual(cst.constant()); for (const auto& term : cst) { if (term.first != pivot) { residual -= IntervalT(term.second) * inv.to_interval(term.first); ++this->_op_count; } } return residual; } void propagate(const LinearConstraintT& cst, NumAbstractDomain& inv) { for (const auto& term : cst) { const Number& c = term.second; VariableRef pivot = term.first; IntervalT rhs = this->compute_residual(cst, pivot, inv) / IntervalT(c); if (cst.is_equality()) { this->refine(pivot, rhs, inv); } else if (cst.is_inequality()) { if (c > 0) { this->refine(pivot, rhs.lower_half_line(), inv); } else { this->refine(pivot, rhs.upper_half_line(), inv); } } else { // cst is a disequation boost::optional< Number > k = rhs.singleton(); if (k) { IntervalT old_i = inv.to_interval(pivot); IntervalT new_i = trim_bound(old_i, BoundT(*k)); if (new_i.is_bottom()) { throw BottomFound(); } if (old_i != new_i) { inv.refine(pivot, new_i); this->_refined_variables.insert(pivot); } ++this->_op_count; } } } } void build_trigger_table() { // Build the trigger table for (LinearConstraintRef cst : this->_csts) { for (const auto& term : cst.get()) { this->_trigger_table[term.first].push_back(cst); } } } /// \brief Slove a large linear constraint system void solve_large_system(NumAbstractDomain& inv) { this->_op_count = 0; this->_refined_variables.clear(); for (const LinearConstraintT& cst : this->_csts) { this->propagate(cst, inv); } do { VariableSet vars_to_process(this->_refined_variables); this->_refined_variables.clear(); for (VariableRef var : vars_to_process) { for (const LinearConstraintT& cst : this->_trigger_table[var]) { this->propagate(cst, inv); } } } while (!this->_refined_variables.empty() && this->_op_count <= this->_max_op); } /// \brief Slove a small linear constraint system void solve_small_system(NumAbstractDomain& inv) { std::size_t cycle = 0; do { ++cycle; this->_refined_variables.clear(); for (const LinearConstraintT& cst : this->_csts) { this->propagate(cst, inv); } } while (!this->_refined_variables.empty() && cycle <= this->_max_cycles); } public: /// \brief Constructor explicit LinearIntervalSolver(std::size_t max_cycles) : _max_cycles(max_cycles) {} /// \brief Add a constraint /// /// Warning: the linear constraint should outlive the solver void add(LinearConstraintRef cst) { if (cst.get().is_contradiction()) { this->_is_contradiction = true; } else if (cst.get().is_tautology()) { return; } else { this->_csts.push_back(cst); // cost of one reduction step on the constraint in terms // of accesses to the interval collection this->_op_per_cycle += cst.get().num_terms() * cst.get().num_terms(); } } /// \brief Add a system of constraint /// /// Warning: the linear constrainst system should outlive the solver void add(LinearConstraintSystemRef csts) { for (const LinearConstraintT& cst : csts.get()) { if (cst.is_contradiction()) { this->_is_contradiction = true; return; } else if (cst.is_tautology()) { continue; } else { this->_csts.push_back(cst); // cost of one reduction step on the constraint in terms // of accesses to the interval collection this->_op_per_cycle += cst.num_terms() * cst.num_terms(); } } } /// \brief Return the number of linear constraints std::size_t size() const { return this->_csts.size(); } /// \brief Return true if the solver is empty bool empty() const { return this->_csts.empty(); } /// \brief Solve the system and refine the given invariant void run(NumAbstractDomain& inv) { if (this->_is_contradiction) { inv.set_to_bottom(); return; } if (this->empty()) { return; } this->_max_op = this->_op_per_cycle * this->_max_cycles; this->_is_large_system = this->_csts.size() > LargeSystemCstThreshold || this->_op_per_cycle > LargeSystemOpThreshold; if (this->_is_large_system) { this->build_trigger_table(); } try { if (this->_is_large_system) { this->solve_large_system(inv); } else { this->solve_small_system(inv); } } catch (BottomFound&) { inv.set_to_bottom(); } } }; // end class LinearIntervalSolver } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/octagon.hpp000066400000000000000000001556001473507761200261510ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Standard domain of octagons. * * Based on Antoine Mine's paper: The Octagon Abstract Domain, in * Higher-Order and Symbolic Computation, 19(1): 31-100 (2006) * * Author: Alexandre C. D. Wimmers * * Contributors: Jorge A. Navas * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include //#define VERBOSE namespace ikos { namespace core { namespace numeric { /// \brief Octagon abstract domain /// /// Warning: The memory of this domain is managed in a brute force /// fashion (O(n^2)) as it is intended to be used for small sets of /// variables (~10-20). /// /// XXX: The implementation has several issues (segfaults, unsoundness, etc.). /// Prefer the APRON octagon domain if necessary. template < typename Number, typename VariableRef > class Octagon final : public numeric::AbstractDomain< Number, VariableRef, Octagon< Number, VariableRef > > { public: using BoundT = Bound< Number >; using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using VariableExprT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; using IntervalDomainT = IntervalDomain< Number, VariableRef >; private: /// \brief Index of a variable in the matrix using MatrixIndex = std::size_t; // \brief Map from variable to index using VarIndexMap = boost::container::flat_map< VariableRef, MatrixIndex >; using Parent = numeric::AbstractDomain< Number, VariableRef, Octagon >; private: class Matrix { private: // Matrix represented as single vector for performance. // Using a standard vector< vector<> > results in significant // degradation of performance. private: std::vector< BoundT > _matrix; MatrixIndex _num_var = 0; // size of the matrix public: /// \brief Create an empty matrix Matrix() = default; /// \brief Copy constructor Matrix(const Matrix&) = default; /// \brief Move constructor Matrix(Matrix&&) = default; /// \brief Copy assignment operator Matrix& operator=(const Matrix&) = default; /// \brief Move assignment operator Matrix& operator=(Matrix&&) = default; /// \brief Destructor ~Matrix() = default; /// \brief Return the number of variables MatrixIndex size() const { return this->_num_var; } /// \brief Resize the matrix /// /// \param new_size number of contained variables void resize(MatrixIndex new_size) { if (this->_num_var >= new_size) { // Does not currently support downsizing. return; } this->_matrix.resize(4 * new_size * new_size, BoundT::plus_infinity()); for (MatrixIndex j = 2 * this->_num_var; j > 0; --j) { for (MatrixIndex i = 2 * this->_num_var; i > 0; --i) { std::swap(this->_matrix[2 * new_size * (j - 1) + (i - 1)], this->_matrix[2 * _num_var * (j - 1) + (i - 1)]); } } this->_num_var = new_size; } /// \brief Downsize the matrix void operator-=(MatrixIndex k) { ikos_assert_msg(k >= 1 && k <= this->_num_var, "invalid valuewrong value"); if (this->_num_var == 0) { return; } MatrixIndex new_size = this->_num_var - 1; std::vector< BoundT > new_matrix; new_matrix.resize(4 * new_size * new_size, BoundT::plus_infinity()); for (MatrixIndex j = 2 * this->_num_var; j > 0; --j) { if (j == 2 * k || j == 2 * k - 1) { continue; } for (MatrixIndex i = 2 * this->_num_var; i > 0; --i) { if (i == 2 * k || i == 2 * k - 1) { continue; } if (i > 2 * k) { if (j > 2 * k) { std::swap(new_matrix[2 * new_size * (j - 3) + (i - 3)], this->_matrix[2 * _num_var * (j - 1) + (i - 1)]); } else { // j < 2*k-1 std::swap(new_matrix[2 * new_size * (j - 1) + (i - 3)], this->_matrix[2 * _num_var * (j - 1) + (i - 1)]); } } else { // i < 2*k-1 if (j > 2 * k) { std::swap(new_matrix[2 * new_size * (j - 3) + (i - 1)], this->_matrix[2 * _num_var * (j - 1) + (i - 1)]); } else { // j < 2*k-1 std::swap(new_matrix[2 * new_size * (j - 1) + (i - 1)], this->_matrix[2 * _num_var * (j - 1) + (i - 1)]); } } } } std::swap(this->_matrix, new_matrix); this->_num_var = new_size; } /// \brief Clear the matrix void clear() { this->_num_var = 0; this->_matrix.clear(); } BoundT& operator()(MatrixIndex i, MatrixIndex j) { // Accesses the matrix as one-based and in column-major order // so as to match DBM representations. ikos_assert_msg(i >= 1 && j >= 1 && i <= 2 * this->_num_var && j <= 2 * this->_num_var, "out of bounds matrix access"); return this->_matrix[2 * this->_num_var * (j - 1) + (i - 1)]; } const BoundT& operator()(MatrixIndex i, MatrixIndex j) const { // Accesses the matrix as one-based and in column-major order // so as to match DBM representations. ikos_assert_msg(i >= 1 && j >= 1 && i <= 2 * this->_num_var && j <= 2 * this->_num_var, "out of bounds matrix access"); return this->_matrix[2 * this->_num_var * (j - 1) + (i - 1)]; } /// \brief Print the matrix, for debugging purpose void dump(std::ostream& o) const { for (MatrixIndex i = 1; i <= 2 * this->_num_var; i++) { for (MatrixIndex j = 1; j <= 2 * this->_num_var; j++) { o << "M[" << i << ", " << j << "] = " << this->operator()(i, j) << ";"; } o << "\n"; } } }; // end class Matrix private: bool _is_bottom; bool _is_normalized; Matrix _matrix; VarIndexMap _var_index_map; // IMPORTANT: Treat this as a vector of booleans. std::vector< unsigned char > _norm_vector; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top abstract value explicit Octagon(TopTag) : _is_bottom(false), _is_normalized(true) {} /// \brief Create the bottom abstract value explicit Octagon(BottomTag) : _is_bottom(true), _is_normalized(true) {} public: /// \brief Create the top abstract value static Octagon top() { return Octagon(TopTag{}); } /// \brief Create the bottom abstract value static Octagon bottom() { return Octagon(BottomTag{}); } /// \brief Copy constructor Octagon(const Octagon&) = default; /// \brief Move constructor Octagon(Octagon&&) = default; /// \brief Copy assignment operator Octagon& operator=(const Octagon&) = default; /// \brief Move assignment operator Octagon& operator=(Octagon&&) = default; /// \brief Destructor ~Octagon() override = default; private: /// \brief Helper for normalization static BoundT c(const BoundT& a, const BoundT& b, const BoundT& c, const BoundT& d, const BoundT& e) { // Separating the min()s yields 20-25% increases in performance. return min(a, min(b, min(c, min(d, e)))); } /// \brief Set whether the matrix is normalized or not void set_normalized(bool b) { this->_is_normalized = b; for (auto it = _norm_vector.begin(); it != _norm_vector.end(); ++it) { *it = b ? 1 : 0; } } /// \brief Resize the octagon void resize() { this->_matrix.resize(this->_var_index_map.size()); this->_norm_vector.resize(this->_var_index_map.size(), 0); } /// \brief Compute the strong closure algorithm /// /// TODO(marthaud): This is not thread-safe. void unsafe_normalize() const { if (this->_is_normalized) { return; } auto self = const_cast< Octagon* >(this); if (this->_is_bottom) { self->_is_normalized = true; return; } const MatrixIndex num_var = this->_matrix.size(); for (MatrixIndex k = 1; k <= num_var; ++k) { if (this->_norm_vector[k - 1]) { continue; } for (MatrixIndex i = 1; i <= 2 * num_var; ++i) { for (MatrixIndex j = 1; j <= 2 * num_var; ++j) { // to ensure the "closed" property self->_matrix(i, j) = c(this->_matrix(i, j), this->_matrix(i, 2 * k - 1) + this->_matrix(2 * k - 1, j), this->_matrix(i, 2 * k) + this->_matrix(2 * k, j), this->_matrix(i, 2 * k - 1) + this->_matrix(2 * k - 1, 2 * k) + this->_matrix(2 * k, j), this->_matrix(i, 2 * k) + this->_matrix(2 * k, 2 * k - 1) + this->_matrix(2 * k - 1, j)); } } // to ensure for all i,j: m_ij <= (m_i+i- + m_j-j+)/2 for (MatrixIndex i = 1; i <= 2 * num_var; ++i) { for (MatrixIndex j = 1; j <= 2 * num_var; ++j) { self->_matrix(i, j) = min(this->_matrix(i, j), (this->_matrix(i, i + 2 * (i % 2) - 1) + this->_matrix(j + 2 * (j % 2) - 1, j)) / BoundT(2)); } } self->_norm_vector[k - 1] = 1; } // Check for negative cycle for (MatrixIndex i = 1; i <= 2 * num_var; ++i) { if (this->_matrix(i, i) < BoundT(0)) { self->_is_bottom = true; self->_is_normalized = true; return; } self->_matrix(i, i) = BoundT(0); } self->_is_normalized = true; } public: void normalize() override { this->unsafe_normalize(); } bool is_bottom() const override { this->unsafe_normalize(); return this->_is_bottom; } bool is_top() const override { // TODO(marthaud): This is not correct. return !this->_var_index_map.size() && !this->is_bottom(); } void set_to_bottom() override { this->_is_bottom = true; this->_is_normalized = true; this->_matrix.clear(); this->_var_index_map.clear(); this->_norm_vector.clear(); } void set_to_top() override { this->_is_bottom = false; this->_is_normalized = true; this->_matrix.clear(); this->_var_index_map.clear(); this->_norm_vector.clear(); } bool leq(const Octagon& other) const override { // Require normalization of the left operand this->unsafe_normalize(); if (this->_is_bottom) { return true; } if (other._is_bottom) { return false; } // Used to construct a list of variables that appear in both octagons. VarIndexMap temp; MatrixIndex i1; MatrixIndex j1; MatrixIndex i2; MatrixIndex j2; for (auto ito = other._var_index_map.begin(); ito != other._var_index_map.end(); ++ito) { i2 = ito->second; if (this->_var_index_map.find(ito->first) == this->_var_index_map.end()) { if (!other._matrix(2 * i2 - 1, 2 * i2).is_infinite() || !other._matrix(2 * i2, 2 * i2 - 1).is_infinite()) { // Case: Variable exists and is finite in _other but // does not exist in _this. return false; } } else { temp.emplace(ito->first, 0); } } for (auto it = temp.begin(); it != temp.end(); ++it) { // Case: Variable exists in both `this` and `other` i1 = this->_var_index_map.find(it->first)->second; i2 = other._var_index_map.find(it->first)->second; if (!(this->_matrix(2 * i1 - 1, 2 * i1 - 1) <= other._matrix(2 * i2 - 1, 2 * i2 - 1)) || !(this->_matrix(2 * i1 - 1, 2 * i1) <= other._matrix(2 * i2 - 1, 2 * i2)) || !(this->_matrix(2 * i1, 2 * i1 - 1) <= other._matrix(2 * i2, 2 * i2 - 1)) || !(this->_matrix(2 * i1, 2 * i1) <= other._matrix(2 * i2, 2 * i2))) { return false; } for (auto it2 = it + 1; it2 != temp.end(); ++it2) { j1 = this->_var_index_map.find(it2->first)->second; j2 = other._var_index_map.find(it2->first)->second; if (!(this->_matrix(2 * i1 - 1, 2 * j1 - 1) <= other._matrix(2 * i2 - 1, 2 * j2 - 1)) || !(this->_matrix(2 * i1 - 1, 2 * j1) <= other._matrix(2 * i2 - 1, 2 * j2)) || !(this->_matrix(2 * i1, 2 * j1 - 1) <= other._matrix(2 * i2, 2 * j2 - 1)) || !(this->_matrix(2 * i1, 2 * j1) <= other._matrix(2 * i2, 2 * j2))) { return false; } if (!(this->_matrix(2 * j1 - 1, 2 * i1 - 1) <= other._matrix(2 * j2 - 1, 2 * i2 - 1)) || !(this->_matrix(2 * j1 - 1, 2 * i1) <= other._matrix(2 * j2 - 1, 2 * i2)) || !(this->_matrix(2 * j1, 2 * i1 - 1) <= other._matrix(2 * j2, 2 * i2 - 1)) || !(this->_matrix(2 * j1, 2 * i1) <= other._matrix(2 * j2, 2 * i2))) { return false; } } } return true; } bool equals(const Octagon& other) const override { return this->leq(other) && other.leq(*this); } private: /// \brief Apply a pointwise binary operator template < typename BinaryOperator > static Octagon pointwise_binary_op(const Octagon& o1, const Octagon& o2, const BinaryOperator& op) { auto n = Octagon::top(); // Set intersection of the two maps for (auto it = o1._var_index_map.begin(); it != o1._var_index_map.end(); ++it) { if (o2._var_index_map.find(it->first) != o2._var_index_map.end()) { n._var_index_map.emplace(it->first, n._var_index_map.size() + 1); } } if (n._var_index_map.empty()) { return top(); } n.resize(); MatrixIndex i1 = 0; MatrixIndex i2 = 0; MatrixIndex i3 = 0; MatrixIndex j1 = 0; MatrixIndex j2 = 0; MatrixIndex j3 = 0; for (auto it = n._var_index_map.begin(); it != n._var_index_map.end(); ++it) { // Finds the union of each 2x2 identity matrix. i1 = o1._var_index_map.find(it->first)->second; i2 = o2._var_index_map.find(it->first)->second; i3 = it->second; n._matrix(2 * i3 - 1, 2 * i3 - 1) = op(o1._matrix(2 * i1 - 1, 2 * i1 - 1), o2._matrix(2 * i2 - 1, 2 * i2 - 1)); n._matrix(2 * i3 - 1, 2 * i3) = op(o1._matrix(2 * i1 - 1, 2 * i1), o2._matrix(2 * i2 - 1, 2 * i2)); n._matrix(2 * i3, 2 * i3 - 1) = op(o1._matrix(2 * i1, 2 * i1 - 1), o2._matrix(2 * i2, 2 * i2 - 1)); n._matrix(2 * i3, 2 * i3) = op(o1._matrix(2 * i1, 2 * i1), o2._matrix(2 * i2, 2 * i2)); for (auto it2 = it + 1; it2 != n._var_index_map.end(); ++it2) { // Finds the union of each pair of 2x2 relational matrices. j1 = o1._var_index_map.find(it2->first)->second; j2 = o2._var_index_map.find(it2->first)->second; j3 = it2->second; n._matrix(2 * i3 - 1, 2 * j3 - 1) = op(o1._matrix(2 * i1 - 1, 2 * j1 - 1), o2._matrix(2 * i2 - 1, 2 * j2 - 1)); n._matrix(2 * i3 - 1, 2 * j3) = op(o1._matrix(2 * i1 - 1, 2 * j1), o2._matrix(2 * i2 - 1, 2 * j2)); n._matrix(2 * i3, 2 * j3 - 1) = op(o1._matrix(2 * i1, 2 * j1 - 1), o2._matrix(2 * i2, 2 * j2 - 1)); n._matrix(2 * i3, 2 * j3) = op(o1._matrix(2 * i1, 2 * j1), o2._matrix(2 * i2, 2 * j2)); n._matrix(2 * j3 - 1, 2 * i3 - 1) = op(o1._matrix(2 * j1 - 1, 2 * i1 - 1), o2._matrix(2 * j2 - 1, 2 * i2 - 1)); n._matrix(2 * j3 - 1, 2 * i3) = op(o1._matrix(2 * j1 - 1, 2 * i1), o2._matrix(2 * j2 - 1, 2 * i2)); n._matrix(2 * j3, 2 * i3 - 1) = op(o1._matrix(2 * j1, 2 * i1 - 1), o2._matrix(2 * j2, 2 * i2 - 1)); n._matrix(2 * j3, 2 * i3) = op(o1._matrix(2 * j1, 2 * i1), o2._matrix(2 * j2, 2 * i2)); } } return n; } struct JoinOperator { BoundT operator()(const BoundT& x, const BoundT& y) const { return max(x, y); } }; struct WideningOperator { BoundT operator()(const BoundT& x, const BoundT& y) const { if (y <= x) { return x; } else { return BoundT::plus_infinity(); } } }; struct WideningThresholdOperator { BoundT threshold; explicit WideningThresholdOperator(const Number& threshold_) : threshold(threshold_) {} BoundT operator()(const BoundT& x, const BoundT& y) const { if (y <= x) { return x; } else if (threshold >= y) { return threshold; } else { return BoundT::plus_infinity(); } } }; public: Octagon join(const Octagon& other) const override { // Requires normalization this->unsafe_normalize(); other.unsafe_normalize(); if (this->_is_bottom) { return other; } else if (other._is_bottom) { return *this; } else { Octagon oct = this->pointwise_binary_op(*this, other, JoinOperator{}); oct.set_normalized(true); // Returned matrix is normalized return oct; } } void join_with(const Octagon& other) override { this->operator=(this->join(other)); } Octagon widening(const Octagon& other) const override { // The left operand of the widenning cannot be closed, otherwise // termination is not ensured. However, if the right operand is // close precision may be improved. other.unsafe_normalize(); if (this->_is_bottom) { return other; } else if (other._is_bottom) { return *this; } else { Octagon oct = this->pointwise_binary_op(*this, other, WideningOperator{}); oct.set_normalized(false); // Returned matrix is not normalized return oct; } } void widen_with(const Octagon& other) override { this->operator=(this->widening(other)); } Octagon widening_threshold(const Octagon& other, const Number& threshold) const override { // The left operand of the widenning cannot be closed, otherwise // termination is not ensured. However, if the right operand is // close precision may be improved. other.unsafe_normalize(); if (this->_is_bottom) { return other; } else if (other._is_bottom) { return *this; } else { Octagon oct = this->pointwise_binary_op(*this, other, WideningThresholdOperator{threshold}); oct.set_normalized(false); // Returned matrix is not normalized return oct; } } void widen_threshold_with(const Octagon& other, const Number& threshold) override { this->operator=(this->widening_threshold(other, threshold)); } Octagon meet(const Octagon& other) const override { // Does not require normalization of any of the two operands if (this->_is_bottom || other._is_bottom) { return bottom(); } else { auto n = Octagon::top(); // Set union of the two maps for (auto it = this->_var_index_map.begin(); it != this->_var_index_map.end(); ++it) { n._var_index_map.emplace(it->first, n._var_index_map.size() + 1); } for (auto it = other._var_index_map.begin(); it != other._var_index_map.end(); ++it) { n._var_index_map.emplace(it->first, n._var_index_map.size() + 1); } if (n._var_index_map.empty()) { return top(); } n.resize(); n.set_normalized(false); typename VarIndexMap::const_iterator testi1; typename VarIndexMap::const_iterator testi2; typename VarIndexMap::const_iterator testj1; typename VarIndexMap::const_iterator testj2; MatrixIndex i1 = 0; MatrixIndex i2 = 0; MatrixIndex i3 = 0; MatrixIndex j1 = 0; MatrixIndex j2 = 0; MatrixIndex j3 = 0; for (auto it = n._var_index_map.begin(); it != n._var_index_map.end(); ++it) { // Finds the intersection on each 2x2 identity matrix. testi1 = this->_var_index_map.find(it->first); testi2 = other._var_index_map.find(it->first); i3 = it->second; if (testi1 == this->_var_index_map.end()) { i1 = 0; } else { i1 = testi1->second; } if (testi2 == other._var_index_map.end()) { i2 = 0; } else { i2 = testi2->second; } n._matrix(2 * i3 - 1, 2 * i3 - 1) = (!i1) ? other._matrix(2 * i2 - 1, 2 * i2 - 1) : ((!i2) ? this->_matrix(2 * i1 - 1, 2 * i1 - 1) : min(this->_matrix(2 * i1 - 1, 2 * i1 - 1), other._matrix(2 * i2 - 1, 2 * i2 - 1))); n._matrix(2 * i3 - 1, 2 * i3) = (!i1) ? other._matrix(2 * i2 - 1, 2 * i2) : ((!i2) ? this->_matrix(2 * i1 - 1, 2 * i1) : min(this->_matrix(2 * i1 - 1, 2 * i1), other._matrix(2 * i2 - 1, 2 * i2))); n._matrix(2 * i3, 2 * i3 - 1) = (!i1) ? other._matrix(2 * i2, 2 * i2 - 1) : ((!i2) ? this->_matrix(2 * i1, 2 * i1 - 1) : min(this->_matrix(2 * i1, 2 * i1 - 1), other._matrix(2 * i2, 2 * i2 - 1))); n._matrix(2 * i3, 2 * i3) = (!i1) ? other._matrix(2 * i2, 2 * i2) : ((!i2) ? this->_matrix(2 * i1, 2 * i1) : min(this->_matrix(2 * i1, 2 * i1), other._matrix(2 * i2, 2 * i2))); for (auto it2 = it + 1; it2 != n._var_index_map.end(); ++it2) { // Finds the intersection of each pair of 2x2 relational matrices. testj1 = this->_var_index_map.find(it2->first); testj2 = other._var_index_map.find(it2->first); j3 = it2->second; if (testj1 == this->_var_index_map.end()) { j1 = 0; } else { j1 = testj1->second; } if (testj2 == other._var_index_map.end()) { j2 = 0; } else { j2 = testj2->second; } if (((i1 && !j1) || (!i1 && j1)) && ((i2 && !j2) || (!i2 && j2))) { continue; } if (i1 > j1) { std::swap(i1, j1); } if (i2 > j2) { std::swap(i2, j2); } n._matrix(2 * i3 - 1, 2 * j3 - 1) = (!i1 || !j1) ? other._matrix(2 * i2 - 1, 2 * j2 - 1) : ((!i2 || !j2) ? this->_matrix(2 * i1 - 1, 2 * j1 - 1) : min(this->_matrix(2 * i1 - 1, 2 * j1 - 1), other._matrix(2 * i2 - 1, 2 * j2 - 1))); n._matrix(2 * i3 - 1, 2 * j3) = (!i1 || !j1) ? other._matrix(2 * i2 - 1, 2 * j2) : ((!i2 || !j2) ? this->_matrix(2 * i1 - 1, 2 * j1) : min(this->_matrix(2 * i1 - 1, 2 * j1), other._matrix(2 * i2 - 1, 2 * j2))); n._matrix(2 * i3, 2 * j3 - 1) = (!i1 || !j1) ? other._matrix(2 * i2, 2 * j2 - 1) : ((!i2 || !j2) ? this->_matrix(2 * i1, 2 * j1 - 1) : min(this->_matrix(2 * i1, 2 * j1 - 1), other._matrix(2 * i2, 2 * j2 - 1))); n._matrix(2 * i3, 2 * j3) = (!i1 || !j1) ? other._matrix(2 * i2, 2 * j2) : ((!i2 || !j2) ? this->_matrix(2 * i1, 2 * j1) : min(this->_matrix(2 * i1, 2 * j1), other._matrix(2 * i2, 2 * j2))); n._matrix(2 * j3 - 1, 2 * i3 - 1) = (!i1 || !j1) ? other._matrix(2 * j2 - 1, 2 * i2 - 1) : ((!i2 || !j2) ? this->_matrix(2 * j1 - 1, 2 * i1 - 1) : min(this->_matrix(2 * j1 - 1, 2 * i1 - 1), other._matrix(2 * j2 - 1, 2 * i2 - 1))); n._matrix(2 * j3 - 1, 2 * i3) = (!i1 || !j1) ? other._matrix(2 * j2 - 1, 2 * i2) : ((!i2 || !j2) ? this->_matrix(2 * j1 - 1, 2 * i1) : min(this->_matrix(2 * j1 - 1, 2 * i1), other._matrix(2 * j2 - 1, 2 * i2))); n._matrix(2 * j3, 2 * i3 - 1) = (!i1 || !j1) ? other._matrix(2 * j2, 2 * i2 - 1) : ((!i2 || !j2) ? this->_matrix(2 * j1, 2 * i1 - 1) : min(this->_matrix(2 * j1, 2 * i1 - 1), other._matrix(2 * j2, 2 * i2 - 1))); n._matrix(2 * j3, 2 * i3) = (!i1 || !j1) ? other._matrix(2 * j2, 2 * i2) : ((!i2 || !j2) ? this->_matrix(2 * j1, 2 * i1) : min(this->_matrix(2 * j1, 2 * i1), other._matrix(2 * j2, 2 * i2))); } } return n; } } void meet_with(const Octagon& other) override { this->operator=(this->meet(other)); } Octagon narrowing(const Octagon& other) const override { // Does not require normalization of any of the two operands if (this->_is_bottom || other._is_bottom) { return bottom(); } else { auto n = Octagon::top(); // Set union of the two maps for (auto it = this->_var_index_map.begin(); it != this->_var_index_map.end(); ++it) { n._var_index_map.emplace(it->first, n._var_index_map.size() + 1); } for (auto it = other._var_index_map.begin(); it != other._var_index_map.end(); ++it) { n._var_index_map.emplace(it->first, n._var_index_map.size() + 1); } if (n._var_index_map.empty()) { return top(); } n.resize(); n.set_normalized(false); typename VarIndexMap::const_iterator testi1; typename VarIndexMap::const_iterator testi2; typename VarIndexMap::const_iterator testj1; typename VarIndexMap::const_iterator testj2; MatrixIndex i1 = 0; MatrixIndex i2 = 0; MatrixIndex i3 = 0; MatrixIndex j1 = 0; MatrixIndex j2 = 0; MatrixIndex j3 = 0; for (auto it = n._var_index_map.begin(); it != n._var_index_map.end(); ++it) { // Finds the narrowing on each 2x2 identity matrix. testi1 = this->_var_index_map.find(it->first); testi2 = other._var_index_map.find(it->first); i3 = it->second; if (testi1 == this->_var_index_map.end()) { i1 = 0; } else { i1 = testi1->second; } if (testi2 == other._var_index_map.end()) { i2 = 0; } else { i2 = testi2->second; } n._matrix(2 * i3 - 1, 2 * i3 - 1) = (!i2) ? this->_matrix(2 * i1 - 1, 2 * i1 - 1) : ((!i1 || this->_matrix(2 * i1 - 1, 2 * i1 - 1).is_infinite()) ? other._matrix(2 * i2 - 1, 2 * i2 - 1) : this->_matrix(2 * i1 - 1, 2 * i1 - 1)); n._matrix(2 * i3 - 1, 2 * i3) = (!i2) ? this->_matrix(2 * i1 - 1, 2 * i1) : ((!i1 || this->_matrix(2 * i1 - 1, 2 * i1).is_infinite()) ? other._matrix(2 * i2 - 1, 2 * i2) : this->_matrix(2 * i1 - 1, 2 * i1)); n._matrix(2 * i3, 2 * i3 - 1) = (!i2) ? this->_matrix(2 * i1, 2 * i1 - 1) : ((!i1 || this->_matrix(2 * i1, 2 * i1 - 1).is_infinite()) ? other._matrix(2 * i2, 2 * i2 - 1) : this->_matrix(2 * i1, 2 * i1 - 1)); n._matrix(2 * i3, 2 * i3) = (!i2) ? this->_matrix(2 * i1, 2 * i1) : ((!i1 || this->_matrix(2 * i1, 2 * i1).is_infinite()) ? other._matrix(2 * i2, 2 * i2) : this->_matrix(2 * i1, 2 * i1)); for (auto it2 = it + 1; it2 != n._var_index_map.end(); ++it2) { // Finds the narrowing of each pair of 2x2 relational matrices. testj1 = this->_var_index_map.find(it2->first); testj2 = other._var_index_map.find(it2->first); j3 = it2->second; if (testj1 == this->_var_index_map.end()) { j1 = 0; } else { j1 = testj1->second; } if (testj2 == other._var_index_map.end()) { j2 = 0; } else { j2 = testj2->second; } if (((i1 && !j1) || (!i1 && j1)) && ((i2 && !j2) || (!i2 && j2))) { continue; } if (i1 > j1) { std::swap(i1, j1); } if (i2 > j2) { std::swap(i2, j2); } n._matrix(2 * i3 - 1, 2 * j3 - 1) = (!i2 || !j2) ? this->_matrix(2 * i1 - 1, 2 * j1 - 1) : ((!i1 || !j1 || this->_matrix(2 * i1 - 1, 2 * j1 - 1).is_infinite()) ? other._matrix(2 * i2 - 1, 2 * j2 - 1) : this->_matrix(2 * i1 - 1, 2 * j1 - 1)); n._matrix(2 * i3 - 1, 2 * j3) = (!i2 || !j2) ? this->_matrix(2 * i1 - 1, 2 * j1) : ((!i1 || !j1 || this->_matrix(2 * i1 - 1, 2 * j1).is_infinite()) ? other._matrix(2 * i2 - 1, 2 * j2) : this->_matrix(2 * i1 - 1, 2 * j1)); n._matrix(2 * i3, 2 * j3 - 1) = (!i2 || !j2) ? this->_matrix(2 * i1, 2 * j1 - 1) : ((!i1 || !j1 || this->_matrix(2 * i1, 2 * j1 - 1).is_infinite()) ? other._matrix(2 * i2, 2 * j2 - 1) : this->_matrix(2 * i1, 2 * j1 - 1)); n._matrix(2 * i3, 2 * j3) = (!i2 || !j2) ? this->_matrix(2 * i1, 2 * j1) : ((!i1 || !j1 || this->_matrix(2 * i1, 2 * j1).is_infinite()) ? other._matrix(2 * i2, 2 * j2) : this->_matrix(2 * i1, 2 * j1)); n._matrix(2 * j3 - 1, 2 * i3 - 1) = (!i2 || !j2) ? this->_matrix(2 * j1 - 1, 2 * i1 - 1) : ((!i1 || !j1 || this->_matrix(2 * j1 - 1, 2 * i1 - 1).is_infinite()) ? other._matrix(2 * j2 - 1, 2 * i2 - 1) : this->_matrix(2 * j1 - 1, 2 * i1 - 1)); n._matrix(2 * j3 - 1, 2 * i3) = (!i2 || !j2) ? this->_matrix(2 * j1 - 1, 2 * i1) : ((!i1 || !j1 || this->_matrix(2 * j1 - 1, 2 * i1).is_infinite()) ? other._matrix(2 * j2 - 1, 2 * i2) : this->_matrix(2 * j1 - 1, 2 * i1)); n._matrix(2 * j3, 2 * i3 - 1) = (!i2 || !j2) ? this->_matrix(2 * j1, 2 * i1 - 1) : ((!i1 || !j1 || this->_matrix(2 * j1, 2 * i1 - 1).is_infinite()) ? other._matrix(2 * j2, 2 * i2 - 1) : this->_matrix(2 * j1, 2 * i1 - 1)); n._matrix(2 * j3, 2 * i3) = (!i2 || !j2) ? this->_matrix(2 * j1, 2 * i1) : ((!i1 || !j1 || this->_matrix(2 * j1, 2 * i1).is_infinite()) ? other._matrix(2 * j2, 2 * i2) : this->_matrix(2 * j1, 2 * i1)); } } return n; } } void narrow_with(const Octagon& other) override { this->operator=(this->narrowing(other)); } Octagon narrowing_threshold(const Octagon& other, const Number& /*threshold*/) const override { // TODO(marthaud): Implement return this->narrowing(other); } void narrow_threshold_with(const Octagon& other, const Number& /*threshold*/) override { // TODO(marthaud): Implement this->narrow_with(other); } private: /// \brief Abstract the variable boost::optional< typename VarIndexMap::iterator > abstract(VariableRef v) { // Requires normalization. auto it = this->_var_index_map.find(v); if (it != this->_var_index_map.end()) { this->unsafe_normalize(); MatrixIndex n = it->second; MatrixIndex odd = 2 * n - 1; MatrixIndex even = 2 * n; MatrixIndex size = 2 * this->_matrix.size(); for (MatrixIndex idx = 1; idx <= size; ++idx) { this->_matrix(idx, odd) = BoundT::plus_infinity(); this->_matrix(idx, even) = BoundT::plus_infinity(); this->_matrix(odd, idx) = BoundT::plus_infinity(); this->_matrix(even, idx) = BoundT::plus_infinity(); } this->_matrix(odd, odd) = BoundT(0); this->_matrix(even, even) = BoundT(0); return boost::optional< typename VarIndexMap::iterator >(it); } // Maintains normalization. return boost::none; } void apply_constraint(MatrixIndex var, bool is_positive, BoundT constraint) { // Application of single variable octagonal constraints. constraint *= BoundT(2); if (is_positive) { // 2*v1 <= constraint this->_matrix(2 * var, 2 * var - 1) = min(this->_matrix(2 * var, 2 * var - 1), constraint); } else { // 2*v1 >= constraint this->_matrix(2 * var - 1, 2 * var) = min(this->_matrix(2 * var - 1, 2 * var), constraint); } if (this->_matrix(2 * var, 2 * var - 1) < -this->_matrix(2 * var - 1, 2 * var)) { this->set_to_bottom(); } } void apply_constraint(MatrixIndex i, MatrixIndex j, bool is1_positive, bool is2_positive, const BoundT& constraint) { // Application of double variable octagonal constraints. if (is1_positive && is2_positive) { // v1 + v2 <= constraint this->_matrix(2 * j, 2 * i - 1) = min(this->_matrix(2 * j, 2 * i - 1), constraint); this->_matrix(2 * i, 2 * j - 1) = min(this->_matrix(2 * i, 2 * j - 1), constraint); } else if (is1_positive && !is2_positive) { // v1 - v2 <= constraint this->_matrix(2 * j - 1, 2 * i - 1) = min(this->_matrix(2 * j - 1, 2 * i - 1), constraint); this->_matrix(2 * i, 2 * j) = min(this->_matrix(2 * i, 2 * j), constraint); } else if (!is1_positive && is2_positive) { // v2 - v1 <= constraint this->_matrix(2 * i - 1, 2 * j - 1) = min(this->_matrix(2 * i - 1, 2 * j - 1), constraint); this->_matrix(2 * j, 2 * i) = min(this->_matrix(2 * j, 2 * i), constraint); } else if (!is1_positive && !is2_positive) { // -v1 - v2 <= constraint this->_matrix(2 * j - 1, 2 * i) = min(this->_matrix(2 * j - 1, 2 * i), constraint); this->_matrix(2 * i - 1, 2 * j) = min(this->_matrix(2 * i - 1, 2 * j), constraint); } if (this->_matrix(2 * j, 2 * i - 1) < -this->_matrix(2 * j - 1, 2 * i) || this->_matrix(2 * j - 1, 2 * i - 1) < -this->_matrix(2 * i - 1, 2 * j - 1)) { this->set_to_bottom(); } } public: void assign(VariableRef x, int n) override { this->assign(x, LinearExpressionT(n)); } void assign(VariableRef x, const Number& n) override { this->assign(x, LinearExpressionT(n)); } void assign(VariableRef x, VariableRef y) override { this->assign(x, LinearExpressionT(y)); } void assign(VariableRef x, const LinearExpressionT& e) override { if (this->_is_bottom) { return; } boost::optional< VariableRef > v = e.variable(); if (v && *v == x) { return; } // add x in the matrix if not found auto it = this->_var_index_map.find(x); MatrixIndex i; if (it == this->_var_index_map.end()) { i = this->_var_index_map.emplace(x, this->_var_index_map.size() + 1) .first->second; this->resize(); } else { i = it->second; } this->abstract(x); // call unsafe_normalize() if (e.is_constant()) { this->apply_constraint(i, true, BoundT(e.constant())); // adding x <= c this->apply_constraint(i, false, BoundT(-e.constant())); // adding -x <= -c } else if (v) { VariableRef y = *v; auto itz = this->_var_index_map.find(y); if (itz == this->_var_index_map.end()) { return; // x has been already abstracted } MatrixIndex j = itz->second; this->apply_constraint(i, j, true, false, BoundT(0)); this->apply_constraint(i, j, false, true, BoundT(0)); } else { // Projection using intervals, requires normalization this->unsafe_normalize(); if (this->_is_bottom) { return; } this->set(x, this->to_interval(e)); } this->set_normalized(false); } private: void add_var(VariableRef x, MatrixIndex i, MatrixIndex j, const BoundT& lb, const BoundT& ub, bool op_eq) { if (lb.is_minus_infinity() && ub.is_plus_infinity()) { this->abstract(x); return; } if (op_eq) { for (MatrixIndex j_idx = 1; j_idx <= 2 * this->_matrix.size(); ++j_idx) { if (j_idx != 2 * j && j_idx != 2 * j - 1) { this->_matrix(2 * j - 1, j_idx) -= lb; this->_matrix(2 * j, j_idx) += ub; } } for (MatrixIndex i_idx = 1; i_idx <= 2 * _matrix.size(); ++i_idx) { if (i_idx != 2 * j && i_idx != 2 * j - 1) { this->_matrix(i_idx, 2 * j) -= lb; this->_matrix(i_idx, 2 * j - 1) += ub; } } this->_matrix(2 * j - 1, 2 * j) -= BoundT(2) * lb; this->_matrix(2 * j, 2 * j - 1) += BoundT(2) * ub; } else { this->abstract(x); this->_matrix(2 * j - 1, 2 * i - 1) = -lb; this->_matrix(2 * i, 2 * j) = -lb; this->_matrix(2 * i - 1, 2 * j - 1) = ub; this->_matrix(2 * j, 2 * i) = ub; } } void subtract_var(VariableRef x, MatrixIndex i, MatrixIndex j, const BoundT& lb, const BoundT& ub, bool op_eq) { this->add_var(x, i, j, -ub, -lb, op_eq); } void multiply_var(VariableRef x, MatrixIndex i, MatrixIndex j, const BoundT& lb, const BoundT& ub, bool op_eq) { if (op_eq) { BoundT t1 = this->_matrix(2 * j - 1, 2 * j); BoundT t2 = this->_matrix(2 * j, 2 * j - 1); this->abstract(x); BoundT ll = (t1 / BoundT(-2)) * lb; BoundT lu = (t1 / BoundT(-2)) * ub; BoundT ul = (t2 / BoundT(2)) * lb; BoundT uu = (t2 / BoundT(2)) * ub; this->_matrix(2 * j - 1, 2 * j) = min(ll, lu, ul, uu) * BoundT(-2); this->_matrix(2 * j, 2 * j - 1) = max(ll, lu, ul, uu) * BoundT(2); } else { BoundT t1 = -this->_matrix(2 * i - 1, 2 * i); BoundT t2 = this->_matrix(2 * i, 2 * i - 1); this->abstract(x); BoundT ll = (t1 / BoundT(-2)) * lb; BoundT lu = (t1 / BoundT(-2)) * ub; BoundT ul = (t2 / BoundT(2)) * lb; BoundT uu = (t2 / BoundT(2)) * ub; this->_matrix(2 * j - 1, 2 * j) = min(ll, lu, ul, uu) * BoundT(-2); this->_matrix(2 * j, 2 * j - 1) = max(ll, lu, ul, uu) * BoundT(2); } } void divide_var(VariableRef x, MatrixIndex i, MatrixIndex j, const BoundT& _lb, const BoundT& _ub, bool op_eq) { IntervalT trim_intv = trim_bound(IntervalT(_lb, _ub), BoundT(0)); if (trim_intv.is_bottom()) { // definite division by zero this->set_to_bottom(); return; } IntervalT zero(Number(0)); if (zero.leq(trim_intv)) { this->abstract(x); return; } const BoundT& lb = trim_intv.lb(); const BoundT& ub = trim_intv.ub(); if (op_eq) { BoundT t1 = this->_matrix(2 * j - 1, 2 * j); BoundT t2 = this->_matrix(2 * j, 2 * j - 1); this->abstract(x); BoundT ll = (t1 / BoundT(-2)) / lb; BoundT lu = (t1 / BoundT(-2)) / ub; BoundT ul = (t2 / BoundT(2)) / lb; BoundT uu = (t2 / BoundT(2)) / ub; this->_matrix(2 * j - 1, 2 * j) = min(ll, lu, ul, uu) * BoundT(-2); this->_matrix(2 * j, 2 * j - 1) = max(ll, lu, ul, uu) * BoundT(2); } else { BoundT t1 = -this->_matrix(2 * i - 1, 2 * i); BoundT t2 = this->_matrix(2 * i, 2 * i - 1); this->abstract(x); BoundT ll = (t1 / BoundT(-2)) / lb; BoundT lu = (t1 / BoundT(-2)) / ub; BoundT ul = (t2 / BoundT(2)) / lb; BoundT uu = (t2 / BoundT(2)) / ub; this->_matrix(2 * j - 1, 2 * j) = min(ll, lu, ul, uu) * BoundT(-2); this->_matrix(2 * j, 2 * j - 1) = max(ll, lu, ul, uu) * BoundT(2); } } /// \brief x = y op [lb, ub] void apply(BinaryOperator op, VariableRef x, VariableRef y, const BoundT& lb, const BoundT& ub) { // Requires normalization. // add x in the DBM if not found if (this->_var_index_map.find(x) == this->_var_index_map.end()) { this->_var_index_map.emplace(x, this->_var_index_map.size() + 1); this->resize(); } if (this->_var_index_map.find(y) == this->_var_index_map.end()) { this->abstract(x); return; } MatrixIndex i = this->_var_index_map.find(x)->second; MatrixIndex j = this->_var_index_map.find(y)->second; this->unsafe_normalize(); switch (op) { case BinaryOperator::Add: { this->add_var(x, i, j, lb, ub, i == j); } break; case BinaryOperator::Sub: { this->subtract_var(x, i, j, lb, ub, i == j); } break; case BinaryOperator::Mul: { this->multiply_var(x, i, j, lb, ub, i == j); } break; case BinaryOperator::Div: { this->divide_var(x, i, j, lb, ub, i == j); } break; case BinaryOperator::Mod: case BinaryOperator::Rem: case BinaryOperator::Shl: case BinaryOperator::Shr: case BinaryOperator::And: case BinaryOperator::Or: case BinaryOperator::Xor: { this->set(x, apply_bin_operator(op, this->to_interval(y), IntervalT(lb, ub))); } break; default: { ikos_unreachable("invalid operation"); } } this->_norm_vector[i - 1] = 0; // Result is not normalized. } public: void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { // Requires normalization. typename VarIndexMap::iterator itz = this->_var_index_map.find(z); if (itz == this->_var_index_map.end()) { this->abstract(x); return; } MatrixIndex n = itz->second; if (x != y) { this->assign(x, y); this->apply(op, x, x, this->_matrix(2 * n - 1, 2 * n) / BoundT(-2), this->_matrix(2 * n, 2 * n - 1) / BoundT(2)); } else { this->apply(op, x, y, this->_matrix(2 * n - 1, 2 * n) / BoundT(-2), this->_matrix(2 * n, 2 * n - 1) / BoundT(2)); } // Sets state to not normalized. } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { // Requires normalization. if (x != y) { this->assign(x, y); this->apply(op, x, x, BoundT(z), BoundT(z)); } else { this->apply(op, x, y, BoundT(z), BoundT(z)); } // Sets state to not normalized. } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { // Requires normalization. if (x != z) { this->assign(x, y); this->apply(op, x, x, z); } else { this->set(x, apply_bin_operator(op, IntervalT(y), this->to_interval(z))); } // Sets state to not normalized. } private: /// \brief Check satisfiability of cst using intervals /// /// Only to be used if cst is too hard for octagons bool check_sat(const LinearConstraintT& cst) { auto inv = IntervalDomainT::top(); this->unsafe_normalize(); for (const auto& term : cst) { inv.set(term.first, this->to_interval(term.first)); } inv.add(cst); return !inv.is_bottom(); } public: void add(const LinearConstraintT& cst) override { // Does not require normalization. if (this->_is_bottom) { return; } bool v1 = false; bool v2 = false; bool is1_positive = false; bool is2_positive = false; MatrixIndex i = 0; MatrixIndex j = 0; for (const auto& term : cst) { if (!v1) { // Calculates and loads information for the first variable. if (term.second == -1) { is1_positive = false; } else if (term.second == 1) { is1_positive = true; } else { ikos_unreachable( "expr contains unexpected coefficient (accepted values are -1, " "0, and 1)."); } i = this->_var_index_map.emplace(term.first, _var_index_map.size() + 1) .first->second; v1 = true; } else if (!v2) { // Calculates and loads information for the second variable, // if it exists. if (term.second == -1) { is2_positive = false; } else if (term.second == 1) { is2_positive = true; } else { ikos_unreachable( "expr contains unexpected coefficient (accepted values are -1, " "0, and 1)."); } j = this->_var_index_map.emplace(term.first, _var_index_map.size() + 1) .first->second; v2 = true; } else { ikos_unreachable("constraint is not an octagon constraint"); } } if (!v1) { if (cst.is_contradiction()) { this->set_to_bottom(); } return; } this->resize(); BoundT constant(cst.constant()); BoundT neg_constant(-cst.constant()); if (cst.is_inequality()) { // Applies inequality constraints in the form of // octagonal constraints. if (v1 && !v2) { this->apply_constraint(i, is1_positive, constant); } else /*if(v1 && v2)*/ { this->apply_constraint(i, j, is1_positive, is2_positive, constant); } } else if (cst.is_equality()) { // Applies equality constraints as two // octagonal constraints. if (v1 && !v2) { this->apply_constraint(i, is1_positive, constant); this->apply_constraint(i, !is1_positive, neg_constant); } else /*if(v1 && v2)*/ { this->apply_constraint(i, j, is1_positive, is2_positive, constant); this->apply_constraint(i, j, !is1_positive, !is2_positive, neg_constant); } } else if (cst.is_disequation()) { // we use intervals to reason about disequations if (!this->check_sat(cst)) { this->set_to_bottom(); return; } } this->_is_normalized = false; } void add(const LinearConstraintSystemT& csts) override { // Does not require normalization. for (const LinearConstraintT& cst : csts) { this->add(cst); } } // Sets state to not normalized. void set(VariableRef x, const IntervalT& value) override { if (this->_is_bottom) { return; } if (value.is_bottom()) { this->set_to_bottom(); return; } // add x in the matrix if not found auto it = this->_var_index_map.find(x); MatrixIndex idx; if (it == this->_var_index_map.end()) { idx = this->_var_index_map.emplace(x, this->_var_index_map.size() + 1) .first->second; this->resize(); } else { idx = it->second; } this->abstract(x); // normalize this->apply_constraint(idx, true, value.ub()); // x <= ub this->apply_constraint(idx, false, -value.lb()); // -x <= -lb } void set(VariableRef x, const CongruenceT& value) override { if (this->_is_bottom) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { boost::optional< Number > n = value.singleton(); if (n) { this->assign(x, *n); } else { this->forget(x); } } } void set(VariableRef x, const IntervalCongruenceT& value) override { this->set(x, value.interval()); } void refine(VariableRef /*x*/, const IntervalT& /*value*/) override { // TODO(marthaud) } void refine(VariableRef /*x*/, const CongruenceT& /*value*/) override { // TODO(marthaud) } void refine(VariableRef /*x*/, const IntervalCongruenceT& /*value*/) override { // TODO(marthaud) } void forget(VariableRef x) override { if (boost::optional< typename VarIndexMap::iterator > it = this->abstract(x)) { MatrixIndex n = (*it)->second; this->_matrix -= n; this->_var_index_map.erase(*it); // update the values in _var_index_map for (auto itz = this->_var_index_map.begin(); itz != this->_var_index_map.end(); ++itz) { if (itz->second > n) { this->_var_index_map[itz->first]--; } } this->_norm_vector.resize(this->_var_index_map.size(), 0); this->_is_normalized = false; } } IntervalT to_interval(VariableRef x) const override { // projection requires normalization. auto it = this->_var_index_map.find(x); if (it == this->_var_index_map.end()) { return IntervalT::top(); } else { MatrixIndex idx = it->second; return IntervalT(this->_matrix(2 * idx - 1, 2 * idx) / BoundT(-2), this->_matrix(2 * idx, 2 * idx - 1) / BoundT(2)); } } IntervalT to_interval(const LinearExpressionT& e) const override { return Parent::to_interval(e); } CongruenceT to_congruence(VariableRef) const override { return CongruenceT::top(); } CongruenceT to_congruence(const LinearExpressionT& /*e*/) const override { return CongruenceT::top(); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return IntervalCongruenceT(this->to_interval(x)); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return Parent::to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { this->unsafe_normalize(); if (this->is_bottom()) { return LinearConstraintSystemT{LinearConstraintT::contradiction()}; } LinearConstraintSystemT csts; BoundT lb(0); BoundT rb(0); MatrixIndex idx1 = 0; MatrixIndex idx2 = 0; for (auto it = this->_var_index_map.begin(); it != this->_var_index_map.end(); ++it) { idx1 = it->second; lb = this->_matrix(2 * idx1 - 1, 2 * idx1) / BoundT(-2); rb = this->_matrix(2 * idx1, 2 * idx1 - 1) / BoundT(2); // lb <= v <= rb csts.add(within_interval(it->first, IntervalT(lb, rb))); for (auto it2 = it + 1; it2 != this->_var_index_map.end(); ++it2) { idx2 = it2->second; // v1 - v2 lb = -this->_matrix(2 * idx2, 2 * idx1); rb = this->_matrix(2 * idx2 - 1, 2 * idx1 - 1); csts.add(within_interval(VariableExprT(it->first) - VariableExprT(it2->first), IntervalT(lb, rb))); // v1 + v2 lb = -this->_matrix(2 * idx2 - 1, 2 * idx1); rb = this->_matrix(2 * idx2, 2 * idx1 - 1); csts.add(within_interval(VariableExprT(it->first) + VariableExprT(it2->first), IntervalT(lb, rb))); } } return csts; } void dump(std::ostream& o) const override { #ifdef VERBOSE /// For debugging purposes /// print internal datastructures o << "DBM:\n{"; for (auto it = this->_var_index_map.begin(); it != this->_var_index_map.end(); ++it) { MatrixIndex i_plus = (2 * it->second); MatrixIndex i_minus = (2 * it->second) - 1; o << it->first << "-" << " -> " << i_minus << ";"; o << it->first << "+" << " -> " << i_plus << ";"; } o << "}\n"; this->_matrix.dump(o); o << "\n"; #else this->to_linear_constraint_system().dump(o); #endif } static std::string name() { return "octagon"; } }; // end class Octagon } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/operator.hpp000066400000000000000000000146641473507761200263560ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Operators for numerical abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Binary arithmetic operations enum class BinaryOperator { /// \brief Addition Add, /// \brief Substraction Sub, /// \brief Multiplication Mul, /// \brief Division /// /// On integers (Z), this is the integer division with rounding towards zero. /// On rationals (Q), this is the exact division. Div, /// \brief Remainder /// /// On integers (Z), this is the integer remainder, see operator% on ZNumber. /// This is undefined on rationals. Rem, /// \brief Modulo /// /// On integers (Z), this is the integer modulo, see mod() on ZNumber. /// This is undefined on rationals. Mod, /// \brief Left binary shift /// /// On integers (Z), this is the left binary shift, see operator<< on ZNumber. /// This is undefined on rationals. Shl, /// \brief Right binary shift /// /// On integers (Z), this is the right binary shift, see operator>> on /// ZNumber. /// This is undefined on rationals. Shr, /// \brief Bitwise AND /// /// On integers (Z), this is the bitwise AND, see operator& on ZNumber. /// This is undefined on rationals. And, /// \brief Bitwise OR /// /// On integers (Z), this is the bitwise OR, see operator| on ZNumber. /// This is undefined on rationals. Or, /// \brief Bitwise XOR /// /// On integers (Z), this is the bitwise XOR, see operator^ on ZNumber. /// This is undefined on rationals. Xor, }; /// \brief Get a textual representation of the given binary operator inline const char* bin_operator_text(BinaryOperator op) { switch (op) { case BinaryOperator::Add: return "+"; case BinaryOperator::Sub: return "-"; case BinaryOperator::Mul: return "*"; case BinaryOperator::Div: return "/"; case BinaryOperator::Rem: return "%"; case BinaryOperator::Mod: return "mod"; case BinaryOperator::Shl: return "<<"; case BinaryOperator::Shr: return ">>"; case BinaryOperator::And: return "&"; case BinaryOperator::Or: return "|"; case BinaryOperator::Xor: return "^"; default: ikos_unreachable("unsupported operator"); } } namespace detail { template < typename T, typename = void > struct ApplyBinOperator {}; } // end namespace detail /// \brief Apply an arithmetic binary operator on the given operands template < typename T > inline T apply_bin_operator(BinaryOperator op, const T& lhs, const T& rhs) { return detail::ApplyBinOperator< T >()(op, lhs, rhs); } namespace detail { /// \brief Implementation for abstract values on ZNumber template < typename T > struct ApplyBinOperator< T, std::enable_if_t< std::is_same< typename T::NumberT, ZNumber >::value > > { inline T operator()(BinaryOperator op, const T& lhs, const T& rhs) const { switch (op) { case BinaryOperator::Add: return lhs + rhs; case BinaryOperator::Sub: return lhs - rhs; case BinaryOperator::Mul: return lhs * rhs; case BinaryOperator::Div: return lhs / rhs; case BinaryOperator::Rem: return lhs % rhs; case BinaryOperator::Mod: return mod(lhs, rhs); case BinaryOperator::Shl: return lhs << rhs; case BinaryOperator::Shr: return lhs >> rhs; case BinaryOperator::And: return lhs & rhs; case BinaryOperator::Or: return lhs | rhs; case BinaryOperator::Xor: return lhs ^ rhs; default: ikos_unreachable("unsupported operator"); } } }; /// \brief Implementation for abstract values on QNumber template < typename T > struct ApplyBinOperator< T, std::enable_if_t< std::is_same< typename T::NumberT, QNumber >::value > > { inline T operator()(BinaryOperator op, const T& lhs, const T& rhs) const { switch (op) { case BinaryOperator::Add: return lhs + rhs; case BinaryOperator::Sub: return lhs - rhs; case BinaryOperator::Mul: return lhs * rhs; case BinaryOperator::Div: return lhs / rhs; default: ikos_unreachable("unsupported operator"); } } }; } // end namespace detail } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/separate_domain.hpp000066400000000000000000000335571473507761200276600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic implementation of non-relational numeric domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Generic implementation of non-relational numeric domains template < typename Number, typename VariableRef, typename Value > class SeparateDomain final : public core::AbstractDomain< SeparateDomain< Number, VariableRef, Value > > { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); static_assert(core::IsAbstractDomain< Value >::value, "Value must implement AbstractDomain"); private: using LinearExpressionT = LinearExpression< Number, VariableRef >; using PatriciaTreeMapT = PatriciaTreeMap< VariableRef, Value >; public: using Iterator = typename PatriciaTreeMapT::Iterator; private: PatriciaTreeMapT _tree; bool _is_bottom; private: struct TopTag {}; struct BottomTag {}; struct BottomFound {}; /// \brief Create the top abstract value explicit SeparateDomain(TopTag) : _is_bottom(false) {} /// \brief Create the bottom abstract value explicit SeparateDomain(BottomTag) : _is_bottom(true) {} public: /// \brief Create the top abstract value static SeparateDomain top() { return SeparateDomain(TopTag{}); } /// \brief Create the bottom abstract value static SeparateDomain bottom() { return SeparateDomain(BottomTag{}); } /// \brief Copy constructor SeparateDomain(const SeparateDomain&) noexcept = default; /// \brief Move constructor SeparateDomain(SeparateDomain&&) noexcept = default; /// \brief Copy assignment operator SeparateDomain& operator=(const SeparateDomain&) noexcept = default; /// \brief Move assignment operator SeparateDomain& operator=(SeparateDomain&&) noexcept = default; /// \brief Destructor ~SeparateDomain() override = default; /// \brief Begin iterator over the pairs (variable, value) Iterator begin() const { ikos_assert(!this->is_bottom()); return this->_tree.begin(); } /// \brief End iterator over the pairs (variable, value) Iterator end() const { ikos_assert(!this->is_bottom()); return this->_tree.end(); } void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->is_bottom() && this->_tree.empty(); } void set_to_bottom() override { this->_is_bottom = true; this->_tree.clear(); } void set_to_top() override { this->_is_bottom = false; this->_tree.clear(); } bool leq(const SeparateDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_tree.leq(other._tree, [](const Value& x, const Value& y) { return x.leq(y); }); } } bool equals(const SeparateDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_tree.equals(other._tree, [](const Value& x, const Value& y) { return x.equals(y); }); } } void join_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void join_loop_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join_loop(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void join_iter_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join_loop(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void widen_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.widening(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void widen_threshold_with(const SeparateDomain& other, const Number& threshold) { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [threshold](const Value& x, const Value& y) { Value z = x.widening_threshold(y, threshold); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void meet_with(const SeparateDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const Value& x, const Value& y) { Value z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } void narrow_with(const SeparateDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const Value& x, const Value& y) { Value z = x.narrowing(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } void narrow_threshold_with(const SeparateDomain& other, const Number& threshold) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [threshold](const Value& x, const Value& y) { Value z = x.narrowing_threshold(y, threshold); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Get the abstract value for the given variable Value get(VariableRef x) const { if (this->is_bottom()) { return Value::bottom(); } else { boost::optional< const Value& > v = this->_tree.at(x); if (v) { return *v; } else { return Value::top(); } } } /// \brief Set the abstract value of the given variable void set(VariableRef x, const Value& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { this->_tree.erase(x); } else { this->_tree.insert_or_assign(x, value); } } /// \brief Refine the abstract value of the given variable void refine(VariableRef v, const Value& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { return; } else { try { this->_tree.update_or_insert( [](const Value& x, const Value& y) { Value z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }, v, value); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Projection /// /// Return an overapproximation of the linear expression `e` as an abstract /// value Value project(const LinearExpressionT& e) const { if (this->is_bottom()) { return Value::bottom(); } Value r(e.constant()); for (const auto& term : e) { r += Value(term.second) * this->get(term.first); } return r; } /// \brief Forget the abstract value of the given variable void forget(VariableRef x) { if (this->is_bottom()) { return; } this->_tree.erase(x); } /// \brief Assign `x = n` void assign(VariableRef x, int n) { this->set(x, Value(n)); } /// \brief Assign `x = n` void assign(VariableRef x, const Number& n) { this->set(x, Value(n)); } /// \brief Assign `x = y` void assign(VariableRef x, VariableRef y) { this->set(x, this->get(y)); } /// \brief Assign `x = e` void assign(VariableRef x, const LinearExpressionT& e) { this->set(x, this->project(e)); } /// \brief Apply `x = y op z` void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) { this->set(x, apply_bin_operator(op, this->get(y), this->get(z))); } /// \brief Apply `x = y op z` void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) { this->set(x, apply_bin_operator(op, this->get(y), Value(z))); } /// \brief Apply `x = y op z` void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) { this->set(x, apply_bin_operator(op, Value(y), this->get(z))); } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { this->_tree.dump(o); } } static std::string name() { return "separate domain of " + Value::name(); } }; // end class SeparateDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/union.hpp000066400000000000000000000521371473507761200256500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic union numerical abstract domain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Union abstract domain template < typename Number, typename VariableRef, typename NumericDomain, std::size_t MaxHeight > class UnionDomain final : public numeric::AbstractDomain< Number, VariableRef, UnionDomain< Number, VariableRef, NumericDomain, MaxHeight > > { public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: /* * Implementation of a binary tree structure */ class Tree; using TreePtr = std::shared_ptr< const Tree >; class Tree { private: std::size_t _size; std::size_t _height; public: explicit Tree(std::size_t size, std::size_t height) : _size(size), _height(height) {} Tree(const Tree&) = delete; Tree(Tree&&) = delete; Tree& operator=(const Tree&) = delete; Tree& operator=(Tree&&) = delete; virtual ~Tree() = default; std::size_t size() const { return this->_size; } std::size_t height() const { return this->_height; } bool is_leaf() const { return this->_height == 0; } bool is_node() const { return !this->is_leaf(); } virtual void dump(std::ostream& o) const = 0; }; // end class Tree class Node final : public Tree { private: TreePtr _left_branch; TreePtr _right_branch; public: Node(const TreePtr& left_branch, const TreePtr& right_branch) : Tree(/*size = */ left_branch->size() + right_branch->size(), /*height = */ 1 + std::max(left_branch->height(), right_branch->height())), _left_branch(left_branch), _right_branch(right_branch) {} const TreePtr& left_branch() const { return this->_left_branch; } const TreePtr& right_branch() const { return this->_right_branch; } void dump(std::ostream& o) const override { o << "N("; this->_left_branch->dump(o); o << ","; this->_right_branch->dump(o); o << ")"; } }; // end class Node class Leaf final : public Tree { private: NumericDomain _value; public: explicit Leaf(NumericDomain value) : Tree(/*size = */ 1, /*height = */ 0), _value(std::move(value)) {} const NumericDomain& value() const { return this->_value; } void dump(std::ostream& o) const override { o << "L("; this->_value.dump(o); o << ")"; } }; // end class Leaf static TreePtr make_node(const TreePtr& left_branch, const TreePtr& right_branch) { if (left_branch == nullptr) { return right_branch; } if (right_branch == nullptr) { return left_branch; } return std::make_shared< const Node >(left_branch, right_branch); } static TreePtr make_leaf(NumericDomain value) { value.normalize(); if (value.is_bottom()) { return nullptr; } return std::make_shared< const Leaf >(std::move(value)); } template < typename UnaryOp > static TreePtr transform(const TreePtr& t, const UnaryOp& op) { if (t == nullptr) { return nullptr; } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return make_leaf(op(leaf->value())); } auto node = std::static_pointer_cast< const Node >(t); return make_node(transform(node->left_branch(), op), transform(node->right_branch(), op)); } static bool is_top(const TreePtr& t) { if (t == nullptr) { return false; // bottom } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value().is_top(); } auto node = std::static_pointer_cast< const Node >(t); return is_top(node->left_branch()) && is_top(node->right_branch()); } static NumericDomain merge(const TreePtr& t) { ikos_assert(t != nullptr); if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value(); } auto node = std::static_pointer_cast< const Node >(t); return merge(node->left_branch()).join(merge(node->right_branch())); } /// \brief Reduce the height of a tree by merging the nodes at a heigh /// greater than max_height static TreePtr reduce_height(const TreePtr& t, std::size_t max_height) { if (t == nullptr) { return nullptr; } if (t->height() <= max_height) { return t; } if (max_height == 0) { return make_leaf(merge(t)); } else { // t->height() > max_height > 0 auto node = std::static_pointer_cast< const Node >(t); return make_node(reduce_height(node->left_branch(), max_height - 1), reduce_height(node->right_branch(), max_height - 1)); } } private: TreePtr _tree; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top abstract value explicit UnionDomain(TopTag) : _tree(make_leaf(NumericDomain::top())) {} /// \brief Create the bottom abstract value explicit UnionDomain(BottomTag) : _tree(nullptr) {} /// \brief Create an abstract value from a tree explicit UnionDomain(TreePtr tree) : _tree(std::move(tree)) {} public: /// \brief Create the top abstract value static UnionDomain top() { return UnionDomain(TopTag{}); } /// \brief Create the bottom abstract value static UnionDomain bottom() { return UnionDomain(BottomTag{}); } /// \brief Copy constructor UnionDomain(const UnionDomain&) noexcept = default; /// \brief Move constructor UnionDomain(UnionDomain&&) noexcept = default; /// \brief Copy assignment operator UnionDomain& operator=(const UnionDomain&) noexcept = default; /// \brief Move assignment operator UnionDomain& operator=(UnionDomain&&) noexcept = default; /// \brief Destructor ~UnionDomain() override = default; void normalize() override {} bool is_bottom() const override { // This is correct because make_leaf() calls .is_bottom() on leaf creation return this->_tree == nullptr; } bool is_top() const override { return is_top(_tree); } void set_to_bottom() override { this->_tree = nullptr; } void set_to_top() override { this->_tree = make_leaf(NumericDomain::top()); } bool leq(const UnionDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return merge(this->_tree).leq(merge(other._tree)); } } bool equals(const UnionDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return merge(this->_tree).equals(merge(other._tree)); } } UnionDomain join(const UnionDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { TreePtr left_branch = reduce_height(this->_tree, MaxHeight - 1); TreePtr right_branch = reduce_height(other._tree, MaxHeight - 1); return UnionDomain(make_node(left_branch, right_branch)); } } void join_with(const UnionDomain& other) override { this->operator=(this->join(other)); } void join_loop_with(const UnionDomain& other) override { this->join_with(other); } void join_iter_with(const UnionDomain& other) override { this->join_with(other); } UnionDomain widening(const UnionDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return UnionDomain( make_leaf(merge(this->_tree).widening(merge(other._tree)))); } } void widen_with(const UnionDomain& other) override { this->operator=(this->widening(other)); } UnionDomain widening_threshold(const UnionDomain& other, const Number& threshold) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return UnionDomain( make_leaf(merge(this->_tree) .widening_threshold(merge(other._tree), threshold))); } } void widen_threshold_with(const UnionDomain& other, const Number& threshold) override { this->operator=(this->widening_threshold(other, threshold)); } UnionDomain meet(const UnionDomain& other) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { NumericDomain other_inv = merge(other._tree); return UnionDomain(transform(_tree, [&](const NumericDomain& inv) { return inv.meet(other_inv); })); } } void meet_with(const UnionDomain& other) override { this->operator=(this->meet(other)); } UnionDomain narrowing(const UnionDomain& other) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { return UnionDomain( make_leaf(merge(this->_tree).narrowing(merge(other._tree)))); } } void narrow_with(const UnionDomain& other) override { this->operator=(this->narrowing(other)); } UnionDomain narrowing_threshold(const UnionDomain& other, const Number& threshold) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { return UnionDomain( make_leaf(merge(this->_tree) .narrowing_threshold(merge(other._tree), threshold))); } } void narrow_threshold_with(const UnionDomain& other, const Number& threshold) override { this->operator=(this->narrowing_threshold(other, threshold)); } void assign(VariableRef x, int n) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.assign(x, n); return inv; }); } void assign(VariableRef x, const Number& n) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.assign(x, n); return inv; }); } void assign(VariableRef x, VariableRef y) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.assign(x, y); return inv; }); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.assign(x, e); return inv; }); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.apply(op, x, y, z); return inv; }); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.apply(op, x, y, z); return inv; }); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.apply(op, x, y, z); return inv; }); } void add(const LinearConstraintT& cst) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.add(cst); return inv; }); } void add(const LinearConstraintSystemT& csts) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.add(csts); return inv; }); } void set(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.set(x, value); return inv; }); } } void set(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.set(x, value); return inv; }); } } void set(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.set(x, value); return inv; }); } } void refine(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.refine(x, value); return inv; }); } } void refine(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.refine(x, value); return inv; }); } } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.refine(x, value); return inv; }); } } void forget(VariableRef x) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.forget(x); return inv; }); } private: static IntervalT to_interval(const TreePtr& t, VariableRef v) { if (t == nullptr) { return IntervalT::bottom(); } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value().to_interval(v); } auto node = std::static_pointer_cast< const Node >(t); return to_interval(node->left_branch(), v) .join(to_interval(node->right_branch(), v)); } public: IntervalT to_interval(VariableRef x) const override { return to_interval(this->_tree, x); } private: static IntervalT to_interval(const TreePtr& t, const LinearExpressionT& e) { if (t == nullptr) { return IntervalT::bottom(); } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value().to_interval(e); } auto node = std::static_pointer_cast< const Node >(t); return to_interval(node->left_branch(), e) .join(to_interval(node->right_branch(), e)); } public: IntervalT to_interval(const LinearExpressionT& e) const override { return to_interval(this->_tree, e); } private: static CongruenceT to_congruence(const TreePtr& t, VariableRef v) { if (t == nullptr) { return CongruenceT::bottom(); } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value().to_congruence(v); } auto node = std::static_pointer_cast< const Node >(t); return to_congruence(node->left_branch(), v) .join(to_congruence(node->right_branch(), v)); } public: CongruenceT to_congruence(VariableRef x) const override { return to_congruence(this->_tree, x); } private: static CongruenceT to_congruence(const TreePtr& t, const LinearExpressionT& e) { if (t == nullptr) { return CongruenceT::bottom(); } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value().to_congruence(e); } auto node = std::static_pointer_cast< const Node >(t); return to_congruence(node->left_branch(), e) .join(to_congruence(node->right_branch(), e)); } public: CongruenceT to_congruence(const LinearExpressionT& e) const override { return to_congruence(this->_tree, e); } private: static IntervalCongruenceT to_interval_congruence(const TreePtr& t, VariableRef v) { if (t == nullptr) { return IntervalCongruenceT::bottom(); } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value().to_interval_congruence(v); } auto node = std::static_pointer_cast< const Node >(t); return to_interval_congruence(node->left_branch(), v) .join(to_interval_congruence(node->right_branch(), v)); } public: IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return to_interval_congruence(this->_tree, x); } private: static IntervalCongruenceT to_interval_congruence( const TreePtr& t, const LinearExpressionT& e) { if (t == nullptr) { return IntervalCongruenceT::bottom(); } if (t->is_leaf()) { auto leaf = std::static_pointer_cast< const Leaf >(t); return leaf->value().to_interval_congruence(e); } auto node = std::static_pointer_cast< const Node >(t); return to_interval_congruence(node->left_branch(), e) .join(to_interval_congruence(node->right_branch(), e)); } public: IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return to_interval_congruence(this->_tree, e); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } return merge(this->_tree).to_linear_constraint_system(); } /// \name Non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.counter_mark(x); return inv; }); } void counter_unmark(VariableRef x) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.counter_unmark(x); return inv; }); } void counter_init(VariableRef x, const Number& c) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.counter_init(x, c); return inv; }); } void counter_incr(VariableRef x, const Number& k) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.counter_incr(x, k); return inv; }); } void counter_forget(VariableRef x) override { this->_tree = transform(this->_tree, [&](NumericDomain inv) { inv.counter_forget(x); return inv; }); } /// @} void dump(std::ostream& o) const override { if (this->_tree == nullptr) { o << "⊥"; } else { this->_tree->dump(o); } } static std::string name() { return "union of " + NumericDomain::name(); } }; // end class union_domain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/var_packing_dbm.hpp000066400000000000000000000323201473507761200276160ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Optimized version of the DBM abstract domain using variable packing * * The idea is to put variables together in the same equivalence class only if * we can express the relation between them using DBM. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief DBM abstract domain using variable packing template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class VarPackingDBM final : public numeric::AbstractDomain< Number, VariableRef, VarPackingDBM< Number, VariableRef, MaxReductionCycles > > { public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; public: template < typename, typename, std::size_t > friend class VarPackingDBMCongruence; private: using VarPackingDomainT = VarPackingDomain< Number, VariableRef, DBM< Number, VariableRef, MaxReductionCycles > >; using LinearIntervalSolverT = LinearIntervalSolver< Number, VariableRef, VarPackingDBM >; private: VarPackingDomainT _inv; private: /// \brief Private constructor explicit VarPackingDBM(VarPackingDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static VarPackingDBM top() { return VarPackingDBM(VarPackingDomainT::top()); } /// \brief Create the bottom abstract value static VarPackingDBM bottom() { return VarPackingDBM(VarPackingDomainT::bottom()); } /// \brief Copy constructor VarPackingDBM(const VarPackingDBM&) = default; /// \brief Move constructor VarPackingDBM(VarPackingDBM&&) = default; /// \brief Copy assignment operator VarPackingDBM& operator=(const VarPackingDBM&) = default; /// \brief Move assignment operator VarPackingDBM& operator=(VarPackingDBM&&) = default; /// \brief Destructor ~VarPackingDBM() override = default; void normalize() override { this->_inv.normalize(); } bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const VarPackingDBM& other) const override { return this->_inv.leq(other._inv); } bool equals(const VarPackingDBM& other) const override { return this->_inv.equals(other._inv); } void join_with(VarPackingDBM&& other) override { this->_inv.join_with(std::move(other._inv)); } void join_with(const VarPackingDBM& other) override { this->_inv.join_with(other._inv); } void join_loop_with(VarPackingDBM&& other) override { this->_inv.join_loop_with(std::move(other._inv)); } void join_loop_with(const VarPackingDBM& other) override { this->_inv.join_loop_with(other._inv); } void join_iter_with(VarPackingDBM&& other) override { this->_inv.join_iter_with(std::move(other._inv)); } void join_iter_with(const VarPackingDBM& other) override { this->_inv.join_iter_with(other._inv); } void widen_with(const VarPackingDBM& other) override { this->_inv.widen_with(other._inv); } void widen_threshold_with(const VarPackingDBM& other, const Number& threshold) override { this->_inv.widen_threshold_with(other._inv, threshold); } void meet_with(const VarPackingDBM& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const VarPackingDBM& other) override { this->_inv.narrow_with(other._inv); } void narrow_threshold_with(const VarPackingDBM& other, const Number& threshold) override { this->_inv.narrow_threshold_with(other._inv, threshold); } VarPackingDBM join(const VarPackingDBM& other) const override { return VarPackingDBM(this->_inv.join(other._inv)); } VarPackingDBM join_loop(const VarPackingDBM& other) const override { return VarPackingDBM(this->_inv.join_loop(other._inv)); } VarPackingDBM join_iter(const VarPackingDBM& other) const override { return VarPackingDBM(this->_inv.join_iter(other._inv)); } VarPackingDBM widening(const VarPackingDBM& other) const override { return VarPackingDBM(this->_inv.widening(other._inv)); } VarPackingDBM widening_threshold(const VarPackingDBM& other, const Number& threshold) const override { return VarPackingDBM(this->_inv.widening_threshold(other._inv, threshold)); } VarPackingDBM meet(const VarPackingDBM& other) const override { return VarPackingDBM(this->_inv.meet(other._inv)); } VarPackingDBM narrowing(const VarPackingDBM& other) const override { return VarPackingDBM(this->_inv.narrowing(other._inv)); } VarPackingDBM narrowing_threshold(const VarPackingDBM& other, const Number& threshold) const override { return VarPackingDBM(this->_inv.narrowing_threshold(other._inv, threshold)); } void assign(VariableRef x, int n) override { this->_inv.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_inv.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_inv.assign(x, y); } void assign(VariableRef x, const LinearExpressionT& e) override { if (this->_inv._is_bottom) { return; } if (e.is_constant() || (e.num_terms() == 1 && e.begin()->second == 1)) { this->_inv.assign(x, e); } else { // Projection using intervals this->_inv.set(x, this->_inv.to_interval(e)); } } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { if (this->_inv.is_bottom()) { return; } IntervalT v_y = this->_inv.to_interval(y); IntervalT v_z = this->_inv.to_interval(z); if (v_y.singleton()) { this->apply(op, x, *v_y.singleton(), z); } else if (v_z.singleton()) { this->apply(op, x, y, *v_z.singleton()); } else { this->_inv.set(x, apply_bin_operator(op, v_y, v_z)); } } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { if (this->_inv.is_bottom()) { return; } if (op == BinaryOperator::Add || op == BinaryOperator::Sub || (op == BinaryOperator::Mul && z == 1) || (op == BinaryOperator::Div && z == 1) || op == BinaryOperator::Mod) { this->_inv.apply(op, x, y, z); return; } this->_inv.set(x, apply_bin_operator(op, this->_inv.to_interval(y), IntervalT(z))); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { if (this->_inv.is_bottom()) { return; } if (op == BinaryOperator::Add || (op == BinaryOperator::Mul && y == 1)) { this->_inv.apply(op, x, y, z); return; } this->_inv.set(x, apply_bin_operator(op, IntervalT(y), this->_inv.to_interval(z))); } void add(const LinearConstraintT& cst) override { if (this->_inv._is_bottom) { return; } if (cst.num_terms() == 0) { if (cst.is_contradiction()) { this->set_to_bottom(); } return; } auto it = cst.begin(); auto it2 = ++cst.begin(); if ((cst.is_inequality() || cst.is_equality()) && ((cst.num_terms() == 1 && it->second == 1) || (cst.num_terms() == 1 && it->second == -1) || (cst.num_terms() == 2 && it->second == 1 && it2->second == -1) || (cst.num_terms() == 2 && it->second == -1 && it2->second == 1))) { this->_inv.add(cst); } else { if (this->_inv.is_bottom()) { return; } LinearIntervalSolverT solver(MaxReductionCycles); solver.add(cst); solver.run(*this); } } void add(const LinearConstraintSystemT& csts) override { if (this->_inv._is_bottom) { return; } LinearIntervalSolverT solver(MaxReductionCycles); for (const LinearConstraintT& cst : csts) { // process each constraint if (cst.num_terms() == 0) { if (cst.is_contradiction()) { this->set_to_bottom(); return; } } else if (cst.is_inequality() || cst.is_equality()) { auto it = cst.begin(); auto it2 = ++cst.begin(); if ((cst.num_terms() == 1 && it->second == 1) || (cst.num_terms() == 1 && it->second == -1) || (cst.num_terms() == 2 && it->second == 1 && it2->second == -1) || (cst.num_terms() == 2 && it->second == -1 && it2->second == 1)) { this->_inv.add(cst); } else { solver.add(cst); } } else { solver.add(cst); } } if (!solver.empty()) { if (this->_inv.is_bottom()) { return; } solver.run(*this); } } void set(VariableRef x, const IntervalT& value) override { this->_inv.set(x, value); } void set(VariableRef x, const CongruenceT& value) override { this->_inv.set(x, value); } void set(VariableRef x, const IntervalCongruenceT& value) override { this->_inv.set(x, value); } void refine(VariableRef x, const IntervalT& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const CongruenceT& value) override { this->_inv.refine(x, value); } void refine(VariableRef x, const IntervalCongruenceT& value) override { this->_inv.refine(x, value); } void forget(VariableRef x) override { this->_inv.forget(x); } IntervalT to_interval(VariableRef x) const override { return this->_inv.to_interval(x); } IntervalT to_interval(const LinearExpressionT& e) const override { return this->_inv.to_interval(e); } CongruenceT to_congruence(VariableRef x) const override { return this->_inv.to_congruence(x); } CongruenceT to_congruence(const LinearExpressionT& e) const override { return this->_inv.to_congruence(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return this->_inv.to_interval_congruence(x); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return this->_inv.to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { return this->_inv.to_linear_constraint_system(); } void dump(std::ostream& o) const override { this->_inv.dump(o); } static std::string name() { return "DBM with variable packing"; } }; // end class VarPackingDBM } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/var_packing_dbm_congruence.hpp000066400000000000000000000401321473507761200320260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Reduced product of DBM (using variable packing) and Congruences * * The implementation is based on Jorge's IntervalCongruenceDomain. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Reduced product of DBM (using variable packing) and congruences template < typename Number, typename VariableRef, std::size_t MaxReductionCycles = 10 > class VarPackingDBMCongruence final : public numeric::AbstractDomain< Number, VariableRef, VarPackingDBMCongruence< Number, VariableRef, MaxReductionCycles > > { public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; private: using VarPackingDBMT = VarPackingDBM< Number, VariableRef, MaxReductionCycles >; using CongruenceDomainT = CongruenceDomain< Number, VariableRef, MaxReductionCycles >; using DomainProduct = numeric:: DomainProduct2< Number, VariableRef, VarPackingDBMT, CongruenceDomainT >; private: DomainProduct _product; private: /// \brief Private constructor explicit VarPackingDBMCongruence(DomainProduct product) : _product(std::move(product)) { this->reduce(); } /// \brief Reduce the equivalence class containing the variable `v` void reduce_equivalence_class(VariableRef v) { if (this->is_bottom()) { return; } auto& equiv_relation = this->_product.first()._inv._equiv_relation; if (!equiv_relation.contains(v)) { return; } auto& equiv_class = equiv_relation.find_equiv_class(v); std::shared_ptr< const DBM< Number, VariableRef > > domain_ptr = equiv_class.domain_ptr(); bool change_dbm = true; bool change_congruence = true; while (change_dbm || change_congruence) { change_dbm = false; change_congruence = false; for (auto it = domain_ptr->var_begin(), et = domain_ptr->var_end(); it != et; ++it) { VariableRef x = *it; IntervalT i = domain_ptr->to_interval(x); CongruenceT c = this->_product.second().to_congruence(x); IntervalCongruenceT val(i, c); if (val.is_bottom()) { this->set_to_bottom(); return; } if (val.interval() != i) { DBM< Number, VariableRef > domain = *domain_ptr; domain.refine(x, val.interval()); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); return; } domain_ptr = std::make_shared< const DBM< Number, VariableRef > >( std::move(domain)); change_dbm = true; } if (val.congruence() != c) { this->_product.second().set(x, val.congruence()); change_congruence = true; } } } equiv_class.set_domain_ptr(domain_ptr); } /// \brief Reduce the abstract value void reduce() { if (this->is_bottom()) { return; } auto& equiv_relation = this->_product.first()._inv._equiv_relation; for (const auto& equiv_class : equiv_relation) { this->reduce_equivalence_class(equiv_class.first); if (this->is_bottom()) { // iterators are invalidated, exit return; } } } public: /// \brief Create the top abstract value static VarPackingDBMCongruence top() { return VarPackingDBMCongruence( DomainProduct(VarPackingDBMT::top(), CongruenceDomainT::top())); } /// \brief Create the bottom abstract value static VarPackingDBMCongruence bottom() { return VarPackingDBMCongruence( DomainProduct(VarPackingDBMT::bottom(), CongruenceDomainT::bottom())); } /// \brief Copy constructor VarPackingDBMCongruence(const VarPackingDBMCongruence&) = default; /// \brief Move constructor VarPackingDBMCongruence(VarPackingDBMCongruence&&) = default; /// \brief Copy assignment operator VarPackingDBMCongruence& operator=(const VarPackingDBMCongruence&) = default; /// \brief Move assignment operator VarPackingDBMCongruence& operator=(VarPackingDBMCongruence&&) = default; /// \brief Destructor ~VarPackingDBMCongruence() override = default; /// \brief Return the first abstract value /// /// Note: does not normalize. const VarPackingDBMT& first() const { return this->_product.first(); } /// \brief Return the first abstract value /// /// Note: does not normalize. VarPackingDBMT& first() { return this->_product.first(); } /// \brief Return the second abstract value /// /// Note: does not normalize. const CongruenceDomainT& second() const { return this->_product.second(); } /// \brief Return the second abstract value /// /// Note: does not normalize. CongruenceDomainT& second() { return this->_product.second(); } void normalize() override { this->_product.normalize(); } bool is_bottom() const override { return this->_product.is_bottom(); } bool is_top() const override { return this->_product.is_top(); } void set_to_bottom() override { this->_product.set_to_bottom(); } void set_to_top() override { this->_product.set_to_top(); } bool leq(const VarPackingDBMCongruence& other) const override { return this->_product.leq(other._product); } bool equals(const VarPackingDBMCongruence& other) const override { return this->_product.equals(other._product); } void join_with(VarPackingDBMCongruence&& other) override { this->_product.join_with(std::move(other._product)); this->reduce(); } void join_with(const VarPackingDBMCongruence& other) override { this->_product.join_with(other._product); this->reduce(); } void join_loop_with(VarPackingDBMCongruence&& other) override { this->_product.join_loop_with(std::move(other._product)); this->reduce(); } void join_loop_with(const VarPackingDBMCongruence& other) override { this->_product.join_loop_with(other._product); this->reduce(); } void join_iter_with(VarPackingDBMCongruence&& other) override { this->_product.join_iter_with(std::move(other._product)); this->reduce(); } void join_iter_with(const VarPackingDBMCongruence& other) override { this->_product.join_iter_with(other._product); this->reduce(); } void widen_with(const VarPackingDBMCongruence& other) override { this->_product.widen_with(other._product); this->reduce(); } void widen_threshold_with(const VarPackingDBMCongruence& other, const Number& threshold) override { this->_product.widen_threshold_with(other._product, threshold); this->reduce(); } void meet_with(const VarPackingDBMCongruence& other) override { this->_product.meet_with(other._product); this->reduce(); } void narrow_with(const VarPackingDBMCongruence& other) override { this->_product.narrow_with(other._product); this->reduce(); } void narrow_threshold_with(const VarPackingDBMCongruence& other, const Number& threshold) override { this->_product.narrow_threshold_with(other._product, threshold); this->reduce(); } VarPackingDBMCongruence join( const VarPackingDBMCongruence& other) const override { return VarPackingDBMCongruence(this->_product.join(other._product)); } VarPackingDBMCongruence join_loop( const VarPackingDBMCongruence& other) const override { return VarPackingDBMCongruence(this->_product.join_loop(other._product)); } VarPackingDBMCongruence join_iter( const VarPackingDBMCongruence& other) const override { return VarPackingDBMCongruence(this->_product.join_iter(other._product)); } VarPackingDBMCongruence widening( const VarPackingDBMCongruence& other) const override { return VarPackingDBMCongruence(this->_product.widening(other._product)); } VarPackingDBMCongruence widening_threshold( const VarPackingDBMCongruence& other, const Number& threshold) const override { return VarPackingDBMCongruence( this->_product.widening_threshold(other._product, threshold)); } VarPackingDBMCongruence meet( const VarPackingDBMCongruence& other) const override { return VarPackingDBMCongruence(this->_product.meet(other._product)); } VarPackingDBMCongruence narrowing( const VarPackingDBMCongruence& other) const override { return VarPackingDBMCongruence(this->_product.narrowing(other._product)); } VarPackingDBMCongruence narrowing_threshold( const VarPackingDBMCongruence& other, const Number& threshold) const override { return VarPackingDBMCongruence( this->_product.narrowing_threshold(other._product, threshold)); } void assign(VariableRef x, int n) override { this->_product.assign(x, n); } void assign(VariableRef x, const Number& n) override { this->_product.assign(x, n); } void assign(VariableRef x, VariableRef y) override { this->_product.assign(x, y); this->reduce_equivalence_class(x); } void assign(VariableRef x, const LinearExpressionT& e) override { this->_product.assign(x, e); this->reduce_equivalence_class(x); } void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { this->_product.apply(op, x, y, z); this->reduce_equivalence_class(x); } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { this->_product.apply(op, x, y, z); this->reduce_equivalence_class(x); } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { this->_product.apply(op, x, y, z); this->reduce_equivalence_class(x); } void add(const LinearConstraintT& cst) override { this->_product.add(cst); if (this->is_bottom()) { return; } if (cst.num_terms() == 0) { return; } auto it = cst.begin(); auto it2 = ++cst.begin(); if ((cst.is_inequality() || cst.is_equality()) && ((cst.num_terms() == 1 && it->second == 1) || (cst.num_terms() == 1 && it->second == -1) || (cst.num_terms() == 2 && it->second == 1 && it2->second == -1) || (cst.num_terms() == 2 && it->second == -1 && it2->second == 1))) { // Variables are together in the same equivalence class this->reduce_equivalence_class(it->first); } else { for (const auto& term : cst) { this->reduce_equivalence_class(term.first); } } } void add(const LinearConstraintSystemT& csts) override { this->_product.add(csts); if (this->is_bottom()) { return; } for (const LinearConstraintT& cst : csts) { if (cst.num_terms() == 0) { continue; } else { auto it = cst.begin(); auto it2 = ++cst.begin(); if ((cst.is_inequality() || cst.is_equality()) && ((cst.num_terms() == 1 && it->second == 1) || (cst.num_terms() == 1 && it->second == -1) || (cst.num_terms() == 2 && it->second == 1 && it2->second == -1) || (cst.num_terms() == 2 && it->second == -1 && it2->second == 1))) { // Variables are together in the same equivalence class this->reduce_equivalence_class(it->first); } else { for (const auto& term : cst) { this->reduce_equivalence_class(term.first); } } } } } void set(VariableRef x, const IntervalT& value) override { this->_product.set(x, value); } void set(VariableRef x, const CongruenceT& value) override { this->_product.set(x, value); } void set(VariableRef x, const IntervalCongruenceT& value) override { this->_product.first().set(x, value.interval()); this->_product.second().set(x, value.congruence()); } void refine(VariableRef x, const IntervalT& value) override { this->_product.first().refine(x, value); this->reduce_equivalence_class(x); } void refine(VariableRef x, const CongruenceT& value) override { this->_product.second().refine(x, value); this->reduce_equivalence_class(x); } void refine(VariableRef x, const IntervalCongruenceT& value) override { this->_product.first().refine(x, value.interval()); this->_product.second().refine(x, value.congruence()); this->reduce_equivalence_class(x); } void forget(VariableRef x) override { this->_product.forget(x); } IntervalT to_interval(VariableRef x) const override { return this->to_interval_congruence(x).interval(); } IntervalT to_interval(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).interval(); } CongruenceT to_congruence(VariableRef x) const override { return this->to_interval_congruence(x).congruence(); } CongruenceT to_congruence(const LinearExpressionT& e) const override { return this->to_interval_congruence(e).congruence(); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { return IntervalCongruenceT(this->_product.first().to_interval(x), this->_product.second().to_congruence(x)); } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return IntervalCongruenceT(this->_product.first().to_interval(e), this->_product.second().to_congruence(e)); } LinearConstraintSystemT to_linear_constraint_system() const override { return this->_product.to_linear_constraint_system(); } void dump(std::ostream& o) const override { this->_product.dump(o); } static std::string name() { return "DBM with variable packing and congruences"; } }; // end class VarPackingDBMCongruence } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/numeric/var_packing_domain.hpp000066400000000000000000001200251473507761200303230ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Abstract domain using variable packing techniques * * Implementation of an abstract domain using variable packing techniques to * improve the performance of a relational abstract domain. * * Based on Arnaud Venet & Guillaume Brat's paper: Precise and efficient static * array bound checking for large embedded C programs, in PLDI, 231-242, 2004. * * The idea is to keep a set of equivalence classes, using the union-find * structure. Each equivalence class holds an abstract domain over all * variables within the class. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { // Forward declaration template < typename Number, typename VariableRef, std::size_t MaxReductionCycles > class VarPackingDBM; // Forward declaration template < typename Number, typename VariableRef, std::size_t MaxReductionCycles > class VarPackingDBMCongruence; /// \brief Generic abstract domain with variable packing /// /// The idea is to keep a set of equivalence classes, using the union-find /// structure. Each equivalence class holds an abstract domain over all /// variables within the class. template < typename Number, typename VariableRef, typename Domain > class VarPackingDomain final : public numeric::AbstractDomain< Number, VariableRef, VarPackingDomain< Number, VariableRef, Domain > > { public: static_assert(numeric::IsAbstractDomain< Domain, Number, VariableRef >::value, "Domain must be a numerical abstract domain"); public: using IntervalT = Interval< Number >; using CongruenceT = Congruence< Number >; using IntervalCongruenceT = IntervalCongruence< Number >; using LinearExpressionT = LinearExpression< Number, VariableRef >; using LinearConstraintT = LinearConstraint< Number, VariableRef >; using LinearConstraintSystemT = LinearConstraintSystem< Number, VariableRef >; public: template < typename, typename, std::size_t > friend class VarPackingDBM; template < typename, typename, std::size_t > friend class VarPackingDBMCongruence; private: /// \brief Shared pointer on the underlying abstract domain using DomainPtr = std::shared_ptr< const Domain >; /// \brief Hash function for VariableRef struct VariableRefHash { std::size_t operator()(VariableRef v) const { return IndexableTraits< VariableRef >::index(v); } }; /// \brief Map from root variable to list of variables using RootVariablesMap = std:: unordered_map< VariableRef, std::vector< VariableRef >, VariableRefHash >; /// \brief Parent class using Parent = numeric::AbstractDomain< Number, VariableRef, VarPackingDomain >; /* * Implementation of Union-Find */ /// \brief Equivalence class /// /// Represents a 'pack' of variables class EquivalenceClass { private: std::size_t _rank; DomainPtr _domain_ptr; // Invariant: _domain_ptr is normalized // TODO(marthaud): We could store the list of variables in the class public: /// \brief Create an empty equivalence class EquivalenceClass() : _rank(0), _domain_ptr(std::make_shared< const Domain >(Domain::top())) {} /// \brief Create an equivalence class with the given domain EquivalenceClass(Domain domain) : _rank(0), _domain_ptr(std::make_shared< const Domain >(std::move(domain))) {} /// \brief Copy constructor EquivalenceClass(const EquivalenceClass&) noexcept = default; /// \brief Move constructor EquivalenceClass(EquivalenceClass&&) noexcept = default; /// \brief Copy assignment operator EquivalenceClass& operator=(const EquivalenceClass&) noexcept = default; /// \brief Move assignment operator EquivalenceClass& operator=(EquivalenceClass&&) noexcept = default; /// \brief Destructor ~EquivalenceClass() = default; /// \brief Return the rank std::size_t rank() const { return this->_rank; } /// \brief Increment the rank void increment_rank() { this->_rank++; } /// \brief Return the abstract domain const Domain& domain() const { return *this->_domain_ptr; } /// \brief Update the abstract domain void set_domain(Domain domain) { domain.normalize(); ikos_assert(!domain.is_bottom()); this->_domain_ptr = std::make_shared< const Domain >(std::move(domain)); } /// \brief Return the abstract domain pointer const DomainPtr& domain_ptr() const { return this->_domain_ptr; } /// \brief Update the abstract domain pointer void set_domain_ptr(const DomainPtr& domain_ptr) { ikos_assert(!domain_ptr->is_bottom()); this->_domain_ptr = domain_ptr; } }; // end class EquivalenceClass /// \brief Equivalence relation /// /// Hold the equivalence classes class EquivalenceRelation { private: using ParentMap = std::unordered_map< VariableRef, VariableRef, VariableRefHash >; using ClassMap = std::unordered_map< VariableRef, EquivalenceClass, VariableRefHash >; private: // Map from variable to parent ParentMap _parents; // Map from root variable to equivalence class ClassMap _classes; public: /// \brief Create an empty equivalence relation explicit EquivalenceRelation() = default; /// \brief Copy constructor EquivalenceRelation(const EquivalenceRelation&) = default; /// \brief Move constructor EquivalenceRelation(EquivalenceRelation&&) = default; /// \brief Copy assignment operator EquivalenceRelation& operator=(const EquivalenceRelation&) = default; /// \brief Move assignment operator EquivalenceRelation& operator=(EquivalenceRelation&&) = default; /// \brief Destructor ~EquivalenceRelation() = default; /// \brief Return true if the equivalence relation contains `v` bool contains(VariableRef v) const { return this->_parents.find(v) != this->_parents.end(); } /// \brief Create an equivalence class containing the given variable /// /// Precondition: `v` is not already present in the relation void add_equiv_class(VariableRef v) { ikos_assert_msg(!this->contains(v), "variable already present"); this->_parents.emplace(v, v); this->_classes.emplace(v, EquivalenceClass()); } /// \brief Create an equivalence class containing the given variable /// /// Precondition: `v` is not already present in the relation void add_equiv_class(VariableRef v, Domain domain) { ikos_assert_msg(!this->contains(v), "variable already present"); this->_parents.emplace(v, v); this->_classes.emplace(v, EquivalenceClass(std::move(domain))); } /// \brief Add a variable in an equivalence class /// /// Precondition: `v` is not already present in the relation /// Precondition: `parent` is present in the relation void add_var_to_equiv_class(VariableRef v, VariableRef parent) { ikos_assert_msg(!this->contains(v), "variable already present"); ikos_assert_msg(this->contains(parent), "variable missing"); VariableRef parent_root = this->find_root_var(parent); EquivalenceClass& parent_class = this->_classes.find(parent_root)->second; if (parent_class.rank() == 0) { parent_class.increment_rank(); } this->_parents.emplace(v, parent_root); } /// \brief Find the root of the equivalence class containing `v` VariableRef find_root_var(VariableRef v) { VariableRef& parent = this->_parents.find(v)->second; if (parent == v) { return v; } else { return parent = this->find_root_var(parent); } } /// \brief Find the root of the equivalence class containing `v` VariableRef cfind_root_var(VariableRef v) const { VariableRef parent = this->_parents.find(v)->second; if (parent == v) { return v; } else { return this->cfind_root_var(parent); } } /// \brief Find the equivalence class containing `v` EquivalenceClass& find_equiv_class(VariableRef v) { return this->_classes.find(this->find_root_var(v))->second; } /// \brief Find the equivalence class containing `v` const EquivalenceClass& cfind_equiv_class(VariableRef v) const { return this->_classes.find(this->cfind_root_var(v))->second; } /// \brief Find the abstract domain containing `v` const Domain& find_domain(VariableRef v) { return this->find_equiv_class(v).domain(); } /// \brief Find the abstract domain containing `v` const Domain& cfind_domain(VariableRef v) const { return this->cfind_equiv_class(v).domain(); } /// \brief Find the abstract domain pointer containing `v` DomainPtr find_domain_ptr(VariableRef v) { return this->find_equiv_class(v).domain_ptr(); } /// \brief Find the abstract domain pointer containing `v` DomainPtr cfind_domain_ptr(VariableRef v) const { return this->cfind_equiv_class(v).domain_ptr(); } /// \brief Merge two equivalence classes /// /// Return whether `x` and `y` where on the same equivalence class bool join_equiv_class(VariableRef x, VariableRef y) { VariableRef x_root = this->find_root_var(x); VariableRef y_root = this->find_root_var(y); if (x_root == y_root) { return false; } EquivalenceClass& x_class = this->_classes.find(x_root)->second; EquivalenceClass& y_class = this->_classes.find(y_root)->second; // Merge the abstract domains Domain domain = x_class.domain().meet(y_class.domain()); if (x_class.rank() > y_class.rank()) { this->_parents.find(y_root)->second = x_root; x_class.set_domain(std::move(domain)); this->_classes.erase(y_root); } else { this->_parents.find(x_root)->second = y_root; if (x_class.rank() == y_class.rank()) { y_class.increment_rank(); } y_class.set_domain(std::move(domain)); this->_classes.erase(x_root); } return true; } private: struct GetVar { const VariableRef& operator()( const std::pair< const VariableRef, VariableRef >& p) const { return p.first; } }; public: /// \brief Begin iterator on the variables auto var_begin() const { return boost::make_transform_iterator(this->_parents.cbegin(), GetVar()); } /// \brief End iterator on the variables auto var_end() const { return boost::make_transform_iterator(this->_parents.cend(), GetVar()); } /// \brief Begin iterator on the equivalence classes auto begin() const { return this->_classes.cbegin(); } /// \brief End iterator on the equivalence classes auto end() const { return this->_classes.cend(); } /// \brief Return the list of variables std::vector< VariableRef > variables() const { return {this->var_begin(), this->var_end()}; } /// \brief Clear the equivalence relation void clear() { this->_parents.clear(); this->_classes.clear(); } /// \brief Forget the given variable void forget(VariableRef v) { auto it = this->_parents.find(v); if (it == this->_parents.end()) { return; } if (it->second != v) { // v is not the root of the equivalence class VariableRef root = this->find_root_var(it->second); // Update parents for (auto& p : this->_parents) { if (p.second == v) { p.second = root; } } EquivalenceClass& equiv_class = this->_classes.find(root)->second; Domain domain = equiv_class.domain(); domain.forget(v); equiv_class.set_domain(std::move(domain)); } else { // v is the root of the equivalence class boost::optional< VariableRef > new_root; // Find a new root for (auto& p : this->_parents) { if (p.second == v && p.first != v) { if (!new_root) { new_root = p.first; } p.second = *new_root; } } if (new_root) { EquivalenceClass equiv_class = std::move(this->_classes.find(v)->second); Domain domain = equiv_class.domain(); domain.forget(v); equiv_class.set_domain(std::move(domain)); this->_classes.emplace(*new_root, std::move(equiv_class)); } this->_classes.erase(v); } this->_parents.erase(v); } /// \brief Forget the equivalence class containing the given variable void forget_equiv_class(VariableRef v) { if (!this->contains(v)) { return; } VariableRef root = this->find_root_var(v); for (auto it = this->_parents.begin(); it != this->_parents.end();) { if (this->find_root_var(it->second) == root) { it = this->_parents.erase(it); } else { ++it; } } this->_classes.erase(root); } /// \brief Return a map from root variables to the list of variables in the /// equivalence class RootVariablesMap root_to_vars() const { RootVariablesMap roots; for (const auto& p : this->_parents) { roots[this->cfind_root_var(p.second)].push_back(p.first); } return roots; } void dump(std::ostream& o) const { o << "({"; for (auto it = this->_parents.begin(), et = this->_parents.end(); it != et;) { DumpableTraits< VariableRef >::dump(o, it->first); o << " -> "; DumpableTraits< VariableRef >::dump(o, it->second); ++it; if (it != et) { o << ", "; } } o << "}, {"; for (auto it = this->_classes.begin(), et = this->_classes.end(); it != et;) { DumpableTraits< VariableRef >::dump(o, it->first); o << " -> "; it->second.domain().dump(o); ++it; if (it != et) { o << ", "; } } o << "})"; } }; // end class EquivalenceRelation private: EquivalenceRelation _equiv_relation; bool _is_bottom; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top abstract value explicit VarPackingDomain(TopTag) : _is_bottom(false) {} /// \brief Create the bottom abstract value explicit VarPackingDomain(BottomTag) : _is_bottom(true) {} public: /// \brief Create the top abstract value static VarPackingDomain top() { return VarPackingDomain(TopTag{}); } /// \brief Create the bottom abstract value static VarPackingDomain bottom() { return VarPackingDomain(BottomTag{}); } /// \brief Copy constructor VarPackingDomain(const VarPackingDomain&) = default; /// \brief Move constructor VarPackingDomain(VarPackingDomain&&) = default; /// \brief Copy assignment operator VarPackingDomain& operator=(const VarPackingDomain&) = default; /// \brief Move assignment operator VarPackingDomain& operator=(VarPackingDomain&&) = default; /// \brief Destructor ~VarPackingDomain() override = default; void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { if (this->_is_bottom) { return false; } for (const auto& equiv_class : this->_equiv_relation) { if (!equiv_class.second.domain().is_top()) { return false; } } return true; } void set_to_bottom() override { this->_equiv_relation.clear(); this->_is_bottom = true; } void set_to_top() override { this->_equiv_relation.clear(); this->_is_bottom = false; } bool leq(const VarPackingDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { RootVariablesMap other_roots = other._equiv_relation.root_to_vars(); // For each equivalence class in `other` for (const auto& other_class : other_roots) { VariableRef other_root = other_class.first; DomainPtr other_domain_ptr = other._equiv_relation.cfind_domain_ptr(other_root); // Set of root variables of equivalence classes we have merged boost::container::flat_set< VariableRef > this_roots; // Domain for `this`, containing all needed variables DomainPtr this_domain_ptr = nullptr; // Merge domains in `this` for (VariableRef v : other_class.second) { if (!this->_equiv_relation.contains(v)) { continue; // v not in `this` } VariableRef this_root = this->_equiv_relation.cfind_root_var(v); if (!this_roots.insert(this_root).second) { continue; // Equivalence class for v already merged } DomainPtr domain_ptr = this->_equiv_relation.cfind_domain_ptr(this_root); // Merge `domain` into `this_domain` if (this_domain_ptr == nullptr) { this_domain_ptr = domain_ptr; } else if (this_domain_ptr == domain_ptr) { // Nothing to do } else { Domain domain = (*this_domain_ptr).meet(*domain_ptr); domain.normalize(); this_domain_ptr = std::make_shared< const Domain >(std::move(domain)); } } // Compare `this_domain_ptr` and `other_domain_ptr` if (this_domain_ptr == nullptr) { if (!other_domain_ptr->is_top()) { return false; } } else if (this_domain_ptr == other_domain_ptr) { // (*this_domain_ptr).leq(*other_domain_ptr) is true } else { if (!((*this_domain_ptr).leq(*other_domain_ptr))) { return false; } } } return true; } } bool equals(const VarPackingDomain& other) const override { return this->leq(other) && other.leq(*this); } private: void merge_existing_equiv_classes(boost::optional< VariableRef >& root, VariableRef v) { if (!this->_equiv_relation.contains(v)) { return; } if (root) { this->_equiv_relation.join_equiv_class(v, *root); } else { root = v; } } void merge_unexisting_equiv_classes(boost::optional< VariableRef >& root, VariableRef v) { if (this->_equiv_relation.contains(v)) { return; } if (root) { this->_equiv_relation.add_var_to_equiv_class(v, *root); } else { root = v; this->_equiv_relation.add_equiv_class(v); } } /// \brief Binary operation with a union semantic (join, widening) /// /// This uses a copy of `other` for ease of implementation. /// /// TODO(marthaud): Try to implement this without copying `other` template < typename BinaryOperator > void union_binary_op_with(VarPackingDomain other, const BinaryOperator& op) { // Forget variables in `this` that are not in `other` // TODO(marthaud): variables() needs to creates a temporary vector because // forget() might invalidate iterators for (VariableRef v : this->_equiv_relation.variables()) { if (!other._equiv_relation.contains(v)) { this->_equiv_relation.forget(v); } } // Forget variables in `other` that are not in `this` // TODO(marthaud): variables() needs to creates a temporary vector because // forget() might invalidate iterators for (VariableRef v : other._equiv_relation.variables()) { if (!this->_equiv_relation.contains(v)) { other._equiv_relation.forget(v); } } { // Iterate on equivalence classes in `this`, merge the variables in // `other` RootVariablesMap this_roots = this->_equiv_relation.root_to_vars(); for (const auto& this_class : this_roots) { boost::optional< VariableRef > root; for (VariableRef v : this_class.second) { other.merge_existing_equiv_classes(root, v); } } } { // Iterator on equivalence classes in `other`, merge the variables in // `this` and compute the binary operation RootVariablesMap other_roots = other._equiv_relation.root_to_vars(); for (const auto& other_class : other_roots) { const VariableRef& other_root = other_class.first; DomainPtr other_domain_ptr = other._equiv_relation.find_domain_ptr(other_root); boost::optional< VariableRef > root; for (VariableRef v : other_class.second) { this->merge_existing_equiv_classes(root, v); } if (root) { EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(*root); if (equiv_class.domain_ptr() == other_domain_ptr) { // Nothing to do, left and right packs are the same } else { equiv_class.set_domain(op(equiv_class.domain(), *other_domain_ptr)); } } } } } /// \brief Binary operation with an intersection semantic (meet, narrowing) template < typename BinaryOperator > void meet_binary_op_with(const VarPackingDomain& other, BinaryOperator op) { RootVariablesMap other_roots = other._equiv_relation.root_to_vars(); for (const auto& other_class : other_roots) { const VariableRef& other_root = other_class.first; DomainPtr other_domain_ptr = other._equiv_relation.cfind_domain_ptr(other_root); boost::optional< VariableRef > root; for (VariableRef v : other_class.second) { this->merge_existing_equiv_classes(root, v); } bool new_domain = !root; for (VariableRef v : other_class.second) { this->merge_unexisting_equiv_classes(root, v); } EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(*root); if (!new_domain) { if (equiv_class.domain_ptr() == other_domain_ptr) { // Nothing to do, left and right packs are the same } else { Domain domain = op(equiv_class.domain(), *other_domain_ptr); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); return; } equiv_class.set_domain(std::move(domain)); } } else { equiv_class.set_domain_ptr(other_domain_ptr); } } } struct JoinOperator { Domain operator()(const Domain& left, const Domain& right) const { return left.join(right); } }; struct MeetOperator { Domain operator()(const Domain& left, const Domain& right) const { return left.meet(right); } }; struct WideningOperator { Domain operator()(const Domain& left, const Domain& right) const { return left.widening(right); } }; struct WideningThresholdOperator { const Number& threshold; Domain operator()(const Domain& left, const Domain& right) const { return left.widening_threshold(right, threshold); } }; struct NarrowingOperator { Domain operator()(const Domain& left, const Domain& right) const { return left.narrowing(right); } }; struct NarrowingThresholdOperator { const Number& threshold; Domain operator()(const Domain& left, const Domain& right) const { return left.narrowing_threshold(right, threshold); } }; public: void join_with(VarPackingDomain&& other) override { if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->union_binary_op_with(std::move(other), JoinOperator{}); } } void join_with(const VarPackingDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->union_binary_op_with(other, JoinOperator{}); } } VarPackingDomain join(const VarPackingDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { VarPackingDomain result = *this; result.union_binary_op_with(other, JoinOperator{}); return result; } } void widen_with(const VarPackingDomain& other) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->union_binary_op_with(other, WideningOperator{}); } } VarPackingDomain widening(const VarPackingDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { VarPackingDomain result = *this; result.union_binary_op_with(other, WideningOperator{}); return result; } } void widen_threshold_with(const VarPackingDomain& other, const Number& threshold) override { if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->union_binary_op_with(other, WideningThresholdOperator{threshold}); } } VarPackingDomain widening_threshold(const VarPackingDomain& other, const Number& threshold) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { VarPackingDomain result = *this; result.union_binary_op_with(other, WideningThresholdOperator{threshold}); return result; } } void meet_with(const VarPackingDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->meet_binary_op_with(other, MeetOperator{}); } } VarPackingDomain meet(const VarPackingDomain& other) const override { if (this->is_bottom() || other.is_bottom()) { return VarPackingDomain::bottom(); } else { VarPackingDomain result = *this; result.meet_binary_op_with(other, MeetOperator{}); return result; } } void narrow_with(const VarPackingDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->meet_binary_op_with(other, NarrowingOperator{}); } } VarPackingDomain narrowing(const VarPackingDomain& other) const override { if (this->is_bottom() || other.is_bottom()) { return VarPackingDomain::bottom(); } else { VarPackingDomain result = *this; result.meet_binary_op_with(other, NarrowingOperator{}); return result; } } void narrow_threshold_with(const VarPackingDomain& other, const Number& threshold) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->meet_binary_op_with(other, NarrowingThresholdOperator{threshold}); } } VarPackingDomain narrowing_threshold(const VarPackingDomain& other, const Number& threshold) const override { if (this->is_bottom() || other.is_bottom()) { return VarPackingDomain::bottom(); } else { VarPackingDomain result = *this; result.meet_binary_op_with(other, NarrowingThresholdOperator{threshold}); return result; } } void assign(VariableRef x, int n) override { this->assign(x, Number(n)); } void assign(VariableRef x, const Number& n) override { if (this->is_bottom()) { return; } this->_equiv_relation.forget(x); Domain domain = Domain::top(); domain.assign(x, n); this->_equiv_relation.add_equiv_class(x, std::move(domain)); } void assign(VariableRef x, VariableRef y) override { if (this->is_bottom()) { return; } if (x == y) { return; } if (!this->_equiv_relation.contains(y)) { this->_equiv_relation.add_equiv_class(y); } this->_equiv_relation.forget(x); this->_equiv_relation.add_var_to_equiv_class(x, y); EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(y); Domain domain = equiv_class.domain(); domain.assign(x, y); equiv_class.set_domain(std::move(domain)); } void assign(VariableRef x, const LinearExpressionT& e) override { if (this->is_bottom()) { return; } if (e.is_constant()) { this->assign(x, e.constant()); return; } boost::optional< VariableRef > root; for (const auto& term : e) { this->merge_existing_equiv_classes(root, term.first); } for (const auto& term : e) { this->merge_unexisting_equiv_classes(root, term.first); } if (e.factor(x) == 0) { this->_equiv_relation.forget(x); this->_equiv_relation.add_var_to_equiv_class(x, *root); } // Otherwise, x has already been merged EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(*root); Domain domain = equiv_class.domain(); domain.assign(x, e); equiv_class.set_domain(std::move(domain)); } private: /// \brief Add a relation x = f(y, z) EquivalenceClass& add_relation(VariableRef x, VariableRef y, VariableRef z) { boost::optional< VariableRef > root; this->merge_existing_equiv_classes(root, y); this->merge_existing_equiv_classes(root, z); this->merge_unexisting_equiv_classes(root, y); this->merge_unexisting_equiv_classes(root, z); if (x != y && x != z) { this->_equiv_relation.forget(x); this->_equiv_relation.add_var_to_equiv_class(x, *root); } // Otherwise, x has already been merged return this->_equiv_relation.find_equiv_class(*root); } /// \brief Add a relation x = f(y) EquivalenceClass& add_relation(VariableRef x, VariableRef y) { if (!this->_equiv_relation.contains(y)) { this->_equiv_relation.add_equiv_class(y); } if (x != y) { this->_equiv_relation.forget(x); this->_equiv_relation.add_var_to_equiv_class(x, y); } return this->_equiv_relation.find_equiv_class(y); } public: void apply(BinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { if (this->is_bottom()) { return; } EquivalenceClass& equiv_class = this->add_relation(x, y, z); Domain domain = equiv_class.domain(); domain.apply(op, x, y, z); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); } else { equiv_class.set_domain(std::move(domain)); } } void apply(BinaryOperator op, VariableRef x, VariableRef y, const Number& z) override { if (this->is_bottom()) { return; } EquivalenceClass& equiv_class = this->add_relation(x, y); Domain domain = equiv_class.domain(); domain.apply(op, x, y, z); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); } else { equiv_class.set_domain(std::move(domain)); } } void apply(BinaryOperator op, VariableRef x, const Number& y, VariableRef z) override { if (this->is_bottom()) { return; } EquivalenceClass& equiv_class = add_relation(x, z); Domain domain = equiv_class.domain(); domain.apply(op, x, y, z); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); } else { equiv_class.set_domain(std::move(domain)); } } void add(const LinearConstraintT& cst) override { if (this->is_bottom()) { return; } if (cst.num_terms() == 0) { if (cst.is_contradiction()) { this->set_to_bottom(); } return; } boost::optional< VariableRef > root; for (const auto& term : cst) { this->merge_existing_equiv_classes(root, term.first); } for (const auto& term : cst) { this->merge_unexisting_equiv_classes(root, term.first); } EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(*root); Domain domain = equiv_class.domain(); domain.add(cst); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); } else { equiv_class.set_domain(std::move(domain)); } } void add(const LinearConstraintSystemT& csts) override { for (const LinearConstraintT& cst : csts) { this->add(cst); } } void set(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } if (value.is_bottom()) { this->set_to_bottom(); return; } this->_equiv_relation.forget(x); if (value.is_top()) { return; } Domain domain = Domain::top(); domain.set(x, value); this->_equiv_relation.add_equiv_class(x, std::move(domain)); } void set(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } if (value.is_bottom()) { this->set_to_bottom(); return; } this->_equiv_relation.forget(x); if (value.is_top()) { return; } Domain domain = Domain::top(); domain.set(x, value); this->_equiv_relation.add_equiv_class(x, std::move(domain)); } void set(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } if (value.is_bottom()) { this->set_to_bottom(); return; } this->_equiv_relation.forget(x); if (value.is_top()) { return; } Domain domain = Domain::top(); domain.set(x, value); this->_equiv_relation.add_equiv_class(x, std::move(domain)); } void refine(VariableRef x, const IntervalT& value) override { if (this->is_bottom()) { return; } if (value.is_bottom()) { this->set_to_bottom(); return; } if (value.is_top()) { return; } if (this->_equiv_relation.contains(x)) { EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(x); Domain domain = equiv_class.domain(); domain.refine(x, value); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); } else { equiv_class.set_domain(std::move(domain)); } } else { Domain domain = Domain::top(); domain.set(x, value); this->_equiv_relation.add_equiv_class(x, std::move(domain)); } } void refine(VariableRef x, const CongruenceT& value) override { if (this->is_bottom()) { return; } if (value.is_bottom()) { this->set_to_bottom(); return; } if (value.is_top()) { return; } if (this->_equiv_relation.contains(x)) { EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(x); Domain domain = equiv_class.domain(); domain.refine(x, value); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); } else { equiv_class.set_domain(std::move(domain)); } } else { Domain domain = Domain::top(); domain.set(x, value); this->_equiv_relation.add_equiv_class(x, std::move(domain)); } } void refine(VariableRef x, const IntervalCongruenceT& value) override { if (this->is_bottom()) { return; } if (value.is_bottom()) { this->set_to_bottom(); return; } if (value.is_top()) { return; } if (this->_equiv_relation.contains(x)) { EquivalenceClass& equiv_class = this->_equiv_relation.find_equiv_class(x); Domain domain = equiv_class.domain(); domain.refine(x, value); domain.normalize(); if (domain.is_bottom()) { this->set_to_bottom(); } else { equiv_class.set_domain(std::move(domain)); } } else { Domain domain = Domain::top(); domain.set(x, value); this->_equiv_relation.add_equiv_class(x, std::move(domain)); } } void forget(VariableRef x) override { if (this->is_bottom()) { return; } this->_equiv_relation.forget(x); } private: /// \brief Forget the equivalence class containing `x` void forget_equiv_class(VariableRef x) { this->_equiv_relation.forget_equiv_class(x); } public: IntervalT to_interval(VariableRef x) const override { if (this->is_bottom()) { return IntervalT::bottom(); } else { if (this->_equiv_relation.contains(x)) { return this->_equiv_relation.cfind_domain(x).to_interval(x); } else { return IntervalT::top(); } } } IntervalT to_interval(const LinearExpressionT& e) const override { return Parent::to_interval(e); } CongruenceT to_congruence(VariableRef x) const override { if (this->is_bottom()) { return CongruenceT::bottom(); } else { if (this->_equiv_relation.contains(x)) { return this->_equiv_relation.cfind_domain(x).to_congruence(x); } else { return CongruenceT::top(); } } } CongruenceT to_congruence(const LinearExpressionT& e) const override { return Parent::to_congruence(e); } IntervalCongruenceT to_interval_congruence(VariableRef x) const override { if (this->is_bottom()) { return IntervalCongruenceT::bottom(); } else { if (this->_equiv_relation.contains(x)) { return this->_equiv_relation.cfind_domain(x).to_interval_congruence(x); } else { return IntervalCongruenceT::top(); } } } IntervalCongruenceT to_interval_congruence( const LinearExpressionT& e) const override { return Parent::to_interval_congruence(e); } LinearConstraintSystemT to_linear_constraint_system() const override { if (this->is_bottom()) { return LinearConstraintSystemT(LinearConstraintT::contradiction()); } LinearConstraintSystemT csts; for (const auto& equiv_class : this->_equiv_relation) { csts.add(equiv_class.second.domain().to_linear_constraint_system()); } return csts; } void dump(std::ostream& o) const override { #if 1 this->to_linear_constraint_system().dump(o); #else this->_equiv_relation.dump(o); #endif } static std::string name() { return Domain::name() + " with variable packing"; } }; // end class VarPackingDomain } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/pointer/000077500000000000000000000000001473507761200240155ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/pointer/operator.hpp000066400000000000000000000045361473507761200263710ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Operators for pointer abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once namespace ikos { namespace core { namespace pointer { /// \brief Predicate on pointers enum class Predicate { EQ, NE, GT, GE, LT, LE, }; } // end namespace pointer } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/pointer/solver.hpp000066400000000000000000000572351473507761200260540ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Solver of pointer constraints systems * * This analysis operates on a simplified version of the constraint resolution * algorithm described in the following paper: * * Arnaud Venet. A Scalable Nonuniform Pointer Analysis for Embedded Programs. * In Proceedings of the International Static Analysis Symposium, SAS 04, * Verona, Italy. Lecture Notes in Computer Science, pages 149-164, * volume 3148, Springer 2004. * * Author: Arnaud J. Venet * * Contributors: * * Jorge A. Navas * * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace pointer { /// \brief Base class for pointer operands template < typename VariableRef, typename MemoryLocationRef > class Operand { public: enum OperandKind { VariableKind, AddressKind }; protected: // Kind of operand OperandKind _kind; protected: /// \brief Protected constructor explicit Operand(OperandKind kind) : _kind(kind) {} public: /// \brief No copy constructor Operand(const Operand&) = delete; /// \brief No move constructor Operand(Operand&&) = delete; /// \brief No copy assignment operator Operand& operator=(const Operand&) = delete; /// \brief No move assignment operator Operand& operator=(Operand&&) = delete; /// \brief Destructor virtual ~Operand() = default; /// \brief Get the kind of operand OperandKind kind() const { return this->_kind; } /// \brief Dump the operand for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class Operand /// \brief Represents a pointer variable plus an offset /// /// For instance, `p + [0, 4]` template < typename VariableRef, typename MemoryLocationRef > class VariableOperand final : public Operand< VariableRef, MemoryLocationRef > { private: using OperandT = Operand< VariableRef, MemoryLocationRef >; private: // Pointer variable VariableRef _var; // Offset interval, in bytes machine_int::Interval _offset; private: /// \brief Private constructor VariableOperand(VariableRef var, machine_int::Interval offset) : OperandT(OperandT::VariableKind), _var(var), _offset(std::move(offset)) {} public: /// \brief Static constructor static std::unique_ptr< VariableOperand > create( VariableRef var, machine_int::Interval offset) { return std::unique_ptr< VariableOperand >( new VariableOperand(var, std::move(offset))); } /// \brief Return the pointer variable VariableRef var() const { return this->_var; } /// \brief Return the offset interval, in bytes const machine_int::Interval& offset() const { return this->_offset; } void dump(std::ostream& o) const override { DumpableTraits< VariableRef >::dump(o, this->_var); o << " + "; o << this->_offset; } }; // end class VariableOperand /// \brief Represents an address (i.e., memory location) plus an offset /// /// For instance, `&x + [0, 4]` template < typename VariableRef, typename MemoryLocationRef > class AddressOperand final : public Operand< VariableRef, MemoryLocationRef > { private: using OperandT = Operand< VariableRef, MemoryLocationRef >; private: // Address MemoryLocationRef _address; // Offset interval, in bytes machine_int::Interval _offset; private: /// \brief Private constructor AddressOperand(MemoryLocationRef address, machine_int::Interval offset) : OperandT(OperandT::AddressKind), _address(address), _offset(std::move(offset)) {} public: /// \brief Static constructor static std::unique_ptr< AddressOperand > create( MemoryLocationRef address, machine_int::Interval offset) { return std::unique_ptr< AddressOperand >( new AddressOperand(address, std::move(offset))); } /// \brief Return the address (i.e., memory location) MemoryLocationRef address() const { return this->_address; } /// \brief Return the offset interval, in bytes const machine_int::Interval& offset() const { return this->_offset; } void dump(std::ostream& o) const override { DumpableTraits< MemoryLocationRef >::dump(o, this->_address); o << " + "; o << this->_offset; } }; // end class AddressOperand /// \brief Base class for pointer constraints template < typename VariableRef, typename MemoryLocationRef > class Constraint { public: enum ConstraintKind { AssignKind, StoreKind, LoadKind }; protected: // Kind of operand ConstraintKind _kind; protected: /// \brief Protected constructor explicit Constraint(ConstraintKind kind) : _kind(kind) {} public: /// \brief No copy constructor Constraint(const Constraint&) = delete; /// \brief No move constructor Constraint(Constraint&&) = delete; /// \brief No copy assignment operator Constraint& operator=(const Constraint&) = delete; /// \brief No move assignment operator Constraint& operator=(Constraint&&) = delete; /// \brief Destructor virtual ~Constraint() = default; /// \brief Get the kind of constraint ConstraintKind kind() const { return this->_kind; } /// \brief Dump the constraint for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class Constraint /// \brief Pointer assignment constraint /// /// Represents a constraint `p = operand` template < typename VariableRef, typename MemoryLocationRef > class AssignConstraint final : public Constraint< VariableRef, MemoryLocationRef > { private: using OperandT = Operand< VariableRef, MemoryLocationRef >; using ConstraintT = Constraint< VariableRef, MemoryLocationRef >; private: // Result pointer variable VariableRef _result; // Operand std::unique_ptr< OperandT > _operand; private: /// \brief Private constructor AssignConstraint(VariableRef result, std::unique_ptr< OperandT > operand) : ConstraintT(ConstraintT::AssignKind), _result(result), _operand(std::move(operand)) {} public: /// \brief Static constructor static std::unique_ptr< AssignConstraint > create( VariableRef result, std::unique_ptr< OperandT > operand) { return std::unique_ptr< AssignConstraint >( new AssignConstraint(result, std::move(operand))); } /// \brief Return the result variable VariableRef result() const { return this->_result; } /// \brief Return the operand const OperandT* operand() const { return this->_operand.get(); } void dump(std::ostream& o) const override { DumpableTraits< VariableRef >::dump(o, this->_result); o << " = "; this->_operand->dump(o); } }; // end class AssignConstraint /// \brief Store constraint /// /// Represents a constraint `*p = operand` template < typename VariableRef, typename MemoryLocationRef > class StoreConstraint final : public Constraint< VariableRef, MemoryLocationRef > { private: using OperandT = Operand< VariableRef, MemoryLocationRef >; using ConstraintT = Constraint< VariableRef, MemoryLocationRef >; private: // Pointer variable VariableRef _pointer; // Operand std::unique_ptr< OperandT > _operand; private: /// \brief Private constructor StoreConstraint(VariableRef pointer, std::unique_ptr< OperandT > operand) : ConstraintT(ConstraintT::StoreKind), _pointer(pointer), _operand(std::move(operand)) {} public: /// \brief Static constructor static std::unique_ptr< StoreConstraint > create( VariableRef pointer, std::unique_ptr< OperandT > operand) { return std::unique_ptr< StoreConstraint >( new StoreConstraint(pointer, std::move(operand))); } /// \brief Return the pointer variable VariableRef pointer() const { return this->_pointer; } /// \brief Return the operand const OperandT* operand() const { return this->_operand.get(); } void dump(std::ostream& o) const override { o << "*"; DumpableTraits< VariableRef >::dump(o, this->_pointer); o << " = "; this->_operand->dump(o); } }; // end class StoreConstraint /// \brief Load constraint /// /// Represents a constraint `p = *operand` template < typename VariableRef, typename MemoryLocationRef > class LoadConstraint final : public Constraint< VariableRef, MemoryLocationRef > { private: using OperandT = Operand< VariableRef, MemoryLocationRef >; using ConstraintT = Constraint< VariableRef, MemoryLocationRef >; private: // Result pointer variable VariableRef _result; // Operand std::unique_ptr< OperandT > _operand; private: /// \brief Private constructor LoadConstraint(VariableRef result, std::unique_ptr< OperandT > operand) : ConstraintT(ConstraintT::LoadKind), _result(result), _operand(std::move(operand)) {} public: /// \brief Static constructor static std::unique_ptr< LoadConstraint > create( VariableRef result, std::unique_ptr< OperandT > operand) { return std::unique_ptr< LoadConstraint >( new LoadConstraint(result, std::move(operand))); } /// \brief Return the result pointer variable VariableRef result() const { return this->_result; } /// \brief Return the operand const OperandT* operand() const { return this->_operand.get(); } void dump(std::ostream& o) const override { DumpableTraits< VariableRef >::dump(o, this->_result); o << " = *("; this->_operand->dump(o); o << ")"; } }; // end class LoadConstraint /// \brief System of pointer constraints template < typename VariableRef, typename MemoryLocationRef > class ConstraintSystem { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); static_assert(core::IsMemoryLocation< MemoryLocationRef >::value, "MemoryLocationRef does not meet the requirements for memory " "location types"); private: /// \brief Hash for VariableRef struct VariableHash { std::size_t operator()(VariableRef v) const { return std::hash< Index >()(IndexableTraits< VariableRef >::index(v)); } }; /// \brief Hash for MemoryLocationRef struct MemoryLocationHash { std::size_t operator()(MemoryLocationRef m) const { return std::hash< Index >()( IndexableTraits< MemoryLocationRef >::index(m)); } }; using OperandT = Operand< VariableRef, MemoryLocationRef >; using VariableOperandT = VariableOperand< VariableRef, MemoryLocationRef >; using AddressOperandT = AddressOperand< VariableRef, MemoryLocationRef >; using ConstraintT = Constraint< VariableRef, MemoryLocationRef >; using AssignConstraintT = AssignConstraint< VariableRef, MemoryLocationRef >; using StoreConstraintT = StoreConstraint< VariableRef, MemoryLocationRef >; using LoadConstraintT = LoadConstraint< VariableRef, MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointsToSetT = PointsToSet< MemoryLocationRef >; using ConstraintVector = std::vector< std::unique_ptr< ConstraintT > >; using PointerMap = std::unordered_map< VariableRef, PointerAbsValueT, VariableHash >; using MemoryMap = std:: unordered_map< MemoryLocationRef, PointerAbsValueT, MemoryLocationHash >; public: using PointerIterator = typename PointerMap::const_iterator; using MemoryIterator = typename MemoryMap::const_iterator; private: // List of pointer constraints ConstraintVector _csts; // Map from pointer variables to pointer abstract values PointerMap _pointers; // Map from memory locations to pointer abstract values // // `_memory[m]` contains the abstract union of all the pointers stored at `m` MemoryMap _memory; // Bit-width of pointer offsets (e.g, 32 or 64) uint64_t _offsets_bit_width; // Signedness of pointer offsets (usually Unsigned) Signedness _offsets_sign; // Number of iterations std::size_t _iteration = 0; // Change seen during iteration bool _change_seen = false; public: /// \brief Default constructor ConstraintSystem(uint64_t offsets_bit_width, Signedness offsets_sign) : _offsets_bit_width(offsets_bit_width), _offsets_sign(offsets_sign) {} /// \brief No copy constructor ConstraintSystem(const ConstraintSystem&) = delete; /// \brief Move constructor ConstraintSystem(ConstraintSystem&&) = default; /// \brief No copy assignment operator ConstraintSystem& operator=(const ConstraintSystem&) = delete; /// \brief Move assignment operator ConstraintSystem& operator=(ConstraintSystem&&) = default; /// \brief Destructor ~ConstraintSystem() = default; /// \brief Add a pointer constraint void add(std::unique_ptr< ConstraintT > cst) { this->_csts.emplace_back(std::move(cst)); } private: class BinaryOp { public: /// \brief Constructor BinaryOp() = default; /// \brief No copy constructor BinaryOp(const BinaryOp&) = delete; /// \brief No move constructor BinaryOp(BinaryOp&&) = delete; /// \brief No copy assignment operator BinaryOp& operator=(const BinaryOp&) = delete; /// \brief No move assignment operator BinaryOp& operator=(BinaryOp&&) = delete; /// \brief Destructor virtual ~BinaryOp() = default; virtual bool convergence_achieved(const PointerAbsValueT& before, const PointerAbsValueT& after) const = 0; virtual void apply(PointerAbsValueT& before, const PointerAbsValueT& after, std::size_t iteration) const = 0; }; class Extrapolate final : public BinaryOp { private: std::size_t _threshold; public: explicit Extrapolate(std::size_t threshold) : _threshold(threshold) {} bool convergence_achieved(const PointerAbsValueT& before, const PointerAbsValueT& after) const override { return after.leq(before); } void apply(PointerAbsValueT& before, const PointerAbsValueT& after, std::size_t iteration) const override { if (iteration < this->_threshold) { before.join_with(after); } else { before.widen_with(after); } } }; class Refine final : public BinaryOp { public: // This refinement is not a narrowing since it will not ensure // convergence. Thus, we need to make sure it is called a finite // number of times. public: Refine() = default; bool convergence_achieved( const PointerAbsValueT& /*before*/, const PointerAbsValueT& /*after*/) const override { return false; } void apply(PointerAbsValueT& before, const PointerAbsValueT& after, std::size_t /*iteration*/) const override { if (after.leq(before)) { // descending chain before.narrow_with(after); } else { // no descending chain before.join_with(after); } } }; /// \brief Perform a step of the fixpoint convergence using the given operator /// /// It processes all the constraints once. void step(const BinaryOp& op) { for (auto it = this->_csts.begin(), et = this->_csts.end(); it != et; ++it) { this->process_constraint(it->get(), op); } } /// \brief Process the given constraint /// /// It updates this->_pointers and this->_memory void process_constraint(const ConstraintT* cst, const BinaryOp& op) { switch (cst->kind()) { case ConstraintT::AssignKind: { auto assign = static_cast< const AssignConstraintT* >(cst); PointerAbsValueT op_value = this->process_operand(assign->operand()); this->add_pointer(assign->result(), op_value, op); } break; case ConstraintT::StoreKind: { auto store = static_cast< const StoreConstraintT* >(cst); PointerAbsValueT ptr_value = this->get_pointer(store->pointer()); PointerAbsValueT op_value = this->process_operand(store->operand()); if (ptr_value.is_bottom()) { return; } for (MemoryLocationRef addr : ptr_value.points_to()) { this->add_memory(addr, op_value, op); } } break; case ConstraintT::LoadKind: { auto load = static_cast< const LoadConstraintT* >(cst); PointerAbsValueT op_value = this->process_operand(load->operand()); if (op_value.is_bottom()) { return; } for (MemoryLocationRef addr : op_value.points_to()) { this->add_pointer(load->result(), this->get_memory(addr), op); } } break; default: { ikos_unreachable("unexpected kind"); } } } /// \brief Return the abstract value for the given operand PointerAbsValueT process_operand(const OperandT* op) { switch (op->kind()) { case OperandT::VariableKind: { auto variable_op = static_cast< const VariableOperandT* >(op); PointerAbsValueT value = this->get_pointer(variable_op->var()); value.add_offset(variable_op->offset()); return value; } case OperandT::AddressKind: { auto address_op = static_cast< const AddressOperandT* >(op); return PointerAbsValueT(Uninitialized::top(), Nullity::top(), PointsToSetT{address_op->address()}, address_op->offset()); } default: { ikos_unreachable("unexpected kind"); } } } public: /// \brief Return the abstract value for the given pointer PointerAbsValueT get_pointer(VariableRef p) { auto it = this->_pointers.find(p); if (it == this->_pointers.end()) { return PointerAbsValueT::bottom(this->_offsets_bit_width, this->_offsets_sign); } else { return it->second; } } /// \brief Begin iterator over the pairs (pointer, abstract value) PointerIterator pointer_begin() const { return this->_pointers.cbegin(); } /// \brief End iterator over the pairs (pointer, abstract value) PointerIterator pointer_end() const { return this->_pointers.cend(); } /// \brief Return the abstract value for pointers stored at the given memory /// location PointerAbsValueT get_memory(MemoryLocationRef m) { auto it = this->_memory.find(m); if (it == this->_memory.end()) { return PointerAbsValueT::bottom(this->_offsets_bit_width, this->_offsets_sign); } else { return it->second; } } /// \brief Begin iterator over the pairs (memory location, abstract value) MemoryIterator memory_begin() const { return this->_memory.cbegin(); } /// \brief End iterator over the pairs (memory location, abstract value) MemoryIterator memory_end() const { return this->_memory.cend(); } private: /// \brief Add a pointer abstraction for the given pointer void add_pointer(VariableRef p, const PointerAbsValueT& value, const BinaryOp& op) { // Get a reference on the current value auto it = this->_pointers.find(p); if (it == this->_pointers.end()) { // add default value auto res = this->_pointers .emplace(p, PointerAbsValueT::bottom(this->_offsets_bit_width, this->_offsets_sign)); it = res.first; } this->add_apply(it->second, value, op); } /// \brief Add a pointer abstraction for the given memory location void add_memory(MemoryLocationRef m, const PointerAbsValueT& value, const BinaryOp& op) { // Get a reference on the current value auto it = this->_memory.find(m); if (it == this->_memory.end()) { // add default value auto res = this->_memory .emplace(m, PointerAbsValueT::bottom(this->_offsets_bit_width, this->_offsets_sign)); it = res.first; } this->add_apply(it->second, value, op); } /// \brief Add `after` in `before`, applying the given binary operator `op` void add_apply(PointerAbsValueT& before, const PointerAbsValueT& after, const BinaryOp& op) { if (!op.convergence_achieved(before, after)) { this->_change_seen = true; op.apply(before, after, this->_iteration); } } public: /// \brief Solve the constraint system void solve(std::size_t widening_threshold = 50, std::size_t /*narrowing_threshold*/ = 1) { this->_iteration = 0; Extrapolate widening_op(widening_threshold); do { this->_iteration++; this->_change_seen = false; this->step(widening_op); } while (this->_change_seen); // TODO(marthaud): commented out because this is unsound. // // The algorithm here does not compute a proper fixpoint, because the // widening and narrowing operations should be applied between two // consecutive iterations. We can have several constraints updating the // same pointer, thus calling the widening/narrowing several times on the // same iteration. This is unsound. // // As a short fix, the narrowing step is disabled. // // See https://babelfish.arc.nasa.gov/jira/projects/IKOS/issues/IKOS-71 // Refine narrowing_op; // this->_iteration = 0; // for (; this->_iteration < narrowing_threshold; ++this->_iteration) { // this->step(narrowing_op); // } } /// \brief Dump the constraint system, for debugging purpose void dump(std::ostream& o) const { o << "{\n"; for (auto it = this->_csts.begin(), et = this->_csts.end(); it != et; ++it) { o << " "; it->get()->dump(o); o << "\n"; } o << "}"; } }; // end class ConstraintSystem } // end namespace pointer } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/scalar/000077500000000000000000000000001473507761200236025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/scalar/abstract_domain.hpp000066400000000000000000000456531473507761200274620ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for scalar abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace scalar { /// \brief Base class for scalar abstract domains /// /// A scalar is either a machine integer, a floating point or a pointer. template < typename VariableRef, typename MemoryLocationRef, typename Derived > class AbstractDomain : public core::AbstractDomain< Derived > { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); static_assert(machine_int::IsVariable< VariableRef >::value, "VariableRef must implement machine_int::VariableTraits"); static_assert(scalar::IsVariable< VariableRef >::value, "VariableRef must implement scalar::VariableTraits"); static_assert(core::IsMemoryLocation< MemoryLocationRef >::value, "MemoryLocationRef does not meet the requirements for memory " "location types"); public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; public: /// \brief Perform the widening of two abstract values with a threshold virtual void widen_threshold_with(const Derived& other, const MachineInt& threshold) = 0; /// \brief Perform the widening of two abstract values with a threshold virtual Derived widening_threshold(const Derived& other, const MachineInt& threshold) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.widen_threshold_with(other, threshold); return tmp; } /// \brief Perform the narrowing of two abstract values with a threshold virtual void narrow_threshold_with(const Derived& other, const MachineInt& threshold) = 0; /// \brief Perform the narrowing of two abstract values with a threshold virtual Derived narrowing_threshold(const Derived& other, const MachineInt& threshold) const { Derived tmp(static_cast< const Derived& >(*this)); tmp.narrow_threshold_with(other, threshold); return tmp; } /// \name Uninitialized abstract domain methods /// @{ /// \brief Add the constraint `x == initialized` virtual void uninit_assert_initialized(VariableRef x) = 0; /// \brief Return true if `x` is initialized, otherwise false virtual bool uninit_is_initialized(VariableRef x) const = 0; /// \brief Return true if `x` is uninitialized, otherwise false virtual bool uninit_is_uninitialized(VariableRef x) const = 0; /// \brief Refine the uninitialized value of a variable virtual void uninit_refine(VariableRef x, Uninitialized value) = 0; /// \brief Get the uninitialized value for the given variable virtual Uninitialized uninit_to_uninitialized(VariableRef x) const = 0; /// @} /// \name Machine integer abstract domain methods /// @{ /// \brief Assign `x = n` virtual void int_assign(VariableRef x, const MachineInt& n) = 0; /// \brief Assign `x = undefined` virtual void int_assign_undef(VariableRef x) = 0; /// \brief Assign `x` to a non deterministic integer virtual void int_assign_nondet(VariableRef x) = 0; /// \brief Assign `x = y` virtual void int_assign(VariableRef x, VariableRef y) = 0; /// \brief Assign `x = e` /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of `x`. virtual void int_assign(VariableRef x, const IntLinearExpression& e) = 0; /// \brief Apply `x = op y` virtual void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) = 0; /// \brief Apply `x = y op z` virtual void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) = 0; /// \brief Apply `x = y op z` virtual void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) = 0; /// \brief Apply `x = y op z` virtual void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) = 0; // \brief Add the constraint `x pred y` virtual void int_add(IntPredicate pred, VariableRef x, VariableRef y) = 0; // \brief Add the constraint `x pred y` virtual void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) = 0; // \brief Add the constraint `x pred y` virtual void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) = 0; /// \brief Set the interval value of a variable virtual void int_set(VariableRef x, const IntInterval& value) = 0; /// \brief Set the congruence value of a variable virtual void int_set(VariableRef x, const IntCongruence& value) = 0; /// \brief Set the interval-congruence value of a variable virtual void int_set(VariableRef x, const IntIntervalCongruence& value) = 0; /// \brief Refine the value of a variable with an interval virtual void int_refine(VariableRef x, const IntInterval& value) = 0; /// \brief Refine the value of a variable with a congruence virtual void int_refine(VariableRef x, const IntCongruence& value) = 0; /// \brief Refine the value of a variable with an interval-congruence virtual void int_refine(VariableRef x, const IntIntervalCongruence& value) = 0; /// \brief Forget an integer variable virtual void int_forget(VariableRef x) = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the value of `x` as an interval virtual IntInterval int_to_interval(VariableRef x) const = 0; /// \brief Projection to an interval /// /// Return an overapproximation of the linear expression `e` as an interval /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual IntInterval int_to_interval(const IntLinearExpression& e) const = 0; /// \brief Projection to a congruence /// /// Return an overapproximation of the value of `x` as a congruence virtual IntCongruence int_to_congruence(VariableRef x) const = 0; /// \brief Projection to a congruence /// /// Return an overapproximation of the linear expression `e` as a congruence /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual IntCongruence int_to_congruence( const IntLinearExpression& e) const = 0; /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the value of `x` as an interval-congruence virtual IntIntervalCongruence int_to_interval_congruence( VariableRef x) const = 0; /// \brief Projection to an interval-congruence /// /// Return an overapproximation of the linear expression `e` as an /// interval-congruence /// /// Note that it wraps on integer overflow. /// Note that it will automatically cast variables to the type of /// `e.constant()`. virtual IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const = 0; /// @} /// \name Non-negative loop counter abstract domain methods /// @{ /// \brief Mark the variable `x` as a non-negative loop counter virtual void counter_mark(VariableRef x) = 0; /// \brief Mark the variable `x` as a normal variable, without losing /// information virtual void counter_unmark(VariableRef x) = 0; /// \brief Initialize a non-negative loop counter: `x = c` /// /// Precondition: `c >= 0` virtual void counter_init(VariableRef x, const MachineInt& c) = 0; /// \brief Increment a non-negative loop counter counter: `x += k` /// /// Precondition: `k >= 0` virtual void counter_incr(VariableRef x, const MachineInt& k) = 0; /// \brief Forget a non-negative loop counter virtual void counter_forget(VariableRef x) = 0; /// @} /// \name Floating point abstract domain methods /// @{ /// \brief Assign `x = undefined` virtual void float_assign_undef(VariableRef x) = 0; /// \brief Assign `x` to a non deterministic floating point virtual void float_assign_nondet(VariableRef x) = 0; /// \brief Assign `x = y` virtual void float_assign(VariableRef x, VariableRef y) = 0; /// \brief Forget a floating point variable virtual void float_forget(VariableRef x) = 0; /// @} /// \name Nullity abstract domain methods /// @{ /// \brief Add the constraint `p == null` virtual void nullity_assert_null(VariableRef p) = 0; /// \brief Add the constraint `p != null` virtual void nullity_assert_non_null(VariableRef p) = 0; /// \brief Return true if `p` is null, otherwise false virtual bool nullity_is_null(VariableRef p) const = 0; /// \brief Return true if `p` is non null, otherwise false virtual bool nullity_is_non_null(VariableRef p) const = 0; /// \brief Set the nullity of the pointer `p` to the given value virtual void nullity_set(VariableRef p, Nullity value) = 0; /// \brief Refine the pointer `p` with the given nullity value virtual void nullity_refine(VariableRef p, Nullity value) = 0; /// \brief Get the nullity value for the given variable virtual Nullity nullity_to_nullity(VariableRef p) const = 0; /// @} /// \name Pointer abstract domain methods /// @{ /// \brief Assign `p` to an address (i.e, memory location) /// /// This is equivalent to `p = &x` or `p = malloc()` virtual void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) = 0; /// \brief Assign `p = null` virtual void pointer_assign_null(VariableRef p) = 0; /// \brief Assign `p = undefined` virtual void pointer_assign_undef(VariableRef p) = 0; /// \brief Assign `p` to a non deterministic pointer virtual void pointer_assign_nondet(VariableRef p) = 0; /// \brief Assign `p = q` virtual void pointer_assign(VariableRef p, VariableRef q) = 0; /// \brief Assign `p = q + o` virtual void pointer_assign(VariableRef p, VariableRef q, VariableRef o) = 0; /// \brief Assign `p = q + o` virtual void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) = 0; /// \brief Assign `p = q + o` virtual void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) = 0; // \brief Add the constraint `p pred q` virtual void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) = 0; /// \brief Refine the pointer `p` with the given set of addresses virtual void pointer_refine(VariableRef p, const PointsToSetT& addrs) = 0; /// \brief Refine the pointer `p` with the given set of addresses and offsets virtual void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) = 0; /// \brief Refine the pointer `p` with the given pointer abstract value virtual void pointer_refine(VariableRef p, const PointerAbsValueT& value) = 0; /// \brief Refine the pointer `p` with the given pointer set virtual void pointer_refine(VariableRef p, const PointerSetT& set) = 0; /// \brief Assign `x = offset-of p` virtual void pointer_offset_to_int(VariableRef x, VariableRef p) = 0; /// \brief Project the offset of the pointer `p` to an interval virtual IntInterval pointer_offset_to_interval(VariableRef p) const = 0; /// \brief Project the offset of the pointer `p` to a congruence virtual IntCongruence pointer_offset_to_congruence(VariableRef p) const = 0; /// \brief Project the offset of the pointer `p` to an interval-congruence virtual IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const = 0; /// \brief Return the points-to set of `p` virtual PointsToSetT pointer_to_points_to(VariableRef p) const = 0; /// \brief Return the pointer abstract value of `p` virtual PointerAbsValueT pointer_to_pointer(VariableRef p) const = 0; /// \brief Forget the offset of a pointer variable virtual void pointer_forget_offset(VariableRef p) = 0; /// \brief Forget a pointer variable virtual void pointer_forget(VariableRef p) = 0; /// @} /// \name Dynamically typed variables abstract domain methods /// @{ /// \brief Assign a dynamically typed variable to a dynamically typed variable virtual void dynamic_assign(VariableRef x, VariableRef y) = 0; /// \brief Write undefined to a dynamically typed variable virtual void dynamic_write_undef(VariableRef x) = 0; /// \brief Write a non deterministic value to a dynamically typed variable virtual void dynamic_write_nondet(VariableRef x) = 0; /// \brief Write an integer to a dynamically typed variable virtual void dynamic_write_int(VariableRef x, const MachineInt& n) = 0; /// \brief Write a non deterministic integer to a dynamically typed variable virtual void dynamic_write_nondet_int(VariableRef x) = 0; /// \brief Write an integer variable to a dynamically typed variable virtual void dynamic_write_int(VariableRef x, VariableRef y) = 0; /// \brief Write a non deterministic float to a dynamically typed variable virtual void dynamic_write_nondet_float(VariableRef x) = 0; /// \brief Write null to a dynamically typed variable virtual void dynamic_write_null(VariableRef x) = 0; /// \brief Write a pointer to a dynamically typed variable virtual void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) = 0; /// \brief Write a pointer variable to a dynamically typed variable virtual void dynamic_write_pointer(VariableRef x, VariableRef y) = 0; /// \brief Read an integer variable from a dynamically typed variable virtual void dynamic_read_int(VariableRef x, VariableRef y) = 0; /// \brief Read a pointer variable from a dynamically typed variable virtual void dynamic_read_pointer(VariableRef x, VariableRef y) = 0; /// \brief Return true if `x` is the integer zero virtual bool dynamic_is_zero(VariableRef x) const = 0; /// \brief Return true if `x` is the null pointer virtual bool dynamic_is_null(VariableRef x) const = 0; /// \brief Forget a dynamically typed variable virtual void dynamic_forget(VariableRef x) = 0; /// @} /// \name Scalar abstract domain methods /// @{ /// \brief Assign `x = undefined` virtual void scalar_assign_undef(VariableRef x) = 0; /// \brief Assign `x` to a non deterministic value virtual void scalar_assign_nondet(VariableRef x) = 0; /// \brief Assign `x = ptr-to-int p` virtual void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) = 0; /// \brief Assign `p = int-to-ptr x` virtual void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) = 0; /// \brief Forget a scalar variable virtual void scalar_forget(VariableRef x) = 0; /// @} }; // end class AbstractDomain /// \brief Check if a type is a scalar abstract domain template < typename T, typename VariableRef, typename MemoryLocationRef > struct IsAbstractDomain : std::is_base_of< scalar::AbstractDomain< VariableRef, MemoryLocationRef, T >, T > {}; } // end namespace scalar } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/scalar/composite.hpp000066400000000000000000001615531473507761200263300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Scalar abstract domain made from several underlying abstract domains * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { namespace scalar { /// \brief Scalar abstract domain made from several underlying abstract domains /// /// The composite domain is a scalar domain implemented on top of: /// * An uninitialized abstract domain /// * A machine integer abstract domain /// * A nullity abstract domain /// /// The composite domain can express invariants on machine integer variables, /// floating point variables and pointer variables. /// /// For each machine integer `x`, it keeps track of its value and whether it is /// initialized or not. /// /// For each floating point `x`, it keeps track of whether it is initialized or /// not. /// /// For each pointer `p`, it keep track of its address, its offset, its nullity /// and whether it is initialized or not. /// /// The offset of `p` is modelled directly by the underlying machine integer /// abstract domain `MachineIntDomain` with the special variable /// `offset_var(p)`. /// /// The address of `p` is modelled by keeping track of all possible memory /// locations (e.g., &'s and malloc's) to which `p` may point to, also called /// the points-to set. /// /// The nullity (null/non-null) of `p` is modelled by the underlying nullity /// abstract domain `NullityDomain`. /// /// The initialization of a variable `x` is modelled by the underlying /// uninitialized abstract domain `UninitializedDomain`. template < typename VariableRef, typename MemoryLocationRef, typename UninitializedDomain, typename MachineIntDomain, typename NullityDomain > class CompositeDomain final : public scalar::AbstractDomain< VariableRef, MemoryLocationRef, CompositeDomain< VariableRef, MemoryLocationRef, UninitializedDomain, MachineIntDomain, NullityDomain > > { public: static_assert( uninitialized::IsAbstractDomain< UninitializedDomain, VariableRef >::value, "UninitializedDomain must implement uninitialized::AbstractDomain"); static_assert( machine_int::IsAbstractDomain< MachineIntDomain, VariableRef >::value, "MachineIntDomain must implement machine_int::AbstractDomain"); static_assert(nullity::IsAbstractDomain< NullityDomain, VariableRef >::value, "NullityDomain must implement nullity::AbstractDomain"); public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; private: using PointsToMap = SeparateDomain< VariableRef, PointsToSetT >; using IntVariableTrait = machine_int::VariableTraits< VariableRef >; using ScalarVariableTrait = scalar::VariableTraits< VariableRef >; private: /// \brief Underlying uninitialized abstract domains UninitializedDomain _uninitialized; /// \brief Underlying machine integer abstract domains MachineIntDomain _integer; /// \brief Underlying nullity abstract domains NullityDomain _nullity; /// \brief Map pointer variables to set of addresses PointsToMap _points_to_map; private: /// \brief Constructor CompositeDomain(UninitializedDomain uninitialized, MachineIntDomain integer, NullityDomain nullity, PointsToMap points_to_map) : _uninitialized(std::move(uninitialized)), _integer(std::move(integer)), _nullity(std::move(nullity)), _points_to_map(std::move(points_to_map)) { this->normalize(); } public: /// \brief Create an abstract value with the given underlying abstract values /// /// \param uninitialized The uninitialized abstract value /// \param integer The machine integer abstract value /// \param nullity The nullity abstract value CompositeDomain(UninitializedDomain uninitialized, MachineIntDomain integer, NullityDomain nullity) : _uninitialized(std::move(uninitialized)), _integer(std::move(integer)), _nullity(std::move(nullity)), _points_to_map(PointsToMap::top()) { this->normalize(); } /// \brief Copy constructor CompositeDomain(const CompositeDomain&) noexcept( (std::is_nothrow_copy_constructible< UninitializedDomain >::value) && (std::is_nothrow_copy_constructible< MachineIntDomain >::value) && (std::is_nothrow_copy_constructible< NullityDomain >::value)) = default; /// \brief Move constructor CompositeDomain(CompositeDomain&&) noexcept( (std::is_nothrow_move_constructible< UninitializedDomain >::value) && (std::is_nothrow_move_constructible< MachineIntDomain >::value) && (std::is_nothrow_move_constructible< NullityDomain >::value)) = default; /// \brief Copy assignment operator CompositeDomain& operator=(const CompositeDomain&) noexcept( (std::is_nothrow_copy_assignable< UninitializedDomain >::value) && (std::is_nothrow_copy_assignable< MachineIntDomain >::value) && (std::is_nothrow_copy_assignable< NullityDomain >::value)) = default; /// \brief Move assignment operator CompositeDomain& operator=(CompositeDomain&&) noexcept( (std::is_nothrow_move_assignable< UninitializedDomain >::value) && (std::is_nothrow_move_assignable< MachineIntDomain >::value) && (std::is_nothrow_move_assignable< NullityDomain >::value)) = default; /// \brief Destructor ~CompositeDomain() override = default; /// \name Implement core abstract domain methods /// @{ void normalize() override { this->_uninitialized.normalize(); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_nullity.normalize(); if (this->_nullity.is_bottom()) { this->set_to_bottom(); return; } this->_points_to_map.normalize(); if (this->_points_to_map.is_bottom()) { this->set_to_bottom(); return; } this->_integer.normalize(); if (this->_integer.is_bottom()) { this->set_to_bottom(); return; } } private: /// \brief Return true if the abstract value is bottom /// /// This is not always correct since it doesn't check this->_integer bool is_bottom_fast() const { return this->_uninitialized.is_bottom(); } public: bool is_bottom() const override { return this->_uninitialized.is_bottom() || this->_nullity.is_bottom() || this->_points_to_map.is_bottom() || this->_integer.is_bottom(); } bool is_top() const override { return this->_uninitialized.is_top() && this->_nullity.is_top() && this->_points_to_map.is_top() && this->_integer.is_top(); } void set_to_bottom() override { this->_uninitialized.set_to_bottom(); this->_integer.set_to_bottom(); this->_nullity.set_to_bottom(); this->_points_to_map.set_to_bottom(); } void set_to_top() override { this->_uninitialized.set_to_top(); this->_integer.set_to_top(); this->_nullity.set_to_top(); this->_points_to_map.set_to_top(); } bool leq(const CompositeDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_uninitialized.leq(other._uninitialized) && this->_integer.leq(other._integer) && this->_nullity.leq(other._nullity) && this->_points_to_map.leq(other._points_to_map); } } bool equals(const CompositeDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_uninitialized.equals(other._uninitialized) && this->_integer.equals(other._integer) && this->_nullity.equals(other._nullity) && this->_points_to_map.equals(other._points_to_map); } } void join_with(CompositeDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_with(std::move(other._uninitialized)); this->_integer.join_with(std::move(other._integer)); this->_nullity.join_with(std::move(other._nullity)); this->_points_to_map.join_with(std::move(other._points_to_map)); } } void join_with(const CompositeDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_with(other._uninitialized); this->_integer.join_with(other._integer); this->_nullity.join_with(other._nullity); this->_points_to_map.join_with(other._points_to_map); } } void join_loop_with(CompositeDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_loop_with(std::move(other._uninitialized)); this->_integer.join_loop_with(std::move(other._integer)); this->_nullity.join_loop_with(std::move(other._nullity)); this->_points_to_map.join_loop_with(std::move(other._points_to_map)); } } void join_loop_with(const CompositeDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_loop_with(other._uninitialized); this->_integer.join_loop_with(other._integer); this->_nullity.join_loop_with(other._nullity); this->_points_to_map.join_loop_with(other._points_to_map); } } void join_iter_with(CompositeDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_iter_with(std::move(other._uninitialized)); this->_integer.join_iter_with(std::move(other._integer)); this->_nullity.join_iter_with(std::move(other._nullity)); this->_points_to_map.join_iter_with(std::move(other._points_to_map)); } } void join_iter_with(const CompositeDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_iter_with(other._uninitialized); this->_integer.join_iter_with(other._integer); this->_nullity.join_iter_with(other._nullity); this->_points_to_map.join_iter_with(other._points_to_map); } } void widen_with(const CompositeDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.widen_with(other._uninitialized); this->_integer.widen_with(other._integer); this->_nullity.widen_with(other._nullity); this->_points_to_map.widen_with(other._points_to_map); } } void widen_threshold_with(const CompositeDomain& other, const MachineInt& threshold) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.widen_with(other._uninitialized); this->_integer.widen_threshold_with(other._integer, threshold); this->_nullity.widen_with(other._nullity); this->_points_to_map.widen_with(other._points_to_map); } } void meet_with(const CompositeDomain& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_uninitialized.meet_with(other._uninitialized); this->_integer.meet_with(other._integer); this->_nullity.meet_with(other._nullity); this->_points_to_map.meet_with(other._points_to_map); } } void narrow_with(const CompositeDomain& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_uninitialized.narrow_with(other._uninitialized); this->_integer.narrow_with(other._integer); this->_nullity.narrow_with(other._nullity); this->_points_to_map.narrow_with(other._points_to_map); } } void narrow_threshold_with(const CompositeDomain& other, const MachineInt& threshold) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_uninitialized.narrow_with(other._uninitialized); this->_integer.narrow_threshold_with(other._integer, threshold); this->_nullity.narrow_with(other._nullity); this->_points_to_map.narrow_with(other._points_to_map); } } CompositeDomain join(const CompositeDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return CompositeDomain(this->_uninitialized.join(other._uninitialized), this->_integer.join(other._integer), this->_nullity.join(other._nullity), this->_points_to_map.join(other._points_to_map)); } } CompositeDomain join_loop(const CompositeDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return CompositeDomain(this->_uninitialized.join_loop( other._uninitialized), this->_integer.join_loop(other._integer), this->_nullity.join_loop(other._nullity), this->_points_to_map.join_loop( other._points_to_map)); } } CompositeDomain join_iter(const CompositeDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return CompositeDomain(this->_uninitialized.join_iter( other._uninitialized), this->_integer.join_iter(other._integer), this->_nullity.join_iter(other._nullity), this->_points_to_map.join_iter( other._points_to_map)); } } CompositeDomain widening(const CompositeDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return CompositeDomain(this->_uninitialized.widening( other._uninitialized), this->_integer.widening(other._integer), this->_nullity.widening(other._nullity), this->_points_to_map.widening( other._points_to_map)); } } CompositeDomain widening_threshold( const CompositeDomain& other, const MachineInt& threshold) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return CompositeDomain(this->_uninitialized.widening( other._uninitialized), this->_integer.widening_threshold(other._integer, threshold), this->_nullity.widening(other._nullity), this->_points_to_map.widening( other._points_to_map)); } } CompositeDomain meet(const CompositeDomain& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return CompositeDomain(this->_uninitialized.meet(other._uninitialized), this->_integer.meet(other._integer), this->_nullity.meet(other._nullity), this->_points_to_map.meet(other._points_to_map)); } } CompositeDomain narrowing(const CompositeDomain& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return CompositeDomain(this->_uninitialized.narrowing( other._uninitialized), this->_integer.narrowing(other._integer), this->_nullity.narrowing(other._nullity), this->_points_to_map.narrowing( other._points_to_map)); } } CompositeDomain narrowing_threshold( const CompositeDomain& other, const MachineInt& threshold) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return CompositeDomain(this->_uninitialized.narrowing( other._uninitialized), this->_integer.narrowing_threshold(other._integer, threshold), this->_nullity.narrowing(other._nullity), this->_points_to_map.narrowing( other._points_to_map)); } } /// @} /// \name Implement uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef x) override { this->_uninitialized.assert_initialized(x); } bool uninit_is_initialized(VariableRef x) const override { return this->_uninitialized.is_initialized(x); } bool uninit_is_uninitialized(VariableRef x) const override { return this->_uninitialized.is_uninitialized(x); } void uninit_refine(VariableRef x, Uninitialized value) override { this->_uninitialized.refine(x, value); } Uninitialized uninit_to_uninitialized(VariableRef x) const override { return this->_uninitialized.get(x); } /// @} /// \name Implement machine integer abstract domain methods /// @{ void int_assign(VariableRef x, const MachineInt& n) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.assign(x, n); } void int_assign_undef(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_uninitialized(x); this->_integer.forget(x); } void int_assign_nondet(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void int_assign(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); this->_integer.assign(x, y); } void int_assign(VariableRef x, const IntLinearExpression& e) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } for (const auto& term : e) { ikos_assert(ScalarVariableTrait::is_int(term.first)); this->_uninitialized.assert_initialized(term.first); } if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.assign(x, e); } void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y); } // \brief Assert that x is initialized (throw if not), but only if the // operation, op, is not logical "and" or "or" as these are used in // bitfield operations which may start with uninitialized memory. // Is only called if one of the operands is constant. void assert_initialized_if_not_and_or(IntBinaryOperator op, VariableRef x) { if ((op == IntBinaryOperator::And) || (op == IntBinaryOperator::Or)) { return; } this->_uninitialized.assert_initialized(x); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); ikos_assert(ScalarVariableTrait::is_int(z)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(y); this->_uninitialized.assert_initialized(z); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->assert_initialized_if_not_and_or(op, y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(z)); if (this->is_bottom_fast()) { return; } this->assert_initialized_if_not_and_or(op, z); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y, z); } void int_add(IntPredicate pred, VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(x); this->_uninitialized.assert_initialized(y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_integer.add(pred, x, y); } void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(x); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_integer.add(pred, x, y); } void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_integer.add(pred, x, y); } void int_set(VariableRef x, const IntInterval& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.set(x, value); } void int_set(VariableRef x, const IntCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.set(x, value); } void int_set(VariableRef x, const IntIntervalCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.set(x, value); } void int_refine(VariableRef x, const IntInterval& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.refine(x, value); } void int_refine(VariableRef x, const IntCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.refine(x, value); } void int_refine(VariableRef x, const IntIntervalCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.refine(x, value); } void int_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.forget(x); this->_integer.forget(x); } IntInterval int_to_interval(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); return this->_integer.to_interval(x); } IntInterval int_to_interval(const IntLinearExpression& e) const override { return this->_integer.to_interval(e); } IntCongruence int_to_congruence(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); return this->_integer.to_congruence(x); } IntCongruence int_to_congruence(const IntLinearExpression& e) const override { return this->_integer.to_congruence(e); } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); return this->_integer.to_interval_congruence(x); } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { return this->_integer.to_interval_congruence(e); } /// @} /// \name Implement non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_mark(x); } void counter_unmark(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_incr(x, k); } void counter_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_forget(x); } /// @} /// \name Implement floating point abstract domain methods /// @{ void float_assign_undef(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_float(x)); this->_uninitialized.assign_uninitialized(x); } void float_assign_nondet(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_float(x)); this->_uninitialized.assign_initialized(x); } void float_assign(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_float(x)); ikos_assert(ScalarVariableTrait::is_float(y)); this->_uninitialized.assign(x, y); } void float_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_float(x)); this->_uninitialized.forget(x); } /// @} /// \name Implement nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); this->_nullity.assert_null(p); this->_points_to_map.refine(p, PointsToSetT::empty()); } void nullity_assert_non_null(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); this->_nullity.assert_non_null(p); if (this->_points_to_map.get(p).is_empty()) { this->set_to_bottom(); } } bool nullity_is_null(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_nullity.is_null(p); } bool nullity_is_non_null(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_nullity.is_non_null(p); } void nullity_set(VariableRef p, Nullity value) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_nullity.set(p, value); } void nullity_refine(VariableRef p, Nullity value) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_nullity.refine(p, value); } Nullity nullity_to_nullity(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_nullity.get(p); } /// @} /// \name Implement pointer abstract domain methods /// @{ void pointer_assign(VariableRef p, MemoryLocationRef addr, Nullity nullity) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(p); this->_nullity.set(p, nullity); this->_points_to_map.set(p, PointsToSetT{addr}); VariableRef offset = ScalarVariableTrait::offset_var(p); this->_integer.assign(offset, MachineInt::zero(IntVariableTrait::bit_width(offset), IntVariableTrait::sign(offset))); } void pointer_assign_null(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(p); this->_nullity.assign_null(p); this->_points_to_map.set(p, PointsToSetT::empty()); VariableRef offset = ScalarVariableTrait::offset_var(p); this->_integer.assign(offset, MachineInt::zero(IntVariableTrait::bit_width(offset), IntVariableTrait::sign(offset))); } void pointer_assign_undef(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_uninitialized(p); this->_nullity.forget(p); this->_points_to_map.set(p, PointsToSetT::empty()); this->_integer.forget(ScalarVariableTrait::offset_var(p)); } void pointer_assign_nondet(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(p); this->_nullity.forget(p); this->_points_to_map.forget(p); this->_integer.forget(ScalarVariableTrait::offset_var(p)); } void pointer_assign(VariableRef p, VariableRef q) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(p, q); this->_nullity.assign(p, q); this->_points_to_map.set(p, this->_points_to_map.get(q)); this->_integer.assign(ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q)); } void pointer_assign(VariableRef p, VariableRef q, VariableRef o) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); ikos_assert(ScalarVariableTrait::is_int(o)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(q); this->_uninitialized.assert_initialized(o); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(p); this->_nullity.assign(p, q); this->_points_to_map.set(p, this->_points_to_map.get(q)); this->_integer.apply(IntBinaryOperator::Add, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q), o); } void pointer_assign(VariableRef p, VariableRef q, const MachineInt& o) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(q); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(p); this->_nullity.assign(p, q); this->_points_to_map.set(p, this->_points_to_map.get(q)); this->_integer.apply(IntBinaryOperator::Add, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q), o); } void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(q); for (const auto& term : o) { ikos_assert(ScalarVariableTrait::is_int(term.first)); this->_uninitialized.assert_initialized(term.first); } if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(p); this->_nullity.assign(p, q); this->_points_to_map.set(p, this->_points_to_map.get(q)); VariableRef offset_p = ScalarVariableTrait::offset_var(p); VariableRef offset_q = ScalarVariableTrait::offset_var(q); auto one = MachineInt(1, IntVariableTrait::bit_width(offset_p), IntVariableTrait::sign(offset_p)); IntLinearExpression offset(o); offset.add(one, offset_q); this->_integer.assign(offset_p, offset); } void pointer_add(PointerPredicate pred, VariableRef p, VariableRef q) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); this->_uninitialized.assert_initialized(q); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_nullity.add(pred, p, q); if (this->_nullity.is_bottom()) { this->set_to_bottom(); return; } PointsToSetT addrs_p = this->_points_to_map.get(p); PointsToSetT addrs_q = this->_points_to_map.get(q); Nullity nullity_p = this->_nullity.get(p); Nullity nullity_q = this->_nullity.get(q); switch (pred) { case PointerPredicate::EQ: { // p == q PointsToSetT addrs_pq = addrs_p.meet(addrs_q); if (addrs_pq.is_bottom() || (addrs_pq.is_empty() && nullity_p.is_non_null())) { this->set_to_bottom(); return; } // p and q's points-to sets this->_points_to_map.set(p, addrs_pq); this->_points_to_map.set(q, addrs_pq); // p and q's offsets this->_integer.add(IntPredicate::EQ, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q)); } break; case PointerPredicate::NE: { // p != q if (nullity_p.is_non_null() && nullity_q.is_non_null() && addrs_p.singleton() && addrs_p == addrs_q) { // p and q's offsets this->_integer.add(IntPredicate::NE, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q)); } } break; case PointerPredicate::GT: { // p > q if (nullity_p.is_non_null() && nullity_q.is_non_null() && addrs_p.singleton() && addrs_p == addrs_q) { // p and q's offsets this->_integer.add(IntPredicate::GT, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q)); } } break; case PointerPredicate::GE: { // p >= q if (nullity_p.is_non_null() && nullity_q.is_non_null() && addrs_p.singleton() && addrs_p == addrs_q) { // p and q's offsets this->_integer.add(IntPredicate::GE, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q)); } } break; case PointerPredicate::LT: { // p < q if (nullity_p.is_non_null() && nullity_q.is_non_null() && addrs_p.singleton() && addrs_p == addrs_q) { // p and q's offsets this->_integer.add(IntPredicate::LT, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q)); } } break; case PointerPredicate::LE: { // p <= q if (nullity_p.is_non_null() && nullity_q.is_non_null() && addrs_p.singleton() && addrs_p == addrs_q) { // p and q's offsets this->_integer.add(IntPredicate::LE, ScalarVariableTrait::offset_var(p), ScalarVariableTrait::offset_var(q)); } } break; } } void pointer_refine(VariableRef p, const PointsToSetT& addrs) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_points_to_map.refine(p, addrs); } void pointer_refine(VariableRef p, const PointsToSetT& addrs, const IntInterval& offset) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_points_to_map.refine(p, addrs); this->_integer.refine(ScalarVariableTrait::offset_var(p), offset); } void pointer_refine(VariableRef p, const PointerAbsValueT& value) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_uninitialized()) { this->_uninitialized.refine(p, Uninitialized::uninitialized()); this->_points_to_map.refine(p, PointsToSetT::empty()); } else if (value.is_null()) { this->_uninitialized.refine(p, Uninitialized::initialized()); this->_nullity.refine(p, Nullity::null()); this->_points_to_map.refine(p, PointsToSetT::empty()); } else { this->_uninitialized.refine(p, value.uninitialized()); this->_nullity.refine(p, value.nullity()); this->_points_to_map.refine(p, value.points_to()); this->_integer.refine(ScalarVariableTrait::offset_var(p), value.offset()); } } void pointer_refine(VariableRef p, const PointerSetT& set) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } else if (set.is_bottom()) { this->set_to_bottom(); } else if (set.points_to().is_empty()) { // The pointer set only contains null and uninitialized pointers this->_points_to_map.refine(p, PointsToSetT::empty()); } else { this->_points_to_map.refine(p, set.points_to()); this->_integer.refine(ScalarVariableTrait::offset_var(p), set.offsets()); } } void pointer_offset_to_int(VariableRef x, VariableRef p) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert( IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(ScalarVariableTrait::offset_var(p))); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } VariableRef offset = ScalarVariableTrait::offset_var(p); this->_uninitialized.assign_initialized(x); if (x == offset) { return; // No-op } else if (IntVariableTrait::sign(x) == IntVariableTrait::sign(offset)) { this->_integer.assign(x, offset); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, offset); } } IntInterval pointer_offset_to_interval(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_integer.to_interval(ScalarVariableTrait::offset_var(p)); } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_integer.to_congruence(ScalarVariableTrait::offset_var(p)); } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_integer.to_interval_congruence( ScalarVariableTrait::offset_var(p)); } PointsToSetT pointer_to_points_to(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return this->_points_to_map.get(p); } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); return PointerAbsValueT(this->_uninitialized.get(p), this->_nullity.get(p), this->_points_to_map.get(p), this->_integer.to_interval( ScalarVariableTrait::offset_var(p))); } void pointer_forget_offset(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_integer.forget(ScalarVariableTrait::offset_var(p)); } void pointer_forget(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.forget(p); this->_nullity.forget(p); this->_points_to_map.forget(p); this->_integer.forget(ScalarVariableTrait::offset_var(p)); } /// @} /// \name Implement dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(ScalarVariableTrait::is_dynamic(y)); ikos_assert(IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); if (IntVariableTrait::sign(x) == IntVariableTrait::sign(y)) { this->_integer.assign(x, y); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, y); } this->_nullity.assign(x, y); this->_points_to_map.set(x, this->_points_to_map.get(y)); this->_integer.assign(ScalarVariableTrait::offset_var(x), ScalarVariableTrait::offset_var(y)); } void dynamic_write_undef(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_uninitialized(x); this->_integer.forget(x); this->_nullity.forget(x); this->_points_to_map.forget(x); this->_integer.forget(ScalarVariableTrait::offset_var(x)); } void dynamic_write_nondet(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); this->_nullity.forget(x); this->_points_to_map.forget(x); this->_integer.forget(ScalarVariableTrait::offset_var(x)); } void dynamic_write_int(VariableRef x, const MachineInt& n) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(IntVariableTrait::bit_width(x) == n.bit_width()); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); if (IntVariableTrait::sign(x) == n.sign()) { this->_integer.assign(x, n); } else { this->_integer.assign(x, n.sign_cast(IntVariableTrait::sign(x))); } this->_nullity.forget(x); this->_points_to_map.forget(x); this->_integer.forget(ScalarVariableTrait::offset_var(x)); } void dynamic_write_nondet_int(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); this->_nullity.forget(x); this->_points_to_map.forget(x); this->_integer.forget(ScalarVariableTrait::offset_var(x)); } void dynamic_write_int(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(ScalarVariableTrait::is_int(y)); ikos_assert(IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); if (IntVariableTrait::sign(x) == IntVariableTrait::sign(y)) { this->_integer.assign(x, y); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, y); } this->_nullity.forget(x); this->_points_to_map.forget(x); this->_integer.forget(ScalarVariableTrait::offset_var(x)); } void dynamic_write_nondet_float(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); this->_nullity.forget(x); this->_points_to_map.forget(x); this->_integer.forget(ScalarVariableTrait::offset_var(x)); } void dynamic_write_null(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); this->_nullity.assign_null(x); this->_points_to_map.set(x, PointsToSetT::empty()); VariableRef offset = ScalarVariableTrait::offset_var(x); this->_integer.assign(offset, MachineInt::zero(IntVariableTrait::bit_width(offset), IntVariableTrait::sign(offset))); } void dynamic_write_pointer(VariableRef x, MemoryLocationRef addr, Nullity nullity) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); this->_nullity.set(x, nullity); this->_points_to_map.set(x, PointsToSetT{addr}); VariableRef offset = ScalarVariableTrait::offset_var(x); this->_integer.assign(offset, MachineInt::zero(IntVariableTrait::bit_width(offset), IntVariableTrait::sign(offset))); } void dynamic_write_pointer(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(ScalarVariableTrait::is_pointer(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); this->_integer.forget(x); this->_nullity.assign(x, y); this->_points_to_map.set(x, this->_points_to_map.get(y)); this->_integer.assign(ScalarVariableTrait::offset_var(x), ScalarVariableTrait::offset_var(y)); } void dynamic_read_int(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_dynamic(y)); ikos_assert(IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); if (IntVariableTrait::sign(x) == IntVariableTrait::sign(y)) { this->_integer.assign(x, y); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, y); } } void dynamic_read_pointer(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_pointer(x)); ikos_assert(ScalarVariableTrait::is_dynamic(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); this->_nullity.assign(x, y); this->_points_to_map.set(x, this->_points_to_map.get(y)); this->_integer.assign(ScalarVariableTrait::offset_var(x), ScalarVariableTrait::offset_var(y)); } bool dynamic_is_zero(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); IntInterval value = this->_integer.to_interval(x); return value.is_bottom() || value.is_zero(); } bool dynamic_is_null(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); return this->_nullity.is_null(x); } void dynamic_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.forget(x); this->_integer.forget(x); this->_nullity.forget(x); this->_points_to_map.forget(x); this->_integer.forget(ScalarVariableTrait::offset_var(x)); } /// @} /// \name Implement scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef x) override { if (this->is_bottom_fast()) { return; } else if (ScalarVariableTrait::is_int(x)) { this->int_assign_undef(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_assign_undef(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_assign_undef(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_write_undef(x); } else { ikos_unreachable("unexpected type"); } } void scalar_assign_nondet(VariableRef x) override { if (this->is_bottom_fast()) { return; } else if (ScalarVariableTrait::is_int(x)) { this->int_assign_nondet(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_assign_nondet(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_assign_nondet(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_write_nondet(x); } else { ikos_unreachable("unexpected type"); } } void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef absolute_zero) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert( IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(ScalarVariableTrait::offset_var(p))); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); this->normalize(); if (this->is_bottom()) { return; } this->_uninitialized.assign_initialized(x); if (this->_nullity.is_null(p)) { auto zero = MachineInt::zero(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); this->_integer.assign(x, zero); } else if (this->_points_to_map.get(p) == PointsToSetT{absolute_zero}) { VariableRef offset = ScalarVariableTrait::offset_var(p); if (IntVariableTrait::sign(x) == IntVariableTrait::sign(offset)) { this->_integer.assign(x, offset); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, offset); } } else { this->_integer.forget(x); } } void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef absolute_zero) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert( IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(ScalarVariableTrait::offset_var(p))); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(x); this->normalize(); if (this->is_bottom()) { return; } IntIntervalCongruence value = this->_integer.to_interval_congruence(x); auto zero = MachineInt::zero(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); auto nullity = Nullity::top(); if (value.contains(zero)) { if (value.singleton()) { nullity = Nullity::null(); } else { nullity = Nullity::top(); } } else { nullity = Nullity::non_null(); } this->_uninitialized.assign_initialized(p); this->_nullity.set(p, nullity); this->_points_to_map.set(p, PointsToSetT{absolute_zero}); VariableRef offset = ScalarVariableTrait::offset_var(p); if (IntVariableTrait::sign(offset) == IntVariableTrait::sign(x)) { this->_integer.assign(offset, x); } else { this->_integer.apply(IntUnaryOperator::SignCast, offset, x); } } void scalar_forget(VariableRef x) override { if (this->is_bottom_fast()) { return; } else if (ScalarVariableTrait::is_int(x)) { this->int_forget(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_forget(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_forget(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_forget(x); } else { ikos_unreachable("unexpected type"); } } /// @} void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "("; this->_uninitialized.dump(o); o << ", "; this->_integer.dump(o); o << ", "; this->_nullity.dump(o); o << ", "; this->_points_to_map.dump(o); o << ")"; } } static std::string name() { return "composite domain using " + UninitializedDomain::name() + ", " + MachineIntDomain::name() + " and " + NullityDomain::name(); } }; // end class CompositeDomain } // end namespace scalar } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/scalar/dummy.hpp000066400000000000000000000424271473507761200254570ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief A dummy scalar abstract domain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { namespace scalar { /// \brief Dummy scalar abstract domain /// /// This class implements a scalar abstract domain that ignores all operations. template < typename VariableRef, typename MemoryLocationRef > class DummyDomain final : public scalar::AbstractDomain< VariableRef, MemoryLocationRef, DummyDomain< VariableRef, MemoryLocationRef > > { public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; private: using IntVariableTrait = machine_int::VariableTraits< VariableRef >; using ScalarVariableTrait = scalar::VariableTraits< VariableRef >; private: bool _is_bottom; private: /// \brief Private constructor explicit DummyDomain(bool is_bottom) : _is_bottom(is_bottom) {} public: /// \brief Create the top abstract value static DummyDomain top() { return DummyDomain(false); } /// \brief Create the bottom abstract value static DummyDomain bottom() { return DummyDomain(true); } /// \brief Copy constructor DummyDomain(const DummyDomain&) noexcept = default; /// \brief Move constructor DummyDomain(DummyDomain&&) noexcept = default; /// \brief Copy assignment operator DummyDomain& operator=(const DummyDomain&) noexcept = default; /// \brief Move assignment operator DummyDomain& operator=(DummyDomain&&) noexcept = default; /// \brief Destructor ~DummyDomain() override = default; /// \name Implement core abstract domain methods /// @{ void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->_is_bottom; } void set_to_bottom() override { this->_is_bottom = true; } void set_to_top() override { this->_is_bottom = false; } bool leq(const DummyDomain& other) const override { return static_cast< int >(this->_is_bottom) >= static_cast< int >(other._is_bottom); } bool equals(const DummyDomain& other) const override { return this->_is_bottom == other._is_bottom; } void join_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom && other._is_bottom); } void widen_with(const DummyDomain& other) override { this->join_with(other); } void widen_threshold_with(const DummyDomain& other, const MachineInt& /*threshold*/) override { this->join_with(other); } void meet_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom || other._is_bottom); } void narrow_with(const DummyDomain& other) override { this->meet_with(other); } void narrow_threshold_with(const DummyDomain& other, const MachineInt& /*threshold*/) override { this->meet_with(other); } /// @} /// \name Implement uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef) override {} bool uninit_is_initialized(VariableRef) const override { return this->_is_bottom; } bool uninit_is_uninitialized(VariableRef) const override { return this->_is_bottom; } void uninit_refine(VariableRef, Uninitialized value) override { if (value.is_bottom()) { this->_is_bottom = true; } } Uninitialized uninit_to_uninitialized(VariableRef) const override { if (this->_is_bottom) { return Uninitialized::bottom(); } else { return Uninitialized::top(); } } /// @} /// \name Implement machine integer abstract domain methods /// @{ void int_assign(VariableRef, const MachineInt&) override {} void int_assign_undef(VariableRef) override {} void int_assign_nondet(VariableRef) override {} void int_assign(VariableRef, VariableRef) override {} void int_assign(VariableRef, const IntLinearExpression&) override {} void int_apply(IntUnaryOperator, VariableRef, VariableRef) override {} void int_apply(IntBinaryOperator, VariableRef, VariableRef, VariableRef) override {} void int_apply(IntBinaryOperator, VariableRef, VariableRef, const MachineInt&) override {} void int_apply(IntBinaryOperator, VariableRef, const MachineInt&, VariableRef) override {} void int_add(IntPredicate, VariableRef, VariableRef) override {} void int_add(IntPredicate, VariableRef, const MachineInt&) override {} void int_add(IntPredicate, const MachineInt&, VariableRef) override {} void int_set(VariableRef, const IntInterval& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void int_set(VariableRef, const IntCongruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void int_set(VariableRef, const IntIntervalCongruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void int_refine(VariableRef, const IntInterval& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void int_refine(VariableRef, const IntCongruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void int_refine(VariableRef, const IntIntervalCongruence& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void int_forget(VariableRef) override {} IntInterval int_to_interval(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->_is_bottom) { return IntInterval::bottom(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); } else { return IntInterval::top(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); } } IntInterval int_to_interval(const IntLinearExpression& e) const override { if (this->_is_bottom) { return IntInterval::bottom(e.constant().bit_width(), e.constant().sign()); } else { return IntInterval::top(e.constant().bit_width(), e.constant().sign()); } } IntCongruence int_to_congruence(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->_is_bottom) { return IntCongruence::bottom(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); } else { return IntCongruence::top(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); } } IntCongruence int_to_congruence(const IntLinearExpression& e) const override { if (this->_is_bottom) { return IntCongruence::bottom(e.constant().bit_width(), e.constant().sign()); } else { return IntCongruence::top(e.constant().bit_width(), e.constant().sign()); } } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->_is_bottom) { return IntIntervalCongruence::bottom(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); } else { return IntIntervalCongruence::top(IntVariableTrait::bit_width(x), IntVariableTrait::sign(x)); } } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { if (this->_is_bottom) { return IntIntervalCongruence::bottom(e.constant().bit_width(), e.constant().sign()); } else { return IntIntervalCongruence::top(e.constant().bit_width(), e.constant().sign()); } } /// @} /// \name Implement non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef) override {} void counter_unmark(VariableRef) override {} void counter_init(VariableRef, const MachineInt&) override {} void counter_incr(VariableRef, const MachineInt&) override {} void counter_forget(VariableRef) override {} /// @} /// \name Implement floating point abstract domain methods /// @{ void float_assign_undef(VariableRef) override {} void float_assign_nondet(VariableRef) override {} void float_assign(VariableRef, VariableRef) override {} void float_forget(VariableRef) override {} /// @} /// \name Implement nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef) override {} void nullity_assert_non_null(VariableRef) override {} bool nullity_is_null(VariableRef) const override { return this->_is_bottom; } bool nullity_is_non_null(VariableRef) const override { return this->_is_bottom; } void nullity_set(VariableRef, Nullity value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void nullity_refine(VariableRef, Nullity value) override { if (value.is_bottom()) { this->_is_bottom = true; } } Nullity nullity_to_nullity(VariableRef) const override { if (this->_is_bottom) { return Nullity::bottom(); } else { return Nullity::top(); } } /// @} /// \name Implement pointer abstract domain methods /// @{ void pointer_assign(VariableRef, MemoryLocationRef, Nullity) override {} void pointer_assign_null(VariableRef) override {} void pointer_assign_undef(VariableRef) override {} void pointer_assign_nondet(VariableRef) override {} void pointer_assign(VariableRef, VariableRef) override {} void pointer_assign(VariableRef, VariableRef, VariableRef) override {} void pointer_assign(VariableRef, VariableRef, const MachineInt&) override {} void pointer_assign(VariableRef, VariableRef, const IntLinearExpression&) override {} void pointer_add(PointerPredicate, VariableRef, VariableRef) override {} void pointer_refine(VariableRef, const PointsToSetT& addrs) override { if (addrs.is_bottom()) { this->_is_bottom = true; } } void pointer_refine(VariableRef, const PointsToSetT& addrs, const IntInterval& offset) override { if (addrs.is_bottom() || offset.is_bottom()) { this->_is_bottom = true; } } void pointer_refine(VariableRef, const PointerAbsValueT& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void pointer_refine(VariableRef, const PointerSetT& set) override { if (set.is_bottom()) { this->_is_bottom = true; } } void pointer_offset_to_int(VariableRef, VariableRef) override {} IntInterval pointer_offset_to_interval(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->_is_bottom) { return IntInterval::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return IntInterval::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->_is_bottom) { return IntCongruence::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return IntCongruence::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->_is_bottom) { return IntIntervalCongruence::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return IntIntervalCongruence::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } PointsToSetT pointer_to_points_to(VariableRef) const override { if (this->_is_bottom) { return PointsToSetT::bottom(); } else { return PointsToSetT::top(); } } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->_is_bottom) { return PointerAbsValueT::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return PointerAbsValueT::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } void pointer_forget_offset(VariableRef) override {} void pointer_forget(VariableRef) override {} /// @} /// \name Implement dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef, VariableRef) override {} void dynamic_write_undef(VariableRef) override {} void dynamic_write_nondet(VariableRef) override {} void dynamic_write_int(VariableRef, const MachineInt&) override {} void dynamic_write_nondet_int(VariableRef) override {} void dynamic_write_int(VariableRef, VariableRef) override {} void dynamic_write_nondet_float(VariableRef) override {} void dynamic_write_null(VariableRef) override {} void dynamic_write_pointer(VariableRef, MemoryLocationRef, Nullity) override { } void dynamic_write_pointer(VariableRef, VariableRef) override {} void dynamic_read_int(VariableRef, VariableRef) override {} void dynamic_read_pointer(VariableRef, VariableRef) override {} bool dynamic_is_zero(VariableRef) const override { return this->_is_bottom; } bool dynamic_is_null(VariableRef) const override { return this->_is_bottom; } void dynamic_forget(VariableRef) override {} /// @} /// \name Implement scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef) override {} void scalar_assign_nondet(VariableRef) override {} void scalar_pointer_to_int(VariableRef, VariableRef, MemoryLocationRef) override {} virtual void scalar_int_to_pointer(VariableRef, VariableRef, MemoryLocationRef) override {} void scalar_forget(VariableRef) override {} /// @} void dump(std::ostream& o) const override { if (this->_is_bottom) { o << "⊥"; } else { o << "T"; } } static std::string name() { return "dummy scalar domain"; } }; // end class DummyDomain } // end namespace scalar } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/scalar/machine_int.hpp000066400000000000000000001153051473507761200265760ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Machine integer scalar abstract domain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace scalar { /// \brief Machine integer scalar abstract domain /// /// This class implements a scalar abstract domain that handles machine integers /// and ignore floating points and pointers safely. template < typename VariableRef, typename MemoryLocationRef, typename UninitializedDomain, typename MachineIntDomainT > class MachineIntDomain final : public scalar::AbstractDomain< VariableRef, MemoryLocationRef, MachineIntDomain< VariableRef, MemoryLocationRef, UninitializedDomain, MachineIntDomainT > > { public: static_assert( uninitialized::IsAbstractDomain< UninitializedDomain, VariableRef >::value, "UninitializedDomain must implement uninitialized::AbstractDomain"); static_assert( machine_int::IsAbstractDomain< MachineIntDomainT, VariableRef >::value, "MachineIntDomain must implement machine_int::AbstractDomain"); public: using IntUnaryOperator = machine_int::UnaryOperator; using IntBinaryOperator = machine_int::BinaryOperator; using IntPredicate = machine_int::Predicate; using IntLinearExpression = LinearExpression< MachineInt, VariableRef >; using IntInterval = machine_int::Interval; using IntCongruence = machine_int::Congruence; using IntIntervalCongruence = machine_int::IntervalCongruence; using PointerPredicate = pointer::Predicate; using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using PointerSetT = PointerSet< MemoryLocationRef >; private: using IntVariableTrait = machine_int::VariableTraits< VariableRef >; using ScalarVariableTrait = scalar::VariableTraits< VariableRef >; private: /// \brief Underlying uninitialized abstract domains UninitializedDomain _uninitialized; /// \brief Underlying machine integer abstract domains MachineIntDomainT _integer; public: /// \brief Create an abstract value with the given underlying abstract values /// /// \param uninitialized The uninitialized abstract value /// \param integer The machine integer abstract value MachineIntDomain(UninitializedDomain uninitialized, MachineIntDomainT integer) : _uninitialized(std::move(uninitialized)), _integer(std::move(integer)) { this->normalize(); } /// \brief Copy constructor MachineIntDomain(const MachineIntDomain&) noexcept( (std::is_nothrow_copy_constructible< UninitializedDomain >::value) && (std::is_nothrow_copy_constructible< MachineIntDomainT >::value)) = default; /// \brief Move constructor MachineIntDomain(MachineIntDomain&&) noexcept( (std::is_nothrow_move_constructible< UninitializedDomain >::value) && (std::is_nothrow_move_constructible< MachineIntDomainT >::value)) = default; /// \brief Copy assignment operator MachineIntDomain& operator=(const MachineIntDomain&) noexcept( (std::is_nothrow_copy_assignable< UninitializedDomain >::value) && (std::is_nothrow_copy_assignable< MachineIntDomainT >::value)) = default; /// \brief Move assignment operator MachineIntDomain& operator=(MachineIntDomain&&) noexcept( (std::is_nothrow_move_assignable< UninitializedDomain >::value) && (std::is_nothrow_move_assignable< MachineIntDomainT >::value)) = default; /// \brief Destructor ~MachineIntDomain() override = default; /// \name Implement core abstract domain methods /// @{ void normalize() override { this->_uninitialized.normalize(); if (this->_uninitialized.is_bottom()) { this->_integer.set_to_bottom(); return; } this->_integer.normalize(); if (this->_integer.is_bottom()) { this->_uninitialized.set_to_bottom(); return; } } private: /// \brief Return true if the abstract value is bottom /// /// This is not always correct since it doesn't check this->_integer bool is_bottom_fast() const { return this->_uninitialized.is_bottom(); } public: bool is_bottom() const override { return this->_uninitialized.is_bottom() || this->_integer.is_bottom(); } bool is_top() const override { return this->_uninitialized.is_top() && this->_integer.is_top(); } void set_to_bottom() override { this->_uninitialized.set_to_bottom(); this->_integer.set_to_bottom(); } void set_to_top() override { this->_uninitialized.set_to_top(); this->_integer.set_to_top(); } bool leq(const MachineIntDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_uninitialized.leq(other._uninitialized) && this->_integer.leq(other._integer); } } bool equals(const MachineIntDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_uninitialized.equals(other._uninitialized) && this->_integer.equals(other._integer); } } void join_with(MachineIntDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_with(std::move(other._uninitialized)); this->_integer.join_with(std::move(other._integer)); } } void join_with(const MachineIntDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_with(other._uninitialized); this->_integer.join_with(other._integer); } } void join_loop_with(MachineIntDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_loop_with(std::move(other._uninitialized)); this->_integer.join_loop_with(std::move(other._integer)); } } void join_loop_with(const MachineIntDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_loop_with(other._uninitialized); this->_integer.join_loop_with(other._integer); } } void join_iter_with(MachineIntDomain&& other) override { this->normalize(); other.normalize(); if (this->is_bottom()) { this->operator=(std::move(other)); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_iter_with(std::move(other._uninitialized)); this->_integer.join_iter_with(std::move(other._integer)); } } void join_iter_with(const MachineIntDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.join_iter_with(other._uninitialized); this->_integer.join_iter_with(other._integer); } } void widen_with(const MachineIntDomain& other) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.widen_with(other._uninitialized); this->_integer.widen_with(other._integer); } } void widen_threshold_with(const MachineIntDomain& other, const MachineInt& threshold) override { this->normalize(); if (this->is_bottom()) { this->operator=(other); } else if (other.is_bottom()) { return; } else { this->_uninitialized.widen_with(other._uninitialized); this->_integer.widen_threshold_with(other._integer, threshold); } } void meet_with(const MachineIntDomain& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_uninitialized.meet_with(other._uninitialized); this->_integer.meet_with(other._integer); } } void narrow_with(const MachineIntDomain& other) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_uninitialized.narrow_with(other._uninitialized); this->_integer.narrow_with(other._integer); } } void narrow_threshold_with(const MachineIntDomain& other, const MachineInt& threshold) override { this->normalize(); if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_uninitialized.narrow_with(other._uninitialized); this->_integer.narrow_threshold_with(other._integer, threshold); } } MachineIntDomain join(const MachineIntDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return MachineIntDomain(this->_uninitialized.join(other._uninitialized), this->_integer.join(other._integer)); } } MachineIntDomain join_loop(const MachineIntDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return MachineIntDomain(this->_uninitialized.join_loop( other._uninitialized), this->_integer.join_loop(other._integer)); } } MachineIntDomain join_iter(const MachineIntDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return MachineIntDomain(this->_uninitialized.join_iter( other._uninitialized), this->_integer.join_iter(other._integer)); } } MachineIntDomain widening(const MachineIntDomain& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return MachineIntDomain(this->_uninitialized.widening( other._uninitialized), this->_integer.widening(other._integer)); } } MachineIntDomain widening_threshold( const MachineIntDomain& other, const MachineInt& threshold) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return MachineIntDomain(this->_uninitialized.widening( other._uninitialized), this->_integer.widening_threshold(other._integer, threshold)); } } MachineIntDomain meet(const MachineIntDomain& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return MachineIntDomain(this->_uninitialized.meet(other._uninitialized), this->_integer.meet(other._integer)); } } MachineIntDomain narrowing(const MachineIntDomain& other) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return MachineIntDomain(this->_uninitialized.narrowing( other._uninitialized), this->_integer.narrowing(other._integer)); } } MachineIntDomain narrowing_threshold( const MachineIntDomain& other, const MachineInt& threshold) const override { if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return MachineIntDomain(this->_uninitialized.narrowing( other._uninitialized), this->_integer.narrowing_threshold(other._integer, threshold)); } } /// @} /// \name Implement uninitialized abstract domain methods /// @{ void uninit_assert_initialized(VariableRef x) override { this->_uninitialized.assert_initialized(x); } bool uninit_is_initialized(VariableRef x) const override { return this->_uninitialized.is_initialized(x); } bool uninit_is_uninitialized(VariableRef x) const override { return this->_uninitialized.is_uninitialized(x); } void uninit_refine(VariableRef x, Uninitialized value) override { this->_uninitialized.refine(x, value); } Uninitialized uninit_to_uninitialized(VariableRef x) const override { return this->_uninitialized.get(x); } /// @} /// \name Implement machine integer abstract domain methods /// @{ void int_assign(VariableRef x, const MachineInt& n) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.assign(x, n); } void int_assign_undef(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_uninitialized(x); this->_integer.forget(x); } void int_assign_nondet(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void int_assign(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); this->_integer.assign(x, y); } void int_assign(VariableRef x, const IntLinearExpression& e) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } for (const auto& term : e) { ikos_assert(ScalarVariableTrait::is_int(term.first)); this->_uninitialized.assert_initialized(term.first); } if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.assign(x, e); } void int_apply(IntUnaryOperator op, VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, VariableRef z) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); ikos_assert(ScalarVariableTrait::is_int(z)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(y); this->_uninitialized.assert_initialized(z); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, VariableRef y, const MachineInt& z) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y, z); } void int_apply(IntBinaryOperator op, VariableRef x, const MachineInt& y, VariableRef z) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(z)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(z); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_uninitialized.assign_initialized(x); this->_integer.apply(op, x, y, z); } void int_add(IntPredicate pred, VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(x); this->_uninitialized.assert_initialized(y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_integer.add(pred, x, y); } void int_add(IntPredicate pred, VariableRef x, const MachineInt& y) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(x); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_integer.add(pred, x, y); } void int_add(IntPredicate pred, const MachineInt& x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(y); if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); return; } this->_integer.add(pred, x, y); } void int_set(VariableRef x, const IntInterval& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.set(x, value); } void int_set(VariableRef x, const IntCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.set(x, value); } void int_set(VariableRef x, const IntIntervalCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.set(x, value); } void int_refine(VariableRef x, const IntInterval& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.refine(x, value); } void int_refine(VariableRef x, const IntCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.refine(x, value); } void int_refine(VariableRef x, const IntIntervalCongruence& value) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.refine(x, value); } void int_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.forget(x); this->_integer.forget(x); } IntInterval int_to_interval(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); return this->_integer.to_interval(x); } IntInterval int_to_interval(const IntLinearExpression& e) const override { return this->_integer.to_interval(e); } IntCongruence int_to_congruence(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); return this->_integer.to_congruence(x); } IntCongruence int_to_congruence(const IntLinearExpression& e) const override { return this->_integer.to_congruence(e); } IntIntervalCongruence int_to_interval_congruence( VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_int(x)); return this->_integer.to_interval_congruence(x); } IntIntervalCongruence int_to_interval_congruence( const IntLinearExpression& e) const override { return this->_integer.to_interval_congruence(e); } /// @} /// \name Implement non-negative loop counter abstract domain methods /// @{ void counter_mark(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_mark(x); } void counter_unmark(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_unmark(x); } void counter_init(VariableRef x, const MachineInt& c) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_init(x, c); } void counter_incr(VariableRef x, const MachineInt& k) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_incr(x, k); } void counter_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_int(x)); this->_integer.counter_forget(x); } /// @} /// \name Implement floating point abstract domain methods /// @{ void float_assign_undef(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_float(x)); this->_uninitialized.assign_uninitialized(x); } void float_assign_nondet(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_float(x)); this->_uninitialized.assign_initialized(x); } void float_assign(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_float(x)); ikos_assert(ScalarVariableTrait::is_float(y)); this->_uninitialized.assign(x, y); } void float_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_float(x)); this->_uninitialized.forget(x); } /// @} /// \name Implement nullity abstract domain methods /// @{ void nullity_assert_null(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_uninitialized.assert_initialized(p); } void nullity_assert_non_null(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_uninitialized.assert_initialized(p); } bool nullity_is_null(VariableRef) const override { return this->is_bottom(); } bool nullity_is_non_null(VariableRef) const override { return this->is_bottom(); } void nullity_set(VariableRef, Nullity value) override { if (value.is_bottom()) { this->set_to_bottom(); } } void nullity_refine(VariableRef, Nullity value) override { if (value.is_bottom()) { this->set_to_bottom(); } } Nullity nullity_to_nullity(VariableRef) const override { if (this->is_bottom()) { return Nullity::bottom(); } else { return Nullity::top(); } } /// @} /// \name Implement pointer abstract domain methods /// @{ void pointer_assign(VariableRef p, MemoryLocationRef, Nullity) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_uninitialized.assign_initialized(p); } void pointer_assign_null(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_uninitialized.assign_initialized(p); } void pointer_assign_undef(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_uninitialized.assign_uninitialized(p); } void pointer_assign_nondet(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_uninitialized.assign_initialized(p); } void pointer_assign(VariableRef p, VariableRef q) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); this->_uninitialized.assign(p, q); } void pointer_assign(VariableRef p, VariableRef q, VariableRef o) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); ikos_assert(ScalarVariableTrait::is_int(o)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(q); this->_uninitialized.assert_initialized(o); this->_uninitialized.assign_initialized(p); } void pointer_assign(VariableRef p, VariableRef q, const MachineInt&) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(q); this->_uninitialized.assign_initialized(p); } void pointer_assign(VariableRef p, VariableRef q, const IntLinearExpression& o) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(q); for (const auto& term : o) { ikos_assert(ScalarVariableTrait::is_int(term.first)); this->_uninitialized.assert_initialized(term.first); } this->_uninitialized.assign_initialized(p); } void pointer_add(PointerPredicate, VariableRef p, VariableRef q) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_pointer(q)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); this->_uninitialized.assert_initialized(q); } void pointer_refine(VariableRef, const PointsToSetT& addrs) override { if (addrs.is_bottom()) { this->set_to_bottom(); } } void pointer_refine(VariableRef, const PointsToSetT& addrs, const IntInterval& offset) override { if (addrs.is_bottom() || offset.is_bottom()) { this->set_to_bottom(); } } void pointer_refine(VariableRef, const PointerAbsValueT& value) override { if (value.is_bottom()) { this->set_to_bottom(); } } void pointer_refine(VariableRef, const PointerSetT& set) override { if (set.is_bottom()) { this->set_to_bottom(); } } void pointer_offset_to_int(VariableRef x, VariableRef p) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } IntInterval pointer_offset_to_interval(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->is_bottom()) { return IntInterval::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return IntInterval::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } IntCongruence pointer_offset_to_congruence(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->is_bottom()) { return IntCongruence::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return IntCongruence::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } IntIntervalCongruence pointer_offset_to_interval_congruence( VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->is_bottom()) { return IntIntervalCongruence::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return IntIntervalCongruence::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } PointsToSetT pointer_to_points_to(VariableRef) const override { if (this->is_bottom()) { return PointsToSetT::bottom(); } else { return PointsToSetT::top(); } } PointerAbsValueT pointer_to_pointer(VariableRef p) const override { ikos_assert(ScalarVariableTrait::is_pointer(p)); auto o = ScalarVariableTrait::offset_var(p); if (this->is_bottom()) { return PointerAbsValueT::bottom(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } else { return PointerAbsValueT::top(IntVariableTrait::bit_width(o), IntVariableTrait::sign(o)); } } void pointer_forget_offset(VariableRef) override {} void pointer_forget(VariableRef p) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); this->_uninitialized.forget(p); } /// @} /// \name Implement dynamically typed variables abstract domain methods /// @{ void dynamic_assign(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(ScalarVariableTrait::is_dynamic(y)); ikos_assert(IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); if (IntVariableTrait::sign(x) == IntVariableTrait::sign(y)) { this->_integer.assign(x, y); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, y); } } void dynamic_write_undef(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_uninitialized(x); this->_integer.forget(x); } void dynamic_write_nondet(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void dynamic_write_int(VariableRef x, const MachineInt& n) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(IntVariableTrait::bit_width(x) == n.bit_width()); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); if (IntVariableTrait::sign(x) == n.sign()) { this->_integer.assign(x, n); } else { this->_integer.assign(x, n.sign_cast(IntVariableTrait::sign(x))); } } void dynamic_write_nondet_int(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void dynamic_write_int(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(ScalarVariableTrait::is_int(y)); ikos_assert(IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); if (IntVariableTrait::sign(x) == IntVariableTrait::sign(y)) { this->_integer.assign(x, y); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, y); } } void dynamic_write_nondet_float(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void dynamic_write_null(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void dynamic_write_pointer(VariableRef x, MemoryLocationRef, Nullity) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void dynamic_write_pointer(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_assert(ScalarVariableTrait::is_pointer(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); this->_integer.forget(x); } void dynamic_read_int(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_dynamic(y)); ikos_assert(IntVariableTrait::bit_width(x) == IntVariableTrait::bit_width(y)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assign(x, y); if (IntVariableTrait::sign(x) == IntVariableTrait::sign(y)) { this->_integer.assign(x, y); } else { this->_integer.apply(IntUnaryOperator::SignCast, x, y); } } void dynamic_read_pointer(VariableRef x, VariableRef y) override { ikos_assert(ScalarVariableTrait::is_pointer(x)); ikos_assert(ScalarVariableTrait::is_dynamic(y)); this->_uninitialized.assign(x, y); } bool dynamic_is_zero(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); IntInterval value = this->_integer.to_interval(x); return value.is_bottom() || value.is_zero(); } bool dynamic_is_null(VariableRef x) const override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); ikos_ignore(x); return this->is_bottom(); } void dynamic_forget(VariableRef x) override { ikos_assert(ScalarVariableTrait::is_dynamic(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.forget(x); this->_integer.forget(x); } /// @} /// \name Implement scalar abstract domain methods /// @{ void scalar_assign_undef(VariableRef x) override { if (this->is_bottom_fast()) { return; } else if (ScalarVariableTrait::is_int(x)) { this->int_assign_undef(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_assign_undef(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_assign_undef(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_write_undef(x); } else { ikos_unreachable("unexpected type"); } } void scalar_assign_nondet(VariableRef x) override { if (this->is_bottom_fast()) { return; } else if (ScalarVariableTrait::is_int(x)) { this->int_assign_nondet(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_assign_nondet(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_assign_nondet(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_write_nondet(x); } else { ikos_unreachable("unexpected type"); } } void scalar_pointer_to_int(VariableRef x, VariableRef p, MemoryLocationRef) override { ikos_assert(ScalarVariableTrait::is_int(x)); ikos_assert(ScalarVariableTrait::is_pointer(p)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(p); this->_uninitialized.assign_initialized(x); this->_integer.forget(x); } void scalar_int_to_pointer(VariableRef p, VariableRef x, MemoryLocationRef) override { ikos_assert(ScalarVariableTrait::is_pointer(p)); ikos_assert(ScalarVariableTrait::is_int(x)); if (this->is_bottom_fast()) { return; } this->_uninitialized.assert_initialized(x); this->_uninitialized.assign_initialized(p); } void scalar_forget(VariableRef x) override { if (this->is_bottom_fast()) { return; } else if (ScalarVariableTrait::is_int(x)) { this->int_forget(x); } else if (ScalarVariableTrait::is_float(x)) { this->float_forget(x); } else if (ScalarVariableTrait::is_pointer(x)) { this->pointer_forget(x); } else if (ScalarVariableTrait::is_dynamic(x)) { this->dynamic_forget(x); } else { ikos_unreachable("unexpected type"); } } /// @} void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "("; this->_uninitialized.dump(o); o << ", "; this->_integer.dump(o); o << ")"; } } static std::string name() { return "machine integer scalar domain using " + UninitializedDomain::name() + " and " + MachineIntDomainT::name(); } }; // end class MachineIntDomain } // end namespace scalar } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/separate_domain.hpp000066400000000000000000000251211473507761200262020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic implementation of non-relational domains * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { /// \brief Generic implementation of non-relational domains template < typename Key, typename Value > class SeparateDomain final : public AbstractDomain< SeparateDomain< Key, Value > > { public: static_assert(IsAbstractDomain< Value >::value, "Value must implement AbstractDomain"); private: using PatriciaTreeMapT = PatriciaTreeMap< Key, Value >; public: using Iterator = typename PatriciaTreeMapT::Iterator; private: PatriciaTreeMapT _tree; bool _is_bottom; private: struct TopTag {}; struct BottomTag {}; struct BottomFound {}; /// \brief Create the top abstract value explicit SeparateDomain(TopTag) : _is_bottom(false) {} /// \brief Create the bottom abstract value explicit SeparateDomain(BottomTag) : _is_bottom(true) {} public: /// \brief Create the top abstract value static SeparateDomain top() { return SeparateDomain(TopTag{}); } /// \brief Create the bottom abstract value static SeparateDomain bottom() { return SeparateDomain(BottomTag{}); } /// \brief Copy constructor SeparateDomain(const SeparateDomain&) noexcept = default; /// \brief Move constructor SeparateDomain(SeparateDomain&&) noexcept = default; /// \brief Copy assignment operator SeparateDomain& operator=(const SeparateDomain&) noexcept = default; /// \brief Move assignment operator SeparateDomain& operator=(SeparateDomain&&) noexcept = default; /// \brief Destructor ~SeparateDomain() override = default; /// \brief Begin iterator over the pairs (key, value) Iterator begin() const { ikos_assert(!this->is_bottom()); return this->_tree.begin(); } /// \brief End iterator over the pairs (key, value) Iterator end() const { ikos_assert(!this->is_bottom()); return this->_tree.end(); } void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->is_bottom() && this->_tree.empty(); } void set_to_bottom() override { this->_is_bottom = true; this->_tree.clear(); } void set_to_top() override { this->_is_bottom = false; this->_tree.clear(); } bool leq(const SeparateDomain& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return this->_tree.leq(other._tree, [](const Value& x, const Value& y) { return x.leq(y); }); } } bool equals(const SeparateDomain& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_tree.equals(other._tree, [](const Value& x, const Value& y) { return x.equals(y); }); } } void join_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void join_loop_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join_loop(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void join_iter_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.join_loop(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void widen_with(const SeparateDomain& other) override { if (other.is_bottom()) { return; } else if (this->is_bottom()) { this->operator=(other); } else { this->_tree.intersect_with(other._tree, [](const Value& x, const Value& y) { Value z = x.widening(y); if (z.is_top()) { return boost::optional< Value >( boost::none); } return boost::optional< Value >(z); }); } } void meet_with(const SeparateDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const Value& x, const Value& y) { Value z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } void narrow_with(const SeparateDomain& other) override { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { try { this->_tree.join_with(other._tree, [](const Value& x, const Value& y) { Value z = x.narrowing(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Set the abstract value of the given key void set(const Key& key, const Value& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { this->_tree.erase(key); } else { this->_tree.insert_or_assign(key, value); } } /// \brief Refine the abstract value of the given key void refine(const Key& key, const Value& value) { if (this->is_bottom()) { return; } else if (value.is_bottom()) { this->set_to_bottom(); } else if (value.is_top()) { return; } else { try { this->_tree.update_or_insert( [](const Value& x, const Value& y) { Value z = x.meet(y); if (z.is_bottom()) { throw BottomFound(); } return boost::optional< Value >(z); }, key, value); } catch (BottomFound&) { this->set_to_bottom(); } } } /// \brief Forget the abstract value of the given key void forget(const Key& key) { if (this->is_bottom()) { return; } this->_tree.erase(key); } /// \brief Get the abstract value for the given key Value get(const Key& key) const { if (this->is_bottom()) { return Value::bottom(); } else { boost::optional< const Value& > v = this->_tree.at(key); if (v) { return *v; } else { return Value::top(); } } } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { this->_tree.dump(o); } } static std::string name() { return "separate domain of " + Value::name(); } }; // end class SeparateDomain } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/uninitialized/000077500000000000000000000000001473507761200252055ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/uninitialized/abstract_domain.hpp000066400000000000000000000101101473507761200310410ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for abstract domains keeping track of (un)initialized * variables * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace uninitialized { /// \brief Base class for abstract domains keeping track of (un)initialized /// variables template < typename VariableRef, typename Derived > class AbstractDomain : public core::AbstractDomain< Derived > { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); public: /// \brief Assign `x = initialized` virtual void assign_initialized(VariableRef x) = 0; /// \brief Assign `x = uninitialized` virtual void assign_uninitialized(VariableRef x) = 0; /// \brief Assign `x = y` virtual void assign(VariableRef x, VariableRef y) = 0; /// \brief Add the constraint `x == initialized` virtual void assert_initialized(VariableRef x) = 0; /// \brief Return true if `x` is initialized, otherwise false virtual bool is_initialized(VariableRef x) const = 0; /// \brief Return true if `x` is uninitialized, otherwise false virtual bool is_uninitialized(VariableRef x) const = 0; /// \brief Set the uninitialized value of a variable virtual void set(VariableRef x, const Uninitialized& value) = 0; /// \brief Refine the uninitialized value of a variable virtual void refine(VariableRef x, const Uninitialized& value) = 0; /// \brief Forget a variable virtual void forget(VariableRef x) = 0; /// \brief Get the uninitialized value for the given variable virtual Uninitialized get(VariableRef x) const = 0; }; // end class AbstractDomain /// \brief Check if a type is an uninitialized abstract domain template < typename T, typename VariableRef > struct IsAbstractDomain : std::is_base_of< uninitialized::AbstractDomain< VariableRef, T >, T > {}; } // end namespace uninitialized } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/uninitialized/dummy.hpp000066400000000000000000000127561473507761200270640ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief A dummy uninitialized abstract domain that is either top or bottom * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { namespace uninitialized { /// \brief Dummy uninitialized abstract domain that is either top or bottom /// /// This can be used to disable an uninitialized variable analysis in a generic /// implementation template < typename VariableRef > class DummyDomain final : public uninitialized::AbstractDomain< VariableRef, DummyDomain< VariableRef > > { private: bool _is_bottom; private: /// \brief Private constructor explicit DummyDomain(bool is_bottom) : _is_bottom(is_bottom) {} public: /// \brief Create the top abstract value static DummyDomain top() { return DummyDomain(false); } /// \brief Create the bottom abstract value static DummyDomain bottom() { return DummyDomain(true); } /// \brief Copy constructor DummyDomain(const DummyDomain&) noexcept = default; /// \brief Move constructor DummyDomain(DummyDomain&&) noexcept = default; /// \brief Copy assignment operator DummyDomain& operator=(const DummyDomain&) noexcept = default; /// \brief Move assignment operator DummyDomain& operator=(DummyDomain&&) noexcept = default; /// \brief Destructor ~DummyDomain() override = default; void normalize() override {} bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return !this->_is_bottom; } void set_to_bottom() override { this->_is_bottom = true; } void set_to_top() override { this->_is_bottom = false; } bool leq(const DummyDomain& other) const override { return static_cast< int >(this->_is_bottom) >= static_cast< int >(other._is_bottom); } bool equals(const DummyDomain& other) const override { return this->_is_bottom == other._is_bottom; } void join_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom && other._is_bottom); } void widen_with(const DummyDomain& other) override { this->join_with(other); } void meet_with(const DummyDomain& other) override { this->_is_bottom = (this->_is_bottom || other._is_bottom); } void narrow_with(const DummyDomain& other) override { this->meet_with(other); } void assign_initialized(VariableRef) override {} void assign_uninitialized(VariableRef) override {} void assign(VariableRef, VariableRef) override {} void assert_initialized(VariableRef) override {} bool is_initialized(VariableRef) const override { return this->_is_bottom; } bool is_uninitialized(VariableRef) const override { return this->_is_bottom; } void set(VariableRef, const Uninitialized& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void refine(VariableRef, const Uninitialized& value) override { if (value.is_bottom()) { this->_is_bottom = true; } } void forget(VariableRef) override {} Uninitialized get(VariableRef) const override { if (this->_is_bottom) { return Uninitialized::bottom(); } else { return Uninitialized::top(); } } void dump(std::ostream& o) const override { if (this->_is_bottom) { o << "⊥"; } else { o << "T"; } } static std::string name() { return "dummy uninitialized domain"; } }; // end class DummyDomain } // end namespace uninitialized } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/domain/uninitialized/separate_domain.hpp000066400000000000000000000142321473507761200310530ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of an abstract domain keeping track of (un)initialized * variables using a separate domain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace uninitialized { /// \brief Uninitialized abstract domain /// /// Implementation of the uninitialized abstract domain interface using /// a separate domain. template < typename VariableRef > class SeparateDomain final : public uninitialized::AbstractDomain< VariableRef, SeparateDomain< VariableRef > > { private: using SeparateDomainT = core::SeparateDomain< VariableRef, Uninitialized >; public: using Iterator = typename SeparateDomainT::Iterator; private: SeparateDomainT _inv; private: /// \brief Private constructor explicit SeparateDomain(SeparateDomainT inv) : _inv(std::move(inv)) {} public: /// \brief Create the top abstract value static SeparateDomain top() { return SeparateDomain(SeparateDomainT::top()); } /// \brief Create the bottom abstract value static SeparateDomain bottom() { return SeparateDomain(SeparateDomainT::bottom()); } /// \brief Copy constructor SeparateDomain(const SeparateDomain&) noexcept = default; /// \brief Move constructor SeparateDomain(SeparateDomain&&) noexcept = default; /// \brief Copy assignment operator SeparateDomain& operator=(const SeparateDomain&) noexcept = default; /// \brief Move assignment operator SeparateDomain& operator=(SeparateDomain&&) noexcept = default; /// \brief Destructor ~SeparateDomain() override = default; /// \brief Begin iterator over the pairs (variable, uninitialized) Iterator begin() const { return this->_inv.begin(); } /// \brief End iterator over the pairs (variable, uninitialized) Iterator end() const { return this->_inv.end(); } void normalize() override {} bool is_bottom() const override { return this->_inv.is_bottom(); } bool is_top() const override { return this->_inv.is_top(); } void set_to_bottom() override { this->_inv.set_to_bottom(); } void set_to_top() override { this->_inv.set_to_top(); } bool leq(const SeparateDomain& other) const override { return this->_inv.leq(other._inv); } bool equals(const SeparateDomain& other) const override { return this->_inv.equals(other._inv); } void join_with(const SeparateDomain& other) override { this->_inv.join_with(other._inv); } void widen_with(const SeparateDomain& other) override { this->_inv.widen_with(other._inv); } void meet_with(const SeparateDomain& other) override { this->_inv.meet_with(other._inv); } void narrow_with(const SeparateDomain& other) override { this->_inv.narrow_with(other._inv); } void assign_initialized(VariableRef x) override { this->_inv.set(x, Uninitialized::initialized()); } void assign_uninitialized(VariableRef x) override { this->_inv.set(x, Uninitialized::uninitialized()); } void assign(VariableRef x, VariableRef y) override { this->_inv.set(x, this->_inv.get(y)); } void assert_initialized(VariableRef x) override { this->_inv.refine(x, Uninitialized::initialized()); } bool is_initialized(VariableRef x) const override { Uninitialized value = this->_inv.get(x); return value.is_bottom() || value.is_initialized(); } bool is_uninitialized(VariableRef x) const override { Uninitialized value = this->_inv.get(x); return value.is_bottom() || value.is_uninitialized(); } void set(VariableRef x, const Uninitialized& value) override { this->_inv.set(x, value); } void refine(VariableRef x, const Uninitialized& value) override { this->_inv.refine(x, value); } void forget(VariableRef x) override { this->_inv.forget(x); } Uninitialized get(VariableRef x) const override { return this->_inv.get(x); } void dump(std::ostream& o) const override { return this->_inv.dump(o); } static std::string name() { return "uninitialized domain"; } }; // end class SeparateDomain } // end namespace uninitialized } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/000077500000000000000000000000001473507761200225215ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/machine_int/000077500000000000000000000000001473507761200247775ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/machine_int/variable_factory.hpp000066400000000000000000000157161473507761200310360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Example of machine integer variable management * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace core { namespace example { namespace machine_int { /// \brief Simple machine integer variable factory based on strings /// /// This is an example of a variable factory. /// /// Variables provided by this factory have a name, an index, a bit-width and a /// signedness. /// /// This factory can be used for any machine integer abstract domain (namespace /// `machine_int`). class VariableFactory { public: class Variable { public: friend class VariableFactory; private: std::string _name; Index _id; uint64_t _bit_width; Signedness _sign; private: /// \brief Private constructor Variable(std::string name, Index id, uint64_t bit_width, Signedness sign) : _name(std::move(name)), _id(id), _bit_width(bit_width), _sign(sign) {} public: /// \brief No default constructor Variable() = delete; /// \brief No copy constructor Variable(const Variable&) = delete; /// \brief Move constructor Variable(Variable&&) = default; /// \brief No copy assignment operator Variable& operator=(const Variable&) = delete; /// \brief Move assignment operator Variable& operator=(Variable&&) = default; /// \brief Destructor ~Variable() = default; /// \brief Return the name of the variable const std::string& name() const { return this->_name; } /// \brief Return the unique index of the variable Index index() const { return this->_id; } /// \brief Return the bit-width of the variable uint64_t bit_width() const { return this->_bit_width; } /// \brief Return the sign of the variable Signedness sign() const { return this->_sign; } }; // end class Variable public: using VariableRef = const Variable*; private: using Map = std::unordered_map< std::string, Variable >; private: Index _next_id = 1; Map _map; public: /// \brief Create a variable factory VariableFactory() = default; /// \brief Create a variable factory, starting with the given index explicit VariableFactory(Index start_id) : _next_id(start_id) {} /// \brief No copy constructor VariableFactory(const VariableFactory&) = delete; /// \brief No move constructor VariableFactory(VariableFactory&&) = delete; /// \brief No copy assignment operator VariableFactory& operator=(const VariableFactory&) = delete; /// \brief No move assignment operator VariableFactory& operator=(VariableFactory&&) = delete; /// \brief Destructor ~VariableFactory() = default; /// \brief Get or create a variable with the given name, bit width and sign VariableRef get(const std::string& name, uint64_t bit_width, Signedness sign) { // This is sound because references are kept valid when using // std::unordered_map::emplace() auto it = this->_map.find(name); if (it != this->_map.end()) { return &(it->second); } else { auto res = this->_map.emplace(name, Variable(name, this->_next_id++, bit_width, sign)); ikos_assert(res.second); return &(res.first->second); } } }; // end class VariableFactory /// \brief Write a variable on a stream inline std::ostream& operator<<(std::ostream& o, VariableFactory::VariableRef var) { o << var->name(); return o; } } // end namespace machine_int } // end namespace example } // end namespace core } // end namespace ikos namespace ikos { namespace core { /// \brief Implement IndexableTraits for /// example::machine_int::VariableFactory::VariableRef template <> struct IndexableTraits< example::machine_int::VariableFactory::VariableRef > { static Index index(example::machine_int::VariableFactory::VariableRef var) { return var->index(); } }; /// \brief Implement DumpableTraits for /// example::machine_int::VariableFactory::VariableRef template <> struct DumpableTraits< example::machine_int::VariableFactory::VariableRef > { static void dump(std::ostream& o, example::machine_int::VariableFactory::VariableRef var) { o << var->name(); } }; namespace machine_int { /// \brief Implement VariableTraits for /// example::machine_int::VariableFactory::VariableRef template <> struct VariableTraits< example::machine_int::VariableFactory::VariableRef > { static uint64_t bit_width( example::machine_int::VariableFactory::VariableRef var) { return var->bit_width(); } static Signedness sign( example::machine_int::VariableFactory::VariableRef var) { return var->sign(); } }; } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/memory_factory.hpp000066400000000000000000000136721473507761200263020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Example of memory location management * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { namespace example { /// \brief Simple memory location factory based on strings /// /// This is an example of a memory location factory. /// /// Memory locations provided by this factory have a name and an index. /// /// This factory can be used for any scalar abstract domain, memory abstract /// domain, lifetime abstract domain, etc. class MemoryFactory { public: class MemoryLocation { public: friend class MemoryFactory; private: std::string _name; Index _id; private: /// \brief Private constructor MemoryLocation(std::string name, Index id) : _name(std::move(name)), _id(id) {} public: /// \brief No default constructor MemoryLocation() = delete; /// \brief No copy constructor MemoryLocation(const MemoryLocation&) = delete; /// \brief Move constructor MemoryLocation(MemoryLocation&&) = default; /// \brief No copy assignment operator MemoryLocation& operator=(const MemoryLocation&) = delete; /// \brief Move assignment operator MemoryLocation& operator=(MemoryLocation&&) = default; /// \brief Destructor ~MemoryLocation() = default; /// \brief Return the name of the memory location const std::string& name() const { return this->_name; } /// \brief Return the unique index of the memory location Index index() const { return this->_id; } }; // end class MemoryLocation public: using MemoryLocationRef = const MemoryLocation*; private: using Map = std::unordered_map< std::string, MemoryLocation >; private: Index _next_id = 1; Map _map; public: /// \brief Create a memory factory MemoryFactory() = default; /// \brief Create a memory factory, starting with the given index explicit MemoryFactory(Index start_id) : _next_id(start_id) {} /// \brief No copy constructor MemoryFactory(const MemoryFactory&) = delete; /// \brief No move constructor MemoryFactory(MemoryFactory&&) = delete; /// \brief No copy assignment operator MemoryFactory& operator=(const MemoryFactory&) = delete; /// \brief No move assignment operator MemoryFactory& operator=(MemoryFactory&&) = delete; /// \brief Destructor ~MemoryFactory() = default; /// \brief Get or create a memory location with the given name MemoryLocationRef get(const std::string& name) { // This is sound because references are kept valid when using // std::unordered_map::emplace() auto it = this->_map.find(name); if (it != this->_map.end()) { return &(it->second); } else { auto res = this->_map.emplace(name, MemoryLocation(name, this->_next_id++)); ikos_assert(res.second); return &(res.first->second); } } }; // end class MemoryFactory /// \brief Write a memory location on a stream inline std::ostream& operator<<(std::ostream& o, MemoryFactory::MemoryLocationRef m) { o << m->name(); return o; } } // end namespace example } // end namespace core } // end namespace ikos namespace ikos { namespace core { /// \brief Implement IndexableTraits for /// example::MemoryFactory::MemoryLocationRef template <> struct IndexableTraits< example::MemoryFactory::MemoryLocationRef > { static Index index(example::MemoryFactory::MemoryLocationRef m) { return m->index(); } }; /// \brief Implement DumpableTraits for /// example::MemoryFactory::MemoryLocationRef template <> struct DumpableTraits< example::MemoryFactory::MemoryLocationRef > { static void dump(std::ostream& o, example::MemoryFactory::MemoryLocationRef m) { o << m->name(); } }; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/muzq.hpp000066400000000000000000000660441473507761200242400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief MuZQ is a micro language for semantic modeling over integer and * rational numbers. * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace muzq { /// \brief Base class for statements template < typename VariableRef > class Statement { public: static_assert( IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); public: enum StatementKind { ZLinearAssignmentKind, QLinearAssignmentKind, ZBinaryOperationKind, QBinaryOperationKind, ZLinearAssertionKind, QLinearAssertionKind, CheckPointKind, }; protected: // Kind of statement StatementKind _kind; protected: /// \brief Protected constructor explicit Statement(StatementKind kind) : _kind(kind) {} public: /// \brief No copy constructor Statement(const Statement&) = delete; /// \brief No move constructor Statement(Statement&&) = delete; /// \brief No copy assignment operator Statement& operator=(const Statement&) = delete; /// \brief No move assignment operator Statement& operator=(Statement&&) = delete; /// \brief Destructor virtual ~Statement() = default; /// \brief Get the kind of statement StatementKind kind() const { return this->_kind; } /// \brief Dump the statement for debugging purpose virtual void dump(std::ostream&) const = 0; }; // end class Statement /// \brief Linear assignment on integers template < typename VariableRef > class ZLinearAssignment final : public Statement< VariableRef > { public: using StatementT = Statement< VariableRef >; using LinearExpressionT = LinearExpression< ZNumber, VariableRef >; private: VariableRef _result; LinearExpressionT _operand; public: /// \brief Create a linear assignment ZLinearAssignment(VariableRef result, LinearExpressionT operand) : StatementT(StatementT::ZLinearAssignmentKind), _result(result), _operand(std::move(operand)) {} /// \brief Return the result variable VariableRef result() const { return this->_result; } /// \brief Return the operand const LinearExpressionT& operand() const { return this->_operand; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const StatementT* s) { return s->kind() == StatementT::ZLinearAssignmentKind; } /// \brief Dump the statement for debugging purpose void dump(std::ostream& o) const override { DumpableTraits< VariableRef >::dump(o, this->_result); o << " = "; this->_operand.dump(o); } }; // end class ZLinearAssignment /// \brief Linear assignment on rationals template < typename VariableRef > class QLinearAssignment final : public Statement< VariableRef > { public: using StatementT = Statement< VariableRef >; using LinearExpressionT = LinearExpression< QNumber, VariableRef >; private: VariableRef _result; LinearExpressionT _operand; public: /// \brief Create a linear assignment QLinearAssignment(VariableRef result, LinearExpressionT operand) : StatementT(StatementT::QLinearAssignmentKind), _result(result), _operand(std::move(operand)) {} /// \brief Return the result variable VariableRef result() const { return this->_result; } /// \brief Return the operand const LinearExpressionT& operand() const { return this->_operand; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const StatementT* s) { return s->kind() == StatementT::QLinearAssignmentKind; } /// \brief Dump the statement for debugging purpose void dump(std::ostream& o) const override { DumpableTraits< VariableRef >::dump(o, this->_result); o << " = "; this->_operand.dump(o); } }; // end class QLinearAssignment /// \brief Linear assignment on integers template < typename VariableRef > class ZBinaryOperation final : public Statement< VariableRef > { public: using StatementT = Statement< VariableRef >; private: VariableRef _result; numeric::BinaryOperator _op; VariableRef _left; VariableRef _right; public: /// \brief Create a binary operation ZBinaryOperation(VariableRef result, numeric::BinaryOperator op, VariableRef left, VariableRef right) : StatementT(StatementT::ZBinaryOperationKind), _result(result), _op(op), _left(left), _right(right) {} /// \brief Return the result variable VariableRef result() const { return this->_result; } /// \brief Return the binary operator numeric::BinaryOperator op() const { return this->_op; } /// \brief Return the left operand VariableRef left() const { return this->_left; } /// \brief Return the right operand VariableRef right() const { return this->_right; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const StatementT* s) { return s->kind() == StatementT::ZBinaryOperationKind; } /// \brief Dump the statement for debugging purpose void dump(std::ostream& o) const override { DumpableTraits< VariableRef >::dump(o, this->_result); o << " = "; DumpableTraits< VariableRef >::dump(o, this->_left); o << " " << numeric::bin_operator_text(this->_op) << " "; DumpableTraits< VariableRef >::dump(o, this->_right); } }; // end class ZBinaryOperation /// \brief Linear assignment on rationals template < typename VariableRef > class QBinaryOperation final : public Statement< VariableRef > { public: using StatementT = Statement< VariableRef >; private: VariableRef _result; numeric::BinaryOperator _op; VariableRef _left; VariableRef _right; public: /// \brief Create a binary operation QBinaryOperation(VariableRef result, numeric::BinaryOperator op, VariableRef left, VariableRef right) : StatementT(StatementT::QBinaryOperationKind), _result(result), _op(op), _left(left), _right(right) {} /// \brief Return the result variable VariableRef result() const { return this->_result; } /// \brief Return the binary operator numeric::BinaryOperator op() const { return this->_op; } /// \brief Return the left operand VariableRef left() const { return this->_left; } /// \brief Return the right operand VariableRef right() const { return this->_right; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const StatementT* s) { return s->kind() == StatementT::QBinaryOperationKind; } /// \brief Dump the statement for debugging purpose void dump(std::ostream& o) const override { DumpableTraits< VariableRef >::dump(o, this->_result); o << " = "; DumpableTraits< VariableRef >::dump(o, this->_left); o << " " << numeric::bin_operator_text(this->_op) << " "; DumpableTraits< VariableRef >::dump(o, this->_right); } }; // end class QBinaryOperation /// \brief Linear assertion on integers template < typename VariableRef > class ZLinearAssertion final : public Statement< VariableRef > { public: using StatementT = Statement< VariableRef >; using LinearConstraintT = LinearConstraint< ZNumber, VariableRef >; private: LinearConstraintT _cst; public: /// \brief Create a linear assertion explicit ZLinearAssertion(LinearConstraintT cst) : StatementT(StatementT::ZLinearAssertionKind), _cst(std::move(cst)) {} const LinearConstraintT& constraint() const { return this->_cst; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const StatementT* s) { return s->kind() == StatementT::ZLinearAssertionKind; } /// \brief Dump the statement for debugging purpose void dump(std::ostream& o) const override { o << "assert("; this->_cst.dump(o); o << ")"; } }; // end class ZLinearAssertion /// \brief Linear assertion on rationals template < typename VariableRef > class QLinearAssertion final : public Statement< VariableRef > { public: using StatementT = Statement< VariableRef >; using LinearConstraintT = LinearConstraint< QNumber, VariableRef >; private: LinearConstraintT _cst; public: /// \brief Create a linear assertion explicit QLinearAssertion(LinearConstraintT cst) : StatementT(StatementT::QLinearAssertionKind), _cst(std::move(cst)) {} const LinearConstraintT& constraint() const { return this->_cst; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const StatementT* s) { return s->kind() == StatementT::QLinearAssertionKind; } /// \brief Dump the statement for debugging purpose void dump(std::ostream& o) const override { o << "assert("; this->_cst.dump(o); o << ")"; } }; // end class QLinearAssertion /// \brief Checkpoint template < typename VariableRef > class CheckPoint final : public Statement< VariableRef > { public: using StatementT = Statement< VariableRef >; private: std::string _name; public: /// \brief Create a checkpoint statement explicit CheckPoint(std::string name) : StatementT(StatementT::CheckPointKind), _name(std::move(name)) {} /// \brief Return the checkpoint name const std::string& name() const { return this->_name; } /// \brief Method for type support (isa, cast, dyn_cast) static bool classof(const StatementT* s) { return s->kind() == StatementT::CheckPointKind; } /// \brief Dump the statement for debugging purpose void dump(std::ostream& o) const override { o << "checkpoint(" << this->_name << ")"; } }; // end class CheckPoint /// \brief Helper for vectors of unique_ptr template < typename T > struct VectorUniquePtrExposeRawPtr { T* operator()(const std::unique_ptr< T >& p) const { return p.get(); } }; /// \brief Helper for maps of unique_ptr template < typename K, typename T > struct MapUniquePtrExposeRawPtr { T* operator()(const std::pair< const K, std::unique_ptr< T > >& p) const { return p.second.get(); } }; // Forward declaration template < typename VariableRef > class ControlFlowGraph; /// \brief Basic block /// /// Represents a node in the control flow graph template < typename VariableRef > class BasicBlock { public: using StatementT = Statement< VariableRef >; using StatementIterator = boost::transform_iterator< VectorUniquePtrExposeRawPtr< StatementT >, typename std::vector< std::unique_ptr< StatementT > >::const_iterator >; using BasicBlockIterator = typename std::vector< BasicBlock* >::const_iterator; private: // Name std::string _name; // List of statements std::vector< std::unique_ptr< StatementT > > _statements; // List of successor basic blocks std::vector< BasicBlock* > _successors; // List of predecessor basic blocks std::vector< BasicBlock* > _predecessors; private: /// \brief Private constructor explicit BasicBlock(std::string name) : _name(std::move(name)) {} public: /// \brief No copy constructor BasicBlock(const BasicBlock&) = delete; /// \brief No move constructor BasicBlock(BasicBlock&&) = delete; /// \brief No copy assignment operator BasicBlock& operator=(const BasicBlock&) = delete; /// \brief No move assignment operator BasicBlock& operator=(BasicBlock&&) = delete; /// \brief Destructor ~BasicBlock() = default; /// \brief Return the name const std::string& name() const { return this->_name; } /// \brief Begin iterator over the statements StatementIterator begin() const { return boost::make_transform_iterator(this->_statements.cbegin(), VectorUniquePtrExposeRawPtr< StatementT >()); } /// \brief End iterator over the statements StatementIterator end() const { return boost::make_transform_iterator(this->_statements.cend(), VectorUniquePtrExposeRawPtr< StatementT >()); } /// \brief Add a statement at the end of the basic block void add(std::unique_ptr< StatementT > stmt) { this->_statements.emplace_back(std::move(stmt)); } /// \brief Return the number of statements std::size_t num_statements() const { return this->_statements.size(); } /// \brief Return true if the basic block is empty bool empty() const { return this->_statements.empty(); } /// \brief Begin iterator over the successors BasicBlockIterator successor_begin() const { return this->_successors.cbegin(); } /// \brief End iterator over the successors BasicBlockIterator successor_end() const { return this->_successors.cend(); } /// \brief Begin iterator over the predecessors BasicBlockIterator predecessor_begin() const { return this->_predecessors.cbegin(); } /// \brief End iterator over the predecessors BasicBlockIterator predecessor_end() const { return this->_predecessors.cend(); } /// \brief Is the given basic block a successor? bool is_successor(const BasicBlock* bb) const { return std::find(this->_successors.begin(), this->_successors.end(), bb) != this->_successors.end(); } /// \brief Add the given basic block as a successor void add_successor(BasicBlock* bb) { if (!this->is_successor(bb)) { this->_successors.push_back(bb); bb->_predecessors.push_back(this); } } /// \brief Dump the basic block for debugging purpose void dump(std::ostream& o) const { o << this->_name << ":\n"; for (auto it = this->begin(), et = this->end(); it != et; ++it) { o << " "; (*it)->dump(o); o << ";\n"; } o << "--> ["; for (auto it = this->successor_begin(), et = this->successor_end(); it != et;) { o << (*it)->name(); ++it; if (it != et) { o << ", "; } } o << "]\n"; } // Friends friend class ControlFlowGraph< VariableRef >; }; // end class BasicBlock /// \brief Control Flow Graph /// /// It represents a code in the muzq language. template < typename VariableRef > class ControlFlowGraph { public: using BasicBlockT = BasicBlock< VariableRef >; using BasicBlockIterator = boost::transform_iterator< MapUniquePtrExposeRawPtr< std::string, BasicBlockT >, typename std::unordered_map< std::string, std::unique_ptr< BasicBlockT > >::const_iterator >; private: // Map from name to basic block std::unordered_map< std::string, std::unique_ptr< BasicBlockT > > _blocks; // Entry point BasicBlockT* _entry; public: /// \brief Create a control flow graph /// /// \param entry Name of the entry point explicit ControlFlowGraph(const std::string& entry) { this->_entry = this->get(entry); } /// \brief Return the entry point BasicBlockT* entry() const { return this->_entry; } /// \brief Begin iterator over the basic blocks BasicBlockIterator begin() const { return boost::make_transform_iterator(this->_blocks.cbegin(), MapUniquePtrExposeRawPtr< std::string, BasicBlockT >()); } /// \brief End iterator over the basic blocks BasicBlockIterator end() const { return boost::make_transform_iterator(this->_blocks.cend(), MapUniquePtrExposeRawPtr< std::string, BasicBlockT >()); } /// \brief Get or create the basic block with the given name BasicBlockT* get(const std::string& name) { auto it = this->_blocks.find(name); if (it != this->_blocks.end()) { return it->second.get(); } else { auto bb = std::unique_ptr< BasicBlockT >(new BasicBlockT(name)); auto res = this->_blocks.emplace(name, std::move(bb)); ikos_assert(res.second); return res.first->second.get(); } } /// \brief Dump the control flow graph for debugging purpose void dump(std::ostream& o) const { for (auto it = this->begin(), et = this->end(); it != et; ++it) { (*it)->dump(o); o << "\n"; } } }; // end class ControlFlowGraph /// \brief Apply a statement visitor on a statement /// /// A statement visitor looks like: /// /// \code{.cpp} /// struct MyStatementVisitor { /// using ResultType = int; /// /// int operator()(ZLinearAssignment* s) { ... } /// int operator()(QLinearAssignment* s) { ... } /// int operator()(ZBinaryOperation* s) { ... } /// int operator()(QBinaryOperation* s) { ... } /// int operator()(ZLinearAssertion* s) { ... } /// int operator()(QLinearAssertion* s) { ... } /// int operator()(CheckPoint* s) { ... } /// }; /// \endcode template < typename Visitor, typename VariableRef > typename Visitor::ResultType apply_visitor(Visitor& visitor, Statement< VariableRef >* s) { using StatementT = Statement< VariableRef >; switch (s->kind()) { case StatementT::ZLinearAssignmentKind: return visitor(cast< ZLinearAssignment< VariableRef > >(s)); case StatementT::QLinearAssignmentKind: return visitor(cast< QLinearAssignment< VariableRef > >(s)); case StatementT::ZBinaryOperationKind: return visitor(cast< ZBinaryOperation< VariableRef > >(s)); case StatementT::QBinaryOperationKind: return visitor(cast< QBinaryOperation< VariableRef > >(s)); case StatementT::ZLinearAssertionKind: return visitor(cast< ZLinearAssertion< VariableRef > >(s)); case StatementT::QLinearAssertionKind: return visitor(cast< QLinearAssertion< VariableRef > >(s)); case StatementT::CheckPointKind: return visitor(cast< CheckPoint< VariableRef > >(s)); default: ikos_unreachable("unexpected statement"); } } } // end namespace muzq } // end namespace core } // end namespace ikos namespace ikos { namespace core { /// \brief Implement GraphTraits for ControlFlowGraph template < typename VariableRef > struct GraphTraits< muzq::ControlFlowGraph< VariableRef >* > { using GraphRef = muzq::ControlFlowGraph< VariableRef >*; using NodeRef = muzq::BasicBlock< VariableRef >*; using SuccessorNodeIterator = typename muzq::BasicBlock< VariableRef >::BasicBlockIterator; using PredecessorNodeIterator = typename muzq::BasicBlock< VariableRef >::BasicBlockIterator; static NodeRef entry(GraphRef cfg) { return cfg->entry(); } static SuccessorNodeIterator successor_begin(NodeRef bb) { return bb->successor_begin(); } static SuccessorNodeIterator successor_end(NodeRef bb) { return bb->successor_end(); } static PredecessorNodeIterator predecessor_begin(NodeRef bb) { return bb->predecessor_begin(); } static PredecessorNodeIterator predecessor_end(NodeRef bb) { return bb->predecessor_end(); } }; /// \brief Implement DumpableTraits for BasicBlock* template < typename VariableRef > struct DumpableTraits< muzq::BasicBlock< VariableRef >* > { static void dump(std::ostream& stream, muzq::BasicBlock< VariableRef >* bb) { bb->dump(stream); } }; /// \brief Implement DumpableTraits for ControlFlowGraph* template < typename VariableRef > struct DumpableTraits< muzq::ControlFlowGraph< VariableRef >* > { static void dump(std::ostream& stream, muzq::ControlFlowGraph< VariableRef >* cfg) { cfg->dump(stream); } }; } // end namespace core } // end namespace ikos namespace ikos { namespace core { namespace muzq { /// \brief Fixpoint iterator on a ControlFlowGraph template < typename VariableRef, typename ZNumDomain, typename QNumDomain > class FixpointIterator final : public InterleavedFwdFixpointIterator< ControlFlowGraph< VariableRef >*, DomainProduct2< ZNumDomain, QNumDomain > > { private: static_assert( numeric::IsAbstractDomain< ZNumDomain, ZNumber, VariableRef >::value, "ZNumDomain must be a numeric abstract domain on ZNumber"); static_assert( numeric::IsAbstractDomain< QNumDomain, QNumber, VariableRef >::value, "QNumDomain must be a numeric abstract domain on QNumber"); public: using BasicBlockT = BasicBlock< VariableRef >; using ControlFlowGraphT = ControlFlowGraph< VariableRef >; using AbstractDomain = DomainProduct2< ZNumDomain, QNumDomain >; using Parent = InterleavedFwdFixpointIterator< ControlFlowGraphT*, AbstractDomain >; public: using StatementT = Statement< VariableRef >; using ZLinearAssignmentT = ZLinearAssignment< VariableRef >; using QLinearAssignmentT = QLinearAssignment< VariableRef >; using ZBinaryOperationT = ZBinaryOperation< VariableRef >; using QBinaryOperationT = QBinaryOperation< VariableRef >; using ZLinearAssertionT = ZLinearAssertion< VariableRef >; using QLinearAssertionT = QLinearAssertion< VariableRef >; using CheckPointT = CheckPoint< VariableRef >; private: // Invariant at checkpoints std::unordered_map< std::string, AbstractDomain > _checkpoints; public: /// \brief Create a fixpoint iterator on the given ControlFlowGraph explicit FixpointIterator(ControlFlowGraphT& cfg) : Parent(&cfg, AbstractDomain(ZNumDomain::bottom(), QNumDomain::bottom())) {} /// \brief Return the invariant at the given checkpoint const AbstractDomain& checkpoint(const std::string& name) { auto it = this->_checkpoints.find(name); if (it != this->_checkpoints.end()) { return it->second; } else { auto bottom = AbstractDomain(ZNumDomain::bottom(), QNumDomain::bottom()); auto res = this->_checkpoints.emplace(name, std::move(bottom)); return res.first->second; } } private: /// \brief Execution engine /// /// Helper to execute sequential statements struct ExecutionEngine { public: AbstractDomain inv; std::unordered_map< std::string, AbstractDomain >& checkpoints; public: using ResultType = void; void operator()(ZLinearAssignmentT* s) { inv.first().assign(s->result(), s->operand()); } void operator()(QLinearAssignmentT* s) { inv.second().assign(s->result(), s->operand()); } void operator()(ZBinaryOperationT* s) { inv.first().apply(s->op(), s->result(), s->left(), s->right()); } void operator()(QBinaryOperationT* s) { inv.second().apply(s->op(), s->result(), s->left(), s->right()); } void operator()(ZLinearAssertionT* s) { inv.first().add(s->constraint()); } void operator()(QLinearAssertionT* s) { inv.second().add(s->constraint()); } void operator()(CheckPointT* s) { auto it = checkpoints.find(s->name()); if (it != checkpoints.end()) { it->second = inv; } else { checkpoints.emplace(s->name(), inv); } } }; // end class ExecutionEngine public: /// \brief Semantic transformer for a node /// /// This method is called with the abstract value representing the state /// of the program upon entering the node. The method should return an /// abstract value representing the state of the program after the node. AbstractDomain analyze_node(BasicBlockT* bb, AbstractDomain inv) override { ExecutionEngine engine{std::move(inv), this->_checkpoints}; for (StatementT* stmt : *bb) { apply_visitor(engine, stmt); } return engine.inv; } /// \brief Semantic transformer for an edge /// /// This method is called with the abstract value representing the state of /// the program after exiting the source node. The method should return an /// abstract value representing the state of the program after the edge, at /// the entry of the destination node. AbstractDomain analyze_edge(BasicBlockT* /*src*/, BasicBlockT* /*dest*/, AbstractDomain inv) override { return inv; } /// \brief Process the computed abstract value for a node /// /// This method is called when the fixpoint is reached, and with the abstract /// value representing the state of the program upon entering the node. void process_pre(BasicBlockT*, const AbstractDomain&) override {} /// \brief Process the computed abstract value for a node /// /// This method is called when the fixpoint is reached, and with the abstract /// value representing the state of the program after the node. void process_post(BasicBlockT*, const AbstractDomain&) override {} public: /// \brief Dump the fixpoint for debugging purpose void dump(std::ostream& o) const { for (auto it = this->_checkpoints.begin(), et = this->_checkpoints.end(); it != et; ++it) { o << "Invariant at " << it->first << ":\n"; it->second.dump(o); o << "\n"; } } }; // end class FixpointIterator } // end namespace muzq } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/scalar/000077500000000000000000000000001473507761200237665ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/scalar/variable_factory.hpp000066400000000000000000000320161473507761200300150ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Example of scalar variable management * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace example { namespace scalar { /// \brief Simple scalar variable factory based on strings /// /// This is an example of a variable factory. /// /// Variables provided by this factory have a name and an index. /// /// This factory can be used for any scalar abstract domain or memory abstract /// domain. class VariableFactory { public: enum VariableKind { IntVariableKind, FloatVariableKind, PointerVariableKind, DynamicVariableKind, }; class Variable { private: /// \brief Variable name std::string _name; /// \brief Variable index Index _id; /// \brief Variable kind VariableKind _kind; /// \brief Variable bit width (if any) uint64_t _bit_width; /// \brief Variable signedness (if any) Signedness _sign; /// \brief Offset variable (if any) Variable* _offset_var; private: /// \brief Private constructor Variable(std::string name, Index id, VariableKind kind, uint64_t bit_width, Signedness sign, Variable* offset_var) : _name(std::move(name)), _id(id), _kind(kind), _bit_width(bit_width), _sign(sign), _offset_var(offset_var) {} public: static Variable make_int(std::string name, Index id, uint64_t bit_width, Signedness sign) { return {std::move(name), id, IntVariableKind, bit_width, sign, nullptr}; } static Variable make_float(std::string name, Index id) { return {std::move(name), id, FloatVariableKind, 0, Signed, nullptr}; } static Variable make_pointer(std::string name, Index id, Variable* offset_var) { return {std::move(name), id, PointerVariableKind, 0, Signed, offset_var}; } static Variable make_dynamic(std::string name, Index id, uint64_t bit_width, Signedness sign, Variable* offset_var) { return {std::move(name), id, DynamicVariableKind, bit_width, sign, offset_var}; } /// \brief No default constructor Variable() = delete; /// \brief No copy constructor Variable(const Variable&) = delete; /// \brief Move constructor Variable(Variable&&) = default; /// \brief No copy assignment operator Variable& operator=(const Variable&) = delete; /// \brief Move assignment operator Variable& operator=(Variable&&) = default; /// \brief Destructor ~Variable() = default; /// \brief Return the name of the variable const std::string& name() const { return this->_name; } /// \brief Return the unique index of the variable Index index() const { return this->_id; } /// \brief Return the kind of the variable VariableKind kind() const { return this->_kind; } /// \brief Return the bit width of the variable uint64_t bit_width() const { ikos_assert(this->_kind == IntVariableKind || this->_kind == DynamicVariableKind); return this->_bit_width; } /// \brief Return the signedness of the variable Signedness sign() const { ikos_assert(this->_kind == IntVariableKind || this->_kind == DynamicVariableKind); return this->_sign; } /// \brief Return the offset variable of the variable Variable* offset_var() const { ikos_assert(this->_kind == PointerVariableKind || this->_kind == DynamicVariableKind); return this->_offset_var; } }; // end class Variable public: using VariableRef = const Variable*; private: using Map = std::unordered_map< std::string, Variable >; private: Index _next_id = 1; Map _map; public: /// \brief Create a variable factory VariableFactory() = default; /// \brief Create a variable factory, starting with the given index explicit VariableFactory(Index start_id) : _next_id(start_id) {} /// \brief No copy constructor VariableFactory(const VariableFactory&) = delete; /// \brief No move constructor VariableFactory(VariableFactory&&) = delete; /// \brief No copy assignment operator VariableFactory& operator=(const VariableFactory&) = delete; /// \brief No move assignment operator VariableFactory& operator=(VariableFactory&&) = delete; /// \brief Destructor ~VariableFactory() = default; /// \brief Get or create a machine integer variable VariableRef get_int(const std::string& name, uint64_t bit_width, Signedness sign) { // This is sound because references are kept valid when using // std::unordered_map::emplace() auto it = this->_map.find(name); if (it != this->_map.end()) { return &(it->second); } auto res = this->_map.emplace(name, Variable::make_int(name, this->_next_id++, bit_width, sign)); ikos_assert(res.second); return &(res.first->second); } /// \brief Get or create a floating point variable VariableRef get_float(const std::string& name) { // This is sound because references are kept valid when using // std::unordered_map::emplace() auto it = this->_map.find(name); if (it != this->_map.end()) { return &(it->second); } auto res = this->_map.emplace(name, Variable::make_float(name, this->_next_id++)); ikos_assert(res.second); return &(res.first->second); } /// \brief Get or create a pointer variable VariableRef get_pointer(const std::string& name, uint64_t offset_bit_width, Signedness offset_sign) { // This is sound because references are kept valid when using // std::unordered_map::emplace() auto it = this->_map.find(name); if (it != this->_map.end()) { return &(it->second); } auto res = this->_map.emplace(name + ".offset", Variable::make_int(name + ".offset", this->_next_id++, offset_bit_width, offset_sign)); ikos_assert(res.second); Variable* offset_var = &(res.first->second); res = this->_map.emplace(name, Variable::make_pointer(name, this->_next_id++, offset_var)); ikos_assert(res.second); return &(res.first->second); } /// \brief Get or create a dynamically typed variable VariableRef get_dynamic(const std::string& name, uint64_t bit_width, Signedness sign, uint64_t offset_bit_width, Signedness offset_sign) { // This is sound because references are kept valid when using // std::unordered_map::emplace() auto it = this->_map.find(name); if (it != this->_map.end()) { return &(it->second); } auto res = this->_map.emplace(name + ".offset", Variable::make_int(name + ".offset", this->_next_id++, offset_bit_width, offset_sign)); ikos_assert(res.second); Variable* offset_var = &(res.first->second); res = this->_map.emplace(name, Variable::make_dynamic(name, this->_next_id++, bit_width, sign, offset_var)); ikos_assert(res.second); return &(res.first->second); } }; // end class VariableFactory /// \brief Write a variable on a stream inline std::ostream& operator<<(std::ostream& o, VariableFactory::VariableRef var) { o << var->name(); return o; } } // end namespace scalar } // end namespace example } // end namespace core } // end namespace ikos namespace ikos { namespace core { /// \brief Implement IndexableTraits for /// example::scalar::VariableFactory::VariableRef template <> struct IndexableTraits< example::scalar::VariableFactory::VariableRef > { static Index index(example::scalar::VariableFactory::VariableRef var) { return var->index(); } }; /// \brief Implement DumpableTraits for /// example::scalar::VariableFactory::VariableRef template <> struct DumpableTraits< example::scalar::VariableFactory::VariableRef > { static void dump(std::ostream& o, example::scalar::VariableFactory::VariableRef var) { o << var->name(); } }; namespace machine_int { /// \brief Implement VariableTraits for /// example::scalar::VariableFactory::VariableRef template <> struct VariableTraits< example::scalar::VariableFactory::VariableRef > { static uint64_t bit_width(example::scalar::VariableFactory::VariableRef var) { return var->bit_width(); } static Signedness sign(example::scalar::VariableFactory::VariableRef var) { return var->sign(); } }; } // end namespace machine_int namespace scalar { /// \brief Implement VariableTraits for /// example::scalar::VariableFactory::VariableRef template <> struct VariableTraits< example::scalar::VariableFactory::VariableRef > { static bool is_int(example::scalar::VariableFactory::VariableRef var) { return var->kind() == example::scalar::VariableFactory::IntVariableKind; } static bool is_float(example::scalar::VariableFactory::VariableRef var) { return var->kind() == example::scalar::VariableFactory::FloatVariableKind; } static bool is_pointer(example::scalar::VariableFactory::VariableRef var) { return var->kind() == example::scalar::VariableFactory::PointerVariableKind; } static bool is_dynamic(example::scalar::VariableFactory::VariableRef var) { return var->kind() == example::scalar::VariableFactory::DynamicVariableKind; } static example::scalar::VariableFactory::VariableRef offset_var( example::scalar::VariableFactory::VariableRef var) { return var->offset_var(); } }; } // end namespace scalar } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/example/variable_factory.hpp000066400000000000000000000137141473507761200265540ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Example of variable management * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { namespace example { /// \brief Simple variable factory based on strings /// /// This is an example of a variable factory. /// /// Variables provided by this factory have a name and an index. /// /// This factory can be used for any numerical abstract domain (namespace /// `numeric`), the nullity domain, the uninitialized domain, etc. /// /// For a factory to use with a machine integer abstract domain (namespace /// `machine_int`), see `ikos/core/example/machine_int/variable_factory.hpp` class VariableFactory { public: class Variable { public: friend class VariableFactory; private: std::string _name; Index _id; private: /// \brief Private constructor Variable(std::string name, Index id) : _name(std::move(name)), _id(id) {} public: /// \brief No default constructor Variable() = delete; /// \brief No copy constructor Variable(const Variable&) = delete; /// \brief Move constructor Variable(Variable&&) = default; /// \brief No copy assignment operator Variable& operator=(const Variable&) = delete; /// \brief Move assignment operator Variable& operator=(Variable&&) = default; /// \brief Destructor ~Variable() = default; /// \brief Return the name of the variable const std::string& name() const { return this->_name; } /// \brief Return the unique index of the variable Index index() const { return this->_id; } }; // end class Variable public: using VariableRef = const Variable*; private: using Map = std::unordered_map< std::string, Variable >; private: Index _next_id = 1; Map _map; public: /// \brief Create a variable factory VariableFactory() = default; /// \brief Create a variable factory, starting with the given index explicit VariableFactory(Index start_id) : _next_id(start_id) {} /// \brief No copy constructor VariableFactory(const VariableFactory&) = delete; /// \brief No move constructor VariableFactory(VariableFactory&&) = delete; /// \brief No copy assignment operator VariableFactory& operator=(const VariableFactory&) = delete; /// \brief No move assignment operator VariableFactory& operator=(VariableFactory&&) = delete; /// \brief Destructor ~VariableFactory() = default; /// \brief Get or create a variable with the given name VariableRef get(const std::string& name) { // This is sound because references are kept valid when using // std::unordered_map::emplace() auto it = this->_map.find(name); if (it != this->_map.end()) { return &(it->second); } else { auto res = this->_map.emplace(name, Variable(name, this->_next_id++)); ikos_assert(res.second); return &(res.first->second); } } }; // end class VariableFactory /// \brief Write a variable on a stream inline std::ostream& operator<<(std::ostream& o, VariableFactory::VariableRef var) { o << var->name(); return o; } } // end namespace example } // end namespace core } // end namespace ikos namespace ikos { namespace core { /// \brief Implement IndexableTraits for example::VariableFactory::VariableRef template <> struct IndexableTraits< example::VariableFactory::VariableRef > { static Index index(example::VariableFactory::VariableRef var) { return var->index(); } }; /// \brief Implement DumpableTraits for example::VariableFactory::VariableRef template <> struct DumpableTraits< example::VariableFactory::VariableRef > { static void dump(std::ostream& o, example::VariableFactory::VariableRef var) { o << var->name(); } }; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/exception.hpp000066400000000000000000000103101473507761200235700ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Exception definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Base class for ikos exceptions class Exception : public std::exception { public: /// \brief Create a new exception /// /// Note that a call to what() will return an empty string. Exception() noexcept = default; /// \brief Copy constructor Exception(const Exception&) noexcept = default; /// \brief Move constructor Exception(Exception&&) noexcept = default; /// \brief Copy assignment operator Exception& operator=(const Exception&) noexcept = default; /// \brief Move assignment operator Exception& operator=(Exception&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override { return ""; } /// \brief Destructor ~Exception() override = default; }; // end class Exception /// \brief Exception for logical errors class LogicError : public Exception { private: /// \brief Explanatory message /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _msg; public: /// \brief Constructor /// /// \param msg Explanatory message explicit LogicError(const std::string& msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief Constructor /// /// \param msg Explanatory message explicit LogicError(const char* msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief No default constructor LogicError() = delete; /// \brief Copy constructor LogicError(const LogicError&) noexcept = default; /// \brief Move constructor LogicError(LogicError&&) noexcept = default; /// \brief Copy assignment operator LogicError& operator=(const LogicError&) noexcept = default; /// \brief Move assignment operator LogicError& operator=(LogicError&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override { return this->_msg->c_str(); } /// \brief Destructor ~LogicError() override = default; }; // end class LogicError } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/fixpoint/000077500000000000000000000000001473507761200227265ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/fixpoint/concurrent_fwd_fixpoint_iterator.hpp000066400000000000000000000560161473507761200323220ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Interleaved concurrent forward fixpoint iterator * * The interleaved concurrent fixpoint iterator is described in Sung Kook Kim's, * Arnaud J. Venet's, and Aditya V. Thakur's paper: "Deterministic Parallel * Fixpoint Computation", in POPL 2020. * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { /// \brief Interleaved concurrent forward fixpoint iterator /// /// This class computes a fixpoint on a control flow graph. template < typename GraphRef, typename AbstractValue, typename GraphTrait = GraphTraits< GraphRef > > class InterleavedConcurrentFwdFixpointIterator : public ForwardFixpointIterator< GraphRef, AbstractValue, GraphTrait > { private: using NodeRef = typename GraphTrait::NodeRef; using WpoT = Wpo< GraphRef, GraphTrait >; using WpoNodeT = WpoNode< GraphRef, GraphTrait >; using WpoNodeKind = typename WpoNodeT::Kind; using WpoIndex = std::size_t; private: class WorkNode; private: GraphRef _cfg; WpoT _wpo; AbstractValue _bottom; NodeRef _entry; std::vector< WorkNode, tbb::cache_aligned_allocator< WorkNode > > _work_nodes; std::unordered_map< NodeRef, WorkNode* > _node_to_work; bool _converged; public: /// \brief Create an interleaved concurrent forward fixpoint iterator /// /// \param cfg The control flow graph /// \param bottom The bottom abstract value explicit InterleavedConcurrentFwdFixpointIterator(GraphRef cfg, AbstractValue bottom) : _cfg(cfg), _wpo(cfg), _bottom(std::move(bottom)), _entry(GraphTrait::entry(cfg)), _converged(false) {} /// \brief No copy constructor InterleavedConcurrentFwdFixpointIterator( const InterleavedConcurrentFwdFixpointIterator&) = delete; /// \brief Move constructor InterleavedConcurrentFwdFixpointIterator( InterleavedConcurrentFwdFixpointIterator&&) = default; /// \brief No copy assignment operator InterleavedConcurrentFwdFixpointIterator& operator=( const InterleavedConcurrentFwdFixpointIterator&) = delete; /// \brief Move assignment operator InterleavedConcurrentFwdFixpointIterator& operator=( InterleavedConcurrentFwdFixpointIterator&&) = default; /// \brief Return the control flow graph GraphRef cfg() const override { return this->_cfg; } /// \brief Return the weak partial order of the graph const WpoT& wpo() const { return this->_wpo; } /// \brief Return the bottom abstract value const AbstractValue& bottom() const { return this->_bottom; } /// \brief Return the entry node of the graph NodeRef entry() const { return this->_entry; } /// \brief Return true if the fixpoint is reached bool converged() const override { return this->_converged; } /// \brief Return the pre invariant for the given node const AbstractValue& pre(NodeRef node) const override { auto it = this->_node_to_work.find(node); if (it != this->_node_to_work.end()) { return it->second->pre(); } else { return this->_bottom; } } /// \brief Return the post invariant for the given node const AbstractValue& post(NodeRef node) const override { auto it = this->_node_to_work.find(node); if (it != this->_node_to_work.end()) { return it->second->post(); } else { return this->_bottom; } } /// \brief Extrapolate the new state after an increasing iteration /// /// This is called after each iteration of a cycle, until the fixpoint is /// reached. In order to converge, the widening operator must be applied. /// This method gives the user the ability to use different widening /// strategies. /// /// By default, it applies a join for the first iteration, and then the /// widening until it reaches the fixpoint. /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual AbstractValue extrapolate(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); if (iteration <= 1) { return before.join_iter(after); } else { return before.widening(after); } } /// \brief Check if the increasing iterations fixpoint is reached /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual bool is_increasing_iterations_fixpoint(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); ikos_ignore(iteration); return after.leq(before); } /// \brief Refine the new state after a decreasing iteration /// /// This is called after each iteration of a cycle, until the post fixpoint /// is reached. In order to converge, the narrowing operator must be applied. /// This method gives the user the ability to use different narrowing /// strategies. /// /// By default, it applies the narrowing until it reaches the post fixpoint. /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual AbstractValue refine(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); ikos_ignore(iteration); return before.narrowing(after); } /// \brief Check if the decreasing iterations fixpoint is reached /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual bool is_decreasing_iterations_fixpoint(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); ikos_ignore(iteration); return before.leq(after); } private: /// \brief Represents a work node /// /// This is associated to a weak partial order node and a graph node class WorkNode { private: using WorkNodeVector = std::vector< WorkNode*, tbb::cache_aligned_allocator< WorkNode* > >; private: std::mutex _mutex; WpoNodeKind _kind; NodeRef _node; WpoIndex _index; InterleavedConcurrentFwdFixpointIterator& _iterator; // Reference count of number of inputs that are not yet updated std::atomic< std::size_t > _ref_count; WorkNodeVector _successors; // For head nodes FixpointIterationKind _iteration_kind; unsigned _iteration_count; // For plain and head nodes WorkNodeVector _predecessors; std::mutex _post_mutex; AbstractValue _pre; AbstractValue _post; // For exit nodes WorkNode* _head; public: /// \brief Constructor WorkNode(WpoNodeKind kind, NodeRef node, WpoIndex index, InterleavedConcurrentFwdFixpointIterator& iterator, std::size_t ref_count, AbstractValue pre, AbstractValue post) : _kind(kind), _node(node), _index(index), _iterator(iterator), _ref_count(ref_count), _iteration_kind(FixpointIterationKind::Increasing), _iteration_count(0), _pre(std::move(pre)), _post(std::move(post)), _head(nullptr) { this->_pre.normalize(); } /// \brief Copy constructor /// /// Required by old versions of TBB WorkNode(const WorkNode& other) : _kind(other._kind), _node(other._node), _index(other._index), _iterator(other._iterator), _ref_count(other._ref_count.load()), _successors(other._successors), _iteration_kind(other._iteration_kind), _iteration_count(other._iteration_count), _predecessors(other._predecessors), _pre(other._pre), _post(other._post), _head(other._head) {} /// \brief Move constructor WorkNode(WorkNode&& other) : _kind(other._kind), _node(other._node), _index(other._index), _iterator(other._iterator), _ref_count(other._ref_count.load()), _successors(std::move(other._successors)), _iteration_kind(other._iteration_kind), _iteration_count(other._iteration_count), _predecessors(std::move(other._predecessors)), _pre(std::move(other._pre)), _post(std::move(other._post)), _head(other._head) {} /// \brief No copy assignment operator WorkNode& operator=(const WorkNode&) = delete; /// \brief No move assignment operator WorkNode& operator=(WorkNode&&) = delete; /// \brief Destructor ~WorkNode() = default; /// \brief Return the node kind WpoNodeKind kind() const { return this->_kind; } /// \brief Return the graph node NodeRef node() const { return this->_node; } /// \brief Set the head of the given exit node void set_head(WorkNode* work_node) { ikos_assert(work_node != nullptr); ikos_assert(this->_kind == WpoNodeKind::Exit); this->_head = work_node; } /// \brief Add a successor work node void add_successor(WorkNode* work_node) { ikos_assert(work_node != nullptr); this->_successors.push_back(work_node); } /// \brief Add a predecessor work node void add_predecessor(WorkNode* work_node) { ikos_assert(work_node != nullptr); ikos_assert(this->_kind != WpoNodeKind::Exit); this->_predecessors.push_back(work_node); } /// \brief Return the pre invariant const AbstractValue& pre() const { ikos_assert(this->_kind != WpoNodeKind::Exit); return this->_pre; } /// \brief Return the post invariant const AbstractValue& post() const { ikos_assert(this->_kind != WpoNodeKind::Exit); return this->_post; } /// \brief Update the node const WorkNodeVector& update() { std::lock_guard< std::mutex > lock(this->_mutex); switch (_kind) { case WpoNodeKind::Plain: return this->update_plain(); case WpoNodeKind::Head: return this->update_head(); case WpoNodeKind::Exit: return this->update_exit(); default: ikos_unreachable("unexpected kind"); } } /// \brief Decrement the reference counter std::size_t decr_ref_count() { return --this->_ref_count; } private: /// \brief Reset the reference counter void reset_ref_count() { this->_ref_count = this->_iterator.wpo().num_predecessors_reducible(this->_index); } /// \brief Thread-safe read access to the post invariant AbstractValue get_post() { std::lock_guard< std::mutex > lock(this->_post_mutex); return AbstractValue(this->_post); } /// \brief Thread-safe write access to the post invariant void set_post(AbstractValue post) { post.normalize(); std::lock_guard< std::mutex > lock(this->_post_mutex); this->_post = std::move(post); } const WorkNodeVector& update_plain() { ikos_assert(this->_kind == WpoNodeKind::Plain); // The assumption is that the pre for entry node has already been // initialized, and the entry node will be processed only once. if (this->_node != this->_iterator.entry()) { this->_pre = this->_iterator.bottom(); } // Collect invariants from incoming edges for (WorkNode* pred : this->_predecessors) { this->_pre.join_with(this->_iterator.analyze_edge(pred->_node, this->_node, pred->get_post())); } this->_pre.normalize(); this->set_post(this->_iterator.analyze_node(this->_node, this->_pre)); this->reset_ref_count(); return this->_successors; } /// \brief Update a head node const WorkNodeVector& update_head() { ikos_assert(this->_kind == WpoNodeKind::Head); // Initialization if (this->_iteration_count == 0) { // Collect invariants from incoming edges for (WorkNode* pred : this->_predecessors) { if (!this->_iterator.wpo().is_back_edge(this->_node, pred->_node)) { this->_pre.join_with( this->_iterator.analyze_edge(pred->_node, this->_node, pred->get_post())); } } this->_pre.normalize(); this->_iteration_count++; } this->set_post(this->_iterator.analyze_node(this->_node, this->_pre)); return this->_successors; } /// \brief Update a exit node const WorkNodeVector& update_exit() { ikos_assert(this->_kind == WpoNodeKind::Exit); bool converged = this->_head->update_head_backedge(); if (converged) { this->reset_ref_count(); this->handle_irreducible(); return this->_successors; } else { this->reset_ref_count(); return this->_head->update_head(); } } /// \brief Returns true if the loop converged, false otherwise bool update_head_backedge() { ikos_assert(this->_kind == WpoNodeKind::Head); // Invariant from the head of the loop AbstractValue new_pre_in = this->_iterator.bottom(); // Invariant from the tail of the loop AbstractValue new_pre_back = this->_iterator.bottom(); for (WorkNode* pred : this->_predecessors) { if (!this->_iterator.wpo().is_back_edge(this->_node, pred->_node)) { new_pre_in.join_with(this->_iterator.analyze_edge(pred->_node, this->_node, pred->get_post())); } else { new_pre_back.join_with( this->_iterator.analyze_edge(pred->_node, this->_node, pred->get_post())); } } new_pre_in.join_loop_with(std::move(new_pre_back)); AbstractValue new_pre(std::move(new_pre_in)); new_pre.normalize(); if (this->_iteration_kind == FixpointIterationKind::Increasing) { // Increasing iteration with widening AbstractValue inv = this->_iterator.extrapolate(this->_node, this->_iteration_count, this->_pre, new_pre); inv.normalize(); if (this->_iterator .is_increasing_iterations_fixpoint(this->_node, this->_iteration_count, this->_pre, inv)) { // Post-fixpoint reached // Use this iteration as a decreasing iteration this->_iteration_kind = FixpointIterationKind::Decreasing; this->_iteration_count = 1; } else { this->_pre = std::move(inv); this->_iteration_count++; return false; // Not converged } } if (this->_iteration_kind == FixpointIterationKind::Decreasing) { // Decreasing iteration with narrowing AbstractValue inv = this->_iterator.refine(this->_node, this->_iteration_count, this->_pre, new_pre); inv.normalize(); if (this->_iterator .is_decreasing_iterations_fixpoint(this->_node, this->_iteration_count, this->_pre, inv)) { // No more refinement possible this->_pre = std::move(inv); this->_iteration_kind = FixpointIterationKind::Increasing; this->_iteration_count = 0; this->reset_ref_count(); return true; // Converged } else { this->_pre = std::move(inv); this->_iteration_count++; return false; // Not converged } } ikos_unreachable("unreachable"); } /// \brief Handle irreducible edges void handle_irreducible() { ikos_assert(this->_kind == WpoNodeKind::Exit); for (const auto& p : this->_iterator.wpo().irreducibles(this->_index)) { this->_iterator._work_nodes[p.first]._ref_count += p.second; } } }; // end class WorkNode /// \brief Worker on a node for tbb::parallel_for_each class Worker { public: // Required by tbb::parallel_for_each using argument_type = WorkNode*; public: /// \brief Constructor Worker() = default; /// \brief No copy constructor Worker(const Worker&) = delete; /// \brief No move constructor Worker(Worker&&) = delete; /// \brief No copy assignment operator Worker& operator=(const Worker&) = delete; /// \brief No move assignment operator Worker& operator=(Worker&&) = delete; /// \brief Destructor ~Worker() = default; /// \brief Process a work node void operator()(WorkNode* work_node, tbb::feeder< argument_type >& feeder) const { const auto& successors = work_node->update(); for (WorkNode* successor : successors) { if (successor->decr_ref_count() == 0) { feeder.add(successor); } } } }; public: /// \brief Compute the fixpoint with the given initial abstract value void run(AbstractValue init) override { std::size_t size = this->_wpo.size(); // Clear the fixpoint this->clear(); // Build the work nodes this->_work_nodes.reserve(size); for (std::size_t idx = 0; idx < size; idx++) { WpoNodeKind kind = this->_wpo.kind(idx); NodeRef node = this->_wpo.node(idx); AbstractValue pre = this->_bottom; if (node == this->_entry && kind != WpoNodeKind::Exit) { pre = std::move(init); } this->_work_nodes.push_back(WorkNode( /* kind = */ kind, /* node = */ node, /* index = */ idx, /* iterator = */ *this, /* ref_count = */ this->_wpo.num_predecessors(idx), /* pre = */ std::move(pre), /* post = */ this->_bottom)); } // Build the node to work-node map for (std::size_t idx = 0; idx < size; idx++) { WorkNode& work_node = this->_work_nodes[idx]; if (work_node.kind() != WpoNodeKind::Exit) { this->_node_to_work.emplace(work_node.node(), &work_node); } } // Link the work nodes (predecessors/successors) for (std::size_t idx = 0; idx < size; idx++) { WorkNode& work_node = this->_work_nodes[idx]; for (std::size_t succ : this->_wpo.successors(idx)) { work_node.add_successor(&this->_work_nodes[succ]); } if (work_node.kind() == WpoNodeKind::Exit) { work_node.set_head(&this->_work_nodes[this->_wpo.head_of_exit(idx)]); } else { NodeRef node = work_node.node(); for (auto it = GraphTrait::predecessor_begin(node), et = GraphTrait::predecessor_end(node); it != et; ++it) { work_node.add_predecessor(this->_node_to_work[*it]); } } } // Run the analysis std::array< WorkNode*, 1 > root = {this->_node_to_work[this->_entry]}; tbb::parallel_for_each(std::begin(root), std::end(root), Worker()); this->_converged = true; // Call process_pre/process_post methods for (WorkNode& work_node : this->_work_nodes) { if (work_node.kind() != WpoNodeKind::Exit) { NodeRef node = work_node.node(); this->process_pre(node, work_node.pre()); this->process_post(node, work_node.post()); } } } /// \brief Clear the current fixpoint void clear() override { this->_converged = false; this->_work_nodes.clear(); this->_node_to_work.clear(); } /// \brief Destructor ~InterleavedConcurrentFwdFixpointIterator() override = default; }; // end class InterleavedConcurrentFwdFixpointIterator } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/fixpoint/fixpoint_iterator.hpp000066400000000000000000000130601473507761200272100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for fixpoint iterators. * * Author: Arnaud J. Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { /// \brief Base class for forward fixpoint iterators template < typename GraphRef, typename AbstractValue, typename GraphTrait = GraphTraits< GraphRef > > class ForwardFixpointIterator { public: static_assert(IsGraph< GraphRef, GraphTrait >::value, "GraphRef does not implement GraphTraits"); static_assert(IsAbstractDomain< AbstractValue >::value, "AbstractValue does not implement AbstractDomain"); public: /// \brief Reference to a node of the graph using NodeRef = typename GraphTrait::NodeRef; public: /// \brief Default constructor ForwardFixpointIterator() = default; /// \brief Copy constructor ForwardFixpointIterator(const ForwardFixpointIterator&) noexcept = default; /// \brief Move constructor ForwardFixpointIterator(ForwardFixpointIterator&&) noexcept = default; /// \brief Copy assignment operator ForwardFixpointIterator& operator=(const ForwardFixpointIterator&) noexcept = default; /// \brief Move assignment operator ForwardFixpointIterator& operator=(ForwardFixpointIterator&&) noexcept = default; /// \brief Return the control flow graph virtual GraphRef cfg() const = 0; /// \brief Return the pre abstract value for the given node virtual const AbstractValue& pre(NodeRef node) const = 0; /// \brief Return the post invariant for the given node virtual const AbstractValue& post(NodeRef node) const = 0; /// \brief Compute the fixpoint with the given initial abstract value virtual void run(AbstractValue init) = 0; /// \brief Return true if the fixpoint is reached virtual bool converged() const = 0; /// \brief Clear the current fixpoint virtual void clear() = 0; /// \brief Semantic transformer for a node /// /// This method is called with the abstract value representing the state /// of the program upon entering the node. The method should return an /// abstract value representing the state of the program after the node. virtual AbstractValue analyze_node(NodeRef node, AbstractValue state) = 0; /// \brief Semantic transformer for an edge /// /// This method is called with the abstract value representing the state of /// the program after exiting the source node. The method should return an /// abstract value representing the state of the program after the edge, at /// the entry of the destination node. virtual AbstractValue analyze_edge(NodeRef src, NodeRef dest, AbstractValue state) = 0; /// \brief Process the computed abstract value for a node /// /// This method is called when the fixpoint is reached, and with the abstract /// value representing the state of the program upon entering the node. virtual void process_pre(NodeRef, const AbstractValue&) = 0; /// \brief Process the computed abstract value for a node /// /// This method is called when the fixpoint is reached, and with the abstract /// value representing the state of the program after the node. virtual void process_post(NodeRef, const AbstractValue&) = 0; /// \brief Destructor virtual ~ForwardFixpointIterator() = default; }; // end class ForwardFixpointIterator /// \brief Kind of fixpoint iteration enum class FixpointIterationKind { Increasing, Decreasing }; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/fixpoint/fwd_fixpoint_iterator.hpp000066400000000000000000000424631473507761200300610ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Forward fixpoint iterators of varying complexity and precision. * * The interleaved fixpoint iterator is described in G. Amato and F. Scozzari's * paper: Localizing widening and narrowing. In Proceedings of SAS 2013, * pages 25-42. LNCS 7935, 2013. * * Author: Arnaud J. Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { namespace interleaved_fwd_fixpoint_iterator_impl { template < typename GraphRef, typename AbstractValue, typename GraphTrait > class WtoIterator; template < typename GraphRef, typename AbstractValue, typename GraphTrait > class WtoProcessor; } // end namespace interleaved_fwd_fixpoint_iterator_impl /// \brief Interleaved forward fixpoint iterator /// /// This class computes a fixpoint on a control flow graph. template < typename GraphRef, typename AbstractValue, typename GraphTrait = GraphTraits< GraphRef > > class InterleavedFwdFixpointIterator : public ForwardFixpointIterator< GraphRef, AbstractValue, GraphTrait > { friend class interleaved_fwd_fixpoint_iterator_impl:: WtoIterator< GraphRef, AbstractValue, GraphTrait >; private: using NodeRef = typename GraphTrait::NodeRef; using InvariantTable = std::unordered_map< NodeRef, AbstractValue >; using WtoT = Wto< GraphRef, GraphTrait >; using WtoIterator = interleaved_fwd_fixpoint_iterator_impl:: WtoIterator< GraphRef, AbstractValue, GraphTrait >; using WtoProcessor = interleaved_fwd_fixpoint_iterator_impl:: WtoProcessor< GraphRef, AbstractValue, GraphTrait >; private: GraphRef _cfg; WtoT _wto; AbstractValue _bottom; InvariantTable _pre; InvariantTable _post; bool _converged; public: /// \brief Create an interleaved forward fixpoint iterator /// /// \param cfg The control flow graph /// \param bottom The bottom abstract value InterleavedFwdFixpointIterator(GraphRef cfg, AbstractValue bottom) : _cfg(cfg), _wto(cfg), _bottom(std::move(bottom)), _converged(false) {} /// \brief No copy constructor InterleavedFwdFixpointIterator(const InterleavedFwdFixpointIterator&) = delete; /// \brief Move constructor InterleavedFwdFixpointIterator(InterleavedFwdFixpointIterator&&) = default; /// \brief No copy assignment operator InterleavedFwdFixpointIterator& operator=( const InterleavedFwdFixpointIterator&) = delete; /// \brief Move assignment operator InterleavedFwdFixpointIterator& operator=(InterleavedFwdFixpointIterator&&) = default; /// \brief Return the control flow graph GraphRef cfg() const override { return this->_cfg; } /// \brief Return the weak topological order of the graph const WtoT& wto() const { return this->_wto; } /// \brief Return the bottom abstract value const AbstractValue& bottom() const { return this->_bottom; } /// \brief Return true if the fixpoint is reached bool converged() const override { return this->_converged; } private: /// \brief Set the invariant for the given node void set(InvariantTable& table, NodeRef node, AbstractValue inv) const { inv.normalize(); auto it = table.find(node); if (it != table.end()) { it->second = std::move(inv); } else { table.emplace(node, std::move(inv)); } } /// \brief Set the pre invariant for the given node void set_pre(NodeRef node, AbstractValue inv) { this->set(this->_pre, node, std::move(inv)); } /// \brief Set the post invariant for the given node void set_post(NodeRef node, AbstractValue inv) { this->set(this->_post, node, std::move(inv)); } /// \brief Return the invariant for the given node const AbstractValue& get(const InvariantTable& table, NodeRef node) const { auto it = table.find(node); if (it != table.end()) { return it->second; } else { return this->_bottom; } } public: /// \brief Return the pre invariant for the given node const AbstractValue& pre(NodeRef node) const override { return this->get(this->_pre, node); } /// \brief Return the post invariant for the given node const AbstractValue& post(NodeRef node) const override { return this->get(this->_post, node); } /// \brief Extrapolate the new state after an increasing iteration /// /// This is called after each iteration of a cycle, until the fixpoint is /// reached. In order to converge, the widening operator must be applied. /// This method gives the user the ability to use different widening /// strategies. /// /// By default, it applies a join for the first iteration, and then the /// widening until it reaches the fixpoint. /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual AbstractValue extrapolate(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); if (iteration <= 1) { return before.join_iter(after); } else { return before.widening(after); } } /// \brief Check if the increasing iterations fixpoint is reached /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual bool is_increasing_iterations_fixpoint(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); ikos_ignore(iteration); return after.leq(before); } /// \brief Refine the new state after a decreasing iteration /// /// This is called after each iteration of a cycle, until the post fixpoint /// is reached. In order to converge, the narrowing operator must be applied. /// This method gives the user the ability to use different narrowing /// strategies. /// /// By default, it applies the narrowing until it reaches the post fixpoint. /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual AbstractValue refine(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); ikos_ignore(iteration); return before.narrowing(after); } /// \brief Check if the decreasing iterations fixpoint is reached /// /// \param head Head of the cycle /// \param iteration Iteration number /// \param before Abstract value before the iteration /// \param after Abstract value after the iteration virtual bool is_decreasing_iterations_fixpoint(NodeRef head, unsigned iteration, const AbstractValue& before, const AbstractValue& after) { ikos_ignore(head); ikos_ignore(iteration); return before.leq(after); } /// \brief Notify the beginning of the analysis of a cycle /// /// This method is called before analyzing a cycle. virtual void notify_enter_cycle(NodeRef head) { ikos_ignore(head); } /// \brief Notify the beginning of an iteration on a cycle /// /// This method is called for each iteration on a cycle. virtual void notify_cycle_iteration(NodeRef head, unsigned iteration, FixpointIterationKind kind) { ikos_ignore(head); ikos_ignore(iteration); ikos_ignore(kind); } /// \brief Notify the end of the analysis of a cycle /// /// This method is called after reaching a fixpoint on a cycle. virtual void notify_leave_cycle(NodeRef head) { ikos_ignore(head); } /// \brief Compute the fixpoint with the given initial abstract value void run(AbstractValue init) override { this->clear(); this->set_pre(GraphTrait::entry(this->_cfg), std::move(init)); // Compute the fixpoint WtoIterator iterator(*this); this->_wto.accept(iterator); this->_converged = true; // Call process_pre/process_post methods WtoProcessor processor(*this); this->_wto.accept(processor); } /// \brief Clear the pre invariants void clear_pre() { this->_pre.clear(); } /// \brief Clear the post invariants void clear_post() { this->_post.clear(); } /// \brief Clear the current fixpoint void clear() override { this->_converged = false; this->_pre.clear(); this->_post.clear(); } /// \brief Destructor ~InterleavedFwdFixpointIterator() override = default; }; // end class InterleavedFwdFixpointIterator namespace interleaved_fwd_fixpoint_iterator_impl { template < typename GraphRef, typename AbstractValue, typename GraphTrait > class WtoIterator final : public WtoComponentVisitor< GraphRef, GraphTrait > { public: using InterleavedIterator = InterleavedFwdFixpointIterator< GraphRef, AbstractValue, GraphTrait >; using NodeRef = typename GraphTrait::NodeRef; using WtoVertexT = WtoVertex< GraphRef, GraphTrait >; using WtoCycleT = WtoCycle< GraphRef, GraphTrait >; using WtoT = Wto< GraphRef, GraphTrait >; using WtoNestingT = WtoNesting< GraphRef, GraphTrait >; private: /// \brief Fixpoint engine InterleavedIterator& _iterator; /// \brief Graph entry point NodeRef _entry; public: explicit WtoIterator(InterleavedIterator& iterator) : _iterator(iterator), _entry(GraphTrait::entry(iterator.cfg())) {} void visit(const WtoVertexT& vertex) override { NodeRef node = vertex.node(); AbstractValue pre = this->_iterator.bottom(); // Use the invariant for the entry point if (node == this->_entry) { pre = this->_iterator.pre(node); } // Collect invariants from incoming edges for (auto it = GraphTrait::predecessor_begin(node), et = GraphTrait::predecessor_end(node); it != et; ++it) { NodeRef pred = *it; pre.join_with( this->_iterator.analyze_edge(pred, node, this->_iterator.post(pred))); } pre.normalize(); this->_iterator.set_pre(node, pre); this->_iterator.set_post(node, this->_iterator.analyze_node(node, pre)); } void visit(const WtoCycleT& cycle) override { NodeRef head = cycle.head(); AbstractValue pre = this->_iterator.bottom(); const WtoNestingT& cycle_nesting = this->_iterator.wto().nesting(head); this->_iterator.notify_enter_cycle(head); // Collect invariants from incoming edges for (auto it = GraphTrait::predecessor_begin(head), et = GraphTrait::predecessor_end(head); it != et; ++it) { NodeRef pred = *it; if (this->_iterator.wto().nesting(pred) <= cycle_nesting) { pre.join_with(this->_iterator.analyze_edge(pred, head, this->_iterator.post(pred))); } } // Fixpoint iterations FixpointIterationKind kind = FixpointIterationKind::Increasing; for (unsigned iteration = 1;; ++iteration) { this->_iterator.notify_cycle_iteration(head, iteration, kind); pre.normalize(); this->_iterator.set_pre(head, pre); this->_iterator.set_post(head, this->_iterator.analyze_node(head, pre)); for (auto it = cycle.begin(), et = cycle.end(); it != et; ++it) { it->accept(*this); } // Invariant from the head of the loop AbstractValue new_pre_in = this->_iterator.bottom(); // Invariant from the tail of the loop AbstractValue new_pre_back = this->_iterator.bottom(); for (auto it = GraphTrait::predecessor_begin(head), et = GraphTrait::predecessor_end(head); it != et; ++it) { NodeRef pred = *it; AbstractValue inv = this->_iterator.analyze_edge(pred, head, this->_iterator.post(pred)); if (this->_iterator.wto().nesting(pred) <= cycle_nesting) { new_pre_in.join_with(std::move(inv)); } else { new_pre_back.join_with(std::move(inv)); } } new_pre_in.join_loop_with(std::move(new_pre_back)); AbstractValue new_pre(std::move(new_pre_in)); new_pre.normalize(); if (kind == FixpointIterationKind::Increasing) { // Increasing iteration with widening AbstractValue inv = this->_iterator.extrapolate(head, iteration, pre, new_pre); inv.normalize(); if (this->_iterator.is_increasing_iterations_fixpoint(head, iteration, pre, inv)) { // Post-fixpoint reached // Use this iteration as a decreasing iteration kind = FixpointIterationKind::Decreasing; iteration = 1; } else { pre = std::move(inv); } } if (kind == FixpointIterationKind::Decreasing) { // Decreasing iteration with narrowing AbstractValue inv = this->_iterator.refine(head, iteration, pre, new_pre); inv.normalize(); if (this->_iterator.is_decreasing_iterations_fixpoint(head, iteration, pre, inv)) { // No more refinement possible this->_iterator.set_pre(head, std::move(inv)); break; } else { pre = std::move(inv); } } } this->_iterator.notify_leave_cycle(head); } }; // end class WtoIterator template < typename GraphRef, typename AbstractValue, typename GraphTrait > class WtoProcessor final : public WtoComponentVisitor< GraphRef, GraphTrait > { public: using InterleavedIterator = InterleavedFwdFixpointIterator< GraphRef, AbstractValue, GraphTrait >; using NodeRef = typename GraphTrait::NodeRef; using WtoVertexT = WtoVertex< GraphRef, GraphTrait >; using WtoCycleT = WtoCycle< GraphRef, GraphTrait >; private: InterleavedIterator& _iterator; public: explicit WtoProcessor(InterleavedIterator& iterator) : _iterator(iterator) {} void visit(const WtoVertexT& vertex) override { NodeRef node = vertex.node(); this->_iterator.process_pre(node, this->_iterator.pre(node)); this->_iterator.process_post(node, this->_iterator.post(node)); } void visit(const WtoCycleT& cycle) override { NodeRef head = cycle.head(); this->_iterator.process_pre(head, this->_iterator.pre(head)); this->_iterator.process_post(head, this->_iterator.post(head)); for (auto it = cycle.begin(), et = cycle.end(); it != et; ++it) { it->accept(*this); } } }; // end class WtoProcessor } // end namespace interleaved_fwd_fixpoint_iterator_impl } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/fixpoint/wpo.hpp000066400000000000000000000655001473507761200242520ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Construction and management of weak partial orderings (WPOs). * * The construction of weak partial orderings is based on Sung Kook Kim's, * Arnaud J. Venet's, and Aditya V. Thakur's paper: "Deterministic Parallel * Fixpoint Computation", in POPL 2020. * * Author: Sung Kook Kim * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { template < typename GraphRef, typename GraphTrait > class Wpo; template < typename GraphRef, typename GraphTrait > class WpoNode; namespace wpo_impl { template < typename GraphRef, typename GraphTrait > class WpoBuilder; } // end namespace wpo_impl /// \brief Node of a weak partial order /// /// This is either head, plain, or exit. template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class WpoNode final { public: /// \brief Kind of the node enum class Kind { Plain, Head, Exit }; private: using NodeRef = typename GraphTrait::NodeRef; using WpoIndex = std::size_t; private: /// \brief Graph node NodeRef _node; /// \brief Kind of node Kind _kind; /// \brief Successors of forward blue arrow std::vector< WpoIndex > _successors; /// \brief Predecessors of forward blue arrow std::vector< WpoIndex > _predecessors; /// \brief Sucessors of 'lifted' forward arrow /// This is meant to be used to construct the WTO std::vector< WpoIndex > _successors_lifted; /// \brief Backward arrow WpoIndex _head_or_exit; /// \brief Number of predecessors std::size_t _num_predecessors; /// \brief Number of reducible predecessors std::size_t _num_predecessors_reducible; /// \brief Postorder DFN (used to calculate priority of a node in scheduling) std::size_t _post_order; /// \brief Irreducible forward arrows for this exit's component (for exits /// only) std::unordered_map< WpoIndex, std::size_t > _irreducibles; /// \brief Size of the component std::size_t _size; public: /// \brief Constructor WpoNode(NodeRef node, Kind kind, std::size_t size, std::size_t post_order) : _node(node), _kind(kind), _num_predecessors(0), _num_predecessors_reducible(0), _post_order(post_order), _size(size) {} /// \brief No copy constructor WpoNode(const WpoNode&) = delete; /// \brief Move constructor WpoNode(WpoNode&&) = default; /// \brief No copy assignment operator WpoNode& operator=(const WpoNode&) = delete; /// \brief No move assignment operator WpoNode& operator=(WpoNode&&) = delete; /// \brief Return the graph node NodeRef node() const { return this->_node; } /// \brief Return the kind of node Kind kind() const { return this->_kind; } /// \brief Check the kind of this node bool is_plain() const { return this->_kind == Kind::Plain; } bool is_head() const { return this->_kind == Kind::Head; } bool is_exit() const { return this->_kind == Kind::Exit; } /// \brief Return the successors const std::vector< WpoIndex >& successors() const { return this->_successors; } /// \brief Return the predecessors const std::vector< WpoIndex >& predecessors() const { return this->_predecessors; } /// \brief Return the successors of lifted forward arrows const std::vector< WpoIndex >& successors_lifted() const { return this->_successors_lifted; } /// \brief Return the irreducible forward arrows for this exit's component const std::unordered_map< WpoIndex, std::size_t >& irreducibles() const { ikos_assert_msg(this->_kind == Kind::Exit, "trying to get irreducibles from non-exit"); return this->_irreducibles; } /// \brief Return the size of the component std::size_t size() const { return this->_size; } /// \brief Return the number of predecessors std::size_t num_predecessors() const { return this->_num_predecessors; } /// \brief Return the number of reducible predecessors std::size_t num_predecessors_reducible() const { return this->_num_predecessors_reducible; } /// \brief Return the post order std::size_t post_order() const { return this->_post_order; } /// \brief Return the head of the exit node WpoIndex head() const { ikos_assert_msg(this->_kind == Kind::Exit, "trying to get head from non-exit"); return this->_head_or_exit; } /// \brief Return the exit of the head node WpoIndex exit() const { ikos_assert_msg(this->_kind == Kind::Head, "trying to get exit from non-head"); return this->_head_or_exit; } private: /// \brief Add a successor void add_successor(WpoIndex idx) { this->_successors.push_back(idx); } /// \brief Add a predecessor void add_predecessor(WpoIndex idx) { this->_predecessors.push_back(idx); } /// \brief Check if the given node is a successor bool is_successor(WpoIndex idx) const { return std::find(this->_successors.begin(), this->_successors.end(), idx) != this->_successors.end(); } /// \brief Add a successor of lifted forward arrow void add_successor_lifted(WpoIndex idx) { this->_successors_lifted.push_back(idx); } /// \brief Check if the given node is a successor of lifted forward arrow bool is_successor_lifted(WpoIndex idx) const { return std::find(this->_successor_lifted.begin(), this->_successor_lifted.end(), idx) != this->_successor_lifted.end(); } /// \brief Increment the number of irreducibles that is directing to idx void inc_irreducible(WpoIndex idx) { ikos_assert_msg(this->_kind == Kind::Exit, "trying to access irreducibles from non-exit"); this->_irreducibles[idx]++; } /// \brief Increment the number of predecessors void inc_num_predecessors() { this->_num_predecessors++; } /// \brief Increment the number of reducible predecessors void inc_num_predecessors_reducible() { this->_num_predecessors_reducible++; } /// \brief Set head or an exit void set_head_exit(WpoIndex idx) { ikos_assert_msg(this->_kind != Kind::Plain, "trying to access head_or_exit from plain"); this->_head_or_exit = idx; } public: /// \brief Dump the node, for debugging purpose void dump(std::ostream& o, WpoIndex idx) const { o << "WpoNode:\n"; o << " index: " << idx << "\n"; DumpableTraits< NodeRef >::dump(o, this->_node); o << "\n"; switch (this->_kind) { case Kind::Plain: { o << " kind: plain\n"; break; } case Kind::Head: { o << " kind: head\n"; o << " exit: " << this->_head_or_exit << "\n"; break; } case Kind::Exit: { o << " kind: exit\n"; o << " head: " << this->_head_or_exit << "\n"; break; } } o << " successors: "; for (auto succ : this->_successors) { o << succ << " "; } o << "\n"; o << " successors_lifted: "; for (auto succ : this->_successors_lifted) { o << succ << " "; } o << "\n"; o << " predecessors: "; for (auto pred : this->_predecessors) { o << pred << " "; } o << "\n"; o << " number of predecessors: " << this->_num_predecessors << "\n"; o << " number of reducible predecessors: " << this->_num_predecessors_reducible << "\n"; o << " post order: " << this->_post_order << "\n"; o << " irreducibles: "; for (const auto& p : this->_irreducibles) { o << p.first << "," << p.second << " "; } o << "\n"; o << " size: " << this->_size << "\n"; } public: template < typename T1, typename T2 > friend class wpo_impl::WpoBuilder; }; // end class WpoNode /// \brief Weak Partial Ordering template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class Wpo { public: static_assert(IsGraph< GraphRef, GraphTrait >::value, "GraphRef does not implement GraphTraits"); private: using NodeRef = typename GraphTrait::NodeRef; using WpoNodeT = WpoNode< GraphRef, GraphTrait >; using Kind = typename WpoNodeT::Kind; using WpoIndex = std::size_t; private: // WPO nodes std::vector< WpoNodeT > _wpo_nodes; // Back predecessors std::unordered_map< NodeRef, std::unordered_set< NodeRef > > _back_predecessors; public: /// \brief Compute the weak partial order of the given graph explicit Wpo(GraphRef cfg) { NodeRef root = GraphTrait::entry(cfg); if (GraphTrait::successor_begin(root) == GraphTrait::successor_end(root)) { this->_wpo_nodes.emplace_back(root, Kind::Plain, 1, 1); return; } wpo_impl::WpoBuilder< GraphRef, GraphTrait > builder(cfg, this->_wpo_nodes, this->_back_predecessors); } /// \brief No copy constructor Wpo(const Wpo& other) = delete; /// \brief No move constructor Wpo(Wpo&& other) = delete; /// \brief No copy assignment operator Wpo& operator=(const Wpo& other) = delete; /// \brief No move assignment operator Wpo& operator=(Wpo&& other) = delete; /// \brief Return the total number of nodes std::size_t size() const { return this->_wpo_nodes.size(); } /// \brief Return the entry node index WpoIndex entry() { return this->_wpo_nodes.size() - 1; } /// \brief Return the successors of a given node index const std::vector< WpoIndex >& successors(WpoIndex idx) const { return this->_wpo_nodes[idx].successors(); } /// \brief Return the predecessors of a given node index const std::vector< WpoIndex >& predecessors(WpoIndex idx) const { return this->_wpo_nodes[idx].predecessors(); } /// \brief Return the number of predecessors of a given node index std::size_t num_predecessors(WpoIndex idx) const { return this->_wpo_nodes[idx].num_predecessors(); } /// \brief Return the number of reducible predecessors of a given node index std::size_t num_predecessors_reducible(WpoIndex idx) const { return this->_wpo_nodes[idx].num_predecessors_reducible(); } /// \brief Return the post order of a given node index std::size_t post_order(WpoIndex idx) const { return this->_wpo_nodes[idx].post_order(); } /// \brief Return the irreducibles for the exit's component const std::unordered_map< WpoIndex, std::size_t >& irreducibles( WpoIndex exit) const { return this->_wpo_nodes[exit].irreducibles(); } /// \brief Return the head of the given exit node index WpoIndex head_of_exit(WpoIndex exit) const { return exit + 1; } /// \brief Return the exit of the given head node index WpoIndex exit_of_head(WpoIndex head) const { return head - 1; } /// \brief Return the node for the given index NodeRef node(WpoIndex idx) const { return this->_wpo_nodes[idx].node(); } /// \brief Return the kind of the given index Kind kind(WpoIndex idx) const { return this->_wpo_nodes[idx].kind(); } /// \brief Check the kind of this given node index bool is_plain(WpoIndex idx) const { return this->_wpo_nodes[idx].is_plain(); } bool is_head(WpoIndex idx) const { return this->_wpo_nodes[idx].is_head(); } bool is_exit(WpoIndex idx) const { return this->_wpo_nodes[idx].is_exit(); } /// \brief Checks whether a given edge is a backedge bool is_back_edge(NodeRef head, NodeRef pred) const { auto it = this->_back_predecessors.find(head); if (it == this->_back_predecessors.end()) { return false; } else { const auto& preds = it->second; return preds.find(pred) != preds.end(); } } void dump(std::ostream& o) const { for (std::size_t idx = 0; idx < this->_wpo_nodes.size(); idx++) { o << "# "; this->_wpo_nodes[idx].dump(o, idx); } } }; // end class Wpo namespace wpo_impl { template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class WpoBuilder { private: using NodeRef = typename GraphTrait::NodeRef; using WpoNodeT = WpoNode< GraphRef, GraphTrait >; using WpoT = Wpo< GraphRef, GraphTrait >; using Kind = typename WpoNodeT::Kind; using WpoIndex = std::size_t; struct Edge { WpoIndex from; WpoIndex to; }; private: /// \brief Reference to the WPO nodes std::vector< WpoNodeT >& _wpo_nodes; /// \brief Reference to a map that contains back edges std::unordered_map< NodeRef, std::unordered_set< NodeRef > >& _back_predecessors; /// \brief Map a node to its DFN std::unordered_map< NodeRef, std::size_t > _node_to_dfn; /// \brief Map a node to its post DFN std::unordered_map< NodeRef, std::size_t > _node_to_post_dfn; /// \brief Map a DFN to a node std::vector< NodeRef > _dfn_to_node; /// \brief Maps DFN to DFNs of its back-edge predecessors std::vector< std::vector< std::size_t > > _back_predecessors_dfn; /// \brief Maps DFN to DFNs of its non-back-edge predecessors std::vector< std::vector< std::size_t > > _non_back_predecessors_dfn; /// \brief Maps DFN to cross/forward edges (DFN is the lowest common ancestor) std::unordered_map< std::size_t, std::vector< Edge > > _cross_forward_edges; /// \brief Next DFN std::size_t _next_dfn; /// \brief Next post DFN std::size_t _next_post_dfn; /// \brief Next node index std::size_t _next_idx; /// \brief Map DFN to index std::vector< std::size_t > _dfn_to_index; public: /// \brief Constructor WpoBuilder(GraphRef cfg, std::vector< WpoNodeT >& wpo_nodes, std::unordered_map< NodeRef, std::unordered_set< NodeRef > >& back_predecessors) : _wpo_nodes(wpo_nodes), _back_predecessors(back_predecessors), _next_dfn(1), _next_post_dfn(1), _next_idx(0) { this->construct_auxilary(cfg); this->construct_wpo(); } private: /// \brief Construct auxilary data-structures /// /// Performs DFS iteratively to classify the edges and find the lowest /// common ancestors of cross/forward edges. /// Nodes are identifed by their DFNs afterwards. void construct_auxilary(GraphRef cfg) { using RankMap = std::unordered_map< std::size_t, std::size_t >; using RankPropertyMap = boost::associative_property_map< RankMap >; using ParentMap = std::unordered_map< std::size_t, std::size_t >; using ParentPropertyMap = boost::associative_property_map< ParentMap >; struct Tuple { NodeRef node; bool finished; std::size_t pred_dfn; }; std::stack< Tuple > stack; std::vector< bool > black; std::vector< std::size_t > ancestor; RankMap rank_map; ParentMap parent_map; RankPropertyMap rank_property_map(rank_map); ParentPropertyMap parent_property_map(parent_map); boost::disjoint_sets< RankPropertyMap, ParentPropertyMap > dsets(rank_property_map, parent_property_map); stack.push(Tuple{/* node = */ GraphTrait::entry(cfg), /* finished = */ false, /* pred = */ 0}); while (!stack.empty()) { NodeRef node = stack.top().node; bool finished = stack.top().finished; std::size_t pred_dfn = stack.top().pred_dfn; stack.pop(); if (finished) { // DFS is done for this node // Update the post DFN this->_node_to_post_dfn[node] = this->_next_post_dfn++; // Mark as visited std::size_t dfn = this->node_to_dfn(node); black[dfn] = true; dsets.union_set(dfn, pred_dfn); ancestor[dsets.find_set(pred_dfn)] = pred_dfn; } else if (this->node_to_dfn(node) != 0) { // Forward edge, can be ignored continue; } else { // Unvisited node std::size_t dfn = this->_next_dfn++; this->_dfn_to_node.push_back(node); this->_node_to_dfn[node] = dfn; black.resize(this->_next_dfn); this->_back_predecessors_dfn.resize(this->_next_dfn); this->_non_back_predecessors_dfn.resize(this->_next_dfn); // Lowest common ancestor dsets.make_set(dfn); ancestor.resize(this->_next_dfn); ancestor[dfn] = dfn; // This will be popped after its successors are visited stack.push(Tuple{/* node = */ node, /* finished = */ true, /* pred = */ pred_dfn}); // Successors are visited in reverse order to match the WTO for (auto it = GraphTrait::successor_end(node), et = GraphTrait::successor_begin(node); it != et;) { --it; NodeRef succ = *it; std::size_t succ_dfn = this->node_to_dfn(succ); if (succ_dfn == 0) { // Unvisited stack.push(Tuple{/* node = */ succ, /* finished = */ false, /* pred = */ dfn}); } else if (black[succ_dfn]) { // Cross edge auto lca = ancestor[dsets.find_set(succ_dfn)]; this->_cross_forward_edges[lca].push_back(Edge{dfn, succ_dfn}); } else { // Back edge this->_back_predecessors_dfn[succ_dfn].push_back(dfn); this->_back_predecessors[succ].insert(node); } } if (pred_dfn != 0) { // Tree edge this->_non_back_predecessors_dfn[dfn].push_back(pred_dfn); } } } } void construct_wpo() { std::vector< std::size_t > rank(this->_next_dfn); std::vector< std::size_t > parent(this->_next_dfn); // A partition of vertices. Each subset is known to be strongly connected boost::disjoint_sets< std::size_t*, std::size_t* > dsets(&rank[0], &parent[0]); // Maps representative of a set to the vertex with minimum DFN std::vector< std::size_t > rep(this->_next_dfn); // Maps a head to its exit std::vector< std::size_t > exit(this->_next_dfn); // Maps a head to its size of components std::vector< std::size_t > size(this->_next_dfn); // Maps a vertex to original non-back edges that now target the vertex std::vector< std::vector< Edge > > origin(this->_next_dfn); // Maps DFN to index this->_dfn_to_index.resize(2 * this->_next_dfn); std::size_t dfn = this->_next_dfn; // Initialization for (std::size_t v = 1; v < this->_next_dfn; v++) { dsets.make_set(v); rep[v] = v; exit[v] = v; for (std::size_t u : this->_non_back_predecessors_dfn[v]) { origin[v].push_back(Edge{u, v}); } } // In reverse DFS order, build WPOs for SCCs bottom-up for (std::size_t h = this->_next_dfn - 1; h > 0; h--) { // Restore cross/fwd edges which has h as the LCA auto it = this->_cross_forward_edges.find(h); if (it != this->_cross_forward_edges.end()) { for (const Edge& edge : it->second) { std::size_t rep_to = rep[dsets.find_set(edge.to)]; this->_non_back_predecessors_dfn[rep_to].push_back(edge.from); origin[rep_to].push_back(edge); } } // Find nested SCCs bool is_scc = false; std::unordered_set< std::size_t > exits_h; for (std::size_t v : this->_back_predecessors_dfn[h]) { if (v != h) { exits_h.insert(rep[dsets.find_set(v)]); } else { // Self-loop is_scc = true; } } if (!exits_h.empty()) { is_scc = true; } // Invariant: h \notin exits_h std::unordered_set< std::size_t > components_h(exits_h); std::vector< std::size_t > worklist_h(exits_h.begin(), exits_h.end()); // Find components while (!worklist_h.empty()) { std::size_t v = worklist_h.back(); worklist_h.pop_back(); for (std::size_t u : this->_non_back_predecessors_dfn[v]) { std::size_t rep_u = rep[dsets.find_set(u)]; if (components_h.find(rep_u) == components_h.end() && rep_u != h) { components_h.insert(rep_u); worklist_h.push_back(rep_u); } } } // Invariant: h \notin components_h // Found components & exits if (!is_scc) { size[h] = 1; this->add_wpo_node(h, this->dfn_to_node(h), Kind::Plain, /*size=*/1); continue; } // Invariant: wpo_nodes = ...::h // End // Size of this component is initialized to 2: head and exit. std::size_t size_h = 2; for (std::size_t v : components_h) { size_h += size[v]; } size[h] = size_h; // Invariant: size_h = size[h] = number of all nodes in C_h. // New exit is added std::size_t x = dfn++; this->add_wpo_node(x, this->dfn_to_node(h), Kind::Exit, size_h); this->add_wpo_node(h, this->dfn_to_node(h), Kind::Head, size_h); this->set_head_exit(h, x); // Invariant: wpo_nodes = ...::x::h if (exits_h.empty()) { this->add_successor(/* from = */ h, /* to = */ x, /* exit = */ x, /* irreducible = */ false); } else { for (std::size_t xx : exits_h) { this->add_successor(/* from = */ exit[xx], /* to = */ x, /* exit = */ x, /* irreducible = */ false); } } // Invariant: Forward arrows to x are all constructed // Add forward arrow for (std::size_t v : components_h) { for (const Edge& edge : origin[v]) { std::size_t u = edge.from; std::size_t vv = edge.to; std::size_t x_u = exit[rep[dsets.find_set(u)]]; std::size_t x_v = exit[v]; this->add_successor(/* from = */ x_u, /* to = */ vv, /* exit = */ x_v, /* irreducible = */ v != vv); // Invariant: u \cfgarrow vv, u \notin C_v, vv \in C_v, u,v \in C_h // Invariant: x_u \forwardarrow vv. } } for (std::size_t v : components_h) { dsets.union_set(v, h); rep[dsets.find_set(v)] = h; } exit[h] = x; // Invariant: exit[h] = h if C_h is trivial SCC, x_h if C_h is non-trivial // SCC } std::vector< std::size_t > top_levels; // Top level components for (std::size_t v = 1; v < this->_next_dfn; v++) { if (rep[dsets.find_set(v)] == v) { top_levels.push_back(v); for (const Edge& edge : origin[v]) { std::size_t u = edge.from; std::size_t vv = edge.to; std::size_t x_u = exit[rep[dsets.find_set(u)]]; std::size_t x_v = exit[v]; this->add_successor(/* from = */ x_u, /* to = */ vv, /* exit = */ x_v, /* irreducible = */ v != vv); } } } } /// \brief Return the DFN for a given node std::size_t node_to_dfn(NodeRef n) const { auto it = this->_node_to_dfn.find(n); if (it != this->_node_to_dfn.end()) { return it->second; } else { return 0; } } /// \brief Return the node for a given DFN const NodeRef& dfn_to_node(std::size_t dfn) const { return this->_dfn_to_node.at(dfn - 1); } /// \brief Add a weak partial order node void add_wpo_node(std::size_t dfn, NodeRef node, Kind kind, std::size_t size) { this->_dfn_to_index[dfn] = this->_next_idx++; this->_wpo_nodes.emplace_back(node, kind, size, this->_node_to_post_dfn[node]); } /// \brief Return the WPO node from a DFN WpoNodeT& dfn_to_wpo_node(std::size_t dfn) { return this->_wpo_nodes[this->_dfn_to_index[dfn]]; } /// \brief Return the WPO node index from a DFN WpoIndex dfn_to_index(std::size_t dfn) { return this->_dfn_to_index[dfn]; } /// \brief Set the head and exit of a WPO node void set_head_exit(std::size_t h, std::size_t x) { auto idx = this->dfn_to_index(h); this->dfn_to_wpo_node(x).set_head_exit(idx); this->dfn_to_wpo_node(h).set_head_exit(idx - 1); } /// \brief Add a successor to a weak partial order node void add_successor(std::size_t from_dfn, std::size_t to_dfn, std::size_t exit_dfn, bool irreducible) { WpoNodeT& from_node = this->dfn_to_wpo_node(from_dfn); WpoNodeT& to_node = this->dfn_to_wpo_node(to_dfn); std::size_t to_idx = this->dfn_to_index(to_dfn); if (from_node.is_successor(to_idx)) { return; } from_node.add_successor(to_idx); to_node.inc_num_predecessors(); to_node.add_predecessor(this->dfn_to_index(from_dfn)); if (irreducible) { // Irreducible arrow of exit's component this->dfn_to_wpo_node(exit_dfn).inc_irreducible(to_idx); } else { to_node.inc_num_predecessors_reducible(); } } }; // end class WpoBuilder } // end namespace wpo_impl } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/fixpoint/wto.hpp000066400000000000000000000424151473507761200242560ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Construction and management of weak topological orderings (WTOs). * * The construction of weak topological orderings is based on F. Bourdoncle's * paper: "Efficient chaotic iteration strategies with widenings", Formal * Methods in Programming and Their Applications, 1993, pages 128-141. * * Author: Arnaud J. Venet * * Contributor: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { template < typename GraphRef, typename GraphTrait > class Wto; template < typename GraphRef, typename GraphTrait > class WtoVertex; template < typename GraphRef, typename GraphTrait > class WtoCycle; template < typename GraphRef, typename GraphTrait > class WtoComponentVisitor; /// \brief Helper for sequential containers of unique_ptr template < typename T > struct SeqExposeConstRef { const T& operator()(const std::unique_ptr< T >& p) const { return *p; } }; /// \brief Represents the nesting of a node /// /// The nesting of a node is the list of cycles containing the node, from /// the outermost to the innermost. template < typename GraphRef, typename GraphTrait > class WtoNesting { public: using NodeRef = typename GraphTrait::NodeRef; private: using NodeList = std::vector< NodeRef >; public: using Iterator = typename NodeList::const_iterator; private: NodeList _nodes; public: /// \brief Constructor WtoNesting() = default; /// \brief Copy constructor WtoNesting(const WtoNesting&) = default; /// \brief Move constructor WtoNesting(WtoNesting&&) = default; /// \brief Copy assignment operator WtoNesting& operator=(const WtoNesting&) = default; /// \brief Move assignment operator WtoNesting& operator=(WtoNesting&&) = default; /// \brief Destructor ~WtoNesting() = default; /// \brief Add a cycle head in the nesting void add(NodeRef head) { this->_nodes.push_back(head); } /// \brief Begin iterator over the head of cycles Iterator begin() const { return this->_nodes.cbegin(); } /// \brief End iterator over the head of cycles Iterator end() const { return this->_nodes.cend(); } /// \brief Return the common prefix of the given nestings WtoNesting operator^(const WtoNesting& other) const { WtoNesting res; for (auto this_it = this->begin(), other_it = other.begin(); this_it != this->end() && other_it != other.end(); ++this_it, ++other_it) { if (*this_it == *other_it) { res.add(*this_it); } else { break; } } return res; } private: /// \brief Compare the given nestings int compare(const WtoNesting& other) const { if (this == &other) { return 0; // equals } auto this_it = this->begin(); auto other_it = other.begin(); while (this_it != this->end()) { if (other_it == other.end()) { return 1; // `this` is nested within `other` } else if (*this_it == *other_it) { ++this_it; ++other_it; } else { return 2; // not comparable } } if (other_it == other.end()) { return 0; // equals } else { return -1; // `other` is nested within `this` } } public: bool operator<(const WtoNesting& other) const { return this->compare(other) == -1; } bool operator<=(const WtoNesting& other) const { return this->compare(other) <= 0; } bool operator==(const WtoNesting& other) const { return this->compare(other) == 0; } bool operator>=(const WtoNesting& other) const { return this->operator<=(other, *this); } bool operator>(const WtoNesting& other) const { return this->compare(other) == 1; } /// \brief Dump the nesting, for debugging purpose void dump(std::ostream& o) const { o << "["; for (auto it = this->begin(), et = this->end(); it != et;) { DumpableTraits< NodeRef >::dump(o, *it); ++it; if (it != et) { o << ", "; } } o << "]"; } }; // end class WtoNesting /// \brief Base class for components of a weak topological order /// /// This is either a vertex or a cycle. template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class WtoComponent { public: /// \brief Default constructor WtoComponent() = default; /// \brief Copy constructor WtoComponent(const WtoComponent&) noexcept = default; /// \brief Move constructor WtoComponent(WtoComponent&&) noexcept = default; /// \brief Copy assignment operator WtoComponent& operator=(const WtoComponent&) noexcept = default; /// \brief Move assignment operator WtoComponent& operator=(WtoComponent&&) noexcept = default; /// \brief Accept the given visitor virtual void accept(WtoComponentVisitor< GraphRef, GraphTrait >&) const = 0; /// \brief Destructor virtual ~WtoComponent() = default; }; // end class WtoComponent /// \brief Represents a vertex template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class WtoVertex final : public WtoComponent< GraphRef, GraphTrait > { public: using NodeRef = typename GraphTrait::NodeRef; private: NodeRef _node; public: /// \brief Constructor explicit WtoVertex(NodeRef node) : _node(node) {} /// \brief Return the graph node NodeRef node() const { return this->_node; } /// \brief Accept the given visitor void accept(WtoComponentVisitor< GraphRef, GraphTrait >& v) const override { v.visit(*this); } /// \brief Dump the vertex, for debugging purpose void dump(std::ostream& o) const { DumpableTraits< NodeRef >::dump(o, this->_node); } }; // end class WtoVertex /// \brief Represents a cycle template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class WtoCycle final : public WtoComponent< GraphRef, GraphTrait > { public: using NodeRef = typename GraphTrait::NodeRef; using WtoComponentT = WtoComponent< GraphRef, GraphTrait >; private: using WtoComponentPtr = std::unique_ptr< WtoComponentT >; using WtoComponentList = boost::container::slist< WtoComponentPtr >; public: /// \brief Iterator over the components using Iterator = boost::transform_iterator< SeqExposeConstRef< WtoComponentT >, typename WtoComponentList::const_iterator >; private: /// \brief Head of the cycle NodeRef _head; /// \brief List of components WtoComponentList _components; public: /// \brief Constructor WtoCycle(NodeRef head, WtoComponentList components) : _head(head), _components(std::move(components)) {} /// \brief Return the head of the cycle NodeRef head() const { return this->_head; } /// \brief Begin iterator over the components Iterator begin() const { return boost::make_transform_iterator(this->_components.cbegin(), SeqExposeConstRef< WtoComponentT >()); } /// \brief End iterator over the components Iterator end() const { return boost::make_transform_iterator(this->_components.cend(), SeqExposeConstRef< WtoComponentT >()); } /// \brief Accept the given visitor void accept(WtoComponentVisitor< GraphRef, GraphTrait >& v) const override { v.visit(*this); } /// \brief Dump the cycle, for debugging purpose void dump(std::ostream& o) const { o << "("; DumpableTraits< NodeRef >::dump(o, this->_head); for (const auto& c : this->_components) { o << " "; c->dump(o); } o << ")"; } }; // end class WtoCycle /// \brief Weak topological order visitor template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class WtoComponentVisitor { public: using WtoVertexT = WtoVertex< GraphRef, GraphTrait >; using WtoCycleT = WtoCycle< GraphRef, GraphTrait >; public: /// \brief Default constructor WtoComponentVisitor() = default; /// \brief Copy constructor WtoComponentVisitor(const WtoComponentVisitor&) noexcept = default; /// \brief Move constructor WtoComponentVisitor(WtoComponentVisitor&&) noexcept = default; /// \brief Copy assignment operator WtoComponentVisitor& operator=(const WtoComponentVisitor&) noexcept = default; /// \brief Move assignment operator WtoComponentVisitor& operator=(WtoComponentVisitor&&) noexcept = default; /// \brief Visit the given vertex virtual void visit(const WtoVertexT&) = 0; /// \brief Visit the given cycle virtual void visit(const WtoCycleT&) = 0; /// \brief Destructor virtual ~WtoComponentVisitor() = default; }; // end class WtoComponentVisitor /// \brief Weak Topological Ordering template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef > > class Wto { public: static_assert(IsGraph< GraphRef, GraphTrait >::value, "GraphRef does not implement GraphTraits"); public: using NodeRef = typename GraphTrait::NodeRef; using WtoNestingT = WtoNesting< GraphRef, GraphTrait >; using WtoComponentT = WtoComponent< GraphRef, GraphTrait >; using WtoVertexT = WtoVertex< GraphRef, GraphTrait >; using WtoCycleT = WtoCycle< GraphRef, GraphTrait >; private: using WtoComponentPtr = std::unique_ptr< WtoComponentT >; using WtoComponentList = boost::container::slist< WtoComponentPtr >; using Dfn = Bound< ZNumber >; using DfnTable = std::unordered_map< NodeRef, Dfn >; using Stack = std::vector< NodeRef >; using WtoNestingPtr = std::shared_ptr< WtoNestingT >; using NestingTable = std::unordered_map< NodeRef, WtoNestingPtr >; public: /// \brief Iterator over the components using Iterator = boost::transform_iterator< SeqExposeConstRef< WtoComponentT >, typename WtoComponentList::const_iterator >; private: WtoComponentList _components; NestingTable _nesting_table; DfnTable _dfn_table; Dfn _num; Stack _stack; private: /// \brief Visitor to build the nestings of each node class NestingBuilder final : public WtoComponentVisitor< GraphRef, GraphTrait > { private: WtoNestingPtr _nesting; NestingTable& _nesting_table; public: explicit NestingBuilder(NestingTable& nesting_table) : _nesting(std::make_shared< WtoNestingT >()), _nesting_table(nesting_table) {} void visit(const WtoCycleT& cycle) override { NodeRef head = cycle.head(); WtoNestingPtr previous_nesting = this->_nesting; this->_nesting_table.insert(std::make_pair(head, this->_nesting)); this->_nesting = std::make_shared< WtoNestingT >(*this->_nesting); this->_nesting->add(head); for (auto it = cycle.begin(), et = cycle.end(); it != et; ++it) { it->accept(*this); } this->_nesting = previous_nesting; } void visit(const WtoVertexT& vertex) override { this->_nesting_table.insert( std::make_pair(vertex.node(), this->_nesting)); } }; // end class NestingBuilder private: /// \brief Return the depth-first number of the given node Dfn dfn(NodeRef n) const { auto it = this->_dfn_table.find(n); if (it != this->_dfn_table.end()) { return it->second; } else { return Dfn(0); } } /// \brief Set the depth-first number of the given node void set_dfn(NodeRef n, const Dfn& dfn) { auto res = this->_dfn_table.insert(std::make_pair(n, dfn)); if (!res.second) { (res.first)->second = dfn; } } /// \brief Pop a node from the stack NodeRef pop() { ikos_assert_msg(!this->_stack.empty(), "empty stack"); NodeRef top = this->_stack.back(); this->_stack.pop_back(); return top; } /// \brief Push a node on the stack void push(NodeRef n) { this->_stack.push_back(n); } /// \brief Create the cycle component for the given vertex WtoComponentPtr component(NodeRef vertex) { WtoComponentList partition; for (auto it = GraphTrait::successor_begin(vertex), et = GraphTrait::successor_end(vertex); it != et; ++it) { NodeRef succ = *it; if (this->dfn(succ) == Dfn(0)) { this->visit(succ, partition); } } return std::make_unique< WtoCycleT >(vertex, std::move(partition)); } /// \brief Visit the given node /// /// Algorithm to build a weak topological order of a graph Dfn visit(NodeRef vertex, WtoComponentList& partition) { Dfn head(0); Dfn min(0); bool loop; this->push(vertex); this->_num += Dfn(1); head = this->_num; this->set_dfn(vertex, head); loop = false; for (auto it = GraphTrait::successor_begin(vertex), et = GraphTrait::successor_end(vertex); it != et; ++it) { NodeRef succ = *it; Dfn succ_dfn = this->dfn(succ); if (succ_dfn == Dfn(0)) { min = this->visit(succ, partition); } else { min = succ_dfn; } if (min <= head) { head = min; loop = true; } } if (head == this->dfn(vertex)) { this->set_dfn(vertex, Dfn::plus_infinity()); NodeRef element = this->pop(); if (loop) { while (element != vertex) { this->set_dfn(element, Dfn(0)); element = this->pop(); } partition.push_front(this->component(vertex)); } else { partition.push_front(std::make_unique< WtoVertexT >(vertex)); } } return head; } /// \brief Build the nesting table void build_nesting() { NestingBuilder builder(this->_nesting_table); for (auto it = this->begin(), et = this->end(); it != et; ++it) { it->accept(builder); } } public: /// \brief Compute the weak topological order of the given graph explicit Wto(GraphRef cfg) : _num(0) { this->visit(GraphTrait::entry(cfg), this->_components); this->_dfn_table.clear(); this->_stack.clear(); this->build_nesting(); } /// \brief No copy constructor Wto(const Wto& other) = delete; /// \brief Move constructor Wto(Wto&& other) = default; /// \brief No copy assignment operator Wto& operator=(const Wto& other) = delete; /// \brief Move assignment operator Wto& operator=(Wto&& other) = default; /// \brief Destructor ~Wto() = default; /// \brief Begin iterator over the components Iterator begin() const { return boost::make_transform_iterator(this->_components.cbegin(), SeqExposeConstRef< WtoComponentT >()); } /// \brief End iterator over the components Iterator end() const { return boost::make_transform_iterator(this->_components.cend(), SeqExposeConstRef< WtoComponentT >()); } /// \brief Return the nesting of the given node const WtoNestingT& nesting(NodeRef n) const { auto it = this->_nesting_table.find(n); ikos_assert_msg(it != this->_nesting_table.end(), "node not found"); return *(it->second); } /// \brief Accept the given visitor void accept(WtoComponentVisitor< GraphRef, GraphTrait >& v) { for (const auto& c : this->_components) { c->accept(v); } } /// \brief Dump the order, for debugging purpose void dump(std::ostream& o) const { for (auto it = this->begin(), et = this->end(); it != et;) { it->dump(o); ++it; if (it != et) { o << " "; } } } }; // end class Wto } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/linear_constraint.hpp000066400000000000000000000542161473507761200253250ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Data structures for the symbolic manipulation of linear constraints. * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { /// \brief Represents a linear constraint template < typename Number, typename VariableRef > class LinearConstraint { public: using VariableExpressionT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; public: /// \brief Kind of linear constraint enum Kind { Equality, // == Disequation, // != Inequality, // <= }; private: LinearExpressionT _expr; Kind _kind; public: /// \brief No default constructor LinearConstraint() = delete; /// \brief Constructor LinearConstraint(LinearExpressionT expr, Kind kind) : _expr(std::move(expr)), _kind(kind) {} /// \brief Copy constructor LinearConstraint(const LinearConstraint&) = default; /// \brief Move constructor LinearConstraint(LinearConstraint&&) = default; /// \brief Copy assignment operator LinearConstraint& operator=(const LinearConstraint&) = default; /// \brief Move assignment operator LinearConstraint& operator=(LinearConstraint&&) = default; /// \brief Destructor ~LinearConstraint() = default; /// \brief Create the tautology 0 == 0 static LinearConstraint tautology() { return LinearConstraint(LinearExpressionT(), Equality); } /// \brief Create the contradiction 0 != 0 static LinearConstraint contradiction() { return LinearConstraint(LinearExpressionT(), Disequation); } /// \brief Return true if the constraint is a tautology bool is_tautology() const { if (!this->_expr.is_constant()) { return false; } switch (this->_kind) { case Equality: { // x == 0 return this->_expr.constant() == 0; } case Disequation: { // x != 0 return this->_expr.constant() != 0; } case Inequality: { // x <= 0 return this->_expr.constant() <= 0; } default: { ikos_unreachable("unexpected kind"); } } } /// \brief Return true if the constraint is a contradiction bool is_contradiction() const { if (!this->_expr.is_constant()) { return false; } switch (this->_kind) { case Equality: { // x == 0 return this->_expr.constant() != 0; } case Disequation: { // x != 0 return this->_expr.constant() == 0; } case Inequality: { // x <= 0 return this->_expr.constant() > 0; } default: { ikos_unreachable("unexpected kind"); } } } /// \brief Return true if the constraint is an equality (==) bool is_equality() const { return this->_kind == Equality; } /// \brief Return true if the constraint is an disequation (!=) bool is_disequation() const { return this->_kind == Disequation; } /// \brief Return true if the constraint is an inequality (<=) bool is_inequality() const { return this->_kind == Inequality; } /// \brief Retun the linear expression const LinearExpressionT& expression() const { return this->_expr; } /// \brief Return the kind Kind kind() const { return this->_kind; } /// \brief Return the begin iterator over the terms typename LinearExpressionT::TermIterator begin() { return this->_expr.begin(); } typename LinearExpressionT::TermConstIterator begin() const { return this->_expr.begin(); } typename LinearExpressionT::TermConstIterator cbegin() const { return this->_expr.cbegin(); } /// \brief Return the end iterator over the terms typename LinearExpressionT::TermIterator end() { return this->_expr.end(); } typename LinearExpressionT::TermConstIterator end() const { return this->_expr.end(); } typename LinearExpressionT::TermConstIterator cend() const { return this->_expr.cend(); } /// \brief Return the constant Number constant() const { return -this->_expr.constant(); } /// \brief Return the number of terms std::size_t num_terms() const { return this->_expr.num_terms(); } /// \brief Return the factor for the given variable Number factor(VariableRef var) const { return this->_expr.factor(var); } /// \brief Return the set of variables present in the linear constraint PatriciaTreeSet< VariableRef > variables() const { return this->_expr.variables(); } /// \brief Dump the linear constraint, for debugging purpose void dump(std::ostream& o) const { if (this->is_contradiction()) { o << "false"; } else if (this->is_tautology()) { o << "true"; } else { LinearExpressionT e = this->_expr - this->_expr.constant(); Number c = -this->_expr.constant(); e.dump(o); switch (this->_kind) { case Equality: { o << " = "; break; } case Disequation: { o << " != "; break; } case Inequality: { o << " <= "; break; } default: { ikos_unreachable("unexpected kind"); } } o << c; } } }; // end class LinearConstraint /// \brief Write a linear constraint on a stream template < typename Number, typename VariableRef > inline std::ostream& operator<<( std::ostream& o, const LinearConstraint< Number, VariableRef >& e) { e.dump(o); return o; } /// \name Operator <= /// @{ template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( LinearExpression< Number, VariableRef > e, const Number& n) { return LinearConstraint< Number, VariableRef >(std::move(e) - n, LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( LinearExpression< Number, VariableRef > e, int n) { return LinearConstraint< Number, VariableRef >(std::move(e) - n, LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( LinearExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(x) - std::move(y), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( VariableExpression< Number, VariableRef > x, const Number& n) { return LinearConstraint< Number, VariableRef >(std::move(x) - n, LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( VariableExpression< Number, VariableRef > x, int n) { return LinearConstraint< Number, VariableRef >(std::move(x) - n, LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( VariableExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(x) - std::move(y), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( VariableExpression< Number, VariableRef > x, LinearExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(x) - std::move(y), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator<=( LinearExpression< Number, VariableRef > x, const LinearExpression< Number, VariableRef >& y) { return LinearConstraint< Number, VariableRef >(std::move(x) - y, LinearConstraint< Number, VariableRef >::Inequality); } /// @} /// \name Operator >= /// @{ template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( LinearExpression< Number, VariableRef > e, const Number& n) { return LinearConstraint< Number, VariableRef >(n - std::move(e), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( LinearExpression< Number, VariableRef > e, int n) { return LinearConstraint< Number, VariableRef >(n - std::move(e), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( LinearExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(y) - std::move(x), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( VariableExpression< Number, VariableRef > x, const Number& n) { return LinearConstraint< Number, VariableRef >(n - std::move(x), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( VariableExpression< Number, VariableRef > x, int n) { return LinearConstraint< Number, VariableRef >(n - std::move(x), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( VariableExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(y) - std::move(x), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( VariableExpression< Number, VariableRef > x, LinearExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(y) - std::move(x), LinearConstraint< Number, VariableRef >::Inequality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator>=( const LinearExpression< Number, VariableRef >& x, LinearExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(y) - x, LinearConstraint< Number, VariableRef >::Inequality); } /// @} /// \name Operator == /// @{ template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( LinearExpression< Number, VariableRef > e, const Number& n) { return LinearConstraint< Number, VariableRef >(std::move(e) - n, LinearConstraint< Number, VariableRef >::Equality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( LinearExpression< Number, VariableRef > e, int n) { return LinearConstraint< Number, VariableRef >(std::move(e) - n, LinearConstraint< Number, VariableRef >::Equality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( LinearExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(x) - std::move(y), LinearConstraint< Number, VariableRef >::Equality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( VariableExpression< Number, VariableRef > x, const Number& n) { return LinearConstraint< Number, VariableRef >(std::move(x) - n, LinearConstraint< Number, VariableRef >::Equality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( VariableExpression< Number, VariableRef > x, int n) { return LinearConstraint< Number, VariableRef >(std::move(x) - n, LinearConstraint< Number, VariableRef >::Equality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( VariableExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(x) - std::move(y), LinearConstraint< Number, VariableRef >::Equality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( VariableExpression< Number, VariableRef > x, LinearExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(y) - std::move(x), LinearConstraint< Number, VariableRef >::Equality); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator==( LinearExpression< Number, VariableRef > x, const LinearExpression< Number, VariableRef >& y) { return LinearConstraint< Number, VariableRef >(std::move(x) - y, LinearConstraint< Number, VariableRef >::Equality); } /// @} /// \name Operator != /// @{ template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( LinearExpression< Number, VariableRef > e, const Number& n) { return LinearConstraint< Number, VariableRef >(std::move(e) - n, LinearConstraint< Number, VariableRef >::Disequation); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( LinearExpression< Number, VariableRef > e, int n) { return LinearConstraint< Number, VariableRef >(std::move(e) - n, LinearConstraint< Number, VariableRef >::Disequation); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( LinearExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(x) - std::move(y), LinearConstraint< Number, VariableRef >::Disequation); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( VariableExpression< Number, VariableRef > x, const Number& n) { return LinearConstraint< Number, VariableRef >(std::move(x) - n, LinearConstraint< Number, VariableRef >::Disequation); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( VariableExpression< Number, VariableRef > x, int n) { return LinearConstraint< Number, VariableRef >(std::move(x) - n, LinearConstraint< Number, VariableRef >::Disequation); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( VariableExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(x) - std::move(y), LinearConstraint< Number, VariableRef >::Disequation); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( VariableExpression< Number, VariableRef > x, LinearExpression< Number, VariableRef > y) { return LinearConstraint< Number, VariableRef >(std::move(y) - std::move(x), LinearConstraint< Number, VariableRef >::Disequation); } template < typename Number, typename VariableRef > inline LinearConstraint< Number, VariableRef > operator!=( LinearExpression< Number, VariableRef > x, const LinearExpression< Number, VariableRef >& y) { return LinearConstraint< Number, VariableRef >(std::move(x) - y, LinearConstraint< Number, VariableRef >::Disequation); } /// @} /// \brief Represents a set of linear constraints template < typename Number, typename VariableRef > class LinearConstraintSystem { public: using LinearConstraintT = LinearConstraint< Number, VariableRef >; private: using Constraints = std::vector< LinearConstraintT >; public: using Iterator = typename Constraints::iterator; using ConstIterator = typename Constraints::const_iterator; private: Constraints _csts; public: /// \brief Create an empty system of constraints LinearConstraintSystem() = default; /// \brief Create a system of constraints with the given constraint explicit LinearConstraintSystem(LinearConstraintT cst) : _csts{std::move(cst)} {} /// \brief Create a system of constraints with the given constraints LinearConstraintSystem(std::initializer_list< LinearConstraintT > csts) : _csts(std::move(csts)) {} /// \brief Copy constructor LinearConstraintSystem(const LinearConstraintSystem&) = default; /// \brief Move constructor LinearConstraintSystem(LinearConstraintSystem&&) = default; /// \brief Copy assignment operator LinearConstraintSystem& operator=(const LinearConstraintSystem&) = default; /// \brief Move assignment operator LinearConstraintSystem& operator=(LinearConstraintSystem&&) = default; /// \brief Destructor ~LinearConstraintSystem() = default; /// \brief Return true if the system is empty bool empty() const { return this->_csts.empty(); } /// \brief Return the number of constraints std::size_t size() const { return this->_csts.size(); } /// \brief Add a constraint void add(LinearConstraintT cst) { this->_csts.emplace_back(std::move(cst)); } /// \brief Add a system of constraints void add(const LinearConstraintSystem& csts) { this->_csts.reserve(this->_csts.size() + csts.size()); this->_csts.insert(this->_csts.end(), csts.begin(), csts.end()); } /// \brief Add a system of constraints void add(LinearConstraintSystem&& csts) { this->_csts.reserve(this->_csts.size() + csts.size()); this->_csts.insert(this->_csts.end(), std::make_move_iterator(csts.begin()), std::make_move_iterator(csts.end())); } /// \brief Return the begin iterator over the constraints Iterator begin() { return this->_csts.begin(); } ConstIterator begin() const { return this->_csts.begin(); } ConstIterator cbegin() const { return this->_csts.cbegin(); } /// \brief Return the end iterator over the terms Iterator end() { return this->_csts.end(); } ConstIterator end() const { return this->_csts.end(); } ConstIterator cend() const { return this->_csts.cend(); } /// \brief Return the set of variables present in the system PatriciaTreeSet< VariableRef > variables() const { PatriciaTreeSet< VariableRef > vars; for (const LinearConstraintT& cst : this->_csts) { for (const auto& term : cst) { vars.insert(term.first); } } return vars; } /// \brief Dump the linear constraint system, for debugging purpose void dump(std::ostream& o) const { o << "{"; for (auto it = this->_csts.begin(), et = this->_csts.end(); it != et;) { it->dump(o); ++it; if (it != et) { o << "; "; } } o << "}"; } }; // end class LinearConstraintSystem /// \brief Write a linear constraint system on a stream template < typename Number, typename VariableRef > inline std::ostream& operator<<( std::ostream& o, const LinearConstraintSystem< Number, VariableRef >& e) { e.dump(o); return o; } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/linear_expression.hpp000066400000000000000000000441201473507761200253310ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Data structure for the symbolic manipulation of linear expressions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace core { /// \brief Represents a typed variable /// /// This is just a thin wrapper on VariableRef. template < typename Number, typename VariableRef > class VariableExpression { public: static_assert( IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); private: VariableRef _var; public: /// \brief No default constructor VariableExpression() = delete; /// \brief Constructor explicit VariableExpression(VariableRef var) : _var(std::move(var)) {} /// \brief Copy constructor VariableExpression(const VariableExpression&) noexcept = default; /// \brief Move constructor VariableExpression(VariableExpression&&) noexcept = default; /// \brief Copy assignment operator VariableExpression& operator=(const VariableExpression&) noexcept = default; /// \brief Move assignment operator VariableExpression& operator=(VariableExpression&&) noexcept = default; /// \brief Destructor ~VariableExpression() = default; /// \brief Return the variable reference VariableRef var() const { return this->_var; } /// \brief Dump the variable, for debugging purpose void dump(std::ostream& o) const { DumpableTraits< VariableRef >::dump(o, this->_var); } }; // end class VariableExpression /// \brief Represents a linear expression template < typename Number, typename VariableRef > class LinearExpression { public: static_assert( IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); public: using VariableExpressionT = VariableExpression< Number, VariableRef >; private: using Map = boost::container::flat_map< VariableRef, Number >; public: /// \brief Iterator over the terms using TermIterator = typename Map::iterator; /// \brief Constant iterator over the terms using TermConstIterator = typename Map::const_iterator; private: Map _map; Number _cst; public: /// \brief Create a linear expression equals to zero LinearExpression() = default; /// \brief Create a constant expression explicit LinearExpression(Number n) : _cst(std::move(n)) {} /// \brief Create a constant expression explicit LinearExpression(int n) : _cst(n) {} /// \brief Create a variable expression explicit LinearExpression(VariableRef var) { this->_map.emplace(var, Number(1)); } /// \brief Create a variable expression explicit LinearExpression(VariableExpressionT e) { this->_map.emplace(e.var(), Number(1)); } /// \brief Create the expression cst * var LinearExpression(Number cst, VariableRef var) { if (cst != 0) { this->_map.emplace(var, std::move(cst)); } } /// \brief Create the expression cst * var LinearExpression(int cst, VariableRef var) { if (cst != 0) { this->_map.emplace(var, Number(cst)); } } /// \brief Copy constructor LinearExpression(const LinearExpression&) = default; /// \brief Move constructor LinearExpression(LinearExpression&&) = default; /// \brief Copy assignment operator LinearExpression& operator=(const LinearExpression&) = default; /// \brief Move assignment operator LinearExpression& operator=(LinearExpression&&) = default; /// \brief Destructor ~LinearExpression() = default; private: /// \brief Private constructor LinearExpression(Map map, Number cst) : _map(std::move(map)), _cst(std::move(cst)) {} public: /// \brief Add a constant void add(const Number& n) { this->_cst += n; } /// \brief Add a constant void add(int n) { this->_cst += n; } /// \brief Add a variable void add(VariableRef var) { this->add(1, var); } /// \brief Add a term cst * var void add(const Number& cst, VariableRef var) { auto it = this->_map.find(var); if (it != this->_map.end()) { Number r = it->second + cst; if (r == 0) { this->_map.erase(it); } else { it->second = r; } } else { if (cst != 0) { this->_map.emplace(var, cst); } } } /// \brief Add a term cst * var void add(int cst, VariableRef var) { auto it = this->_map.find(var); if (it != this->_map.end()) { Number r = it->second + cst; if (r == 0) { this->_map.erase(it); } else { it->second = r; } } else { if (cst != 0) { this->_map.emplace(var, Number(cst)); } } } /// \brief Return the begin iterator over the terms TermIterator begin() { return this->_map.begin(); } TermConstIterator begin() const { return this->_map.begin(); } TermConstIterator cbegin() const { return this->_map.cbegin(); } /// \brief Return the end iterator over the terms TermIterator end() { return this->_map.end(); } TermConstIterator end() const { return this->_map.end(); } TermConstIterator cend() const { return this->_map.cend(); } /// \brief Return the number of terms std::size_t num_terms() const { return this->_map.size(); } /// \brief Return true if the linear expression is constant bool is_constant() const { return this->_map.empty(); } /// \brief Return the constant const Number& constant() const { return this->_cst; } /// \brief Return the factor for the given variable Number factor(VariableRef var) const { auto it = this->_map.find(var); if (it != this->_map.end()) { return it->second; } else { return Number(0); } } /// \brief Add a number void operator+=(const Number& n) { this->_cst += n; } /// \brief Add a number void operator+=(int n) { this->_cst += n; } /// \brief Add a variable void operator+=(VariableRef var) { this->add(var); } /// \brief Add a linear expression void operator+=(const LinearExpression& expr) { for (const auto& term : expr) { this->add(term.second, term.first); } this->_cst += expr.constant(); } /// \brief Substract a number void operator-=(const Number& n) { this->_cst -= n; } /// \brief Substract a number void operator-=(int n) { this->_cst -= n; } /// \brief Substract a variable void operator-=(VariableRef var) { this->add(-1, var); } /// \brief Substract a linear expression void operator-=(const LinearExpression& expr) { for (const auto& term : expr) { this->add(-term.second, term.first); } this->_cst -= expr.constant(); } /// \brief Unary minus LinearExpression operator-() const { LinearExpression r(*this); r *= -1; return r; } /// \brief Multiply by a constant void operator*=(const Number& n) { if (n == 0) { this->_map.clear(); this->_cst = 0; } else { for (auto& term : this->_map) { term.second *= n; } this->_cst *= n; } } /// \brief Multiply by a constant void operator*=(int n) { if (n == 0) { this->_map.clear(); this->_cst = 0; } else { for (auto& term : this->_map) { term.second *= n; } this->_cst *= n; } } /// \brief If the linear expression is just a variable v, return v, otherwise /// return boost::none. boost::optional< VariableRef > variable() const { if (this->_cst == 0 && this->_map.size() == 1) { auto it = this->_map.begin(); if (it->second == 1) { return it->first; } } return boost::none; } /// \brief Return the set of variables present in the linear expression PatriciaTreeSet< VariableRef > variables() const { PatriciaTreeSet< VariableRef > vars; for (const auto& term : this->_map) { vars.insert(term.first); } return vars; } /// \brief Dump the linear expression, for debugging purpose void dump(std::ostream& o) const { for (auto it = this->_map.begin(), et = this->_map.end(); it != et; ++it) { const Number& cst = it->second; VariableRef var = it->first; if (cst > 0 && it != this->_map.begin()) { o << "+"; } if (cst == -1) { o << "-"; } else if (cst != 1) { o << cst; } DumpableTraits< VariableRef >::dump(o, var); } if (this->_cst > 0 && !this->_map.empty()) { o << "+"; } if (this->_cst != 0 || this->_map.empty()) { o << this->_cst; } } }; // end class LinearExpression /// \brief Write a linear expression on a stream template < typename Number, typename VariableRef > inline std::ostream& operator<<( std::ostream& o, const LinearExpression< Number, VariableRef >& e) { e.dump(o); return o; } /// \name Operator * /// @{ template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( VariableExpression< Number, VariableRef > e, Number n) { return LinearExpression< Number, VariableRef >(std::move(n), e.var()); } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( VariableExpression< Number, VariableRef > e, int n) { return LinearExpression< Number, VariableRef >(n, e.var()); } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( Number n, VariableExpression< Number, VariableRef > e) { return LinearExpression< Number, VariableRef >(std::move(n), e.var()); } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( int n, VariableExpression< Number, VariableRef > e) { return LinearExpression< Number, VariableRef >(n, e.var()); } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( LinearExpression< Number, VariableRef > e, const Number& n) { e *= n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( LinearExpression< Number, VariableRef > e, int n) { e *= n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( const Number& n, LinearExpression< Number, VariableRef > e) { e *= n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator*( int n, LinearExpression< Number, VariableRef > e) { e *= n; return e; } /// @} /// \name Operator + /// @{ template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( VariableExpression< Number, VariableRef > e, const Number& n) { LinearExpression< Number, VariableRef > r(e.var()); r += n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( VariableExpression< Number, VariableRef > e, int n) { LinearExpression< Number, VariableRef > r(e.var()); r += n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( const Number& n, VariableExpression< Number, VariableRef > e) { LinearExpression< Number, VariableRef > r(e.var()); r += n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( int n, VariableExpression< Number, VariableRef > e) { LinearExpression< Number, VariableRef > r(e.var()); r += n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( VariableExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { LinearExpression< Number, VariableRef > r(x.var()); r += y.var(); return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( LinearExpression< Number, VariableRef > e, const Number& n) { e += n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( LinearExpression< Number, VariableRef > e, int n) { e += n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( const Number& n, LinearExpression< Number, VariableRef > e) { e += n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( int n, LinearExpression< Number, VariableRef > e) { e += n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( LinearExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { x += y.var(); return x; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( VariableExpression< Number, VariableRef > x, LinearExpression< Number, VariableRef > y) { y += x.var(); return y; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator+( LinearExpression< Number, VariableRef > x, const LinearExpression< Number, VariableRef >& y) { x += y; return x; } /// @} /// \name Operator - /// @{ template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( VariableExpression< Number, VariableRef > e, const Number& n) { LinearExpression< Number, VariableRef > r(e.var()); r -= n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( VariableExpression< Number, VariableRef > e, int n) { LinearExpression< Number, VariableRef > r(e.var()); r -= n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( const Number& n, VariableExpression< Number, VariableRef > e) { LinearExpression< Number, VariableRef > r(-1, e.var()); r += n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( int n, VariableExpression< Number, VariableRef > e) { LinearExpression< Number, VariableRef > r(-1, e.var()); r += n; return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( VariableExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { LinearExpression< Number, VariableRef > r(x.var()); r -= y.var(); return r; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( LinearExpression< Number, VariableRef > e, const Number& n) { e -= n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( LinearExpression< Number, VariableRef > e, int n) { e -= n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( LinearExpression< Number, VariableRef > x, VariableExpression< Number, VariableRef > y) { x -= y.var(); return x; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( const Number& n, LinearExpression< Number, VariableRef > e) { e *= -1; e += n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( int n, LinearExpression< Number, VariableRef > e) { e *= -1; e += n; return e; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( VariableExpression< Number, VariableRef > x, LinearExpression< Number, VariableRef > y) { y *= -1; y += x.var(); return y; } template < typename Number, typename VariableRef > inline LinearExpression< Number, VariableRef > operator-( LinearExpression< Number, VariableRef > x, const LinearExpression< Number, VariableRef >& y) { x -= y; return x; } /// @} } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/literal.hpp000066400000000000000000000507161473507761200232440ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Data structures for literals * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace core { /// \brief Class to represent a literal /// /// A literal is either a: /// * Constant machine integer /// * Constant floating point /// * Constant memory location /// * Null /// * Undefined /// * Machine integer variable /// * Floating point variable /// * Pointer variable template < typename VariableRef, typename MemoryLocationRef > class Literal { public: static_assert( core::IsVariable< VariableRef >::value, "VariableRef does not meet the requirements for variable types"); static_assert(core::IsMemoryLocation< MemoryLocationRef >::value, "MemoryLocationRef does not meet the requirements for memory " "location types"); private: struct MachineIntLit { MachineInt value; bool operator==(const MachineIntLit& o) const { return value == o.value; } }; struct FloatingPointLit { // TODO(marthaud): Add a class to represent floating points DummyNumber value; bool operator==(const FloatingPointLit&) const { return true; } }; struct MemoryLocationLit { MemoryLocationRef value; bool operator==(const MemoryLocationLit& o) const { return value == o.value; } }; struct NullLit { bool operator==(const NullLit&) const { return true; } }; struct UndefinedLit { bool operator==(const UndefinedLit&) const { return true; } }; struct MachineIntVarLit { VariableRef var; bool operator==(const MachineIntVarLit& o) const { return var == o.var; } }; struct FloatingPointVarLit { VariableRef var; bool operator==(const FloatingPointVarLit& o) const { return var == o.var; } }; struct PointerVarLit { VariableRef var; bool operator==(const PointerVarLit& o) const { return var == o.var; } }; private: using Lit = boost::variant< MachineIntLit, FloatingPointLit, MemoryLocationLit, NullLit, UndefinedLit, MachineIntVarLit, FloatingPointVarLit, PointerVarLit >; private: Lit _lit; private: /// \brief Private constructor explicit Literal(Lit lit) : _lit(std::move(lit)) {} public: /// \brief No default constructor Literal() = delete; /// \brief Copy constructor Literal(const Literal&) = default; /// \brief Move constructor Literal(Literal&&) noexcept = default; /// \brief Copy assignment operator Literal& operator=(const Literal&) = default; /// \brief Move assignment operator Literal& operator=(Literal&&) noexcept = default; /// \brief Destructor ~Literal() = default; bool operator==(const Literal& other) const { return this->_lit == other._lit; } bool operator!=(const Literal& other) const { return !this->operator==(other); } /// \brief Create a constant machine integer literal static Literal machine_int(MachineInt v) { return Literal(Lit(MachineIntLit{std::move(v)})); } /// \brief Create a constant floating point literal static Literal floating_point(DummyNumber) { return Literal(Lit(FloatingPointLit{DummyNumber{}})); } /// \brief Create a constant memory location literal static Literal memory_location(MemoryLocationRef v) { return Literal(Lit(MemoryLocationLit{v})); } /// \brief Create the null literal static Literal null() { return Literal(Lit(NullLit{})); } /// \brief Create the undefined literal static Literal undefined() { return Literal(Lit(UndefinedLit{})); } /// \brief Create a machine integer variable literal static Literal machine_int_var(VariableRef v) { return Literal(Lit(MachineIntVarLit{v})); } /// \brief Create a floating point variable literal static Literal floating_point_var(VariableRef v) { return Literal(Lit(FloatingPointVarLit{v})); } /// \brief Create a pointer variable literal static Literal pointer_var(VariableRef v) { return Literal(Lit(PointerVarLit{v})); } private: /// \brief Visitor that checks if the given literal has the given type template < typename LiteralType > struct IsType : public boost::static_visitor< bool > { template < typename T > bool operator()(const T&) const { return std::is_same< T, LiteralType >::value; } }; public: /// \brief Return true if the literal is a constant machine integer bool is_machine_int() const { return boost::apply_visitor(IsType< MachineIntLit >(), this->_lit); } /// \brief Return true if the literal is a constant floating point bool is_floating_point() const { return boost::apply_visitor(IsType< FloatingPointLit >(), this->_lit); } /// \brief Return true if the literal is a constant memory location bool is_memory_location() const { return boost::apply_visitor(IsType< MemoryLocationLit >(), this->_lit); } /// \brief Return true if the literal is the null constant bool is_null() const { return boost::apply_visitor(IsType< NullLit >(), this->_lit); } /// \brief Return true if the literal is the undefined constant bool is_undefined() const { return boost::apply_visitor(IsType< UndefinedLit >(), this->_lit); } /// \brief Return true if the literal is a machine integer variable bool is_machine_int_var() const { return boost::apply_visitor(IsType< MachineIntVarLit >(), this->_lit); } /// \brief Return true if the literal is a floating point variable bool is_floating_point_var() const { return boost::apply_visitor(IsType< FloatingPointVarLit >(), this->_lit); } /// \brief Return true if the literal is a pointer variable bool is_pointer_var() const { return boost::apply_visitor(IsType< PointerVarLit >(), this->_lit); } private: /// \brief Visitor that returns true if the literal is a constant struct IsConstant : public boost::static_visitor< bool > { bool operator()(const MachineIntLit&) const { return true; } bool operator()(const FloatingPointLit&) const { return true; } bool operator()(const MemoryLocationLit&) const { return true; } bool operator()(const NullLit&) const { return true; } bool operator()(const UndefinedLit&) const { return true; } bool operator()(const MachineIntVarLit&) const { return false; } bool operator()(const FloatingPointVarLit&) const { return false; } bool operator()(const PointerVarLit&) const { return false; } }; public: /// \brief Return true if the literal is a constant bool is_cst() const { return boost::apply_visitor(IsConstant(), this->_lit); } private: /// \brief Visitor that returns true if the literal is a variable struct IsVariable : public boost::static_visitor< bool > { bool operator()(const MachineIntLit&) const { return false; } bool operator()(const FloatingPointLit&) const { return false; } bool operator()(const MemoryLocationLit&) const { return false; } bool operator()(const NullLit&) const { return false; } bool operator()(const UndefinedLit&) const { return false; } bool operator()(const MachineIntVarLit&) const { return true; } bool operator()(const FloatingPointVarLit&) const { return true; } bool operator()(const PointerVarLit&) const { return true; } }; public: // \brief Return true if the literal is a variable bool is_var() const { return boost::apply_visitor(IsVariable(), this->_lit); } private: /// \brief Visitor that returns the machine integer struct GetMachineInt : public boost::static_visitor< const MachineInt& > { const MachineInt& operator()(const MachineIntLit& lit) const { return lit.value; } const MachineInt& operator()(const FloatingPointLit&) const { ikos_unreachable("trying to call machine_int() on a floating point"); } const MachineInt& operator()(const MemoryLocationLit&) const { ikos_unreachable("trying to call machine_int() on a memory location"); } const MachineInt& operator()(const NullLit&) const { ikos_unreachable("trying to call machine_int() on null"); } const MachineInt& operator()(const UndefinedLit&) const { ikos_unreachable("trying to call machine_int() on undefined"); } const MachineInt& operator()(const MachineIntVarLit&) const { ikos_unreachable( "trying to call machine_int() on a machine integer variable"); } const MachineInt& operator()(const FloatingPointVarLit&) const { ikos_unreachable( "trying to call machine_int() on a floating point variable"); } const MachineInt& operator()(const PointerVarLit&) const { ikos_unreachable("trying to call machine_int() on a pointer variable"); } }; public: /// \brief Get the machine integer const MachineInt& machine_int() const { #if BOOST_VERSION == 105800 // workaround for https://svn.boost.org/trac10/ticket/11285 GetMachineInt vis; return this->_lit.apply_visitor(vis); #else return boost::apply_visitor(GetMachineInt(), this->_lit); #endif } private: /// \brief Visitor that returns the floating point struct GetFloatingPoint : public boost::static_visitor< const DummyNumber& > { const DummyNumber& operator()(const MachineIntLit&) const { ikos_unreachable("trying to call floating_point() on a machine integer"); } const DummyNumber& operator()(const FloatingPointLit& lit) const { return lit.value; } const DummyNumber& operator()(const MemoryLocationLit&) const { ikos_unreachable("trying to call floating_point() on a memory location"); } const DummyNumber& operator()(const NullLit&) const { ikos_unreachable("trying to call floating_point() on null"); } const DummyNumber& operator()(const UndefinedLit&) const { ikos_unreachable("trying to call floating_point() on undefined"); } const DummyNumber& operator()(const MachineIntVarLit&) const { ikos_unreachable( "trying to call floating_point() on a machine integer variable"); } const DummyNumber& operator()(const FloatingPointVarLit&) const { ikos_unreachable( "trying to call floating_point() on a floating point variable"); } const DummyNumber& operator()(const PointerVarLit&) const { ikos_unreachable("trying to call floating_point() on a pointer variable"); } }; public: /// \brief Get the floating point const DummyNumber& floating_point() const { return boost::apply_visitor(GetFloatingPoint(), this->_lit); } private: /// \brief Visitor that returns the memory location struct GetMemoryLocation : public boost::static_visitor< MemoryLocationRef > { MemoryLocationRef operator()(const MachineIntLit&) const { ikos_unreachable("trying to call memory_location() on a machine integer"); } MemoryLocationRef operator()(const FloatingPointLit&) const { ikos_unreachable("trying to call memory_location() on a floating point"); } MemoryLocationRef operator()(const MemoryLocationLit& lit) const { return lit.value; } MemoryLocationRef operator()(const NullLit&) const { ikos_unreachable("trying to call memory_location() on null"); } MemoryLocationRef operator()(const UndefinedLit&) const { ikos_unreachable("trying to call memory_location() on undefined"); } MemoryLocationRef operator()(const MachineIntVarLit&) const { ikos_unreachable( "trying to call memory_location() on a machine integer variable"); } MemoryLocationRef operator()(const FloatingPointVarLit&) const { ikos_unreachable( "trying to call memory_location() on a floating point variable"); } MemoryLocationRef operator()(const PointerVarLit&) const { ikos_unreachable( "trying to call memory_location() on a pointer variable"); } }; public: /// \brief Get the memory location MemoryLocationRef memory_location() const { return boost::apply_visitor(GetMemoryLocation(), this->_lit); } private: /// \brief Visitor that returns the variable struct GetVariable : public boost::static_visitor< VariableRef > { VariableRef operator()(const MachineIntLit&) const { ikos_unreachable("trying to call var() on a machine integer"); } VariableRef operator()(const FloatingPointLit&) const { ikos_unreachable("trying to call var() on a floating point"); } VariableRef operator()(const MemoryLocationLit&) const { ikos_unreachable("trying to call var() on a memory location"); } VariableRef operator()(const NullLit&) const { ikos_unreachable("trying to call var() on null"); } VariableRef operator()(const UndefinedLit&) const { ikos_unreachable("trying to call var() on undefined"); } VariableRef operator()(const MachineIntVarLit& lit) const { return lit.var; } VariableRef operator()(const FloatingPointVarLit& lit) const { return lit.var; } VariableRef operator()(const PointerVarLit& lit) const { return lit.var; } }; public: /// \brief Get the variable VariableRef var() const { return boost::apply_visitor(GetVariable(), this->_lit); } public: /// \brief Base class for visitors of literals /// /// Visitors should implement the following methods: /// /// R machine_int(const MachineInt&); /// R floating_point(const DummyNumber&); /// R memory_location(MemoryLocationRef); /// R null(); /// R undefined(); /// R machine_int_var(VariableRef); /// R floating_point_var(VariableRef); /// R pointer_var(VariableRef); template < typename R = void > class Visitor { public: using ResultType = R; }; // end class Visitor private: template < typename Visitor > struct VariantVisitor : public boost::static_visitor< typename Visitor::ResultType > { using ResultType = typename Visitor::ResultType; Visitor& v; /// \brief Constructor explicit VariantVisitor(Visitor& _v) : v(_v) {} ResultType operator()(const MachineIntLit& lit) { return v.machine_int(lit.value); } ResultType operator()(const FloatingPointLit& lit) { return v.floating_point(lit.value); } ResultType operator()(const MemoryLocationLit& lit) { return v.memory_location(lit.value); } ResultType operator()(const NullLit&) { return v.null(); } ResultType operator()(const UndefinedLit&) { return v.undefined(); } ResultType operator()(const MachineIntVarLit& lit) { return v.machine_int_var(lit.var); } ResultType operator()(const FloatingPointVarLit& lit) { return v.floating_point_var(lit.var); } ResultType operator()(const PointerVarLit& lit) { return v.pointer_var(lit.var); } }; // end struct VariantVisitor template < typename Visitor > struct ConstVariantVisitor : public boost::static_visitor< typename Visitor::ResultType > { using ResultType = typename Visitor::ResultType; const Visitor& v; /// \brief Constructor explicit ConstVariantVisitor(const Visitor& _v) : v(_v) {} ResultType operator()(const MachineIntLit& lit) const { return v.machine_int(lit.value); } ResultType operator()(const FloatingPointLit& lit) const { return v.floating_point(lit.value); } ResultType operator()(const MemoryLocationLit& lit) const { return v.memory_location(lit.value); } ResultType operator()(const NullLit&) const { return v.null(); } ResultType operator()(const UndefinedLit&) const { return v.undefined(); } ResultType operator()(const MachineIntVarLit& lit) const { return v.machine_int_var(lit.var); } ResultType operator()(const FloatingPointVarLit& lit) const { return v.floating_point_var(lit.var); } ResultType operator()(const PointerVarLit& lit) const { return v.pointer_var(lit.var); } }; // end struct ConstVariantVisitor public: /// \brief Visit the literal template < typename Visitor, typename = typename std::enable_if_t< std::is_base_of< Literal::Visitor< typename Visitor::ResultType >, Visitor >::value > > typename Visitor::ResultType apply_visitor(Visitor& v) const { VariantVisitor< Visitor > vis(v); return boost::apply_visitor(vis, this->_lit); } /// \brief Visit the literal template < typename Visitor, typename = typename std::enable_if_t< std::is_base_of< Literal::Visitor< typename Visitor::ResultType >, Visitor >::value > > typename Visitor::ResultType apply_visitor(const Visitor& v) const { ConstVariantVisitor< Visitor > vis(v); return boost::apply_visitor(vis, this->_lit); } private: /// \brief Visitor that dumps the literal on a stream struct Dumper : public boost::static_visitor<> { std::ostream& o; explicit Dumper(std::ostream& _o) : o(_o) {} void operator()(const MachineIntLit& lit) { o << "machine_int{" << lit.value << "}"; } void operator()(const FloatingPointLit& lit) { o << "floating_point{" << lit.value << "}"; } void operator()(const MemoryLocationLit& lit) { o << "memory_location{"; DumpableTraits< MemoryLocationRef >::dump(o, lit.value); o << "}"; } void operator()(const NullLit&) { o << "null"; } void operator()(const UndefinedLit&) { o << "undefined"; } void operator()(const MachineIntVarLit& lit) { o << "machine_int_var{"; DumpableTraits< VariableRef >::dump(o, lit.var); o << "}"; } void operator()(const FloatingPointVarLit& lit) { o << "floating_point_var{"; DumpableTraits< VariableRef >::dump(o, lit.var); o << "}"; } void operator()(const PointerVarLit& lit) { o << "pointer_var{"; DumpableTraits< VariableRef >::dump(o, lit.var); o << "}"; } }; public: /// \brief Dump the literal on a stream void dump(std::ostream& o) const { Dumper dumper(o); boost::apply_visitor(dumper, this->_lit); } }; // end class Literal /// \brief Write a literal on a stream template < typename VariableRef, typename MemoryLocationRef > std::ostream& operator<<(std::ostream& o, const Literal< VariableRef, MemoryLocationRef >& l) { l.dump(o); return o; } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number.hpp000066400000000000000000000054471473507761200231010ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Number definitions * * For convenience, this header includes: * * ikos/core/number/bound.hpp * * ikos/core/number/dummy_number.hpp * * ikos/core/number/exception.hpp * * ikos/core/number/machine_int.hpp * * ikos/core/number/q_number.hpp * * ikos/core/number/signedness.hpp * * ikos/core/number/supported_integral.hpp * * ikos/core/number/z_number.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/000077500000000000000000000000001473507761200223565ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/bound.hpp000066400000000000000000000345171473507761200242100ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Bound class (+oo, -oo or a number) * * Author: Arnaud J. Venet * * Contributors: * * Alexandre C. D. Wimmers * * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { /// \brief Bound /// /// This is either -oo, +oo or a number. template < typename Number > class Bound { private: bool _is_infinite; Number _n; // Invariant: _is_infinite => (_n == 1 or _n == -1) private: /// \brief Private constructor Bound(bool is_infinite, int n) : _is_infinite(is_infinite), _n(n) { this->normalize(); } /// \brief Private constructor Bound(bool is_infinite, Number n) : _is_infinite(is_infinite), _n(std::move(n)) { this->normalize(); } /// \brief Normalize the bound void normalize() { if (this->_is_infinite) { this->_n = (this->_n >= 0) ? 1 : -1; } } public: /// \brief No default constructor Bound() = delete; /// \brief Create a bound explicit Bound(int n) : _is_infinite(false), _n(n) {} /// \brief Create a bound explicit Bound(Number n) : _is_infinite(false), _n(std::move(n)) {} /// \brief Copy constructor Bound(const Bound&) noexcept( std::is_nothrow_copy_constructible< Number >::value) = default; /// \brief Move constructor Bound(Bound&&) noexcept(std::is_nothrow_move_constructible< Number >::value) = default; /// \brief Assign a number Bound& operator=(int n) { this->_is_infinite = false; this->_n = n; return *this; } /// \brief Assign a number Bound& operator=(Number n) { this->_is_infinite = false; this->_n = std::move(n); return *this; } /// \brief Copy assignment operator Bound& operator=(const Bound&) noexcept( std::is_nothrow_copy_assignable< Number >::value) = default; /// \brief Move assignment operator Bound& operator=(Bound&&) noexcept( std::is_nothrow_move_assignable< Number >::value) = default; /// \brief Destructor ~Bound() = default; public: /// \brief Return +oo static Bound plus_infinity() { return Bound(true, 1); } /// \brief Return -oo static Bound minus_infinity() { return Bound(true, -1); } public: /// \brief Return true if the bound is infinite bool is_infinite() const { return this->_is_infinite; } /// \brief Return true if the bound is finite bool is_finite() const { return !this->_is_infinite; } /// \brief Return true if the bound is plus infinity bool is_plus_infinity() const { return this->is_infinite() && this->_n == 1; } /// \brief Return true if the bound is minus infinity bool is_minus_infinity() const { return this->is_infinite() && this->_n == -1; } /// \brief Return ture if the bound is zero bool is_zero() const { return this->_n == 0; } /// \brief Unary minus Bound operator-() const { return Bound(this->_is_infinite, -this->_n); } /// \brief Add a bound void operator+=(const Bound& other) { if (this->is_finite() && other.is_finite()) { this->_n += other._n; } else if (this->is_finite() && other.is_infinite()) { this->operator=(other); } else if (this->is_infinite() && other.is_finite()) { return; } else if (this->_n == other._n) { return; } else { ikos_unreachable("undefined operation +oo + -oo"); } } /// \brief Substract a bound void operator-=(const Bound& other) { if (this->is_finite() && other.is_finite()) { this->_n -= other._n; } else if (this->is_finite() && other.is_infinite()) { this->operator=(Bound(true, -other._n)); } else if (this->is_infinite() && other.is_finite()) { return; } else if (this->_n != other._n) { return; } else { ikos_unreachable("undefined operation +oo - +oo"); } } /// \brief Multiply by a bound void operator*=(const Bound& other) { if (this->is_zero()) { return; } else if (other.is_zero()) { this->operator=(other); } else { this->_n *= other._n; this->_is_infinite = (this->_is_infinite || other._is_infinite); this->normalize(); } } /// \brief Lower or equal comparison /// /// This is an optimized implementation. bool leq(const Bound& other) const { if (this->_is_infinite xor other._is_infinite) { if (this->_is_infinite) { return this->_n == -1; } else { return other._n == 1; } } return this->_n <= other._n; } /// \brief Greater or equal comparison /// /// This is an optimized implementation. bool geq(const Bound& other) const { if (this->_is_infinite xor other._is_infinite) { if (this->_is_infinite) { return this->_n == 1; } else { return other._n == -1; } } return this->_n >= other._n; } /// \brief Equality comparison bool equals(const Bound& other) const { return this->_is_infinite == other._is_infinite && this->_n == other._n; } /// \brief Return the number, or boost::none if the bound is infinite boost::optional< Number > number() const { if (this->is_infinite()) { return boost::none; } else { return this->_n; } } /// \brief Write the bound on a stream void dump(std::ostream& o) const { if (this->is_plus_infinity()) { o << "+oo"; } else if (this->is_minus_infinity()) { o << "-oo"; } else { o << this->_n; } } // Friends template < typename T > friend Bound< T > operator+(const Bound< T >& lhs, const Bound< T >& rhs); template < typename T > friend Bound< T > operator-(const Bound< T >& lhs, const Bound< T >& rhs); template < typename T > friend Bound< T > operator*(const Bound< T >& lhs, const Bound< T >& rhs); template < typename T > friend Bound< T > operator/(const Bound< T >& lhs, const Bound< T >& rhs); friend Bound< ZNumber > operator<<(const Bound< ZNumber >& lhs, const Bound< ZNumber >& rhs); friend Bound< ZNumber > operator>>(const Bound< ZNumber >& lhs, const Bound< ZNumber >& rhs); }; // end class Bound /// \brief Add bounds template < typename Number > inline Bound< Number > operator+(const Bound< Number >& lhs, const Bound< Number >& rhs) { using BoundT = Bound< Number >; if (lhs.is_finite() && rhs.is_finite()) { return BoundT(false, lhs._n + rhs._n); } else if (lhs.is_finite() && rhs.is_infinite()) { return rhs; } else if (lhs.is_infinite() && rhs.is_finite()) { return lhs; } else if (lhs._n == rhs._n) { return lhs; } else { ikos_unreachable("undefined operation +oo + -oo"); } } /// \brief Substract bounds template < typename Number > inline Bound< Number > operator-(const Bound< Number >& lhs, const Bound< Number >& rhs) { using BoundT = Bound< Number >; if (lhs.is_finite() && rhs.is_finite()) { return BoundT(false, lhs._n - rhs._n); } else if (lhs.is_finite() && rhs.is_infinite()) { return BoundT(true, -rhs._n); } else if (lhs.is_infinite() && rhs.is_finite()) { return lhs; } else if (lhs._n != rhs._n) { return lhs; } else { ikos_unreachable("undefined operation +oo - +oo"); } } /// \brief Multiply bounds template < typename Number > inline Bound< Number > operator*(const Bound< Number >& lhs, const Bound< Number >& rhs) { using BoundT = Bound< Number >; if (lhs.is_zero() || rhs.is_zero()) { return BoundT(false, 0); } else { return BoundT(lhs._is_infinite || rhs._is_infinite, lhs._n * rhs._n); } } /// \brief Divide bounds template < typename Number > inline Bound< Number > operator/(const Bound< Number >& lhs, const Bound< Number >& rhs) { using BoundT = Bound< Number >; if (rhs.is_zero()) { ikos_unreachable("division by zero"); } else if (lhs.is_finite() && rhs.is_finite()) { return BoundT(false, lhs._n / rhs._n); } else if (lhs.is_finite() && rhs.is_infinite()) { return BoundT(0); } else if (lhs.is_infinite() && rhs.is_finite()) { if (rhs._n >= 0) { return lhs; } else { return -lhs; } } else { return BoundT(true, lhs._n * rhs._n); } } /// \brief Left binary shift of bounds inline Bound< ZNumber > operator<<(const Bound< ZNumber >& lhs, const Bound< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; ikos_assert_msg(rhs.geq(BoundT(0)), "right hand side is negative"); if (lhs.is_zero()) { return lhs; } else if (lhs.is_infinite()) { return lhs; } else if (rhs.is_infinite()) { return BoundT(true, lhs._n); } else { return BoundT(lhs._n << rhs._n); } } /// \brief Right binary shift of bounds inline Bound< ZNumber > operator>>(const Bound< ZNumber >& lhs, const Bound< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; ikos_assert_msg(rhs.geq(BoundT(0)), "right hand side is negative"); if (lhs.is_zero()) { return lhs; } else if (lhs.is_infinite()) { return lhs; } else if (rhs.is_infinite()) { return BoundT((lhs._n >= 0) ? 0 : -1); } else { return BoundT(lhs._n >> rhs._n); } } template < typename Number > inline bool operator<=(const Bound< Number >& lhs, const Bound< Number >& rhs) { return lhs.leq(rhs); } template < typename Number > inline bool operator>=(const Bound< Number >& lhs, const Bound< Number >& rhs) { return lhs.geq(rhs); } template < typename Number > inline bool operator<(const Bound< Number >& lhs, const Bound< Number >& rhs) { return !lhs.geq(rhs); } template < typename Number > inline bool operator>(const Bound< Number >& lhs, const Bound< Number >& rhs) { return !lhs.leq(rhs); } template < typename Number > inline bool operator==(const Bound< Number >& lhs, const Bound< Number >& rhs) { return lhs.equals(rhs); } template < typename Number > inline bool operator!=(const Bound< Number >& lhs, const Bound< Number >& rhs) { return !lhs.equals(rhs); } /// \brief Return the smaller of the given bound template < typename Number > inline const Bound< Number >& min(const Bound< Number >& a, const Bound< Number >& b) { return (a < b) ? a : b; } /// \brief Return the smaller of the given bound template < typename Number > inline const Bound< Number >& min(const Bound< Number >& a, const Bound< Number >& b, const Bound< Number >& c) { return min(min(a, b), c); } /// \brief Return the smaller of the given bound template < typename Number > inline const Bound< Number >& min(const Bound< Number >& a, const Bound< Number >& b, const Bound< Number >& c, const Bound< Number >& d) { return min(min(min(a, b), c), d); } /// \brief Return the greater of the given bound template < typename Number > inline const Bound< Number >& max(const Bound< Number >& a, const Bound< Number >& b) { return (a < b) ? b : a; } /// \brief Return the greater of the given bound template < typename Number > inline const Bound< Number >& max(const Bound< Number >& a, const Bound< Number >& b, const Bound< Number >& c) { return max(max(a, b), c); } /// \brief Return the greater of the given bound template < typename Number > inline const Bound< Number >& max(const Bound< Number >& a, const Bound< Number >& b, const Bound< Number >& c, const Bound< Number >& d) { return max(max(max(a, b), c), d); } /// \brief Return the absolute value of the given bound template < typename Number > inline Bound< Number > abs(const Bound< Number >& b) { return (b >= Bound< Number >(0)) ? b : -b; } /// \brief Write a bound on a stream template < typename Number > inline std::ostream& operator<<(std::ostream& o, const Bound< Number >& bound) { bound.dump(o); return o; } /// \brief Bound on unlimited precision integers using ZBound = Bound< ZNumber >; /// \brief Bound on unlimited precision rationals using QBound = Bound< QNumber >; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/compatibility.hpp000066400000000000000000000056701473507761200257500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Utilities to check machine integer compatibility * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include namespace ikos { namespace core { /// \brief Return true if the given parameters are compatible (same bit-width /// and sign) template < typename X, typename Y > inline bool compatible(const X& x, const Y& y) { return x.bit_width() == y.bit_width() && x.sign() == y.sign(); } /// \brief Assert that the parameters are compatible (same bit-width and sign) template < typename X, typename Y > inline void assert_compatible(const X& x, const Y& y) { ikos_assert_msg(x.bit_width() == y.bit_width(), "parameters have a different bit-width"); ikos_assert_msg(x.sign() == y.sign(), "parameters have a different signedness"); ikos_ignore(x); ikos_ignore(y); } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/dummy_number.hpp000066400000000000000000000045071473507761200256000ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Dummy number * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { struct DummyNumber {}; inline std::ostream& operator<<(std::ostream& o, const DummyNumber&) { o << "dummy"; return o; } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/exception.hpp000066400000000000000000000066771473507761200251050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Exceptions for big numbers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { /// \brief Exception for big numbers class NumberError : public Exception { private: /// \brief Explanatory message /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _msg; public: /// \brief Constructor /// /// \param msg Explanatory message explicit NumberError(const std::string& msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief Constructor /// /// \param msg Explanatory message explicit NumberError(const char* msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief No default constructor NumberError() = delete; /// \brief Copy constructor NumberError(const NumberError&) noexcept = default; /// \brief Move constructor NumberError(NumberError&&) noexcept = default; /// \brief Copy assignment operator NumberError& operator=(const NumberError&) noexcept = default; /// \brief Move assignment operator NumberError& operator=(NumberError&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override { return this->_msg->c_str(); } /// \brief Destructor ~NumberError() override = default; }; // end class NumberError } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/machine_int.hpp000066400000000000000000001533051473507761200253540ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Machine integer class * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { /// \brief Class for arbitrary precision machine integers class MachineInt { private: /// If bit-width <= 64, store directly the integer, /// Otherwise use a pointer on a ZNumber. union { uint64_t i; /// Used to store the <= 64 bits integer value. ZNumber* p; /// Used to store the >64 bits integer value. } _n; uint64_t _bit_width; Signedness _sign; private: /// \brief The biggest uint64_t static const uint64_t ONES = ~uint64_t(0); private: /// \brief Return true if bit-width <= 64 bool is_small() const { return ikos_likely(this->_bit_width <= 64); } /// \brief Return true if bit-width > 64 bool is_large() const { return !this->is_small(); } /// \brief Return 2**n static ZNumber power_of_2(uint64_t n) { return ZNumber(1) << n; } /// \brief Return 2**n static ZNumber power_of_2(const ZNumber& n) { return ZNumber(1) << n; } /// \brief Normalize the machine integer void normalize() { if (this->is_small()) { // Mask out the high bits uint64_t mask = ONES >> (64 - this->_bit_width); this->_n.i &= mask; } else { if (*this->_n.p == 0) { // always normalized return; } else if (this->is_signed()) { // n needs to be within [-2**(n-1), 2**(n-1)-1] *this->_n.p = mod(*this->_n.p + power_of_2(this->_bit_width - 1), power_of_2(this->_bit_width)) - power_of_2(this->_bit_width - 1); } else { // n needs to be within [0, 2**n-1] *this->_n.p = mod(*this->_n.p, power_of_2(this->_bit_width)); } } } public: /// \name Constructors /// @{ /// \brief Default constructor MachineInt() = delete; /// \brief Create a machine integer from an integral type template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > MachineInt(T n, uint64_t bit_width, Signedness sign) : _bit_width(bit_width), _sign(sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); if (this->is_small()) { this->_n.i = static_cast< uint64_t >(n); } else { this->_n.p = new ZNumber(n); } this->normalize(); } /// \brief Create a machine integer from a ZNumber MachineInt(const ZNumber& n, uint64_t bit_width, Signedness sign) : _bit_width(bit_width), _sign(sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); if (this->is_small()) { ZNumber m = mod(n, power_of_2(this->_bit_width)); this->_n.i = m.to< uint64_t >(); } else { this->_n.p = new ZNumber(n); } this->normalize(); } private: struct NormalizedTag {}; /// \brief Private constructor for normalized integers MachineInt(uint64_t n, uint64_t bit_width, Signedness sign, NormalizedTag) : _bit_width(bit_width), _sign(sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); if (this->is_small()) { this->_n.i = n; } else { this->_n.p = new ZNumber(n); } } /// \brief Private constructor for normalized integers MachineInt(const ZNumber& n, uint64_t bit_width, Signedness sign, NormalizedTag) : _bit_width(bit_width), _sign(sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); if (this->is_small()) { this->_n.i = n.to< uint64_t >(); } else { this->_n.p = new ZNumber(n); } } public: /// \brief Copy constructor MachineInt(const MachineInt& o) : _bit_width(o._bit_width), _sign(o._sign) { if (o.is_small()) { this->_n.i = o._n.i; } else { this->_n.p = new ZNumber(*o._n.p); } } /// \brief Move constructor MachineInt(MachineInt&& o) noexcept : _n(o._n), _bit_width(o._bit_width), _sign(o._sign) { o._bit_width = 0; // do not delete o._n.p } /// \brief Destructor ~MachineInt() { if (this->is_large()) { delete this->_n.p; } } /// \brief Create the minimum machine integer for the given bit width and sign static MachineInt min(uint64_t bit_width, Signedness sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); if (sign == Signed) { if (ikos_likely(bit_width <= 64)) { return MachineInt(uint64_t(1) << (bit_width - 1), bit_width, sign, NormalizedTag{}); } else { return MachineInt(-power_of_2(bit_width - 1), bit_width, sign, NormalizedTag{}); } } else { return MachineInt(0, bit_width, sign, NormalizedTag{}); } } /// \brief Create the maximum machine integer for the given bit width and sign static MachineInt max(uint64_t bit_width, Signedness sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); if (sign == Signed) { if (bit_width == 1) { return MachineInt(0, bit_width, sign, NormalizedTag{}); } else if (bit_width <= 64) { return MachineInt(ONES >> (65 - bit_width), bit_width, sign, NormalizedTag{}); } else { return MachineInt(power_of_2(bit_width - 1) - 1, bit_width, sign, NormalizedTag{}); } } else { if (ikos_likely(bit_width <= 64)) { return MachineInt(ONES >> (64 - bit_width), bit_width, sign, NormalizedTag{}); } else { return MachineInt(power_of_2(bit_width) - 1, bit_width, sign, NormalizedTag{}); } } } /// \brief Create the null machine integer for the given bit width and sign static MachineInt zero(uint64_t bit_width, Signedness sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); return MachineInt(0, bit_width, sign, NormalizedTag{}); } /// \brief Create the machine integer with all bits set to 1 for the given bit /// width and sign static MachineInt all_ones(uint64_t bit_width, Signedness sign) { ikos_assert_msg(bit_width > 0, "invalid bit width"); if (ikos_likely(bit_width <= 64)) { return MachineInt(ONES >> (64 - bit_width), bit_width, sign, NormalizedTag{}); } else { if (sign == Signed) { return MachineInt(ZNumber(-1), bit_width, sign, NormalizedTag{}); } else { return MachineInt(power_of_2(bit_width) - 1, bit_width, sign, NormalizedTag{}); } } } /// @} /// \name Assignment Operators /// @{ /// \brief Copy assignment MachineInt& operator=(const MachineInt& o) { if (this == &o) { return *this; } if (this->is_small()) { if (o.is_small()) { this->_n.i = o._n.i; } else { this->_n.p = new ZNumber(*o._n.p); } } else { if (o.is_small()) { delete this->_n.p; this->_n.i = o._n.i; } else { *this->_n.p = *o._n.p; } } this->_bit_width = o._bit_width; this->_sign = o._sign; return *this; } /// \brief Move assignment MachineInt& operator=(MachineInt&& o) noexcept { if (this == &o) { return *this; } if (this->is_large()) { delete this->_n.p; } this->_n = o._n; this->_bit_width = o._bit_width; this->_sign = o._sign; o._bit_width = 0; // do not delete o._n.p return *this; } /// \brief Assignment for integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > MachineInt& operator=(T n) { if (this->is_small()) { this->_n.i = static_cast< uint64_t >(n); } else { *this->_n.p = n; } this->normalize(); return *this; } /// \brief Addition assignment MachineInt& operator+=(const MachineInt& x) { assert_compatible(*this, x); if (this->is_small()) { this->_n.i += x._n.i; } else { *this->_n.p += *x._n.p; } this->normalize(); return *this; } /// \brief Subtraction assignment MachineInt& operator-=(const MachineInt& x) { assert_compatible(*this, x); if (this->is_small()) { this->_n.i -= x._n.i; } else { *this->_n.p -= *x._n.p; } this->normalize(); return *this; } /// \brief Multiplication assignment MachineInt& operator*=(const MachineInt& x) { assert_compatible(*this, x); if (this->is_small()) { this->_n.i *= x._n.i; } else { *this->_n.p *= *x._n.p; } this->normalize(); return *this; } /// \brief Division assignment MachineInt& operator/=(const MachineInt& x) { *this = div(*this, x); return *this; } /// \brief Remainder assignment MachineInt& operator%=(const MachineInt& x) { *this = rem(*this, x); return *this; } /// @} /// \name Value Characterization Functions /// @{ /// \brief Return the bit width of the integer uint64_t bit_width() const { return this->_bit_width; } /// \brief Return the signedness (Signed or Unsigned) of the integer Signedness sign() const { return this->_sign; } bool is_signed() const { return this->_sign == Signed; } bool is_unsigned() const { return this->_sign == Unsigned; } /// @} /// \name Value tests /// @{ /// \brief Return true if this is the minimum machine integer bool is_min() const { if (this->is_signed()) { if (this->is_small()) { return this->_n.i == (uint64_t(1) << (this->_bit_width - 1)); } else { return *this->_n.p == -power_of_2(this->_bit_width - 1); } } else { return this->is_zero(); } } /// \brief Return true if this is the maximum machine integer bool is_max() const { if (this->is_signed()) { if (this->bit_width() == 1) { return this->_n.i == 0; } else if (this->is_small()) { return this->_n.i == (ONES >> (65 - this->_bit_width)); } else { return *this->_n.p == (power_of_2(this->_bit_width - 1) - 1); } } else { if (this->is_small()) { return this->_n.i == (ONES >> (64 - this->_bit_width)); } else { return *this->_n.p == (power_of_2(this->_bit_width) - 1); } } } /// \brief Return true if the machine integer is 0 bool is_zero() const { if (this->is_small()) { return this->_n.i == 0; } else { return *this->_n.p == 0; } } /// \brief Return the high bit (the sign bit) as a bool bool high_bit() const { if (this->is_small()) { return (this->_n.i >> (this->_bit_width - 1)) != 0; } else { if (this->is_signed()) { return *this->_n.p < 0; } else { return *this->_n.p >= power_of_2(this->_bit_width - 1); } } } /// \brief Return true if the machine integer is strictly smaller than 0 /// /// Always false for unsigned integers bool is_negative() const { if (this->is_signed()) { return this->high_bit(); } else { return false; } } /// \brief Return true if the machine integer is greater or equal to 0 /// /// Always true for unsigned integers bool is_non_negative() const { return !this->is_negative(); } /// \brief Return true if the machine integer is strictly greater than 0 bool is_strictly_positive() const { if (this->is_small()) { if (this->is_signed()) { return !this->high_bit() && this->_n.i != 0; } else { return this->_n.i != 0; } } else { return *this->_n.p > 0; } } /// \brief Return true if all bits are set bool all_ones() const { if (this->is_small()) { return this->_n.i == (ONES >> (64 - this->_bit_width)); } else { if (this->is_signed()) { return *this->_n.p == -1; } else { return *this->_n.p == (power_of_2(this->_bit_width) - 1); } } } private: /// \brief Return the number of leading '0' bits in a uint64_t static uint64_t leading_zeros(uint64_t n) { if (n == 0) { return 64; } #if __has_builtin(__builtin_clzll) || IKOS_GNUC_PREREQ(4, 0, 0) // NOLINTNEXTLINE(google-runtime-int) if (std::is_same< uint64_t, unsigned long long >::value) { return static_cast< uint64_t >(__builtin_clzll(n)); } #endif // Use bisection uint64_t zeros = 0; for (uint64_t shift = 64U >> 1U; shift != 0U; shift >>= 1U) { uint64_t tmp = n >> shift; if (tmp != 0) { n = tmp; } else { zeros |= shift; } } return zeros; } /// \brief Return the number of leading '0' bits in a ZNumber static uint64_t leading_zeros(ZNumber n, uint64_t bit_width) { if (n == 0) { return bit_width; } else if (n < 0) { return 0; } // Use bisection uint64_t zeros = 0; for (uint64_t shift = bit_width >> 1U; shift != 0U; shift >>= 1U) { ZNumber tmp = n >> shift; if (tmp != 0) { n = tmp; } else { zeros |= shift; } } return zeros; } /// \brief Return the number of leading '1' bits in a uint64_t static uint64_t leading_ones(uint64_t n) { return leading_zeros(~n); } /// \brief Return the number of leading '1' bits in a ZNumber static uint64_t leading_ones(ZNumber n, uint64_t bit_width) { n = mod(n, power_of_2(bit_width)); n = n ^ (power_of_2(bit_width) - 1); return leading_zeros(n, bit_width); } public: /// \brief Return the number of leading '0' bits uint64_t leading_zeros() const { if (this->is_small()) { uint64_t unused_bits = 64 - this->_bit_width; return leading_zeros(this->_n.i) - unused_bits; } else { return leading_zeros(*this->_n.p, this->_bit_width); } } /// \brief Return the number of leading '1' bits uint64_t leading_ones() const { if (this->is_small()) { return leading_ones(this->_n.i << (64 - this->_bit_width)); } else { return leading_ones(*this->_n.p, this->_bit_width); } } private: /// Sign-extend the number in the bottom `bit-width` bits of `n` to a 64-bit /// signed integer static int64_t sign_extend_64(uint64_t n, uint64_t bit_width) { ikos_assert_msg(bit_width > 0 && bit_width <= 64, "invalid bit-width"); // TODO(marthaud): this is implementation-defined. // See https://stackoverflow.com/a/7602006 // See https://stackoverflow.com/a/13208789 for proper solution // NOLINTNEXTLINE(hicpp-signed-bitwise) return int64_t(n << (64U - bit_width)) >> (64U - bit_width); } public: /// @} /// \name Conversion Functions /// @{ /// \brief Return the machine integer as a ZNumber /// /// If this is a signed integer, the result is within [-2**(n-1), 2**(n-1)-1] /// Otherwise, the result is within [0, 2**n-1] ZNumber to_z_number() const { if (this->is_small()) { if (this->is_signed()) { return ZNumber(sign_extend_64(this->_n.i, this->_bit_width)); } else { return ZNumber(this->_n.i); } } else { return *this->_n.p; } } /// \brief Return true if the machine integer fits in the given integer type template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > bool fits() const { if (this->is_small()) { if (this->is_signed()) { int64_t n = sign_extend_64(this->_n.i, this->_bit_width); if (std::numeric_limits< T >::is_signed) { return int64_t(std::numeric_limits< T >::min()) <= n && n <= int64_t(std::numeric_limits< T >::max()); } else { return int64_t(0) <= n && uint64_t(n) <= uint64_t(std::numeric_limits< T >::max()); } } else { uint64_t n = this->_n.i; if (std::numeric_limits< T >::is_signed) { return n <= uint64_t(std::numeric_limits< T >::max()); } else { return uint64_t(std::numeric_limits< T >::min()) <= n && n <= uint64_t(std::numeric_limits< T >::max()); } } } else { return this->_n.p->fits< T >(); } } /// \brief Return the machine integer as the given integer type template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > T to() const { ikos_assert_msg(this->fits< T >(), "does not fit"); if (this->is_small()) { if (this->is_signed()) { return static_cast< T >(sign_extend_64(this->_n.i, this->_bit_width)); } else { return static_cast< T >(this->_n.i); } } else { return this->_n.p->to< T >(); } } /// \brief Return a string representation of the integer in the given base /// /// The base can vary from 2 to 36, or from -2 to -36 std::string str(int base = 10) const { if (this->is_small()) { if (this->is_signed()) { return std::to_string(sign_extend_64(this->_n.i, this->_bit_width)); } else { return std::to_string(this->_n.i); } } else { return this->_n.p->str(base); } } /// @} /// \name Unary Operators /// @{ // \brief Set the machine integer to the minimum integer void set_min() { if (this->is_signed()) { if (this->is_small()) { this->_n.i = uint64_t(1) << (this->_bit_width - 1); } else { *this->_n.p = -power_of_2(this->_bit_width - 1); } } else { this->set_zero(); } } // \brief Set the machine integer to the maximum integer void set_max() { if (this->is_signed()) { if (this->_bit_width == 1) { this->_n.i = 0; } else if (this->is_small()) { this->_n.i = ONES >> (65 - this->_bit_width); } else { *this->_n.p = power_of_2(this->_bit_width - 1) - 1; } } else { if (this->is_small()) { this->_n.i = ONES >> (64 - this->_bit_width); } else { *this->_n.p = power_of_2(this->_bit_width) - 1; } } } // \brief Set the machine integer to zero void set_zero() { if (this->is_small()) { this->_n.i = 0; } else { *this->_n.p = 0; } } /// \brief Unary plus const MachineInt& operator+() const { return *this; } /// \brief Prefix increment MachineInt& operator++() { if (this->is_small()) { ++this->_n.i; } else { ++(*this->_n.p); } this->normalize(); return *this; } /// \brief Postfix increment const MachineInt operator++(int) { MachineInt r(*this); if (this->is_small()) { ++this->_n.i; } else { ++(*this->_n.p); } this->normalize(); return r; } /// \brief Unary minus const MachineInt operator-() const { if (this->is_small()) { return MachineInt((~this->_n.i) + 1, this->_bit_width, this->_sign); } else { return MachineInt(-(*this->_n.p), this->_bit_width, this->_sign); } } /// \brief Negate the machine integer void negate() { if (this->is_small()) { this->_n.i = (~this->_n.i) + 1; } else { *this->_n.p = -(*this->_n.p); } this->normalize(); } /// \brief Bitwise not const MachineInt operator~() const { if (this->is_small()) { return MachineInt(~this->_n.i, this->_bit_width, this->_sign); } else { return MachineInt(-(*this->_n.p) - 1, this->_bit_width, this->_sign); } } /// \brief Flip all the bits /// /// This is the bitwise not operator. void flip_bits() { if (this->is_small()) { this->_n.i = ~this->_n.i; } else { *this->_n.p = -(*this->_n.p) - 1; } this->normalize(); } /// \brief Prefix decrement MachineInt& operator--() { if (this->is_small()) { --this->_n.i; } else { --(*this->_n.p); } this->normalize(); return *this; } /// \brief Postfix decrement const MachineInt operator--(int) { MachineInt r(*this); if (this->is_small()) { --this->_n.i; } else { --(*this->_n.p); } this->normalize(); return r; } /// \brief Truncate the machine integer to the given bit width MachineInt trunc(uint64_t bit_width) const { ikos_assert(this->_bit_width > bit_width); if (this->is_small()) { return MachineInt(this->_n.i, bit_width, this->_sign); } else { return MachineInt(*this->_n.p, bit_width, this->_sign); } } /// \brief Extend the machine integer to the given bit width MachineInt ext(uint64_t bit_width) const { ikos_assert(this->_bit_width < bit_width); if (this->is_small()) { if (this->is_signed()) { return MachineInt(sign_extend_64(this->_n.i, this->_bit_width), bit_width, this->_sign); } else { return MachineInt(this->_n.i, bit_width, this->_sign, NormalizedTag{}); } } else { return MachineInt(*this->_n.p, bit_width, this->_sign, NormalizedTag{}); } } /// \brief Change the machine integer sign (bitcast) MachineInt sign_cast(Signedness sign) const { ikos_assert(this->_sign != sign); if (this->is_small()) { return MachineInt(this->_n.i, this->_bit_width, sign, NormalizedTag{}); } else { return MachineInt(*this->_n.p, this->_bit_width, sign); } } /// \brief Cast the machine integer to the given bit width and sign /// /// This is equivalent to trunc()/ext() + sign_cast() (in this specific order) MachineInt cast(uint64_t bit_width, Signedness sign) const { if (this->is_small()) { if (this->is_signed()) { return MachineInt(sign_extend_64(this->_n.i, this->_bit_width), bit_width, sign); } else { return MachineInt(this->_n.i, bit_width, sign); } } else { return MachineInt(*this->_n.p, bit_width, sign); } } /// @} private: // Helpers for binary operations /// \brief Check if an overflow occurred static bool check_overflow(const ZNumber& n, uint64_t bit_width, Signedness sign) { if (sign == Signed) { return n >= power_of_2(bit_width - 1); } else { return n >= power_of_2(bit_width); } } /// \brief Check if an underflow occurred static bool check_underflow(const ZNumber& n, uint64_t bit_width, Signedness sign) { if (sign == Signed) { return n < -power_of_2(bit_width - 1); } else { return n < 0; } } public: // Friends friend MachineInt add(const MachineInt& lhs, const MachineInt& rhs, bool& overflow); friend MachineInt add(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator+(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt sub(const MachineInt& lhs, const MachineInt& rhs, bool& overflow); friend MachineInt sub(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator-(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt mul(const MachineInt& lhs, const MachineInt& rhs, bool& overflow); friend MachineInt mul(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator*(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt div(const MachineInt& lhs, const MachineInt& rhs, bool& overflow, bool& exact); friend MachineInt div(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator/(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt rem(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator%(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt mod(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt shl(const MachineInt& lhs, const MachineInt& rhs, bool& overflow); friend MachineInt shl(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt lshr(const MachineInt& lhs, const MachineInt& rhs, bool& exact); friend MachineInt lshr(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt ashr(const MachineInt& lhs, const MachineInt& rhs, bool& exact); friend MachineInt ashr(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt and_(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator&(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt or_(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator|(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt xor_(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt operator^(const MachineInt& lhs, const MachineInt& rhs); friend MachineInt gcd(const MachineInt& a, const MachineInt& b); friend bool operator==(const MachineInt& lhs, const MachineInt& rhs); friend bool operator!=(const MachineInt& lhs, const MachineInt& rhs); friend bool operator<(const MachineInt& lhs, const MachineInt& rhs); friend bool operator<=(const MachineInt& lhs, const MachineInt& rhs); friend bool operator>(const MachineInt& lhs, const MachineInt& rhs); friend bool operator>=(const MachineInt& lhs, const MachineInt& rhs); friend std::ostream& operator<<(std::ostream& o, const MachineInt& n); friend std::size_t hash_value(const MachineInt&); }; // end class MachineInt /// \name Binary Operators /// @{ /// \brief Assert that the shift count is between 0 and bit_width - 1 inline void assert_shift(const MachineInt& n, uint64_t bit_width) { ikos_assert_msg(n.is_non_negative(), "shift count is negative"); ikos_assert_msg(n.to_z_number() < bit_width, "shift count is too big"); ikos_ignore(n); ikos_ignore(bit_width); } /// \brief Addition /// /// Returns the sum of the operands, with wrapping. inline MachineInt add(const MachineInt& lhs, const MachineInt& rhs, bool& overflow) { assert_compatible(lhs, rhs); if (lhs.is_small()) { MachineInt result(lhs._n.i + rhs._n.i, lhs._bit_width, lhs._sign); if (lhs.is_signed()) { overflow = lhs.is_non_negative() == rhs.is_non_negative() && result.is_non_negative() != lhs.is_non_negative(); } else { overflow = result < rhs; } return result; } else { ZNumber n = (*lhs._n.p) + (*rhs._n.p); overflow = MachineInt::check_overflow(n, lhs._bit_width, lhs._sign) || MachineInt::check_underflow(n, lhs._bit_width, lhs._sign); return MachineInt(n, lhs._bit_width, lhs._sign); } } /// \brief Addition /// /// Returns the sum of the operands, with wrapping. inline MachineInt add(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return MachineInt(lhs._n.i + rhs._n.i, lhs._bit_width, lhs._sign); } else { return MachineInt((*lhs._n.p) + (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Addition /// /// Returns the sum of the operands, with wrapping. inline MachineInt operator+(const MachineInt& lhs, const MachineInt& rhs) { return add(lhs, rhs); } /// \brief Subtraction /// /// Returns the difference of the operands, with wrapping. inline MachineInt sub(const MachineInt& lhs, const MachineInt& rhs, bool& overflow) { assert_compatible(lhs, rhs); if (lhs.is_small()) { MachineInt result(lhs._n.i - rhs._n.i, lhs._bit_width, lhs._sign); if (lhs.is_signed()) { overflow = lhs.is_non_negative() != rhs.is_non_negative() && result.is_non_negative() != lhs.is_non_negative(); } else { overflow = result > lhs; } return result; } else { ZNumber n = (*lhs._n.p) - (*rhs._n.p); overflow = MachineInt::check_overflow(n, lhs._bit_width, lhs._sign) || MachineInt::check_underflow(n, lhs._bit_width, lhs._sign); return MachineInt(n, lhs._bit_width, lhs._sign); } } /// \brief Subtraction /// /// Returns the difference of the operands, with wrapping. inline MachineInt sub(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return MachineInt(lhs._n.i - rhs._n.i, lhs._bit_width, lhs._sign); } else { return MachineInt((*lhs._n.p) - (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Subtraction /// /// Returns the difference of the operands, with wrapping. inline MachineInt operator-(const MachineInt& lhs, const MachineInt& rhs) { return sub(lhs, rhs); } /// \brief Multiplication /// /// Returns the product of the operands, with wrapping. inline MachineInt mul(const MachineInt& lhs, const MachineInt& rhs, bool& overflow) { assert_compatible(lhs, rhs); if (lhs.is_small()) { MachineInt result(lhs._n.i * rhs._n.i, lhs._bit_width, lhs._sign); if (lhs.bit_width() == 1) { if (lhs.is_signed()) { overflow = (lhs.is_min() && rhs.is_min()); } else { overflow = false; } } else { overflow = !lhs.is_zero() && !rhs.is_zero() && (div(result, rhs) != lhs || div(result, lhs) != rhs); } return result; } else { ZNumber n = (*lhs._n.p) * (*rhs._n.p); overflow = MachineInt::check_overflow(n, lhs._bit_width, lhs._sign) || MachineInt::check_underflow(n, lhs._bit_width, lhs._sign); return MachineInt(n, lhs._bit_width, lhs._sign); } } /// \brief Multiplication /// /// Returns the product of the operands, with wrapping. inline MachineInt mul(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return MachineInt(lhs._n.i * rhs._n.i, lhs._bit_width, lhs._sign); } else { return MachineInt((*lhs._n.p) * (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Multiplication /// /// Returns the product of the operands, with wrapping. inline MachineInt operator*(const MachineInt& lhs, const MachineInt& rhs) { return mul(lhs, rhs); } /// \brief Division /// /// Returns the quotient of the operands. /// /// For unsigned integers, this is the unsigned division. /// For signed integers, this is the signed division rounded towards zero, with /// wrapping. /// /// Division by zero is undefined behavior. /// /// `overflow` is set to true when dividing INT_MIN / (-1) for signed integers. /// `exact` is set to true if `lhs` is a multiple of `rhs`. inline MachineInt div(const MachineInt& lhs, const MachineInt& rhs, bool& overflow, bool& exact) { assert_compatible(lhs, rhs); ikos_assert_msg(!rhs.is_zero(), "division by zero"); if (lhs.is_small()) { if (lhs.is_signed()) { // Signed division MachineInt abs_lhs = lhs.is_negative() ? -lhs : lhs; MachineInt abs_rhs = rhs.is_negative() ? -rhs : rhs; MachineInt result(abs_lhs._n.i / abs_rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); if (lhs.is_negative() ^ rhs.is_negative()) { result.negate(); } overflow = lhs.is_min() && rhs.all_ones(); exact = (abs_lhs._n.i % abs_rhs._n.i) == 0; return result; } else { // Unsigned division MachineInt result(lhs._n.i / rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); overflow = false; exact = (lhs._n.i % rhs._n.i) == 0; return result; } } else { ZNumber n = (*lhs._n.p) / (*rhs._n.p); overflow = MachineInt::check_overflow(n, lhs._bit_width, lhs._sign) || MachineInt::check_underflow(n, lhs._bit_width, lhs._sign); exact = mod(*lhs._n.p, *rhs._n.p) == 0; return MachineInt(n, lhs._bit_width, lhs._sign); } } /// \brief Division /// /// Returns the quotient of the operands. /// /// For unsigned integers, this is the unsigned division. /// For signed integers, this is the signed division rounded towards zero, with /// wrapping. /// /// Division by zero is undefined behavior. inline MachineInt div(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); ikos_assert_msg(!rhs.is_zero(), "division by zero"); if (lhs.is_small()) { if (lhs.is_signed()) { // Signed division MachineInt abs_lhs = lhs.is_negative() ? -lhs : lhs; MachineInt abs_rhs = rhs.is_negative() ? -rhs : rhs; MachineInt result(abs_lhs._n.i / abs_rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); if (lhs.is_negative() ^ rhs.is_negative()) { result.negate(); } return result; } else { // Unsigned division return MachineInt(lhs._n.i / rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } } else { return MachineInt((*lhs._n.p) / (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Division /// /// Returns the quotient of the operands. /// /// For unsigned integers, this is the unsigned division. /// For signed integers, this is the signed division rounded towards zero, with /// wrapping. /// /// Division by zero is undefined behavior. inline MachineInt operator/(const MachineInt& lhs, const MachineInt& rhs) { return div(lhs, rhs); } /// \brief Remainder /// /// Returns the remainder of the operands. /// /// For unsigned integers, the result is the classic modulo operator. /// For signed integers, the result is either zero or has the same sign as the /// dividend. The sign of the divisor is ignored. inline MachineInt rem(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); ikos_assert_msg(!rhs.is_zero(), "division by zero"); if (lhs.is_small()) { if (lhs.is_signed()) { // Signed remainder MachineInt abs_lhs = lhs.is_negative() ? -lhs : lhs; MachineInt abs_rhs = rhs.is_negative() ? -rhs : rhs; MachineInt result(abs_lhs._n.i % abs_rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); if (lhs.is_negative()) { result.negate(); } return result; } else { // Unsigned remainder return MachineInt(lhs._n.i % rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } } else { return MachineInt((*lhs._n.p) % (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Remainder /// /// Returns the remainder of the operands. /// /// For unsigned integers, the result is the classic modulo operator. /// For signed integers, the result is either zero or has the same sign as the /// dividend. The sign of the divisor is ignored. inline MachineInt operator%(const MachineInt& lhs, const MachineInt& rhs) { return rem(lhs, rhs); } /// \brief Modulo /// /// Returns the modulo of the operands. /// The result is always non-negative. The sign of the divisor is ignored. inline MachineInt mod(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); ikos_assert_msg(!rhs.is_zero(), "division by zero"); if (lhs.is_small()) { if (lhs.is_signed()) { // Signed modulo MachineInt abs_lhs = lhs.is_negative() ? -lhs : lhs; MachineInt abs_rhs = rhs.is_negative() ? -rhs : rhs; MachineInt result(abs_lhs._n.i % abs_rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); if (lhs.is_negative() && !result.is_zero()) { result = abs_rhs - result; } return result; } else { // Unsigned modulo return MachineInt(lhs._n.i % rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } } else { return MachineInt(mod(*lhs._n.p, *rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Left shift /// /// Returns the left binary shift of `lhs` by `rhs`, with wrapping. /// /// For signed integers, `overflow` is set to true if it shifts out any bits /// that disagree with the resultant sign bit. /// For unsigned integers, `overflow` is set to true if it shifts out any /// non-zero bits. inline MachineInt shl(const MachineInt& lhs, const MachineInt& rhs, bool& overflow) { assert_compatible(lhs, rhs); assert_shift(rhs, lhs._bit_width); if (lhs.is_small()) { MachineInt result(lhs._n.i << rhs._n.i, lhs._bit_width, lhs._sign); if (lhs.is_signed()) { if (lhs.is_negative()) { overflow = (rhs._n.i >= lhs.leading_ones()); } else { overflow = (rhs._n.i >= lhs.leading_zeros()); } } else { overflow = (rhs._n.i > lhs.leading_zeros()); } return result; } else { MachineInt result((*lhs._n.p) << (*rhs._n.p), lhs._bit_width, lhs._sign); if (lhs.is_signed()) { ZNumber u = mod(*lhs._n.p, MachineInt::power_of_2(lhs._bit_width)); ZNumber shifted = u >> (lhs._bit_width - (*rhs._n.p)); if ((*result._n.p) >= 0) { // resultant sign bit is 0 overflow = (shifted != 0); } else { // resultant sign bit is 1 overflow = (shifted != MachineInt::power_of_2(*rhs._n.p) - 1); } } else { overflow = ((*lhs._n.p) >> (lhs._bit_width - (*rhs._n.p))) != 0; } return result; } } /// \brief Left shift /// /// Returns the left binary shift of `lhs` by `rhs`, with wrapping. inline MachineInt shl(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); assert_shift(rhs, lhs._bit_width); if (lhs.is_small()) { return MachineInt(lhs._n.i << rhs._n.i, lhs._bit_width, lhs._sign); } else { return MachineInt((*lhs._n.p) << (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Logical shift right /// /// Returns the logical right binary shift of `lhs` by `rhs`. /// The most significant bits of the result are filled with zero bits. /// /// `exact` is set to false if it shifts out any non-zero bits. inline MachineInt lshr(const MachineInt& lhs, const MachineInt& rhs, bool& exact) { assert_compatible(lhs, rhs); assert_shift(rhs, lhs._bit_width); if (lhs.is_small()) { exact = (rhs._n.i == 0) || (lhs._n.i & (MachineInt::ONES >> (64 - rhs._n.i))) == 0; return MachineInt(lhs._n.i >> rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } else { exact = ((*lhs._n.p) & (MachineInt::power_of_2(*rhs._n.p) - 1)) == 0; if (lhs.is_signed()) { ZNumber u = mod(*lhs._n.p, MachineInt::power_of_2(lhs._bit_width)); return MachineInt(u >> (*rhs._n.p), lhs._bit_width, lhs._sign); } else { return MachineInt((*lhs._n.p) >> (*rhs._n.p), lhs._bit_width, lhs._sign); } } } /// \brief Logical shift right /// /// Returns the logical right binary shift of `lhs` by `rhs`. /// The most significant bits of the result are filled with zero bits. inline MachineInt lshr(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); assert_shift(rhs, lhs._bit_width); if (lhs.is_small()) { return MachineInt(lhs._n.i >> rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } else { if (lhs.is_signed()) { ZNumber u = mod(*lhs._n.p, MachineInt::power_of_2(lhs._bit_width)); return MachineInt(u >> (*rhs._n.p), lhs._bit_width, lhs._sign); } else { return MachineInt((*lhs._n.p) >> (*rhs._n.p), lhs._bit_width, lhs._sign); } } } /// \brief Arithmetic shift right /// /// Returns the arithmetic right binary shift of `lhs` by `rhs`. /// The most significant bits of the result are filled with the sign bit of /// `lhs`. /// /// `exact` is set to false if it shifts out any non-zero bits. inline MachineInt ashr(const MachineInt& lhs, const MachineInt& rhs, bool& exact) { assert_compatible(lhs, rhs); assert_shift(rhs, lhs._bit_width); if (lhs.is_small()) { exact = (rhs._n.i == 0) || (lhs._n.i & (MachineInt::ONES >> (64 - rhs._n.i))) == 0; int64_t n = MachineInt::sign_extend_64(lhs._n.i, lhs._bit_width); // NOLINTNEXTLINE(hicpp-signed-bitwise) return MachineInt(n >> static_cast< int64_t >(rhs._n.i), lhs._bit_width, lhs._sign); } else { exact = ((*lhs._n.p) & (MachineInt::power_of_2(*rhs._n.p) - 1)) == 0; if (lhs.is_signed()) { return MachineInt((*lhs._n.p) >> (*rhs._n.p), lhs._bit_width, lhs._sign); } else { ZNumber s = mod((*lhs._n.p) + MachineInt::power_of_2(lhs._bit_width - 1), MachineInt::power_of_2(lhs._bit_width)) - MachineInt::power_of_2(lhs._bit_width - 1); return MachineInt(s >> (*rhs._n.p), lhs._bit_width, lhs._sign); } } } /// \brief Arithmetic shift right /// /// Returns the arithmetic right binary shift of `lhs` by `rhs`. /// The most significant bits of the result are filled with the sign bit of /// `lhs`. inline MachineInt ashr(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); assert_shift(rhs, lhs._bit_width); if (lhs.is_small()) { int64_t n = MachineInt::sign_extend_64(lhs._n.i, lhs._bit_width); // NOLINTNEXTLINE(hicpp-signed-bitwise) return MachineInt(n >> static_cast< int64_t >(rhs._n.i), lhs._bit_width, lhs._sign); } else { if (lhs.is_signed()) { return MachineInt((*lhs._n.p) >> (*rhs._n.p), lhs._bit_width, lhs._sign); } else { ZNumber s = mod((*lhs._n.p) + MachineInt::power_of_2(lhs._bit_width - 1), MachineInt::power_of_2(lhs._bit_width)) - MachineInt::power_of_2(lhs._bit_width - 1); return MachineInt(s >> (*rhs._n.p), lhs._bit_width, lhs._sign); } } } /// \brief Bitwise AND /// /// Returns the bitwise AND of the operands. inline MachineInt and_(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return MachineInt(lhs._n.i & rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } else { return MachineInt((*lhs._n.p) & (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Bitwise AND /// /// Returns the bitwise AND of the operands. inline MachineInt operator&(const MachineInt& lhs, const MachineInt& rhs) { return and_(lhs, rhs); } /// \brief Bitwise OR /// /// Returns the bitwise OR of the operands. inline MachineInt or_(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return MachineInt(lhs._n.i | rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } else { return MachineInt((*lhs._n.p) | (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Bitwise OR /// /// Returns the bitwise OR of the operands. inline MachineInt operator|(const MachineInt& lhs, const MachineInt& rhs) { return or_(lhs, rhs); } /// \brief Bitwise XOR /// /// Returns the bitwise XOR of the operands. inline MachineInt xor_(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return MachineInt(lhs._n.i ^ rhs._n.i, lhs._bit_width, lhs._sign, MachineInt::NormalizedTag{}); } else { return MachineInt((*lhs._n.p) ^ (*rhs._n.p), lhs._bit_width, lhs._sign); } } /// \brief Bitwise XOR /// /// Returns the bitwise XOR of the operands. inline MachineInt operator^(const MachineInt& lhs, const MachineInt& rhs) { return xor_(lhs, rhs); } /// \brief Return the greatest common divisor of the given machine integers inline MachineInt gcd(const MachineInt& a, const MachineInt& b) { assert_compatible(a, b); if (a.is_small()) { MachineInt abs_a = a.is_negative() ? -a : a; MachineInt abs_b = b.is_negative() ? -b : b; uint64_t u = abs_a._n.i; uint64_t v = abs_b._n.i; while (v != 0) { uint64_t r = u % v; u = v; v = r; } return MachineInt(u, a._bit_width, b._sign); } else { return MachineInt(gcd(*a._n.p, *b._n.p), a._bit_width, b._sign); } } /// \brief Return the greatest common divisor of the given machine integers inline MachineInt gcd(const MachineInt& a, const MachineInt& b, const MachineInt& c) { return gcd(gcd(a, b), c); } /// @} /// \name Comparison Operators /// @{ /// \brief Equality operator inline bool operator==(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return lhs._n.i == rhs._n.i; } else { return (*lhs._n.p) == (*rhs._n.p); } } /// \brief Equality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator==(const MachineInt& lhs, T rhs) { return lhs == MachineInt(rhs, lhs.bit_width(), lhs.sign()); } /// \brief Equality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator==(T lhs, const MachineInt& rhs) { return MachineInt(lhs, rhs.bit_width(), rhs.sign()) == rhs; } /// \brief Inequality operator inline bool operator!=(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { return lhs._n.i != rhs._n.i; } else { return (*lhs._n.p) != (*rhs._n.p); } } /// \brief Inequality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator!=(const MachineInt& lhs, T rhs) { return lhs != MachineInt(rhs, lhs.bit_width(), lhs.sign()); } /// \brief Inequality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator!=(T lhs, const MachineInt& rhs) { return MachineInt(lhs, rhs.bit_width(), rhs.sign()) != rhs; } /// \brief Less than comparison inline bool operator<(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { if (lhs.is_signed()) { return MachineInt::sign_extend_64(lhs._n.i, lhs._bit_width) < MachineInt::sign_extend_64(rhs._n.i, rhs._bit_width); } else { return lhs._n.i < rhs._n.i; } } else { return (*lhs._n.p) < (*rhs._n.p); } } /// \brief Less than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<(const MachineInt& lhs, T rhs) { return lhs < MachineInt(rhs, lhs.bit_width(), lhs.sign()); } /// \brief Less than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<(T lhs, const MachineInt& rhs) { return MachineInt(lhs, rhs.bit_width(), rhs.sign()) < rhs; } /// \brief Less or equal comparison inline bool operator<=(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { if (lhs.is_signed()) { return MachineInt::sign_extend_64(lhs._n.i, lhs._bit_width) <= MachineInt::sign_extend_64(rhs._n.i, rhs._bit_width); } else { return lhs._n.i <= rhs._n.i; } } else { return (*lhs._n.p) <= (*rhs._n.p); } } /// \brief Less or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<=(const MachineInt& lhs, T rhs) { return lhs <= MachineInt(rhs, lhs.bit_width(), lhs.sign()); } /// \brief Less or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<=(T lhs, const MachineInt& rhs) { return MachineInt(lhs, rhs.bit_width(), rhs.sign()) <= rhs; } /// \brief Greater than comparison inline bool operator>(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { if (lhs.is_signed()) { return MachineInt::sign_extend_64(lhs._n.i, lhs._bit_width) > MachineInt::sign_extend_64(rhs._n.i, rhs._bit_width); } else { return lhs._n.i > rhs._n.i; } } else { return (*lhs._n.p) > (*rhs._n.p); } } /// \brief Greater than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>(const MachineInt& lhs, T rhs) { return lhs > MachineInt(rhs, lhs.bit_width(), lhs.sign()); } /// \brief Greater than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>(T lhs, const MachineInt& rhs) { return MachineInt(lhs, rhs.bit_width(), rhs.sign()) > rhs; } /// \brief Greater or equal comparison inline bool operator>=(const MachineInt& lhs, const MachineInt& rhs) { assert_compatible(lhs, rhs); if (lhs.is_small()) { if (lhs.is_signed()) { return MachineInt::sign_extend_64(lhs._n.i, lhs._bit_width) >= MachineInt::sign_extend_64(rhs._n.i, rhs._bit_width); } else { return lhs._n.i >= rhs._n.i; } } else { return (*lhs._n.p) >= (*rhs._n.p); } } /// \brief Greater or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>=(const MachineInt& lhs, T rhs) { return lhs >= MachineInt(rhs, lhs.bit_width(), lhs.sign()); } /// \brief Greater or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>=(T lhs, const MachineInt& rhs) { return MachineInt(lhs, rhs.bit_width(), rhs.sign()) >= rhs; } /// @} /// \name Utility functions (min, max, etc.) /// @{ /// \brief Return the smaller of the given machine integers inline const MachineInt& min(const MachineInt& a, const MachineInt& b) { return (a < b) ? a : b; } /// \brief Return the greater of the given machine integers inline const MachineInt& max(const MachineInt& a, const MachineInt& b) { return (a < b) ? b : a; } /// \brief Return the absolute value of the given machine integer /// /// Note that it overflows for the minimum signed integer inline MachineInt abs(const MachineInt& n) { return n.is_negative() ? -n : n; } /// @} /// \name Input / Output /// @{ /// \brief Write a machine integer on a stream inline std::ostream& operator<<(std::ostream& o, const MachineInt& n) { if (n.is_small()) { if (n.is_signed()) { o << MachineInt::sign_extend_64(n._n.i, n._bit_width); } else { o << n._n.i; } } else { o << *n._n.p; } return o; } /// @} /// \brief Return the hash of a MachineInt inline std::size_t hash_value(const MachineInt& n) { std::size_t hash = 0; if (n.is_small()) { boost::hash_combine(hash, n._n.i); } else { boost::hash_combine(hash, *n._n.p); } boost::hash_combine(hash, n._bit_width); boost::hash_combine(hash, n._sign); return hash; } } // end namespace core } // end namespace ikos namespace std { /// \brief Hash for MachineInt template <> struct hash< ikos::core::MachineInt > { std::size_t operator()(const ikos::core::MachineInt& n) const { return ikos::core::hash_value(n); } }; } // end namespace std NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/q_number.hpp000066400000000000000000000522441473507761200247060ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Unlimited precision rationals * * Implementation of big numbers based on GMP, the GNU Multiple Precision * Arithmetic Library (http://gmplib.org). * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { /// \brief Checks wether T is a supported integral type or ZNumber template < typename T > struct IsSupportedIntegralOrZNumber : public IsSupportedIntegral< T > {}; template <> struct IsSupportedIntegralOrZNumber< const ZNumber& > : public std::true_type { }; namespace detail { /// \brief Helper that returns either an integral type or a mpz_class template < typename T > struct ZNumberAdapter : public MpzAdapter< T > {}; template <> struct ZNumberAdapter< const ZNumber& > { const mpz_class& operator()(const ZNumber& n) { return n.mpz(); } }; } // end namespace detail /// \brief Class for unlimited precision rationals class QNumber { private: mpq_class _n; public: /// \brief Create a QNumber from a string representation /// /// Interpret the null-terminated string `str` in the given base. /// /// If the string contains unsuitable characters for the given base, throw /// an exception NumberError. /// /// The base may vary from 2 to 36. static QNumber from_string(const char* str, int base = 10) { try { return QNumber(mpq_class(str, base)); } catch (std::invalid_argument&) { std::ostringstream buf; buf << "QNumber: invalid conversion from string '" << str << "'"; throw NumberError(buf.str()); } } /// \brief Create a QNumber from a string representation /// /// Interpret the string `str` in the given base. /// /// If the string contains unsuitable characters for the given base, throw /// an exception NumberError. /// /// The base may vary from 2 to 36. static QNumber from_string(const std::string& str, int base = 10) { try { return QNumber(mpq_class(str, base)); } catch (std::invalid_argument&) { std::ostringstream buf; buf << "QNumber: invalid conversion from string '" << str << "'"; throw NumberError(buf.str()); } } /// \name Constructors /// @{ /// \brief Default constructor that creates a QNumber equals to 0 QNumber() = default; /// \brief Copy constructor QNumber(const QNumber&) = default; /// \brief Move constructor QNumber(QNumber&&) = default; /// \brief Create a QNumber from a ZNumber explicit QNumber(const ZNumber& n) : _n(n._n) {} /// \brief Create a QNumber from a ZNumber explicit QNumber(ZNumber&& n) : _n(std::move(n)._n) {} /// \brief Create a QNumber from an integral type template < typename N, class = std::enable_if_t< IsSupportedIntegral< N >::value > > explicit QNumber(N n) : _n(detail::MpzAdapter< N >()(n)) {} /// \brief Create a QNumber from a mpq_class explicit QNumber(const mpq_class& n) : _n(n) { ikos_assert_msg(this->_n.get_den() != 0, "denominator is zero"); this->_n.canonicalize(); } /// \brief Create a QNumber from a mpq_class explicit QNumber(mpq_class&& n) : _n(std::move(n)) { ikos_assert_msg(this->_n.get_den() != 0, "denominator is zero"); this->_n.canonicalize(); } /// \brief Create a QNumber from a numerator and a denominator template < typename N, typename D, class = std::enable_if_t< IsSupportedIntegral< N >::value && IsSupportedIntegral< D >::value > > explicit QNumber(N n, D d) : _n(detail::MpzAdapter< N >()(n), detail::MpzAdapter< D >()(d)) { ikos_assert_msg(this->_n.get_den() != 0, "denominator is zero"); this->_n.canonicalize(); } /// \brief Create a QNumber from a numerator and a denominator explicit QNumber(const ZNumber& n, const ZNumber& d) : _n(n._n, d._n) { ikos_assert_msg(this->_n.get_den() != 0, "denominator is zero"); this->_n.canonicalize(); } /// \brief Create a QNumber from a numerator and a denominator explicit QNumber(ZNumber&& n, ZNumber&& d) : _n(std::move(n)._n, std::move(d)._n) { ikos_assert_msg(this->_n.get_den() != 0, "denominator is zero"); this->_n.canonicalize(); } struct NormalizedTag {}; /// \brief Create a QNumber from a normalized mpq_class QNumber(const mpq_class& n, NormalizedTag) : _n(n) {} /// \brief Create a QNumber from a normalized mpq_class QNumber(mpq_class&& n, NormalizedTag) : _n(std::move(n)) {} /// \brief Destructor ~QNumber() = default; /// @} /// \name Assignment Operators /// @{ /// \brief Copy assignment QNumber& operator=(const QNumber&) = default; /// \brief Move assignment QNumber& operator=(QNumber&&) noexcept = default; /// \brief Assignment for ZNumber QNumber& operator=(const ZNumber& n) { this->_n = n._n; return *this; } /// \brief Assignment for ZNumber QNumber& operator=(ZNumber&& n) noexcept { this->_n = std::move(n._n); return *this; } /// \brief Assignment for integral types template < typename N, typename = std::enable_if_t< IsSupportedIntegral< N >::value > > QNumber& operator=(N n) { this->_n = detail::MpzAdapter< N >()(n); return *this; } /// \brief Addition assignment QNumber& operator+=(const QNumber& x) { this->_n += x._n; return *this; } /// \brief Addition assignment with integral types or ZNumber template < typename N, class = std::enable_if_t< IsSupportedIntegralOrZNumber< N >::value > > QNumber& operator+=(N x) { this->_n += detail::ZNumberAdapter< N >()(x); return *this; } /// \brief Subtraction assignment QNumber& operator-=(const QNumber& x) { this->_n -= x._n; return *this; } /// \brief Subtraction assignment with integral types or ZNumber template < typename N, class = std::enable_if_t< IsSupportedIntegralOrZNumber< N >::value > > QNumber& operator-=(N x) { this->_n -= detail::ZNumberAdapter< N >()(x); return *this; } /// \brief Multiplication assignment QNumber& operator*=(const QNumber& x) { this->_n *= x._n; return *this; } /// \brief Multiplication assignment with integral types or ZNumber template < typename N, class = std::enable_if_t< IsSupportedIntegralOrZNumber< N >::value > > QNumber& operator*=(N x) { this->_n *= detail::ZNumberAdapter< N >()(x); return *this; } /// \brief Division assignment QNumber& operator/=(const QNumber& x) { ikos_assert_msg(x._n != 0, "division by zero"); this->_n /= x._n; return *this; } /// \brief Division assignment with integral types or ZNumber template < typename N, class = std::enable_if_t< IsSupportedIntegralOrZNumber< N >::value > > QNumber& operator/=(N x) { ikos_assert_msg(x != 0, "division by zero"); this->_n /= detail::ZNumberAdapter< N >()(x); return *this; } /// @} /// \name Unary Operators /// @{ /// \brief Unary plus const QNumber& operator+() const { return *this; } /// \brief Prefix increment QNumber& operator++() { ++this->_n; return *this; } /// \brief Postfix increment const QNumber operator++(int) { QNumber r(*this); ++this->_n; return r; } /// \brief Unary minus const QNumber operator-() const { return QNumber(-this->_n); } /// \brief Prefix decrement QNumber& operator--() { --this->_n; return *this; } /// \brief Postfix decrement const QNumber operator--(int) { QNumber r(*this); --this->_n; return r; } /// @} /// \name Value generators /// @{ /// \brief Get the numerator ZNumber numerator() const { return ZNumber(this->_n.get_num()); } /// \brief Get the denominator ZNumber denominator() const { return ZNumber(this->_n.get_den()); } /// \brief Round to upper integer ZNumber round_to_upper() const { const mpz_class& num = this->_n.get_num(); const mpz_class& den = this->_n.get_den(); ZNumber q(num / den); ZNumber r(num % den); if (r == 0 || this->_n < 0) { return q; } else { return q + 1; } } /// \brief Round to lower integer ZNumber round_to_lower() const { const mpz_class& num = this->_n.get_num(); const mpz_class& den = this->_n.get_den(); ZNumber q(num / den); ZNumber r(num % den); if (r == 0 || this->_n > 0) { return q; } else { return q - 1; } } /// @} /// \name Conversion Functions /// @{ /// \brief Get the internal representation const mpq_class& mpq() const { return this->_n; } /// \brief Return a string of the QNumber in the given base /// /// The base can vary from 2 to 36, or from -2 to -36 std::string str(int base = 10) const { return this->_n.get_str(base); } /// @} friend std::istream& operator>>(std::istream& i, QNumber& n); }; // end class QNumber /// \name Binary Operators /// @{ /// \brief Addition inline QNumber operator+(const QNumber& lhs, const QNumber& rhs) { return QNumber(lhs.mpq() + rhs.mpq(), QNumber::NormalizedTag{}); } /// \brief Addition with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator+(const QNumber& lhs, T rhs) { return QNumber(lhs.mpq() + detail::ZNumberAdapter< T >()(rhs), QNumber::NormalizedTag{}); } /// \brief Addition with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator+(T lhs, const QNumber& rhs) { return QNumber(detail::ZNumberAdapter< T >()(lhs) + rhs.mpq(), QNumber::NormalizedTag{}); } /// \brief Subtraction inline QNumber operator-(const QNumber& lhs, const QNumber& rhs) { return QNumber(lhs.mpq() - rhs.mpq(), QNumber::NormalizedTag{}); } /// \brief Subtraction with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator-(const QNumber& lhs, T rhs) { return QNumber(lhs.mpq() - detail::ZNumberAdapter< T >()(rhs), QNumber::NormalizedTag{}); } /// \brief Subtraction with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator-(T lhs, const QNumber& rhs) { return QNumber(detail::ZNumberAdapter< T >()(lhs) - rhs.mpq(), QNumber::NormalizedTag{}); } /// \brief Multiplication inline QNumber operator*(const QNumber& lhs, const QNumber& rhs) { return QNumber(lhs.mpq() * rhs.mpq(), QNumber::NormalizedTag{}); } /// \brief Multiplication with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator*(const QNumber& lhs, T rhs) { return QNumber(lhs.mpq() * detail::ZNumberAdapter< T >()(rhs), QNumber::NormalizedTag{}); } /// \brief Multiplication with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator*(T lhs, const QNumber& rhs) { return QNumber(detail::ZNumberAdapter< T >()(lhs) * rhs.mpq(), QNumber::NormalizedTag{}); } /// \brief Division inline QNumber operator/(const QNumber& lhs, const QNumber& rhs) { ikos_assert_msg(rhs.mpq() != 0, "division by zero"); return QNumber(lhs.mpq() / rhs.mpq(), QNumber::NormalizedTag{}); } /// \brief Division with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator/(const QNumber& lhs, T rhs) { ikos_assert_msg(rhs != 0, "division by zero"); return QNumber(lhs.mpq() / detail::ZNumberAdapter< T >()(rhs), QNumber::NormalizedTag{}); } /// \brief Division with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline QNumber operator/(T lhs, const QNumber& rhs) { ikos_assert_msg(rhs.mpq() != 0, "division by zero"); return QNumber(detail::ZNumberAdapter< T >()(lhs) / rhs.mpq(), QNumber::NormalizedTag{}); } /// @} /// \name Comparison Operators /// @{ /// \brief Equality operator inline bool operator==(const QNumber& lhs, const QNumber& rhs) { return lhs.mpq() == rhs.mpq(); } /// \brief Equality operator with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator==(const QNumber& lhs, T rhs) { return lhs.mpq() == detail::ZNumberAdapter< T >()(rhs); } /// \brief Equality operator with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator==(T lhs, const QNumber& rhs) { return detail::ZNumberAdapter< T >()(lhs) == rhs.mpq(); } /// \brief Inequality operator inline bool operator!=(const QNumber& lhs, const QNumber& rhs) { return lhs.mpq() != rhs.mpq(); } /// \brief Inequality operator with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator!=(const QNumber& lhs, T rhs) { return lhs.mpq() != detail::ZNumberAdapter< T >()(rhs); } /// \brief Inequality operator with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator!=(T lhs, const QNumber& rhs) { return detail::ZNumberAdapter< T >()(lhs) != rhs.mpq(); } /// \brief Less than comparison inline bool operator<(const QNumber& lhs, const QNumber& rhs) { return lhs.mpq() < rhs.mpq(); } /// \brief Less than comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator<(const QNumber& lhs, T rhs) { return lhs.mpq() < detail::ZNumberAdapter< T >()(rhs); } /// \brief Less than comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator<(T lhs, const QNumber& rhs) { return detail::ZNumberAdapter< T >()(lhs) < rhs.mpq(); } /// \brief Less or equal comparison inline bool operator<=(const QNumber& lhs, const QNumber& rhs) { return lhs.mpq() <= rhs.mpq(); } /// \brief Less or equal comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator<=(const QNumber& lhs, T rhs) { return lhs.mpq() <= detail::ZNumberAdapter< T >()(rhs); } /// \brief Less or equal comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator<=(T lhs, const QNumber& rhs) { return detail::ZNumberAdapter< T >()(lhs) <= rhs.mpq(); } /// \brief Greater than comparison inline bool operator>(const QNumber& lhs, const QNumber& rhs) { return lhs.mpq() > rhs.mpq(); } /// \brief Greater than comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator>(const QNumber& lhs, T rhs) { return lhs.mpq() > detail::ZNumberAdapter< T >()(rhs); } /// \brief Greater than comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator>(T lhs, const QNumber& rhs) { return detail::ZNumberAdapter< T >()(lhs) > rhs.mpq(); } /// \brief Greater or equal comparison inline bool operator>=(const QNumber& lhs, const QNumber& rhs) { return lhs.mpq() >= rhs.mpq(); } /// \brief Greater or equal comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator>=(const QNumber& lhs, T rhs) { return lhs.mpq() >= detail::ZNumberAdapter< T >()(rhs); } /// \brief Greater or equal comparison with integral types or ZNumber template < typename T, class = std::enable_if_t< IsSupportedIntegralOrZNumber< T >::value > > inline bool operator>=(T lhs, const QNumber& rhs) { return detail::ZNumberAdapter< T >()(lhs) >= rhs.mpq(); } /// @} /// \name Utility functions (min, max, and abs) /// @{ /// \brief Return the smaller of the given numbers inline const QNumber& min(const QNumber& a, const QNumber& b) { return (a < b) ? a : b; } /// \brief Return the smaller of the given numbers inline const QNumber& min(const QNumber& a, const QNumber& b, const QNumber& c) { return min(min(a, b), c); } /// \brief Return the smaller of the given numbers inline const QNumber& min(const QNumber& a, const QNumber& b, const QNumber& c, const QNumber& d) { return min(min(min(a, b), c), d); } /// \brief Return the greater of the given numbers inline const QNumber& max(const QNumber& a, const QNumber& b) { return (a < b) ? b : a; } /// \brief Return the greater of the given numbers inline const QNumber& max(const QNumber& a, const QNumber& b, const QNumber& c) { return max(max(a, b), c); } /// \brief Return the greater of the given numbers inline const QNumber& max(const QNumber& a, const QNumber& b, const QNumber& c, const QNumber& d) { return max(max(max(a, b), c), d); } /// \brief Return the absolute value of the given number inline QNumber abs(const QNumber& n) { return QNumber(abs(n.mpq())); } /// @} /// \name Input / Output /// @{ /// \brief Write a QNumber on a stream, in base 10 inline std::ostream& operator<<(std::ostream& o, const QNumber& n) { o << n.mpq(); return o; } /// \brief Read a QNumber from a stream, in base 10 inline std::istream& operator>>(std::istream& i, QNumber& n) { i >> n._n; return i; } /// @} /// \brief Return the hash of a QNumber inline std::size_t hash_value(const QNumber& n) { const mpq_class& m = n.mpq(); std::size_t result = 0; boost::hash_combine(result, m.get_num_mpz_t()[0]._mp_size); for (int i = 0, e = std::abs(m.get_num_mpz_t()[0]._mp_size); i < e; ++i) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) boost::hash_combine(result, m.get_num_mpz_t()[0]._mp_d[i]); } boost::hash_combine(result, m.get_den_mpz_t()[0]._mp_size); for (int i = 0, e = std::abs(m.get_den_mpz_t()[0]._mp_size); i < e; ++i) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) boost::hash_combine(result, m.get_den_mpz_t()[0]._mp_d[i]); } return result; } } // end namespace core } // end namespace ikos namespace std { /// \brief Hash for QNumber template <> struct hash< ikos::core::QNumber > { std::size_t operator()(const ikos::core::QNumber& n) const { return ikos::core::hash_value(n); } }; } // end namespace std NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/signedness.hpp000066400000000000000000000044221473507761200252330ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Signedness enum * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once namespace ikos { namespace core { /// \brief Signedness (signed or unsigned) enum Signedness { Signed = 0, Unsigned = 1 }; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/supported_integral.hpp000066400000000000000000000057201473507761200270050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Type traits for numbers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { /// \brief Checks whether T is a supported integral type. /// /// Supported integral types are: /// * int, unsigned int /// * long, unsigned long /// * long long, unsigned long long template < typename T > struct IsSupportedIntegral : public std::false_type {}; template <> struct IsSupportedIntegral< int > : public std::true_type {}; template <> struct IsSupportedIntegral< unsigned int > : public std::true_type {}; template <> struct IsSupportedIntegral< long > : public std::true_type {}; template <> struct IsSupportedIntegral< unsigned long > : public std::true_type {}; template <> struct IsSupportedIntegral< long long > : public std::true_type {}; template <> struct IsSupportedIntegral< unsigned long long > : public std::true_type {}; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/number/z_number.hpp000066400000000000000000001122101473507761200247050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Unlimited precision integers * * Implementation of big numbers based on GMP, the GNU Multiple Precision * Arithmetic Library (http://gmplib.org). * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace detail { /// \brief Helper to handle all supported integral types with GMP template < typename T > struct MpzAdapter { T operator()(T n) { return n; } }; /// \brief Helper to handle unsigned long long template < bool > struct MpzAdapterUnsignedLongLong; template <> struct MpzAdapterUnsignedLongLong< true > { unsigned long operator()(unsigned long long n) { return static_cast< unsigned long >(n); } }; template <> struct MpzAdapterUnsignedLongLong< false > { mpz_class operator()(unsigned long long n) { static_assert(sizeof(unsigned long long) == 8, "unexpected size"); static_assert(sizeof(unsigned int) == 4, "unexpected size"); mpz_class r(static_cast< unsigned int >(n >> 32U)); r <<= 32; r += static_cast< unsigned int >(n & 0xFFFFFFFFU); return r; } }; template <> struct MpzAdapter< unsigned long long > : public MpzAdapterUnsignedLongLong< sizeof(unsigned long long) == sizeof(unsigned long) > {}; /// \brief Helper to handle long long template < bool > struct MpzAdapterLongLong; template <> struct MpzAdapterLongLong< true > { long operator()(long long n) { return static_cast< long >(n); } }; template <> struct MpzAdapterLongLong< false > { mpz_class operator()(long long n) { static_assert(sizeof(long long) == 8, "unexpected size"); static_assert(sizeof(int) == 4, "unexpected size"); // NOLINTNEXTLINE(hicpp-signed-bitwise) mpz_class r(static_cast< int >(n >> 32)); r <<= 32; // NOLINTNEXTLINE(hicpp-signed-bitwise) r += static_cast< unsigned int >(n & 0xFFFFFFFF); return r; } }; template <> struct MpzAdapter< long long > : public MpzAdapterLongLong< sizeof(long long) == sizeof(long) > {}; /// \brief Helper to check if a mpz_class fits in the given integer type template < typename T > struct MpzFits; template <> struct MpzFits< unsigned int > { bool operator()(const mpz_class& n) { return n.fits_uint_p(); } }; template <> struct MpzFits< int > { bool operator()(const mpz_class& n) { return n.fits_sint_p(); } }; template <> struct MpzFits< unsigned long > { bool operator()(const mpz_class& n) { return n.fits_ulong_p(); } }; template <> struct MpzFits< long > { bool operator()(const mpz_class& n) { return n.fits_slong_p(); } }; /// \brief Helper to handle unsigned long long template < bool > struct MpzFitsUnsignedLongLong; template <> struct MpzFitsUnsignedLongLong< true > { bool operator()(const mpz_class& n) { return n.fits_ulong_p(); } }; template <> struct MpzFitsUnsignedLongLong< false > { bool operator()(const mpz_class& n) { static_assert(sizeof(unsigned long long) == 8, "unexpected size"); static_assert(sizeof(unsigned int) == 4, "unexpected size"); return mpz_sgn(n.get_mpz_t()) >= 0 && mpz_sizeinbase(n.get_mpz_t(), 2) <= 64; } }; template <> struct MpzFits< unsigned long long > : public MpzFitsUnsignedLongLong< sizeof(unsigned long long) == sizeof(unsigned long) > {}; /// \brief Helper to handle long long template < bool > struct MpzFitsLongLong; template <> struct MpzFitsLongLong< true > { bool operator()(const mpz_class& n) { return n.fits_slong_p(); } }; template <> struct MpzFitsLongLong< false > { bool operator()(const mpz_class& n) { static_assert(sizeof(long long) == 8, "unexpected size"); static_assert(sizeof(int) == 4, "unexpected size"); if (mpz_sgn(n.get_mpz_t()) >= 0) { return mpz_sizeinbase(n.get_mpz_t(), 2) <= 63; } else { mpz_class m(-n - 1); return mpz_sizeinbase(m.get_mpz_t(), 2) <= 63; } } }; template <> struct MpzFits< long long > : public MpzFitsLongLong< sizeof(long long) == sizeof(long) > {}; /// \brief Helper to convert a mpz_class to the given integer type template < typename T > struct MpzTo; template <> struct MpzTo< unsigned int > { unsigned int operator()(const mpz_class& n) { return static_cast< unsigned int >(n.get_ui()); } }; template <> struct MpzTo< int > { int operator()(const mpz_class& n) { return static_cast< int >(n.get_si()); } }; template <> struct MpzTo< unsigned long > { unsigned long operator()(const mpz_class& n) { return n.get_ui(); } }; template <> struct MpzTo< long > { long operator()(const mpz_class& n) { return n.get_si(); } }; /// \brief Helper to handle unsigned long long template < bool > struct MpzToUnsignedLongLong; template <> struct MpzToUnsignedLongLong< true > { unsigned long long operator()(const mpz_class& n) { return static_cast< unsigned long long >(n.get_ui()); } }; template <> struct MpzToUnsignedLongLong< false > { unsigned long long operator()(const mpz_class& n) { static_assert(sizeof(unsigned long long) == 8, "unexpected size"); static_assert(sizeof(unsigned int) == 4, "unexpected size"); auto hi = static_cast< unsigned long long >(mpz_class(n >> 32).get_ui()); auto lo = static_cast< unsigned long long >(mpz_class(n & 0xFFFFFFFF).get_ui()); return (hi << 32U) + lo; } }; template <> struct MpzTo< unsigned long long > : public MpzToUnsignedLongLong< sizeof(unsigned long long) == sizeof(unsigned long) > {}; /// \brief Helper to handle long long template < bool > struct MpzToLongLong; template <> struct MpzToLongLong< true > { long long operator()(const mpz_class& n) { return static_cast< long long >(n.get_si()); } }; template <> struct MpzToLongLong< false > { long long operator()(const mpz_class& n) { static_assert(sizeof(long long) == 8, "unexpected size"); static_assert(sizeof(int) == 4, "unexpected size"); auto hi = static_cast< long long >(mpz_class(n >> 32).get_si()); auto lo = static_cast< long long >(mpz_class(n & 0xFFFFFFFF).get_ui()); // NOLINTNEXTLINE(hicpp-signed-bitwise) return (hi << 32) + lo; } }; template <> struct MpzTo< long long > : public MpzToLongLong< sizeof(long long) == sizeof(long) > {}; } // end namespace detail /// \brief Class for unlimited precision integers class ZNumber { private: mpz_class _n; public: /// \brief Create a ZNumber from a string representation /// /// Interpret the null-terminated string `str` in the given base. /// /// If the string contains unsuitable characters for the given base, throw /// an exception NumberError. /// /// The base may vary from 2 to 36. static ZNumber from_string(const char* str, int base = 10) { try { return ZNumber(mpz_class(str, base)); } catch (std::invalid_argument&) { std::ostringstream buf; buf << "ZNumber: invalid conversion from string '" << str << "'"; throw NumberError(buf.str()); } } /// \brief Create a ZNumber from a string representation /// /// Interpret the string `str` in the given base. /// /// If the string contains unsuitable characters for the given base, throw /// an exception NumberError. /// /// The base may vary from 2 to 36. static ZNumber from_string(const std::string& str, int base = 10) { try { return ZNumber(mpz_class(str, base)); } catch (std::invalid_argument&) { std::ostringstream buf; buf << "ZNumber: invalid conversion from string '" << str << "'"; throw NumberError(buf.str()); } } /// \name Constructors /// @{ /// \brief Default constructor that creates a ZNumber equals to 0 ZNumber() = default; /// \brief Copy constructor ZNumber(const ZNumber&) = default; /// \brief Move constructor // TODO(marthaud): Add noexcept when mpz_class(mpz_class&&) becomes noexcept ZNumber(ZNumber&&) = default; /// \brief Create a ZNumber from a mpz_class explicit ZNumber(const mpz_class& n) : _n(n) {} /// \brief Create a ZNumber from a mpz_class explicit ZNumber(mpz_class&& n) : _n(std::move(n)) {} /// \brief Create a ZNumber from an integral type template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > explicit ZNumber(T n) : _n(detail::MpzAdapter< T >()(n)) {} /// \brief Destructor ~ZNumber() = default; /// @} /// \name Assignment Operators /// @{ /// \brief Copy assignment ZNumber& operator=(const ZNumber&) = default; /// \brief Move assignment ZNumber& operator=(ZNumber&&) noexcept = default; /// \brief Assignment for integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator=(T n) { this->_n = detail::MpzAdapter< T >()(n); return *this; } /// \brief Addition assignment ZNumber& operator+=(const ZNumber& x) { this->_n += x._n; return *this; } /// \brief Addition assignment with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator+=(T x) { this->_n += detail::MpzAdapter< T >()(x); return *this; } /// \brief Subtraction assignment ZNumber& operator-=(const ZNumber& x) { this->_n -= x._n; return *this; } /// \brief Subtraction assignment with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator-=(T x) { this->_n -= detail::MpzAdapter< T >()(x); return *this; } /// \brief Multiplication assignment ZNumber& operator*=(const ZNumber& x) { this->_n *= x._n; return *this; } /// \brief Multiplication assignment with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator*=(T x) { this->_n *= detail::MpzAdapter< T >()(x); return *this; } /// \brief Integer division assignment /// /// Integer division with rounding towards zero. ZNumber& operator/=(const ZNumber& x) { ikos_assert_msg(x._n != 0, "division by zero"); this->_n /= x._n; return *this; } /// \brief Integer division assignment with integral types /// /// Integer division with rounding towards zero. template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator/=(T x) { ikos_assert_msg(x != 0, "division by zero"); this->_n /= detail::MpzAdapter< T >()(x); return *this; } /// \brief Remainder assignment /// /// The result `r` will satisfy: /// `this = q * abs(x) + r` with `0 <= abs(r) < abs(x)` /// /// The sign of `x` is ignored, and the result will have the same sign as /// `this`. ZNumber& operator%=(const ZNumber& x) { ikos_assert_msg(x._n != 0, "division by zero"); this->_n %= x._n; return *this; } /// \brief Remainder assignment with integral types /// /// The result `r` will satisfy: /// `this = q * abs(x) + r` with `0 <= abs(r) < abs(x)` /// /// The sign of `x` is ignored, and the result will have the same sign as /// `this`. template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator%=(T x) { ikos_assert_msg(x != 0, "division by zero"); this->_n %= detail::MpzAdapter< T >()(x); return *this; } /// \brief Bitwise AND assignment ZNumber& operator&=(const ZNumber& x) { this->_n &= x._n; return *this; } /// \brief Bitwise AND assignment with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator&=(T x) { this->_n &= detail::MpzAdapter< T >()(x); return *this; } /// \brief Bitwise OR assignment ZNumber& operator|=(const ZNumber& x) { this->_n |= x._n; return *this; } /// \brief Bitwise OR assignment with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator|=(T x) { this->_n |= detail::MpzAdapter< T >()(x); return *this; } /// \brief Bitwise XOR assignment ZNumber& operator^=(const ZNumber& x) { this->_n ^= x._n; return *this; } /// \brief Bitwise XOR assignment with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator^=(T x) { this->_n ^= detail::MpzAdapter< T >()(x); return *this; } /// \brief Left binary shift assignment /// /// This is undefined if `x` isn't between 0 and 2**32 - 1 ZNumber& operator<<=(const ZNumber& x) { ikos_assert_msg(x._n >= 0, "shift count is negative"); ikos_assert_msg(x._n.fits_ulong_p(), "shift count is too big"); this->_n <<= x._n.get_ui(); return *this; } /// \brief Left binary shift assignment with integral types /// /// This is undefined if `x` isn't between 0 and 2**32 - 1 template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator<<=(T x) { ikos_assert_msg(x >= 0, "shift count is negative"); this->_n <<= static_cast< unsigned long int >(x); return *this; } /// \brief Right binary shift /// /// This is undefined if `x` isn't between 0 and 2**32 - 1 ZNumber& operator>>=(const ZNumber& x) { ikos_assert_msg(x._n >= 0, "shift count is negative"); ikos_assert_msg(x._n.fits_ulong_p(), "shift count is too big"); this->_n >>= x._n.get_ui(); return *this; } /// \brief Right binary shift with integral types /// /// This is undefined if `x` isn't between 0 and 2**32 - 1 template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > ZNumber& operator>>=(T x) { ikos_assert_msg(x >= 0, "shift count is negative"); this->_n >>= static_cast< unsigned long int >(x); return *this; } /// @} /// \name Unary Operators /// @{ /// \brief Unary plus const ZNumber& operator+() const { return *this; } /// \brief Prefix increment ZNumber& operator++() { ++this->_n; return *this; } /// \brief Postfix increment const ZNumber operator++(int) { ZNumber r(*this); ++this->_n; return r; } /// \brief Unary minus const ZNumber operator-() const { return ZNumber(-this->_n); } /// \brief Prefix decrement ZNumber& operator--() { --this->_n; return *this; } /// \brief Postfix decrement const ZNumber operator--(int) { ZNumber r(*this); --this->_n; return r; } /// \brief Return the next power of 2 greater or equal to this number /// /// This is undefined for negative numbers. ZNumber next_power_of_2() const { ikos_assert(this->_n >= 0); if (this->_n <= 1) { return ZNumber(1); } ZNumber n(this->_n - 1); return ZNumber(mpz_class(1) << n.size_in_bits()); } /// @} /// \name Value tests /// @{ /// \brief Return the number of trailing '0' bits /// /// This is undefined if the number is 0. uint64_t trailing_zeros() const { ikos_assert(this->_n != 0); return mpz_scan1(this->_n.get_mpz_t(), 0); } /// \brief Return the number of trailing '1' bits /// /// This is undefined if the number is -1. uint64_t trailing_ones() const { ikos_assert(this->_n != -1); return mpz_scan0(this->_n.get_mpz_t(), 0); } /// \brief Return the number of bits /// /// The sign is ignored. uint64_t size_in_bits() const { return mpz_sizeinbase(this->_n.get_mpz_t(), 2); } /// @} /// \name Conversion Functions /// @{ /// \brief Get the internal representation const mpz_class& mpz() const { return this->_n; } /// \brief Return true if the number fits in the given integer type template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > bool fits() const { return detail::MpzFits< T >()(this->_n); } /// \brief Return the number as the given integer type template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > T to() const { ikos_assert_msg(detail::MpzFits< T >()(this->_n), "does not fit"); return detail::MpzTo< T >()(this->_n); } /// \brief Return a string representation of the ZNumber in the given base /// /// The base can vary from 2 to 36, or from -2 to -36 std::string str(int base = 10) const { return this->_n.get_str(base); } /// @} friend ZNumber mod(const ZNumber&, const ZNumber&); friend ZNumber gcd(const ZNumber&, const ZNumber&); friend ZNumber lcm(const ZNumber&, const ZNumber&); friend void gcd_extended( const ZNumber&, const ZNumber&, ZNumber&, ZNumber&, ZNumber&); friend std::istream& operator>>(std::istream& i, ZNumber& n); friend class QNumber; friend ZNumber single_mask(const ZNumber& size); friend ZNumber double_mask(const ZNumber& low, const ZNumber& high); friend ZNumber make_clipped_mask(const ZNumber& low, const ZNumber& size, const ZNumber& lower_clip, const ZNumber& size_clip); }; // end class ZNumber /// \name Binary Operators /// @{ /// \brief Addition inline ZNumber operator+(const ZNumber& lhs, const ZNumber& rhs) { return ZNumber(lhs.mpz() + rhs.mpz()); } /// \brief Addition with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator+(const ZNumber& lhs, T rhs) { return ZNumber(lhs.mpz() + detail::MpzAdapter< T >()(rhs)); } /// \brief Addition with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator+(T lhs, const ZNumber& rhs) { return ZNumber(detail::MpzAdapter< T >()(lhs) + rhs.mpz()); } /// \brief Subtraction inline ZNumber operator-(const ZNumber& lhs, const ZNumber& rhs) { return ZNumber(lhs.mpz() - rhs.mpz()); } /// \brief Subtraction with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator-(const ZNumber& lhs, T rhs) { return ZNumber(lhs.mpz() - detail::MpzAdapter< T >()(rhs)); } /// \brief Subtraction with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator-(T lhs, const ZNumber& rhs) { return ZNumber(detail::MpzAdapter< T >()(lhs) - rhs.mpz()); } /// \brief Multiplication inline ZNumber operator*(const ZNumber& lhs, const ZNumber& rhs) { return ZNumber(lhs.mpz() * rhs.mpz()); } /// \brief Multiplication with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator*(const ZNumber& lhs, T rhs) { return ZNumber(lhs.mpz() * detail::MpzAdapter< T >()(rhs)); } /// \brief Multiplication with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator*(T lhs, const ZNumber& rhs) { return ZNumber(detail::MpzAdapter< T >()(lhs) * rhs.mpz()); } /// \brief Integer division /// /// Integer division with rounding towards zero. inline ZNumber operator/(const ZNumber& lhs, const ZNumber& rhs) { ikos_assert_msg(rhs.mpz() != 0, "division by zero"); return ZNumber(lhs.mpz() / rhs.mpz()); } /// \brief Integer division with integral types /// /// Integer division with rounding towards zero. template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator/(const ZNumber& lhs, T rhs) { ikos_assert_msg(rhs != 0, "division by zero"); return ZNumber(lhs.mpz() / detail::MpzAdapter< T >()(rhs)); } /// \brief Integer division with integral types /// /// Integer division with rounding towards zero. template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator/(T lhs, const ZNumber& rhs) { ikos_assert_msg(rhs.mpz() != 0, "division by zero"); return ZNumber(detail::MpzAdapter< T >()(lhs) / rhs.mpz()); } /// \brief Remainder /// /// The result `r` will satisfy: /// `lhs = q * abs(rhs) + r` with `0 <= abs(r) < abs(rhs)` /// /// The sign of `rhs` is ignored, and the result will have the same sign as /// `lhs`. inline ZNumber operator%(const ZNumber& lhs, const ZNumber& rhs) { ikos_assert_msg(rhs.mpz() != 0, "division by zero"); return ZNumber(lhs.mpz() % rhs.mpz()); } /// \brief Remainder with integral types /// /// The result `r` will satisfy: /// `lhs = q * abs(rhs) + r` with `0 <= abs(r) < abs(rhs)` /// /// The sign of `rhs` is ignored, and the result will have the same sign as /// `lhs`. template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator%(const ZNumber& lhs, T rhs) { ikos_assert_msg(rhs != 0, "division by zero"); return ZNumber(lhs.mpz() % detail::MpzAdapter< T >()(rhs)); } /// \brief Remainder with integral types /// /// The result `r` will satisfy: /// `lhs = q * abs(rhs) + r` with `0 <= abs(r) < abs(rhs)` /// /// The sign of `rhs` is ignored, and the result will have the same sign as /// `lhs`. template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator%(T lhs, const ZNumber& rhs) { ikos_assert_msg(rhs.mpz() != 0, "division by zero"); return ZNumber(detail::MpzAdapter< T >()(lhs) % rhs.mpz()); } /// \brief Bitwise AND inline ZNumber operator&(const ZNumber& lhs, const ZNumber& rhs) { return ZNumber(lhs.mpz() & rhs.mpz()); } /// \brief Bitwise AND with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator&(const ZNumber& lhs, T rhs) { return ZNumber(lhs.mpz() & detail::MpzAdapter< T >()(rhs)); } /// \brief Bitwise AND with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator&(T lhs, const ZNumber& rhs) { return ZNumber(detail::MpzAdapter< T >()(lhs) & rhs.mpz()); } /// \brief Bitwise OR inline ZNumber operator|(const ZNumber& lhs, const ZNumber& rhs) { return ZNumber(lhs.mpz() | rhs.mpz()); } /// \brief Bitwise OR with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator|(const ZNumber& lhs, T rhs) { return ZNumber(lhs.mpz() | detail::MpzAdapter< T >()(rhs)); } /// \brief Bitwise OR with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator|(T lhs, const ZNumber& rhs) { return ZNumber(detail::MpzAdapter< T >()(lhs) | rhs.mpz()); } /// \brief Bitwise XOR inline ZNumber operator^(const ZNumber& lhs, const ZNumber& rhs) { return ZNumber(lhs.mpz() ^ rhs.mpz()); } /// \brief Bitwise XOR with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator^(const ZNumber& lhs, T rhs) { return ZNumber(lhs.mpz() ^ detail::MpzAdapter< T >()(rhs)); } /// \brief Bitwise XOR with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator^(T lhs, const ZNumber& rhs) { return ZNumber(detail::MpzAdapter< T >()(lhs) ^ rhs.mpz()); } /// \brief Left binary shift /// /// This is undefined if `rhs` isn't between 0 and 2**32 - 1 inline ZNumber operator<<(const ZNumber& lhs, const ZNumber& rhs) { ikos_assert_msg(rhs.mpz() >= 0, "shift count is negative"); ikos_assert_msg(rhs.mpz().fits_ulong_p(), "shift count is too big"); return ZNumber(lhs.mpz() << rhs.mpz().get_ui()); } /// \brief Left binary shift with integral types /// /// This is undefined if `rhs` isn't between 0 and 2**32 - 1 template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator<<(const ZNumber& lhs, T rhs) { ikos_assert_msg(rhs >= 0, "shift count is negative"); return ZNumber(lhs.mpz() << static_cast< unsigned long int >(rhs)); } /// \brief Left binary shift with integral types /// /// This is undefined if `rhs` isn't between 0 and 2**32 - 1 template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator<<(T lhs, const ZNumber& rhs) { ZNumber r(lhs); r <<= rhs; return r; } /// \brief Right binary shift /// /// This is undefined if `rhs` isn't between 0 and 2**32 - 1 inline ZNumber operator>>(const ZNumber& lhs, const ZNumber& rhs) { ikos_assert_msg(rhs.mpz() >= 0, "shift count is negative"); ikos_assert_msg(rhs.mpz().fits_ulong_p(), "shift count is too big"); return ZNumber(lhs.mpz() >> rhs.mpz().get_ui()); } /// \brief Right binary shift with integral types /// /// This is undefined if `rhs` isn't between 0 and 2**32 - 1 template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator>>(const ZNumber& lhs, T rhs) { ikos_assert_msg(rhs >= 0, "shift count is negative"); return ZNumber(lhs.mpz() >> static_cast< unsigned long int >(rhs)); } /// \brief Right binary shift with integral types /// /// This is undefined if `rhs` isn't between 0 and 2**32 - 1 template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline ZNumber operator>>(T lhs, const ZNumber& rhs) { ZNumber r(lhs); r >>= rhs; return r; } /// @} /// \name Comparison Operators /// @{ /// \brief Equality operator inline bool operator==(const ZNumber& lhs, const ZNumber& rhs) { return lhs.mpz() == rhs.mpz(); } /// \brief Equality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator==(const ZNumber& lhs, T rhs) { return lhs.mpz() == detail::MpzAdapter< T >()(rhs); } /// \brief Equality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator==(T lhs, const ZNumber& rhs) { return detail::MpzAdapter< T >()(lhs) == rhs.mpz(); } /// \brief Inequality operator inline bool operator!=(const ZNumber& lhs, const ZNumber& rhs) { return lhs.mpz() != rhs.mpz(); } /// \brief Inequality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator!=(const ZNumber& lhs, T rhs) { return lhs.mpz() != detail::MpzAdapter< T >()(rhs); } /// \brief Inequality operator with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator!=(T lhs, const ZNumber& rhs) { return detail::MpzAdapter< T >()(lhs) != rhs.mpz(); } /// \brief Less than comparison inline bool operator<(const ZNumber& lhs, const ZNumber& rhs) { return lhs.mpz() < rhs.mpz(); } /// \brief Less than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<(const ZNumber& lhs, T rhs) { return lhs.mpz() < detail::MpzAdapter< T >()(rhs); } /// \brief Less than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<(T lhs, const ZNumber& rhs) { return detail::MpzAdapter< T >()(lhs) < rhs.mpz(); } /// \brief Less or equal comparison inline bool operator<=(const ZNumber& lhs, const ZNumber& rhs) { return lhs.mpz() <= rhs.mpz(); } /// \brief Less or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<=(const ZNumber& lhs, T rhs) { return lhs.mpz() <= detail::MpzAdapter< T >()(rhs); } /// \brief Less or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator<=(T lhs, const ZNumber& rhs) { return detail::MpzAdapter< T >()(lhs) <= rhs.mpz(); } /// \brief Greater than comparison inline bool operator>(const ZNumber& lhs, const ZNumber& rhs) { return lhs.mpz() > rhs.mpz(); } /// \brief Greater than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>(const ZNumber& lhs, T rhs) { return lhs.mpz() > detail::MpzAdapter< T >()(rhs); } /// \brief Greater than comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>(T lhs, const ZNumber& rhs) { return detail::MpzAdapter< T >()(lhs) > rhs.mpz(); } /// \brief Greater or equal comparison inline bool operator>=(const ZNumber& lhs, const ZNumber& rhs) { return lhs.mpz() >= rhs.mpz(); } /// \brief Greater or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>=(const ZNumber& lhs, T rhs) { return lhs.mpz() >= detail::MpzAdapter< T >()(rhs); } /// \brief Greater or equal comparison with integral types template < typename T, class = std::enable_if_t< IsSupportedIntegral< T >::value > > inline bool operator>=(T lhs, const ZNumber& rhs) { return detail::MpzAdapter< T >()(lhs) >= rhs.mpz(); } /// @} /// \name Utility functions (min, max, abs, gcd, lcm, etc.) /// @{ /// \brief Return the smaller of the given numbers inline const ZNumber& min(const ZNumber& a, const ZNumber& b) { return (a < b) ? a : b; } /// \brief Return the smaller of the given numbers inline const ZNumber& min(const ZNumber& a, const ZNumber& b, const ZNumber& c) { return min(min(a, b), c); } /// \brief Return the smaller of the given numbers inline const ZNumber& min(const ZNumber& a, const ZNumber& b, const ZNumber& c, const ZNumber& d) { return min(min(min(a, b), c), d); } /// \brief Return the greater of the given numbers inline const ZNumber& max(const ZNumber& a, const ZNumber& b) { return (a < b) ? b : a; } /// \brief Return the greater of the given numbers inline const ZNumber& max(const ZNumber& a, const ZNumber& b, const ZNumber& c) { return max(max(a, b), c); } /// \brief Return the greater of the given numbers inline const ZNumber& max(const ZNumber& a, const ZNumber& b, const ZNumber& c, const ZNumber& d) { return max(max(max(a, b), c), d); } /// \brief Return `n mod d` /// /// The result `r` will satisfy: /// `n = q * abs(d) + r` with `0 <= r < abs(d)` /// /// The sign of `d` is ignored, and the result is always non-negative. inline ZNumber mod(const ZNumber& n, const ZNumber& d) { ikos_assert_msg(d.mpz() != 0, "division by zero"); ZNumber r; mpz_mod(r._n.get_mpz_t(), n._n.get_mpz_t(), d._n.get_mpz_t()); return r; } /// \brief Return the absolute value of the given number inline ZNumber abs(const ZNumber& n) { return ZNumber(abs(n.mpz())); } /// \brief Return the greatest common divisor of the given numbers /// /// The result is always positive even if one or both input operands are /// negative. Except if both inputs are zero; then this function defines /// `gcd(0, 0) = 0`. inline ZNumber gcd(const ZNumber& a, const ZNumber& b) { ZNumber r; mpz_gcd(r._n.get_mpz_t(), a._n.get_mpz_t(), b._n.get_mpz_t()); return r; } /// \brief Return the greatest common divisor of the given numbers inline ZNumber gcd(const ZNumber& a, const ZNumber& b, const ZNumber& c) { return gcd(gcd(a, b), c); } /// \brief Return the least common multiple of the given numbers inline ZNumber lcm(const ZNumber& a, const ZNumber& b) { ZNumber r; mpz_lcm(r._n.get_mpz_t(), a._n.get_mpz_t(), b._n.get_mpz_t()); return r; } /// \brief Run Euclid's algorithm /// /// Compute `g = gcd(a, b)` and `u`, `v` such that `g = a*u + b*v` // /// The value in `g` is always positive, even if one or both of `a` and `b` are /// negative (or zero if both inputs are zero). inline void gcd_extended( const ZNumber& a, const ZNumber& b, ZNumber& g, ZNumber& u, ZNumber& v) { mpz_gcdext(g._n.get_mpz_t(), u._n.get_mpz_t(), v._n.get_mpz_t(), a._n.get_mpz_t(), b._n.get_mpz_t()); } /// @} /// \name Input / Output /// @{ /// \brief Write a ZNumber on a stream, in base 10 inline std::ostream& operator<<(std::ostream& o, const ZNumber& n) { o << n.mpz(); return o; } /// \brief Read a ZNumber from a stream, in base 10 inline std::istream& operator>>(std::istream& i, ZNumber& n) { i >> n._n; return i; } /// @} /// \brief Return the hash of a ZNumber inline std::size_t hash_value(const ZNumber& n) { const mpz_class& m = n.mpz(); std::size_t result = 0; boost::hash_combine(result, m.get_mpz_t()[0]._mp_size); for (int i = 0, e = std::abs(m.get_mpz_t()[0]._mp_size); i < e; ++i) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) boost::hash_combine(result, m.get_mpz_t()[0]._mp_d[i]); } return result; } /// \brief Return a mask with size bits starting at 0. inline ZNumber single_mask(const ZNumber& size) { ZNumber pow2 = ZNumber(1) << size; ZNumber mask = pow2 - 1; return mask; } /// \brief Return a mask with bits [low, high). inline ZNumber double_mask(const ZNumber& low, const ZNumber& high) { ZNumber high_mask = single_mask(high); ZNumber low_mask = single_mask(low); ZNumber result = high_mask - low_mask; return result; } /// \brief return a bit mask with bits in the range /// [0, size_clip), with bits taken from the intersection of /// [low, low + size) with [low_clip, low_clip + size_clip) /// with the result shifted by low_clip to fit in the /// range [0, size_clip). inline ZNumber make_clipped_mask(const ZNumber& low, const ZNumber& size, const ZNumber& lower_clip, const ZNumber& size_clip) { ZNumber upper_clip = lower_clip + size_clip; ZNumber upper = low + size; if ((low >= upper_clip) || (upper <= lower_clip)) { // No overlap. return ZNumber(0); } // Because of the above, we assert // (low < upper_clip) && (upper > lower_clip). ZNumber shifted_low = low - lower_clip; ZNumber shifted_size = size; if (shifted_low < 0) { shifted_size = shifted_size + shifted_low; // shifted_size = size + shifted_low // = (upper - low) + (low - lower_clip) // = upper - lower_clip // > 0 because of the above test. shifted_low = 0; } ZNumber shifted_upper = upper - lower_clip; // By the above shifted_upper > 0. // But we do not want it to exceed size_clip. if (shifted_upper > size_clip) { shifted_upper = size_clip; } ZNumber result = double_mask(shifted_low, shifted_upper); return result; } } // end namespace core } // end namespace ikos namespace std { /// \brief std::hash implementation for ZNumber template <> struct hash< ikos::core::ZNumber > { std::size_t operator()(const ikos::core::ZNumber& n) const { return ikos::core::hash_value(n); } }; } // end namespace std NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/000077500000000000000000000000001473507761200226715ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/dumpable.hpp000066400000000000000000000066061473507761200252030ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for printing objects, for debug purposes. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { /// \brief Traits for printable objects /// /// Elements to provide: /// /// static void dump(std::ostream&, const Dumpable& obj) /// Print the object on the given stream, for debugging purposes template < typename Dumpable, typename = void > struct DumpableTraits {}; /// \brief Default implementation, if Dumpable::dump(std::ostream&) const exists template < typename Dumpable > struct DumpableTraits< Dumpable, decltype(std::declval< const Dumpable& >().dump( std::declval< std::ostream& >())) > { static void dump(std::ostream& stream, const Dumpable& obj) { obj.dump(stream); } }; /// \brief Check if a type implements DumpableTraits template < typename Dumpable, typename DumpableTrait = DumpableTraits< Dumpable >, typename = void > struct IsDumpable : std::false_type {}; template < typename Dumpable, typename DumpableTrait > struct IsDumpable< Dumpable, DumpableTrait, decltype(DumpableTrait::dump(std::declval< std::ostream& >(), std::declval< const Dumpable& >())) > : std::true_type {}; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/graph.hpp000066400000000000000000000142401473507761200245040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for control-flow graphs. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { /// \brief Traits for graphs /// /// This class should be specialized for all graph types. /// /// Elements to provide: /// /// NodeRef - Type of a reference to a node in the graph, // should be cheap to copy, // should be comparable, ie. define bool NodeRef::operator==(NodeRef) /// /// SuccessorNodeIterator - Type returned by successor_begin(NodeRef), /// dereference to a NodeRef /// PredecessorNodeIterator - Type returned by predecessor_begin(NodeRef) /// dereference to a NodeRef /// /// static NodeRef entry(GraphRef) /// Return the entry node of the graph /// /// static SuccessorNodeIterator successor_begin(NodeRef) /// static SuccessorNodeIterator successor_end(NodeRef) /// Return iterators over the successors of the given node /// /// static PredecessorNodeIterator predecessor_begin(NodeRef) /// static PredecessorNodeIterator predecessor_end(NodeRef) /// Return iterators over the predecessors of the given node /// /// The GraphRef type should also be cheap to copy template < typename GraphRef > struct GraphTraits {}; /// \brief Check if a type implements GraphTraits template < typename GraphRef, typename GraphTrait = GraphTraits< GraphRef >, typename = void > struct IsGraph : std::false_type {}; template < typename GraphRef, typename GraphTrait > struct IsGraph< GraphRef, GraphTrait, void_t< // GraphTrait has NodeRef typename GraphTrait::NodeRef, // GraphTrait::NodeRef has: operator==(NodeRef) -> bool decltype(std::declval< typename GraphTrait::NodeRef >() == std::declval< typename GraphTrait::NodeRef >()), // GraphTrait has SuccessorNodeIterator typename GraphTrait::SuccessorNodeIterator, // SuccessorNodeIterator dereferences to NodeRef std::enable_if_t< std::is_same< typename std::iterator_traits< typename GraphTrait::SuccessorNodeIterator >::value_type, typename GraphTrait::NodeRef >::value >, // GraphTrait has PredecessorNodeIterator typename GraphTrait::PredecessorNodeIterator, // PredecessorNodeIterator dereferences to NodeRef std::enable_if_t< std::is_same< typename std::iterator_traits< typename GraphTrait::PredecessorNodeIterator >::value_type, typename GraphTrait::NodeRef >::value >, // GraphTrait has: entry(GraphRef) -> NodeRef std::enable_if_t< std::is_same< decltype(GraphTrait::entry( std::declval< GraphRef >())), typename GraphTrait::NodeRef >::value >, // GraphTrait has: successor_begin(NodeRef) -> SuccessorNodeIterator std::enable_if_t< std::is_same< decltype(GraphTrait::successor_begin( std::declval< typename GraphTrait::NodeRef >())), typename GraphTrait::SuccessorNodeIterator >::value >, // GraphTrait has: successor_end(NodeRef) -> SuccessorNodeIterator std::enable_if_t< std::is_same< decltype(GraphTrait::successor_end( std::declval< typename GraphTrait::NodeRef >())), typename GraphTrait::SuccessorNodeIterator >::value >, // GraphTrait has: predecessor_begin(NodeRef) -> PredecessorNodeIterator std::enable_if_t< std::is_same< decltype(GraphTrait::predecessor_begin( std::declval< typename GraphTrait::NodeRef >())), typename GraphTrait::PredecessorNodeIterator >::value >, // GraphTrait has: predecessor_end(NodeRef) -> PredecessorNodeIterator std::enable_if_t< std::is_same< decltype(GraphTrait::predecessor_end( std::declval< typename GraphTrait::NodeRef >())), typename GraphTrait::PredecessorNodeIterator >::value > > > : std::true_type {}; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/indexable.hpp000066400000000000000000000072551473507761200253460ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for indexing objects * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Type for unique indexes /// /// This unsigned type should be capable of holding a pointer. using Index = std::uintptr_t; /// \brief Traits for indexable objects /// /// IndexableTraits is a structure of traits for indexable objects. These /// objects are used e.g. by the patricia tree for organizing the objects in the /// tree. /// /// An indexable object must provide: /// /// static Index index(const T&) /// Return a unique index /// /// The trait has to be specialized for each specific type. /// /// The traits can be used as: /// \code{.cpp} /// Index index = IndexableTraits< VariableRef >::index(my_variable_ref); /// \endcode template < typename T > struct IndexableTraits {}; /// \brief IndexableTraits implementation for Index template <> struct IndexableTraits< Index > { static Index index(Index idx) { return idx; } }; /// \brief Check if a type implements IndexableTraits template < typename T, typename IndexableTrait = IndexableTraits< T >, typename = void > struct IsIndexable : std::false_type {}; template < typename T, typename IndexableTrait > struct IsIndexable< T, IndexableTrait, // Check if IndexableTrait has: index(const T&) -> Index std::enable_if_t< std::is_same< Index, decltype(IndexableTrait::index( std::declval< T >())) >::value > > : std::true_type {}; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/machine_int/000077500000000000000000000000001473507761200251475ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/machine_int/variable.hpp000066400000000000000000000067761473507761200274650ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for machine integer variables * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Traits for machine integer variables /// /// This class should be specialized for machine integer variables. /// /// Elements to provide: /// /// static uint64_t bit_width(VariableRef) /// Return the bit width of the given variable /// /// static Signedness sign(VariableRef) /// Return the signedness of the given variable template < typename VariableRef > struct VariableTraits {}; /// \brief Check if a type implements VariableTraits template < typename VariableRef, typename VariableTrait = VariableTraits< VariableRef >, typename = void > struct IsVariable : std::false_type {}; template < typename VariableRef, typename VariableTrait > struct IsVariable< VariableRef, VariableTrait, void_t< std::enable_if_t< std::is_same< uint64_t, decltype(VariableTrait::bit_width( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< Signedness, decltype(VariableTrait::sign( std::declval< VariableRef >())) >::value > > > : std::true_type {}; } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/memory/000077500000000000000000000000001473507761200242015ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/memory/value/000077500000000000000000000000001473507761200253155ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/memory/value/cell_factory.hpp000066400000000000000000000110161473507761200304730ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for creating variables representing memory cells * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace memory { /// \brief Traits for creating cell variables /// /// Requirements: /// /// CellFactoryRef has a noexcept copy constructor /// CellFactoryRef has a noexcept move constructor /// CellFactoryRef has a noexcept copy assignment operator /// CellFactoryRef has a noexcept move assignment operator /// /// Elements to provide: /// /// static VariableRef cell(CellFactoryRef factory, /// MemoryLocationRef base, /// const MachineInt& offset, /// const MachineInt& size, /// Signedness sign) /// Get or create the cell with the given base address, offset and size /// If a new cell is created, it will have the given signedness template < typename VariableRef, typename MemoryLocationRef, typename CellFactoryRef > struct CellFactoryTraits {}; /// \brief Check if a type implements CellFactoryTraits template < typename VariableRef, typename MemoryLocationRef, typename CellFactoryRef, typename CellFactoryTrait = CellFactoryTraits< VariableRef, MemoryLocationRef, CellFactoryRef >, typename = void > struct IsCellFactory : std::false_type {}; template < typename VariableRef, typename MemoryLocationRef, typename CellFactoryRef, typename CellFactoryTrait > struct IsCellFactory< VariableRef, MemoryLocationRef, CellFactoryRef, CellFactoryTrait, std::enable_if_t< conjunction< std::is_nothrow_copy_constructible< CellFactoryRef >, std::is_nothrow_move_constructible< CellFactoryRef >, std::is_nothrow_copy_assignable< CellFactoryRef >, std::is_nothrow_move_assignable< CellFactoryRef >, std::is_same< VariableRef, decltype(CellFactoryTrait::cell(std::declval< CellFactoryRef >(), std::declval< MemoryLocationRef >(), std::declval< const MachineInt& >(), std::declval< const MachineInt& >(), std::declval< Signedness >())) > >:: value > > : std::true_type {}; } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/memory/value/cell_variable.hpp000066400000000000000000000106211473507761200306120ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for variables representing memory cells * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { namespace memory { /// \brief Traits for memory cell variables /// /// A cell is a triple `(b, o, s)` modelling all bytes at address `b`, starting /// at offset `o` up to `o + s - 1`. /// /// Elements to provide: /// /// static bool is_cell(VariableRef) /// Return true if the given variable is a memory cell variable /// /// static MemoryLocationRef base(VariableRef) /// Return the base memory location of the given cell /// /// static const MachineInt& offset(VariableRef) /// Return the offset of the given cell /// /// static const MachineInt& size(VariableRef) /// Return the size of the given cell template < typename VariableRef, typename MemoryLocationRef > struct CellVariableTraits {}; /// \brief Check if a type implements CellVariableTraits template < typename VariableRef, typename MemoryLocationRef, typename CellVariableTrait = CellVariableTraits< VariableRef, MemoryLocationRef >, typename = void > struct IsCellVariable : std::false_type {}; template < typename VariableRef, typename MemoryLocationRef, typename CellVariableTrait > struct IsCellVariable< VariableRef, MemoryLocationRef, CellVariableTrait, void_t< std::enable_if_t< std::is_same< bool, decltype(CellVariableTrait::is_cell( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< MemoryLocationRef, decltype(CellVariableTrait::base( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< const MachineInt&, decltype(CellVariableTrait::offset( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< const MachineInt&, decltype(CellVariableTrait::size( std::declval< VariableRef >())) >::value > > > : std::true_type {}; } // end namespace memory } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/memory_location.hpp000066400000000000000000000072571473507761200266150ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Requirements for MemoryLocationRef types * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Check if the given type meets the requirements for memory location /// types /// /// Requirements: /// /// MemoryLocationRef has a noexcept copy constructor /// MemoryLocationRef has a noexcept move constructor /// MemoryLocationRef has a noexcept copy assignment operator /// MemoryLocationRef has a noexcept move assignment operator /// /// bool operator==(MemoryLocationRef x, MemoryLocationRef y) /// Return true if x and y refers to the same memory location /// /// bool operator<(MemoryLocationref x, MemoryLocationref y) /// Return true if index(x) < index(y) /// /// MemoryLocationRef implements DumpableTraits /// /// MemoryLocationRef implements IndexableTraits /// /// The MemoryLocationRef type should be cheap to copy. template < typename MemoryLocationRef > struct IsMemoryLocation : conjunction< std::is_nothrow_copy_constructible< MemoryLocationRef >, std::is_nothrow_move_constructible< MemoryLocationRef >, std::is_nothrow_copy_assignable< MemoryLocationRef >, std::is_nothrow_move_assignable< MemoryLocationRef >, supports_equality< MemoryLocationRef, MemoryLocationRef >, supports_less_than< MemoryLocationRef, MemoryLocationRef >, IsDumpable< MemoryLocationRef >, IsIndexable< MemoryLocationRef > > {}; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/scalar/000077500000000000000000000000001473507761200241365ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/scalar/variable.hpp000066400000000000000000000105351473507761200264400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generic API for scalar variables * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include namespace ikos { namespace core { namespace scalar { /// \brief Traits for scalar variables /// /// Elements to provide: /// /// static bool is_int(VariableRef) /// Return true if the given variable is a machine integer variable /// /// static bool is_float(VariableRef) /// Return true if the given variable is a floating point variable /// /// static bool is_pointer(VariableRef) /// Return true if the given variable is a pointer variable /// /// static bool is_dynamic(VariableRef) /// Return true if the given variable is a dynamically typed variable /// /// static VariableRef offset_var(VariableRef) /// Return the machine integer offset variable of the given pointer variable template < typename VariableRef > struct VariableTraits {}; /// \brief Check if a type implements VariableTraits template < typename VariableRef, typename VariableTrait = VariableTraits< VariableRef >, typename = void > struct IsVariable : std::false_type {}; template < typename VariableRef, typename VariableTrait > struct IsVariable< VariableRef, VariableTrait, void_t< std::enable_if_t< std::is_same< bool, decltype(VariableTrait::is_int( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< bool, decltype(VariableTrait::is_float( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< bool, decltype(VariableTrait::is_pointer( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< bool, decltype(VariableTrait::is_dynamic( std::declval< VariableRef >())) >::value >, std::enable_if_t< std::is_same< VariableRef, decltype(VariableTrait::offset_var( std::declval< VariableRef >())) >::value > > > : std::true_type {}; } // end namespace scalar } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/semantic/variable.hpp000066400000000000000000000070151473507761200251720ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Requirements for VariableRef types * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Check if the given type meets the requirements for Variable types /// /// Requirements: /// /// VariableRef has a noexcept copy constructor /// VariableRef has a noexcept move constructor /// VariableRef has a noexcept copy assignment operator /// VariableRef has a noexcept move assignment operator /// /// bool operator==(VariableRef x, VariableRef y) /// Return true if x and y refers to the same variable /// /// bool operator<(VariableRef x, VariableRef y) /// Return true if index(x) < index(y) /// /// VariableRef implements DumpableTraits /// /// VariableRef implements IndexableTraits /// /// The VariableRef type should be cheap to copy. template < typename VariableRef > struct IsVariable : conjunction< std::is_nothrow_copy_constructible< VariableRef >, std::is_nothrow_move_constructible< VariableRef >, std::is_nothrow_copy_assignable< VariableRef >, std::is_nothrow_move_assignable< VariableRef >, supports_equality< VariableRef, VariableRef >, supports_less_than< VariableRef, VariableRef >, IsDumpable< VariableRef >, IsIndexable< VariableRef > > {}; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/support/000077500000000000000000000000001473507761200226025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/support/assert.hpp000066400000000000000000000070671473507761200246260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Assertion definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #undef ikos_assert #undef ikos_assert_msg #undef ikos_unreachable // clang-format off #ifdef NDEBUG # define ikos_assert(expr) static_cast< void >(0) # define ikos_assert_msg(expr, msg) static_cast< void >(0) # if __has_builtin(__builtin_unreachable) || IKOS_GNUC_PREREQ(4, 5, 0) # define ikos_unreachable(msg) __builtin_unreachable() # elif defined(_MSC_VER) # define ikos_unreachable(msg) __assume(false) # else # include # define ikos_unreachable(msg) abort() # endif #else # include /// \macro ikos_assert /// /// By default, expands to assert(expr) /// /// If the macro NDEBUG is defined, expands to ((void)0). # define ikos_assert(expr) assert(expr) /// \macro ikos_assert_msg /// /// By default, expands to assert((expr) && (msg)) /// /// If the macro NDEBUG is defined, expands to ((void)0). # define ikos_assert_msg(expr, msg) assert((expr) && (msg)) /// \macro ikos_unreachable /// /// Marks that the current location is not supposed to be reachable. /// /// If the macro NDEBUG is defined, expands to an optimizer hint /// that the current location is not supposed to be reachable. On compilers that /// don't support such hints, expands to abort() /// /// Otherwise, expands to assert(false && (msg)) /// /// Use this instead of assert(0). It conveys intent more clearly and allows /// compilers to omit some unnecessary code. # define ikos_unreachable(msg) assert(false && (msg)) #endif // clang-format on NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/support/cast.hpp000066400000000000000000000167071473507761200242600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Casting definitions (isa, cast, dyn_cast) * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { /// \brief Core implementation of isa< T > template < typename To, typename From, typename Enable = void > struct IsaImpl { static bool isa(const From& val) { return To::classof(&val); } }; /// \brief Always allow upcasts, and perform no dynamic check for them template < typename To, typename From > struct IsaImpl< To, From, typename std::enable_if_t< std::is_base_of< To, From >::value > > { static bool isa(const From&) { return true; } }; template < typename To, typename From > struct IsaImplWrap { static bool isa(const From& val) { return IsaImpl< To, From >::isa(val); } }; template < typename To, typename From > struct IsaImplWrap< To, const From > { static bool isa(const From& val) { return IsaImpl< To, From >::isa(val); } }; template < typename To, typename From > struct IsaImplWrap< To, From* > { static bool isa(const From* val) { ikos_assert_msg(val, "isa<> on a null pointer"); return IsaImpl< To, From >::isa(*val); } }; template < typename To, typename From > struct IsaImplWrap< To, From* const > { static bool isa(const From* val) { ikos_assert_msg(val, "isa<> on a null pointer"); return IsaImpl< To, From >::isa(*val); } }; template < typename To, typename From > struct IsaImplWrap< To, const From* > { static bool isa(const From* val) { ikos_assert_msg(val, "isa<> on a null pointer"); return IsaImpl< To, From >::isa(*val); } }; template < typename To, typename From > struct IsaImplWrap< To, const From* const > { static bool isa(const From* val) { ikos_assert_msg(val, "isa<> on a null pointer"); return IsaImpl< To, From >::isa(*val); } }; /// \brief Check if the parameter is an instance of the template type argument /// /// Used like this: /// /// \code{.cpp} /// if (isa< GlobalVariable >(v)) { ... } /// \endcode template < typename X, typename Y > inline bool isa(const Y& val) { return IsaImplWrap< X, Y >::isa(val); } // Calculate what type the 'cast' function should return, based on a requested // type of To and a source type of From. template < typename To, typename From > struct CastRet { using Type = To&; }; template < typename To, typename From > struct CastRet< To, const From > { using Type = const To&; }; template < typename To, typename From > struct CastRet< To, From* > { using Type = To*; }; template < typename To, typename From > struct CastRet< To, const From* > { using Type = const To*; }; template < typename To, typename From > struct CastRet< To, const From* const > { using Type = const To*; }; /// \brief Return the argument parameter cast to the specified type /// /// This casting operator asserts that the type is correct. It does not allow /// a null argument. /// /// Used like this: /// /// \code{.cpp} /// Instruction* inst = cast< Instruction >(val) /// \endcode template < typename X, typename Y > inline typename CastRet< X, Y >::Type cast(Y& val) { ikos_assert_msg(isa< X >(val), "cast<>() argument of incompatible type"); return static_cast< typename CastRet< X, Y >::Type >(val); } /// \brief Return the argument parameter cast to the specified type /// /// This casting operator asserts that the type is correct. It does not allow /// a null argument. /// /// Used like this: /// /// \code{.cpp} /// Instruction* inst = cast< Instruction >(val) /// \endcode template < typename X, typename Y > inline typename CastRet< X, Y* >::Type cast(Y* val) { ikos_assert_msg(isa< X >(val), "cast<>() argument of incompatible type"); return static_cast< typename CastRet< X, Y* >::Type >(val); } /// \brief Return the argument parameter cast to the specified type /// /// This is equivalent to cast< X >, except that a null value is allowed. template < typename X, typename Y > inline typename CastRet< X, Y >::Type cast_or_null(Y& val) { if (val == nullptr) { return nullptr; } ikos_assert_msg(isa< X >(val), "cast_or_null<>() argument of incompatible type"); return static_cast< typename CastRet< X, Y >::Type >(val); } /// \brief Return the argument parameter cast to the specified type /// /// This is equivalent to cast< X >, except that a null value is allowed. template < typename X, typename Y > inline typename CastRet< X, Y* >::Type cast_or_null(Y* val) { if (val == nullptr) { return nullptr; } ikos_assert_msg(isa< X >(val), "cast_or_null<>() argument of incompatible type"); return static_cast< typename CastRet< X, Y* >::Type >(val); } /// \brief Return the argument parameter cast to the specified type /// /// This casting operator returns null if the argument is of the wrong type, so /// it can used to test for a type as well as cast if successful. /// /// Used like this: /// /// \code{.cpp} /// if (Instruction* inst = dyn_cast< Instruction >(val)) { ... } /// \endcode template < typename X, typename Y > inline typename CastRet< X, Y* >::Type dyn_cast(Y* val) { return isa< X >(val) ? cast< X >(val) : nullptr; } /// \brief Return the argument parameter cast to the specified type /// /// This is equivalent to dyn_cast< X >, except that a null value is allowed. template < typename X, typename Y > inline typename CastRet< X, Y* >::Type dyn_cast_or_null(Y* val) { return (val != nullptr && isa< X >(val)) ? cast< X >(val) : nullptr; } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/support/compiler.hpp000066400000000000000000000104271473507761200251310ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Define several macros, based on the current compiler * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once // clang-format off /// \macro __has_builtin /// \brief Evaluates to 1 if the builtin is supported, otherwise 0. #ifndef __has_builtin # define __has_builtin(x) 0 #endif /// \macro __has_attribute /// \brief Evaluates to 1 if the attribute is supported, otherwise 0. #ifndef __has_attribute # define __has_attribute(x) 0 #endif /// \macro IKOS_GNUC_PREREQ /// \brief Evaluates to 1 if the compiler is GCC >= maj.min.patch, otherwise 0. #ifndef IKOS_GNUC_PREREQ # if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) # define IKOS_GNUC_PREREQ(maj, min, patch) \ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ ((maj) << 20) + ((min) << 10) + (patch)) # elif defined(__GNUC__) && defined(__GNUC_MINOR__) # define IKOS_GNUC_PREREQ(maj, min, patch) \ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) # else # define IKOS_GNUC_PREREQ(maj, min, patch) 0 # endif #endif /// \macro ikos_likely /// \brief Tell the compiler that the given condition is likely to yield true /// \macro ikos_unlikely /// \brief Tell the compiler that the given condition is likely to yield false #if __has_builtin(__builtin_expect) || IKOS_GNUC_PREREQ(4, 0, 0) # define ikos_likely(EXPR) __builtin_expect(static_cast< bool >(EXPR), true) # define ikos_unlikely(EXPR) __builtin_expect(static_cast< bool >(EXPR), false) #else # define ikos_likely(EXPR) (EXPR) # define ikos_unlikely(EXPR) (EXPR) #endif /// \macro ikos_attribute_noreturn /// \brief Tell the compiler that the function does not return. #ifdef __GNUC__ # define ikos_attribute_noreturn __attribute__((noreturn)) #elif defined(_MSC_VER) # define ikos_attribute_noreturn __declspec(noreturn) #else # define ikos_attribute_noreturn #endif /// \macro ikos_attribute_unused /// \brief Remove unused function warnings for the given function #if __has_attribute(unused) || IKOS_GNUC_PREREQ(3, 1, 0) # define ikos_attribute_unused __attribute__((__unused__)) #else # define ikos_attribute_unused #endif /// \macro ikos_ignore /// \brief Remove unused variable warnings for the given variable #define ikos_ignore(VAR) static_cast< void >(VAR) // clang-format on NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/support/mpl.hpp000066400000000000000000000144111473507761200241040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Template metaprogramming utilities * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace core { /// Helpers for void_t namespace detail { template < typename... Ts > struct make_void { using type = void; }; } // end namespace detail /// \brief Utility metafunction that maps a sequence of any types to void /// /// This is a backport of C++17 std::void_t, see /// http://en.cppreference.com/w/cpp/types/void_t template < typename... Ts > using void_t = typename detail::make_void< Ts... >::type; /// \brief Remove const, volatile and ref qualifiers /// /// This is a backport of C++20 std::remove_cvref, see /// http://en.cppreference.com/w/cpp/types/remove_cvref template < typename T > struct remove_cvref { using type = std::remove_cv_t< std::remove_reference_t< T > >; }; /// \brief Helper types template < typename T > using remove_cvref_t = typename remove_cvref< T >::type; /// \brief Form the logical conjunction of the parameters /// /// Performs a logical AND on the given sequence of type traits /// /// This is a backport of C++17 std::conjunction, see /// http://en.cppreference.com/w/cpp/types/conjunction template < typename... > struct conjunction : std::true_type {}; template < typename B1 > struct conjunction< B1 > : B1 {}; template < typename B1, typename... Bn > struct conjunction< B1, Bn... > : std::conditional_t< bool(B1::value), conjunction< Bn... >, B1 > {}; /// Helpers for is_detected namespace detail { struct nonesuch { nonesuch() = delete; ~nonesuch() = delete; nonesuch(const nonesuch&) = delete; nonesuch(nonesuch&&) = delete; void operator=(const nonesuch&) = delete; void operator=(nonesuch&&) = delete; }; template < typename Default, typename AlwaysVoid, template < typename... > class Op, typename... Args > struct detector { using value_t = std::false_type; using type = Default; }; template < typename Default, template < typename... > class Op, typename... Args > struct detector< Default, void_t< Op< Args... > >, Op, Args... > { using value_t = std::true_type; using type = Op< Args... >; }; } // end namespace detail /// \brief Detection idiom /// /// `detected_or` is an alias for an unspecified class type with two public /// member typedefs `value_t` and `type`, which are defined as follows: /// * If the template-id `Op` is valid, then `value_t` is an alias /// for `std::true_type`, and type is an alias for `Op`; /// * Otherwise, `value_t` is an alias for `std::false_type` and type is an /// alias for `Default`. /// /// This is a backport from the library fundamentals v2, see /// http://en.cppreference.com/w/cpp/experimental/is_detected template < typename Default, template < typename... > class Op, typename... Args > using detected_or = detail::detector< Default, void, Op, Args... >; /// \brief Detection idiom /// /// `is_detected` is equivalent to `typename /// detected_or::value_t`. It is an /// alias for `std::true_type` if the template-id `Op` is valid; /// otherwise it is an alias for `std::false_type`. /// /// This is a backport from the library fundamentals v2, see /// http://en.cppreference.com/w/cpp/experimental/is_detected template < template < typename... > class Op, typename... Args > using is_detected = typename detail::detector< detail::nonesuch, void, Op, Args... >::value_t; /// Helpers for supports_equality namespace detail { template < typename T, typename U > using equality_t = decltype(std::declval< T >() == std::declval< U >()); } // end namespace detail /// \brief Checks if the given types can be compared with == template < typename T, typename U > using supports_equality = is_detected< detail::equality_t, T, U >; /// Helpers for supports_less_than namespace detail { template < typename T, typename U > using less_than_t = decltype(std::declval< T >() < std::declval< U >()); } // end namespace detail /// \brief Checks if the given types can be compared with < template < typename T, typename U > using supports_less_than = is_detected< detail::less_than_t, T, U >; } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/000077500000000000000000000000001473507761200222025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/lifetime.hpp000066400000000000000000000136161473507761200245200ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Lifetime abstract value * * Author: Thomas Bailleux * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Lifetime abstract value /// /// This is either top, bottom, allocated or deallocated. class Lifetime final : public core::AbstractDomain< Lifetime > { private: enum Kind : unsigned { BottomKind = 0, AllocatedKind = 1, DeallocatedKind = 2, TopKind = 3 }; private: Kind _kind = TopKind; private: /// \brief Private constructor explicit Lifetime(Kind kind) : _kind(kind) {} public: /// \brief Return the top lifetime value static Lifetime top() { return Lifetime(TopKind); } /// \brief Return the bottom lifetime value static Lifetime bottom() { return Lifetime(BottomKind); } /// \brief Return the deallocated lifetime value static Lifetime deallocated() { return Lifetime(DeallocatedKind); } /// \brief Return the allocated lifetime value static Lifetime allocated() { return Lifetime(AllocatedKind); } /// \brief Copy constructor Lifetime(const Lifetime&) noexcept = default; /// \brief Move constructor Lifetime(Lifetime&&) noexcept = default; /// \brief Copy assignment operator Lifetime& operator=(const Lifetime&) noexcept = default; /// \brief Move assignment operator Lifetime& operator=(Lifetime&&) noexcept = default; /// \brief Destructor ~Lifetime() override = default; void normalize() override {} bool is_bottom() const override { return this->_kind == BottomKind; } bool is_top() const override { return this->_kind == TopKind; } /// \brief Return true if this is the deallocated lifetime value bool is_deallocated() const { return this->_kind == DeallocatedKind; } /// \brief Return true if this is the allocated lifetime value bool is_allocated() const { return this->_kind == AllocatedKind; } void set_to_bottom() override { this->_kind = BottomKind; } void set_to_top() override { this->_kind = TopKind; } /// \brief Set the lifetime value to deallocated void set_to_deallocated() { this->_kind = DeallocatedKind; } /// \brief Set the lifetime value to allocated void set_to_allocated() { this->_kind = AllocatedKind; } bool leq(const Lifetime& other) const override { switch (this->_kind) { case BottomKind: return true; case TopKind: return other._kind == TopKind; case AllocatedKind: return other._kind == AllocatedKind || other._kind == TopKind; case DeallocatedKind: return other._kind == DeallocatedKind || other._kind == TopKind; default: ikos_unreachable("unreachable"); } } bool equals(const Lifetime& other) const override { return this->_kind == other._kind; } void join_with(const Lifetime& other) override { this->_kind = static_cast< Kind >(static_cast< unsigned >(this->_kind) | static_cast< unsigned >(other._kind)); } void widen_with(const Lifetime& other) override { this->join_with(other); } void meet_with(const Lifetime& other) override { this->_kind = static_cast< Kind >(static_cast< unsigned >(this->_kind) & static_cast< unsigned >(other._kind)); } void narrow_with(const Lifetime& other) override { this->meet_with(other); } void dump(std::ostream& o) const override { switch (this->_kind) { case BottomKind: { o << "⊥"; break; } case DeallocatedKind: { o << "DA"; break; } case AllocatedKind: { o << "A"; break; } case TopKind: { o << "T"; break; } default: { ikos_unreachable("unreachable"); } } } static std::string name() { return "lifetime"; } }; // end class Lifetime } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/machine_int/000077500000000000000000000000001473507761200244605ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/machine_int/congruence.hpp000066400000000000000000000641211473507761200273250ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Machine integer congruence abstract value * * Bitwise extensions based on Stefan Bygde's paper: Static WCET analysis based * on abstract interpretation and counting of elements, Vasteras : School of * Innovation, Design and Engineering, Malardalen University (2010) * * Author: Maxime Arthaud * * Contributors: * * Jorge A. Navas * * Alexandre C. D. Wimmers * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Machine integer congruence abstract value /// /// This is either bottom, or aZ + b. /// /// Note that top is represented as 1Z + 0. class Congruence final : public core::AbstractDomain< Congruence > { private: /// Use the congruence on unlimited precision integers (ZNumber) internally /// /// Writing a congruence class using MachineInt appears to be very hard, /// because of overflows and the limited bit-width for the modulus. private: /// \brief Congruence on unlimited precision integers using ZCongruence = numeric::ZCongruence; private: ZCongruence _c; uint64_t _bit_width; Signedness _sign; private: /// \brief Return 2**n static ZNumber power_of_2(uint64_t n) { return ZNumber(1) << n; } /// \brief Return 2**n static ZNumber power_of_2(const ZNumber& n) { return ZNumber(1) << n; } /// \brief r(c, a) is the smallest element of c greater or equal than a static ZNumber r(const ZCongruence& c, const ZNumber& a) { ikos_assert(!c.is_bottom() && c.modulus() != 0); return a + mod(c.residue() - a, c.modulus()); } /// \brief l(c, a) is the greatest element of c smaller or equal than a static ZNumber l(const ZCongruence& c, const ZNumber& a) { ikos_assert(!c.is_bottom() && c.modulus() != 0); return a - mod(a - c.residue(), c.modulus()); } /// \brief Reduce the congruence void reduce() { if (this->_c.is_bottom()) { return; } if (this->_c.is_top()) { return; } // lb, ub = [Int::min, Int::max] ZNumber lb; ZNumber ub; if (this->is_signed()) { lb = -power_of_2(this->_bit_width - 1); ub = power_of_2(this->_bit_width - 1) - 1; } else { lb = 0; ub = power_of_2(this->_bit_width) - 1; } if (this->_c.modulus() == 0) { // 0Z + b if (!(lb <= this->_c.residue() && this->_c.residue() <= ub)) { this->set_to_bottom(); } return; } // aZ + b with a != 0 ikos_assert(this->_c.modulus() > 0); ZNumber x = r(this->_c, lb); ZNumber y = l(this->_c, ub); if (x > y) { this->_c.set_to_bottom(); } else if (x == y) { this->_c = ZCongruence(x); } } /// \brief Wrap a congruence in Z to the given bit-width and signedness static ZCongruence wrap(const ZCongruence& c, uint64_t bit_width, Signedness sign) { if (c.is_bottom()) { return ZCongruence::bottom(); } else if (sign == Signed) { ZNumber n = power_of_2(bit_width); ZNumber m = power_of_2(bit_width - 1); return mod(c + m, ZCongruence(n)) - m; } else { ZNumber n = power_of_2(bit_width); return mod(c, ZCongruence(n)); } } /// \brief Weakening operator /// /// \returns weakened version of *this, does not modify *this. Returned /// modulus is guaranteed to be a power of 2. static ZCongruence weaken(ZCongruence c, uint64_t bit_width) { if (c.is_bottom()) { return c; } else if (c.modulus() == 0) { return c; } else { return ZCongruence(gcd(c.modulus(), power_of_2(bit_width)), c.residue()); } } private: struct TopTag {}; struct BottomTag {}; struct NormalizedTag {}; /// \brief Create the top congruence for the given bit-width and signedness Congruence(TopTag, uint64_t bit_width, Signedness sign) : _c(ZCongruence::top()), _bit_width(bit_width), _sign(sign) {} /// \brief Create the bottom congruence for the given bit-width and signedness Congruence(BottomTag, uint64_t bit_width, Signedness sign) : _c(ZCongruence::bottom()), _bit_width(bit_width), _sign(sign) {} /// \brief Create the machine integer congruence from a congruence in Z Congruence(ZCongruence c, uint64_t bit_width, Signedness sign, NormalizedTag) : _c(std::move(c)), _bit_width(bit_width), _sign(sign) {} public: /// \brief Create the top congruence for the given bit-width and signedness static Congruence top(uint64_t bit_width, Signedness sign) { return Congruence(TopTag{}, bit_width, sign); } /// \brief Create the bottom congruence for the given bit-width and signedness static Congruence bottom(uint64_t bit_width, Signedness sign) { return Congruence(BottomTag{}, bit_width, sign); } /// \brief Create the congruence 0Z + n explicit Congruence(const MachineInt& n) : _c(n.to_z_number()), _bit_width(n.bit_width()), _sign(n.sign()) {} /// \brief Create the congruence aZ + b Congruence(const MachineInt& a, const MachineInt& b) : _c(a.to_z_number(), b.to_z_number()), _bit_width(b.bit_width()), _sign(b.sign()) { assert_compatible(a, b); this->reduce(); } /// \brief Create the congruence aZ + b Congruence(ZNumber a, ZNumber b, uint64_t bit_width, Signedness sign) : _c(std::move(a), std::move(b)), _bit_width(bit_width), _sign(sign) { this->reduce(); } /// \brief Create the machine integer congruence from a congruence in Z Congruence(ZCongruence c, uint64_t bit_width, Signedness sign) : _c(std::move(c)), _bit_width(bit_width), _sign(sign) { this->reduce(); } /// \brief Copy constructor Congruence(const Congruence&) = default; /// \brief Move constructor Congruence(Congruence&&) = default; /// \brief Copy assignment operator Congruence& operator=(const Congruence&) = default; /// \brief Move assignment operator Congruence& operator=(Congruence&&) noexcept = default; /// \brief Destructor ~Congruence() override = default; /// \brief Return the bit width of the congruence uint64_t bit_width() const { return this->_bit_width; } /// \brief Return the signedness (Signed or Unsigned) of the congruence Signedness sign() const { return this->_sign; } bool is_signed() const { return this->_sign == Signed; } bool is_unsigned() const { return this->_sign == Unsigned; } /// \brief Return the modulus const ZNumber& modulus() const { ikos_assert(!this->is_bottom()); return this->_c.modulus(); } /// \brief Return the residue const ZNumber& residue() const { ikos_assert(!this->is_bottom()); return this->_c.residue(); } void normalize() override { // Already performed by the reduction } bool is_bottom() const override { return this->_c.is_bottom(); } bool is_top() const override { return this->_c.is_top(); } /// \brief Return true if the congruence is 0Z + 0 bool is_zero() const { return this->_c.is_zero(); } void set_to_bottom() override { this->_c.set_to_bottom(); } void set_to_top() override { this->_c.set_to_top(); } bool leq(const Congruence& other) const override { assert_compatible(*this, other); return this->_c.leq(other._c); } bool equals(const Congruence& other) const override { assert_compatible(*this, other); return this->_c.equals(other._c); } Congruence join(const Congruence& other) const override { assert_compatible(*this, other); return Congruence(this->_c.join(other._c), this->_bit_width, this->_sign); } void join_with(const Congruence& other) override { assert_compatible(*this, other); this->_c.join_with(other._c); this->reduce(); } Congruence widening(const Congruence& other) const override { // equivalent to join, domain is flat return this->join(other); } void widen_with(const Congruence& other) override { // equivalent to join, domain is flat this->join_with(other); } Congruence widening_threshold(const Congruence& other, const MachineInt& /*threshold*/) const { // equivalent to join, domain is flat return this->join(other); } void widen_threshold_with(const Congruence& other, const MachineInt& /*threshold*/) { // equivalent to join, domain is flat this->join_with(other); } Congruence meet(const Congruence& other) const override { assert_compatible(*this, other); return Congruence(this->_c.meet(other._c), this->_bit_width, this->_sign); } void meet_with(const Congruence& other) override { assert_compatible(*this, other); this->_c.meet_with(other._c); this->reduce(); } Congruence narrowing(const Congruence& other) const override { // equivalent to meet, domain is flat return this->meet(other); } void narrow_with(const Congruence& other) override { // equivalent to meet, domain is flat this->meet_with(other); } Congruence narrowing_threshold(const Congruence& other, const MachineInt& /*threshold*/) const { // equivalent to meet, domain is flat return this->meet(other); } void narrow_threshold_with(const Congruence& other, const MachineInt& /*threshold*/) { // equivalent to meet, domain is flat this->meet_with(other); } /// \name Unary Operators /// @{ /// \brief Truncate the machine integer congruence to the given bit width Congruence trunc(uint64_t bit_width) const { ikos_assert(this->bit_width() > bit_width); return Congruence(wrap(this->_c, bit_width, this->_sign), bit_width, this->_sign); } /// \brief Extend the machine integer congruence to the given bit width Congruence ext(uint64_t bit_width) const { ikos_assert(this->bit_width() < bit_width); return Congruence(this->_c, bit_width, this->_sign, NormalizedTag{}); } /// \brief Change the machine integer congruence sign (bitcast) Congruence sign_cast(Signedness sign) const { ikos_assert(this->sign() != sign); return Congruence(wrap(this->_c, this->_bit_width, sign), this->_bit_width, sign); } /// \brief Cast the machine integer congruence to the given bit width and sign /// /// This is equivalent to trunc()/ext() + sign_cast() (in this specific order) Congruence cast(uint64_t bit_width, Signedness sign) const { return Congruence(wrap(this->_c, bit_width, sign), bit_width, sign); } /// \brief Bitwise not operator Congruence not_() const { if (this->is_bottom()) { return *this; } else if (this->is_signed()) { return Congruence(this->_c.modulus(), -this->_c.residue() - 1, this->_bit_width, this->_sign); } else { return Congruence(this->_c.modulus(), power_of_2(this->_bit_width) - this->_c.residue() - 1, this->_bit_width, this->_sign); } } /// @} /// \name Conversion Functions /// @{ /// \brief Return the machine integer congruence as a ZCongruence const ZCongruence& to_z_congruence() const { return this->_c; } struct WrapTag {}; struct TruncTag {}; /// \brief Convert a ZCongruence to a machine integer congruence /// /// Note: it truncates integers /// /// For instance: /// from_z_congruence(ZCongruence(256), 8, Unsigned, TruncTag{}) = Bottom static Congruence from_z_congruence(ZCongruence c, uint64_t bit_width, Signedness sign, TruncTag) { return Congruence(std::move(c), bit_width, sign); } /// \brief Convert a ZCongruence to a machine integer congruence /// /// Note: it wraps integers /// /// For instance: /// from_z_congruence(ZCongruence(256), 8, Unsigned, WrapTag{}) = 0Z + 0 static Congruence from_z_congruence(const ZCongruence& c, uint64_t bit_width, Signedness sign, WrapTag) { return Congruence(wrap(c, bit_width, sign), bit_width, sign); } /// @} /// \brief If the congruence is 0Z + n, return n, otherwise return boost::none boost::optional< MachineInt > singleton() const { if (!this->is_bottom() && this->_c.modulus() == 0) { return MachineInt(this->_c.residue(), this->_bit_width, this->_sign); } else { return boost::none; } } /// \brief Return true if the congruence contains n bool contains(const MachineInt& n) const { return this->_c.contains(n.to_z_number()); } void dump(std::ostream& o) const override { this->_c.dump(o); } static std::string name() { return "congruence"; } // Friends friend Congruence add(const Congruence& lhs, const Congruence& rhs); friend Congruence add_no_wrap(const Congruence& lhs, const Congruence& rhs); friend Congruence sub(const Congruence& lhs, const Congruence& rhs); friend Congruence sub_no_wrap(const Congruence& lhs, const Congruence& rhs); friend Congruence mul(const Congruence& lhs, const Congruence& rhs); friend Congruence mul_no_wrap(const Congruence& lhs, const Congruence& rhs); friend Congruence div(const Congruence& lhs, const Congruence& rhs); friend Congruence rem(const Congruence& lhs, const Congruence& rhs); friend Congruence shl(const Congruence& lhs, const Congruence& rhs); friend Congruence shl_no_wrap(const Congruence& lhs, const Congruence& rhs); friend Congruence lshr(const Congruence& lhs, const Congruence& rhs); friend Congruence ashr(const Congruence& lhs, const Congruence& rhs); friend Congruence and_(const Congruence& lhs, const Congruence& rhs); friend class IntervalCongruence; }; // end class Congruence /// \name Binary Operators /// @{ /// \brief Addition with wrapping inline Congruence add(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Congruence(Congruence::wrap(lhs._c + rhs._c, lhs._bit_width, lhs._sign), lhs._bit_width, lhs._sign); } } /// \brief Addition without wrapping inline Congruence add_no_wrap(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Congruence(lhs._c + rhs._c, lhs._bit_width, lhs._sign); } } /// \brief Substraction with wrapping inline Congruence sub(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Congruence(Congruence::wrap(lhs._c - rhs._c, lhs._bit_width, lhs._sign), lhs._bit_width, lhs._sign); } } /// \brief Substraction without wrapping inline Congruence sub_no_wrap(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Congruence(lhs._c - rhs._c, lhs._bit_width, lhs._sign); } } /// \brief Multiplication with wrapping inline Congruence mul(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Congruence(Congruence::wrap(lhs._c * rhs._c, lhs._bit_width, lhs._sign), lhs._bit_width, lhs._sign); } } /// \brief Multiplication without wrapping inline Congruence mul_no_wrap(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Congruence(lhs._c * rhs._c, lhs._bit_width, lhs._sign); } } /// \brief Division inline Congruence div(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // overflow is undefined behavior return Congruence(lhs._c / rhs._c, lhs._bit_width, lhs._sign); } } /// \brief Exact division inline Congruence div_exact(const Congruence& lhs, const Congruence& rhs) { return div(lhs, rhs); } /// \brief Remainder inline Congruence rem(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Congruence(lhs._c % rhs._c, lhs._bit_width, lhs._sign); } } /// \brief Left shift with wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline Congruence shl(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { if (rhs._c.modulus() == 0) { // aZ + b << 0Z + b' const ZNumber& b = rhs._c.residue(); if (!(0 <= b && b < lhs._bit_width)) { // Invalid operand return Congruence::bottom(lhs._bit_width, lhs._sign); } // aZ + b << 0Z + b' = (a*2^b')Z + b*2^b' ZNumber x = Congruence::power_of_2(b); numeric::ZCongruence c(lhs._c.modulus() * x, lhs._c.residue() * x); return Congruence(Congruence::wrap(c, lhs._bit_width, lhs._sign), lhs._bit_width, lhs._sign); } // aZ + b << a'Z + b' = (gcd(a, b * (2^a' - 1)))*(2^b')Z + b*(2^b') ZNumber x = Congruence::power_of_2(rhs._c.residue()); ZNumber y = Congruence::power_of_2(rhs._c.modulus()); ZNumber a = gcd(lhs._c.modulus(), lhs._c.residue() * (y - 1)) * x; ZNumber b = lhs._c.residue() * x; numeric::ZCongruence c(a, b); return Congruence(Congruence::wrap(c, lhs._bit_width, lhs._sign), lhs._bit_width, lhs._sign); } } /// \brief Left shift without wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline Congruence shl_no_wrap(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { if (rhs._c.modulus() == 0) { // aZ + b << 0Z + b' const ZNumber& b = rhs._c.residue(); if (!(0 <= b && b < lhs._bit_width)) { // Invalid operand return Congruence::bottom(lhs._bit_width, lhs._sign); } // aZ + b << 0Z + b' = (a*2^b')Z + b*2^b' ZNumber x = Congruence::power_of_2(b); numeric::ZCongruence c(lhs._c.modulus() * x, lhs._c.residue() * x); return Congruence(c, lhs._bit_width, lhs._sign); } // aZ + b << a'Z + b' = (gcd(a, b * (2^a' - 1)))*(2^b')Z + b*(2^b') ZNumber x = Congruence::power_of_2(rhs._c.residue()); ZNumber y = Congruence::power_of_2(rhs._c.modulus()); ZNumber a = gcd(lhs._c.modulus(), lhs._c.residue() * (y - 1)) * x; ZNumber b = lhs._c.residue() * x; numeric::ZCongruence c(a, b); return Congruence(c, lhs._bit_width, lhs._sign); } } /// \brief Logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Congruence lshr(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { if (rhs._c.modulus() == 0) { // aZ + b >> 0Z + b' const ZNumber& b = rhs._c.residue(); if (!(0 <= b && b < lhs._bit_width)) { // Invalid operand return Congruence::bottom(lhs._bit_width, lhs._sign); } } if (lhs._c.is_zero() || rhs._c.is_zero()) { // 0 >> aZ + b // aZ + b >> 0 return lhs; } if (lhs._c.modulus() == 0 && rhs._c.modulus() == 0) { // 0Z + b >> 0Z + b' return Congruence( lshr(MachineInt(lhs._c.residue(), lhs._bit_width, lhs._sign), MachineInt(rhs._c.residue(), lhs._bit_width, lhs._sign))); } return Congruence::top(lhs._bit_width, lhs._sign); } } /// \brief Exact logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Congruence lshr_exact(const Congruence& lhs, const Congruence& rhs) { return lshr(lhs, rhs); } /// \brief Arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Congruence ashr(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { if (rhs._c.modulus() == 0) { // aZ + b >> 0Z + b' const ZNumber& b = rhs._c.residue(); if (!(0 <= b && b < lhs._bit_width)) { // Invalid operand return Congruence::bottom(lhs._bit_width, lhs._sign); } } if (lhs._c.is_zero() || rhs._c.is_zero()) { // 0 >> aZ + b // aZ + b >> 0 return lhs; } if (lhs._c.modulus() == 0 && rhs._c.modulus() == 0) { // 0Z + b >> 0Z + b' return Congruence( ashr(MachineInt(lhs._c.residue(), lhs._bit_width, lhs._sign), MachineInt(rhs._c.residue(), lhs._bit_width, lhs._sign))); } return Congruence::top(lhs._bit_width, lhs._sign); } } /// \brief Exact arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Congruence ashr_exact(const Congruence& lhs, const Congruence& rhs) { return ashr(lhs, rhs); } /// \brief Bitwise AND inline Congruence and_(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // First, both numbers are approximated to power of 2 numeric::ZCongruence x = Congruence::weaken(lhs._c, lhs._bit_width); numeric::ZCongruence y = Congruence::weaken(rhs._c, lhs._bit_width); if (x.modulus() == 0 && y.modulus() == 0) { // 0Z + b & 0Z + b' return Congruence( and_(MachineInt(x.residue(), lhs._bit_width, lhs._sign), MachineInt(y.residue(), lhs._bit_width, lhs._sign))); } else if (x.modulus() == 0) { // 0Z + b & gcd(2^n,a')Z + b' ZNumber b = mod(x.residue(), Congruence::power_of_2(lhs._bit_width)); if (b < y.modulus()) { return Congruence( and_(MachineInt(x.residue(), lhs._bit_width, lhs._sign), MachineInt(y.residue(), lhs._bit_width, lhs._sign))); } else { return Congruence(y.modulus(), b & y.residue(), lhs._bit_width, lhs._sign); } } else if (y.modulus() == 0) { // Symmetric return and_(rhs, lhs); } else { return Congruence(min(x.modulus(), y.modulus()), x.residue() & y.residue(), lhs._bit_width, lhs._sign); } } } /// \brief Bitwise OR inline Congruence or_(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return and_(lhs.not_(), rhs.not_()).not_(); } } /// \brief Bitwise XOR inline Congruence xor_(const Congruence& lhs, const Congruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return or_(and_(lhs, rhs.not_()), and_(lhs.not_(), rhs)); } } /// @} /// \name Input / Output /// @{ /// \brief Write a congruence on a stream inline std::ostream& operator<<(std::ostream& o, const Congruence& congruence) { congruence.dump(o); return o; } /// @} } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/machine_int/constant.hpp000066400000000000000000000574441473507761200270400ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Machine integer constant class * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Machine integer constant abstract value class Constant final : public core::AbstractDomain< Constant > { private: enum Kind { BottomKind, TopKind, IntegerKind }; private: Kind _kind; MachineInt _n; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top constant for the given bit-width and signedness Constant(TopTag, uint64_t bit_width, Signedness sign) : _kind(TopKind), _n(0, bit_width, sign) {} /// \brief Create the bottom constant for the given bit-width and signedness Constant(BottomTag, uint64_t bit_width, Signedness sign) : _kind(BottomKind), _n(0, bit_width, sign) {} public: /// \brief Create the top constant for the given bit-width and signedness static Constant top(uint64_t bit_width, Signedness sign) { return Constant(TopTag{}, bit_width, sign); } /// \brief Create the bottom constant for the given bit-width and signedness static Constant bottom(uint64_t bit_width, Signedness sign) { return Constant(BottomTag{}, bit_width, sign); } /// \brief Create the constant n explicit Constant(MachineInt n) : _kind(IntegerKind), _n(std::move(n)) {} /// \brief Copy constructor Constant(const Constant&) = default; /// \brief Move constructor Constant(Constant&&) noexcept = default; /// \brief Copy assignment operator Constant& operator=(const Constant&) = default; /// \brief Move assignment operator Constant& operator=(Constant&&) noexcept = default; /// \brief Destructor ~Constant() override = default; /// \brief Return the bit width of the constant uint64_t bit_width() const { return this->_n.bit_width(); } /// \brief Return the signedness (Signed or Unsigned) of the constant Signedness sign() const { return this->_n.sign(); } void normalize() override {} bool is_bottom() const override { return this->_kind == BottomKind; } bool is_top() const override { return this->_kind == TopKind; } /// \brief Return true if the constant is an integer bool is_integer() const { return this->_kind == IntegerKind; } void set_to_bottom() override { this->_kind = BottomKind; } void set_to_top() override { this->_kind = TopKind; } bool leq(const Constant& other) const override { assert_compatible(*this, other); switch (this->_kind) { case BottomKind: return true; case TopKind: return other._kind == TopKind; case IntegerKind: return other._kind == TopKind || (other._kind == IntegerKind && this->_n == other._n); default: ikos_unreachable("unreachable"); } } bool equals(const Constant& other) const override { assert_compatible(*this, other); if (this->_kind == IntegerKind) { return other._kind == IntegerKind && this->_n == other._n; } else { return this->_kind == other._kind; } } Constant join(const Constant& other) const override { assert_compatible(*this, other); if (this->is_bottom() || other.is_top()) { return other; } else if (this->is_top() || other.is_bottom()) { return *this; } else if (this->_n == other._n) { return *this; } else { return top(this->bit_width(), this->sign()); } } void join_with(const Constant& other) override { this->operator=(this->join(other)); } Constant widening(const Constant& other) const override { // equivalent to join, domain is flat return this->join(other); } void widen_with(const Constant& other) override { // equivalent to join, domain is flat this->join_with(other); } Constant widening_threshold(const Constant& other, const MachineInt& /*threshold*/) const { // equivalent to join, domain is flat return this->join(other); } void widen_threshold_with(const Constant& other, const MachineInt& /*threshold*/) { // equivalent to join, domain is flat this->join_with(other); } Constant meet(const Constant& other) const override { assert_compatible(*this, other); if (this->is_bottom() || other.is_top()) { return *this; } else if (this->is_top() || other.is_bottom()) { return other; } else if (this->_n == other._n) { return *this; } else { return bottom(this->bit_width(), this->sign()); } } void meet_with(const Constant& other) override { this->operator=(this->meet(other)); } Constant narrowing(const Constant& other) const override { // equivalent to meet, domain is flat return this->meet(other); } void narrow_with(const Constant& other) override { // equivalent to meet, domain is flat this->meet_with(other); } Constant narrowing_threshold(const Constant& other, const MachineInt& /*threshold*/) const { // equivalent to meet, domain is flat return this->meet(other); } void narrow_threshold_with(const Constant& other, const MachineInt& /*threshold*/) { // equivalent to meet, domain is flat this->meet_with(other); } /// \name Unary Operators /// @{ /// \brief Truncate the constant to the given bit width Constant trunc(uint64_t bit_width) { ikos_assert(this->bit_width() > bit_width); if (this->is_bottom()) { return bottom(bit_width, this->sign()); } else if (this->is_top()) { return top(bit_width, this->sign()); } else { return Constant(this->_n.trunc(bit_width)); } } /// \brief Extend the constant to the given bit width Constant ext(uint64_t bit_width) { ikos_assert(this->bit_width() < bit_width); if (this->is_bottom()) { return bottom(bit_width, this->sign()); } else if (this->is_top()) { return top(bit_width, this->sign()); } else { return Constant(this->_n.ext(bit_width)); } } /// \brief Change the constant sign (bitcast) Constant sign_cast(Signedness sign) const { ikos_assert(this->sign() != sign); if (this->is_bottom()) { return bottom(this->bit_width(), sign); } else if (this->is_top()) { return top(this->bit_width(), sign); } else { return Constant(this->_n.sign_cast(sign)); } } /// \brief Cast the constant to the given bit width and sign Constant cast(uint64_t bit_width, Signedness sign) const { if (this->is_bottom()) { return bottom(bit_width, sign); } else if (this->is_top()) { return top(bit_width, sign); } else { return Constant(this->_n.cast(bit_width, sign)); } } /// @} /// \brief If the constant in a number n, return n, otherwise return /// boost::none boost::optional< MachineInt > integer() const { if (this->is_integer()) { return this->_n; } else { return boost::none; } } /// \brief If the constant in a singleton n, return n, otherwise return /// boost::none boost::optional< MachineInt > singleton() const { return this->integer(); } /// \brief Return true if the constant contains n bool contains(const MachineInt& n) const { return this->is_top() || (this->is_integer() && this->_n == n); } void dump(std::ostream& o) const override { switch (this->_kind) { case BottomKind: { o << "⊥"; break; } case TopKind: { o << "T"; break; } case IntegerKind: { o << this->_n; break; } } } static std::string name() { return "constant"; } // Friends friend Constant add(const Constant& lhs, const Constant& rhs); friend Constant add_no_wrap(const Constant& lhs, const Constant& rhs); friend Constant sub(const Constant& lhs, const Constant& rhs); friend Constant sub_no_wrap(const Constant& lhs, const Constant& rhs); friend Constant mul(const Constant& lhs, const Constant& rhs); friend Constant mul_no_wrap(const Constant& lhs, const Constant& rhs); friend Constant div(const Constant& lhs, const Constant& rhs); friend Constant div_exact(const Constant& lhs, const Constant& rhs); friend Constant rem(const Constant& lhs, const Constant& rhs); friend Constant shl(const Constant& lhs, const Constant& rhs); friend Constant shl_no_wrap(const Constant& lhs, const Constant& rhs); friend Constant lshr(const Constant& lhs, const Constant& rhs); friend Constant lshr_exact(const Constant& lhs, const Constant& rhs); friend Constant ashr(const Constant& lhs, const Constant& rhs); friend Constant ashr_exact(const Constant& lhs, const Constant& rhs); friend Constant and_(const Constant& lhs, const Constant& rhs); friend Constant or_(const Constant& lhs, const Constant& rhs); friend Constant xor_(const Constant& lhs, const Constant& rhs); }; // end class Constant /// \name Binary Operators /// @{ /// \brief Addition with wrapping inline Constant add(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(add(lhs._n, rhs._n)); } } /// \brief Addition without wrapping inline Constant add_no_wrap(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool overflow; MachineInt n = add(lhs._n, rhs._n, overflow); if (!overflow) { return Constant(n); } else { return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Substraction with wrapping inline Constant sub(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(sub(lhs._n, rhs._n)); } } /// \brief Substraction without wrapping inline Constant sub_no_wrap(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool overflow; MachineInt n = sub(lhs._n, rhs._n, overflow); if (!overflow) { return Constant(n); } else { return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Multiplication with wrapping inline Constant mul(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if ((lhs.is_integer() && lhs._n.is_zero()) || (rhs.is_integer() && rhs._n.is_zero())) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(mul(lhs._n, rhs._n)); } } /// \brief Multiplication without wrapping inline Constant mul_no_wrap(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if ((lhs.is_integer() && lhs._n.is_zero()) || (rhs.is_integer() && rhs._n.is_zero())) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool overflow; MachineInt n = mul(lhs._n, rhs._n, overflow); if (!overflow) { return Constant(n); } else { return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Division inline Constant div(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && rhs._n.is_zero()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool overflow; bool exact; MachineInt n = div(lhs._n, rhs._n, overflow, exact); if (!overflow) { return Constant(n); } else { // overflow is considered undefined behavior return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Exact division inline Constant div_exact(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && rhs._n.is_zero()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool overflow; bool exact; MachineInt n = div(lhs._n, rhs._n, overflow, exact); if (!overflow && exact) { return Constant(n); } else { // overflow or non-exact division are undefined behaviors return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Remainder inline Constant rem(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && rhs._n.is_zero()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(rem(lhs._n, rhs._n)); } } /// \brief Left shift with wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline Constant shl(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && (rhs._n < MachineInt::zero(lhs.bit_width(), lhs.sign()) || rhs._n > MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign()))) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(shl(lhs._n, rhs._n)); } } /// \brief Left shift without wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline Constant shl_no_wrap(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && (rhs._n < MachineInt::zero(lhs.bit_width(), lhs.sign()) || rhs._n > MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign()))) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool overflow; MachineInt n = shl(lhs._n, rhs._n, overflow); if (!overflow) { return Constant(n); } else { return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Constant lshr(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && (rhs._n < MachineInt::zero(lhs.bit_width(), lhs.sign()) || rhs._n > MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign()))) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(lshr(lhs._n, rhs._n)); } } /// \brief Exact logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Constant lshr_exact(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && (rhs._n < MachineInt::zero(lhs.bit_width(), lhs.sign()) || rhs._n > MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign()))) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool exact; MachineInt n = lshr(lhs._n, rhs._n, exact); if (exact) { return Constant(n); } else { return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Constant ashr(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && (rhs._n < MachineInt::zero(lhs.bit_width(), lhs.sign()) || rhs._n > MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign()))) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(ashr(lhs._n, rhs._n)); } } /// \brief Exact arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Constant ashr_exact(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (rhs.is_integer() && (rhs._n < MachineInt::zero(lhs.bit_width(), lhs.sign()) || rhs._n > MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign()))) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_integer() && lhs._n.is_zero()) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { bool exact; MachineInt n = ashr(lhs._n, rhs._n, exact); if (exact) { return Constant(n); } else { return Constant::bottom(lhs.bit_width(), lhs.sign()); } } } /// \brief Bitwise AND inline Constant and_(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if ((lhs.is_integer() && lhs._n.is_zero()) || (rhs.is_integer() && rhs._n.is_zero())) { return Constant(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(and_(lhs._n, rhs._n)); } } /// \brief Bitwise OR inline Constant or_(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if ((lhs.is_integer() && lhs._n.all_ones()) || (rhs.is_integer() && rhs._n.all_ones())) { return Constant(MachineInt::all_ones(lhs.bit_width(), lhs.sign())); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(or_(lhs._n, rhs._n)); } } /// \brief Bitwise XOR inline Constant xor_(const Constant& lhs, const Constant& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom() || rhs.is_bottom()) { return Constant::bottom(lhs.bit_width(), lhs.sign()); } else if (lhs.is_top() || rhs.is_top()) { return Constant::top(lhs.bit_width(), lhs.sign()); } else { return Constant(xor_(lhs._n, rhs._n)); } } /// @} /// \name Input / Output /// @{ /// \brief Write a constant on a stream inline std::ostream& operator<<(std::ostream& o, const Constant& constant) { constant.dump(o); return o; } /// @} } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/machine_int/interval.hpp000066400000000000000000000743461473507761200270330ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Machine integer interval class * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Machine integer interval abstract value class Interval final : public core::AbstractDomain< Interval > { private: using ZBound = Bound< ZNumber >; using ZInterval = numeric::Interval< ZNumber >; private: // Lower bound MachineInt _lb; // Upper bound MachineInt _ub; // Invariant: is_bottom() <=> _lb > _ub public: /// \brief Create the top interval for the given bit-width and signedness static Interval top(uint64_t bit_width, Signedness sign) { return Interval(MachineInt::min(bit_width, sign), MachineInt::max(bit_width, sign)); } /// \brief Create the bottom interval for the given bit-width and signedness static Interval bottom(uint64_t bit_width, Signedness sign) { return Interval(MachineInt::max(bit_width, sign), MachineInt::min(bit_width, sign)); } /// \brief Create the interval [n, n] explicit Interval(const MachineInt& n) : _lb(n), _ub(n) {} /// \brief Create the interval [lb, ub] /// /// If lb > ub, the returned interval is bottom. Interval(MachineInt lb, MachineInt ub) : _lb(std::move(lb)), _ub(std::move(ub)) { assert_compatible(this->_lb, this->_ub); } /// \brief Copy constructor Interval(const Interval&) = default; /// \brief Move constructor Interval(Interval&&) noexcept = default; /// \brief Copy assignment operator Interval& operator=(const Interval&) = default; /// \brief Move assignment operator Interval& operator=(Interval&&) noexcept = default; /// \brief Destructor ~Interval() override = default; /// \brief Return the bit width of the interval uint64_t bit_width() const { return this->_lb.bit_width(); } /// \brief Return the signedness (Signed or Unsigned) of the interval Signedness sign() const { return this->_lb.sign(); } /// \brief Return the lower bound const MachineInt& lb() const { ikos_assert(!this->is_bottom()); return this->_lb; } /// \brief Return the upper bound const MachineInt& ub() const { ikos_assert(!this->is_bottom()); return this->_ub; } void normalize() override {} bool is_bottom() const override { return this->_lb > this->_ub; } bool is_top() const override { return this->_lb.is_min() && this->_ub.is_max(); } /// \brief Return true if the interval is [0, 0] bool is_zero() const { return this->_lb.is_zero() && this->_ub.is_zero(); } void set_to_bottom() override { this->_lb.set_max(); this->_ub.set_min(); } void set_to_top() override { this->_lb.set_min(); this->_ub.set_max(); } /// \brief Return the interval [MachineInt::min, ub] Interval lower_half_line() const { ikos_assert(!this->is_bottom()); return Interval(MachineInt::min(this->bit_width(), this->sign()), this->_ub); } /// \brief Return the interval [lb, MachineInt::max] Interval upper_half_line() const { ikos_assert(!this->is_bottom()); return Interval(this->_lb, MachineInt::max(this->bit_width(), this->sign())); } bool leq(const Interval& other) const override { assert_compatible(*this, other); if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return other._lb <= this->_lb && this->_ub <= other._ub; } } bool equals(const Interval& other) const override { assert_compatible(*this, other); if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_lb == other._lb && this->_ub == other._ub; } } Interval join(const Interval& other) const override { assert_compatible(*this, other); if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return Interval(min(this->_lb, other._lb), max(this->_ub, other._ub)); } } void join_with(const Interval& other) override { this->operator=(this->join(other)); } Interval widening(const Interval& other) const override { assert_compatible(*this, other); if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return Interval(other._lb < this->_lb ? MachineInt::min(this->bit_width(), this->sign()) : this->_lb, this->_ub < other._ub ? MachineInt::max(this->bit_width(), this->sign()) : this->_ub); } } void widen_with(const Interval& other) override { this->operator=(this->widening(other)); } Interval widening_threshold(const Interval& other, const MachineInt& threshold) const { assert_compatible(*this, other); if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { MachineInt th = threshold.cast(this->bit_width(), this->sign()); MachineInt lb = this->_lb; if (other._lb < this->_lb) { if (th <= other._lb) { lb = th; } else { lb = MachineInt::min(this->bit_width(), this->sign()); } } MachineInt ub = this->_ub; if (other._ub > this->_ub) { if (th >= other._ub) { ub = th; } else { ub = MachineInt::max(this->bit_width(), this->sign()); } } return Interval(lb, ub); } } void widen_threshold_with(const Interval& other, const MachineInt& threshold) { this->operator=(this->widening_threshold(other, threshold)); } Interval meet(const Interval& other) const override { assert_compatible(*this, other); if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return Interval(max(this->_lb, other._lb), min(this->_ub, other._ub)); } } void meet_with(const Interval& other) override { this->operator=(this->meet(other)); } Interval narrowing(const Interval& other) const override { assert_compatible(*this, other); if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { return Interval(this->_lb.is_min() ? other._lb : this->_lb, this->_ub.is_max() ? other._ub : this->_ub); } } void narrow_with(const Interval& other) override { this->operator=(this->narrowing(other)); } Interval narrowing_threshold(const Interval& other, const MachineInt& threshold) const { assert_compatible(*this, other); if (this->is_bottom()) { return *this; } else if (other.is_bottom()) { return other; } else { MachineInt th = threshold.cast(this->bit_width(), this->sign()); return Interval(this->_lb.is_min() || this->_lb == th ? other._lb : this->_lb, this->_ub.is_max() || this->_ub == th ? other._ub : this->_ub); } } void narrow_threshold_with(const Interval& other, const MachineInt& threshold) { this->operator=(this->narrowing_threshold(other, threshold)); } /// \name Unary Operators /// @{ /// \brief Truncate the machine integer interval to the given bit width Interval trunc(uint64_t bit_width) const { ikos_assert(this->bit_width() > bit_width); if (this->is_bottom()) { return bottom(bit_width, this->sign()); } else if (this->_lb == this->_ub) { return Interval(this->_lb.trunc(bit_width)); } else { // For unsigned integers, check that the first (m-n) bits match. // For signed integers, check the first (m-n+1) bits: if the result sign // bit is different, return top. MachineInt n(this->sign() == Unsigned ? bit_width : (bit_width - 1), this->bit_width(), this->sign()); if (lshr(this->_lb, n) == lshr(this->_ub, n)) { // Identical upper bits return Interval(this->_lb.trunc(bit_width), this->_ub.trunc(bit_width)); } else { return Interval::top(bit_width, this->sign()); } } } /// \brief Extend the machine integer interval to the given bit width Interval ext(uint64_t bit_width) const { ikos_assert(this->bit_width() < bit_width); if (this->is_bottom()) { return bottom(bit_width, this->sign()); } else { return Interval(this->_lb.ext(bit_width), this->_ub.ext(bit_width)); } } /// \brief Change the machine integer interval sign (bitcast) Interval sign_cast(Signedness sign) const { ikos_assert(this->sign() != sign); if (this->is_bottom()) { return bottom(this->bit_width(), sign); } else if (this->_lb == this->_ub) { return Interval(this->_lb.sign_cast(sign)); } else { if (this->_lb.high_bit() == this->_ub.high_bit()) { // Identical high bit MachineInt lb = this->_lb.sign_cast(sign); MachineInt ub = this->_ub.sign_cast(sign); return (lb <= ub) ? Interval(lb, ub) : Interval(ub, lb); } else { return Interval::top(this->bit_width(), sign); } } } /// \brief Cast the machine integer interval to the given bit width and sign /// /// This is equivalent to trunc()/ext() + sign_cast() (in this specific order) Interval cast(uint64_t bit_width, Signedness sign) const { if (this->bit_width() == bit_width) { if (this->sign() == sign) { return *this; } else { return this->sign_cast(sign); } } else if (this->bit_width() < bit_width) { if (this->sign() == sign) { return this->ext(bit_width); } else { return this->ext(bit_width).sign_cast(sign); } } else { if (this->sign() == sign) { return this->trunc(bit_width); } else { return this->trunc(bit_width).sign_cast(sign); } } } /// @} /// \name Conversion Functions /// @{ /// \brief Return the machine integer interval as a ZInterval ZInterval to_z_interval() const { if (this->is_bottom()) { return ZInterval::bottom(); } else { return ZInterval(ZBound(this->_lb.to_z_number()), ZBound(this->_ub.to_z_number())); } } struct WrapTag {}; struct TruncTag {}; /// \brief Convert a ZInterval to a machine integer interval /// /// Note that it wraps the interval. /// /// For instance: /// from_z_interval([255, 256], 8, Unsigned, WrapTag{}) = Top static Interval from_z_interval(const ZInterval& i, uint64_t bit_width, Signedness sign, WrapTag) { if (i.is_bottom()) { return bottom(bit_width, sign); } const ZBound& lb = i.lb(); const ZBound& ub = i.ub(); if (lb.is_infinite() || ub.is_infinite()) { return top(bit_width, sign); } ZNumber z_lb = *lb.number(); ZNumber z_ub = *ub.number(); MachineInt i_lb(z_lb, bit_width, sign); MachineInt i_ub(z_ub, bit_width, sign); if (i_ub.to_z_number() - i_lb.to_z_number() == z_ub - z_lb) { return Interval(i_lb, i_ub); } return top(bit_width, sign); } /// \brief Convert a ZInterval to a machine integer interval /// /// Note that it truncates the interval. /// /// For instance: /// from_z_interval([255, 256], 8, Unsigned, TruncTag{}) = [255, 255] static Interval from_z_interval(const ZInterval& i, uint64_t bit_width, Signedness sign, TruncTag) { if (i.is_bottom()) { return bottom(bit_width, sign); } ZInterval j = i.meet(Interval::top(bit_width, sign).to_z_interval()); if (j.is_bottom()) { return bottom(bit_width, sign); } return Interval(MachineInt(*j.lb().number(), bit_width, sign), MachineInt(*j.ub().number(), bit_width, sign)); } /// @} /// \brief If the interval is a singleton [n, n], return n, otherwise return /// boost::none boost::optional< MachineInt > singleton() const { if (this->_lb == this->_ub) { return this->_lb; } else { return boost::none; } } /// \brief Return true if the interval contains n bool contains(const MachineInt& n) const { assert_compatible(this->_lb, n); if (this->is_bottom()) { return false; } else { return this->_lb <= n && n <= this->_ub; } } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else if (this->is_top()) { o << "T"; } else { o << "[" << this->_lb << ", " << this->_ub << "]"; } } static std::string name() { return "interval"; } // Friends friend Interval rem(const Interval& lhs, const Interval& rhs); friend Interval shl(const Interval& lhs, const Interval& rhs); friend Interval shl_no_wrap(const Interval& lhs, const Interval& rhs); friend Interval lshr(const Interval& lhs, const Interval& rhs); friend Interval ashr(const Interval& lhs, const Interval& rhs); friend Interval and_(const Interval& lhs, const Interval& rhs); friend Interval or_(const Interval& lhs, const Interval& rhs); friend Interval xor_(const Interval& lhs, const Interval& rhs); }; // end class Interval /// \name Binary Operators /// @{ /// \brief Addition with wrapping inline Interval add(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Interval::from_z_interval(lhs.to_z_interval() + rhs.to_z_interval(), lhs.bit_width(), lhs.sign(), Interval::WrapTag{}); } } /// \brief Addition without wrapping inline Interval add_no_wrap(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Interval::from_z_interval(lhs.to_z_interval() + rhs.to_z_interval(), lhs.bit_width(), lhs.sign(), Interval::TruncTag{}); } } /// \brief Substraction with wrapping inline Interval sub(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Interval::from_z_interval(lhs.to_z_interval() - rhs.to_z_interval(), lhs.bit_width(), lhs.sign(), Interval::WrapTag{}); } } /// \brief Substraction without wrapping inline Interval sub_no_wrap(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Interval::from_z_interval(lhs.to_z_interval() - rhs.to_z_interval(), lhs.bit_width(), lhs.sign(), Interval::TruncTag{}); } } /// \brief Multiplication with wrapping inline Interval mul(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Interval::from_z_interval(lhs.to_z_interval() * rhs.to_z_interval(), lhs.bit_width(), lhs.sign(), Interval::WrapTag{}); } } /// \brief Multiplication without wrapping inline Interval mul_no_wrap(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return Interval::from_z_interval(lhs.to_z_interval() * rhs.to_z_interval(), lhs.bit_width(), lhs.sign(), Interval::TruncTag{}); } } /// \brief Division inline Interval div(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // overflow is undefined behavior return Interval::from_z_interval(lhs.to_z_interval() / rhs.to_z_interval(), lhs.bit_width(), lhs.sign(), Interval::TruncTag{}); } } /// \brief Exact division inline Interval div_exact(const Interval& lhs, const Interval& rhs) { return div(lhs, rhs); } /// \brief Remainder inline Interval rem(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { boost::optional< MachineInt > n = lhs.singleton(); boost::optional< MachineInt > d = rhs.singleton(); if (d && (*d).is_zero()) { // [a, b] % 0 = ⊥ return Interval::bottom(lhs.bit_width(), lhs.sign()); } else if (n && d) { // [n, n] % [d, d] = [n % d, n % d] return Interval(rem(*n, *d)); } else if (lhs.sign() == Signed) { // Signed remainder // [a, b] % [c, d] <= max(abs(a), abs(b)) // [a, b] % [c, d] <= max(abs(c), abs(d)) - 1 MachineInt zero = MachineInt::zero(lhs.bit_width(), lhs.sign()); MachineInt one(1, lhs.bit_width(), lhs.sign()); MachineInt max_int = MachineInt::max(lhs.bit_width(), lhs.sign()); // Check .is_min() to prevent overflows on abs() MachineInt n_ub = lhs._lb.is_min() ? max_int : max(abs(lhs._lb), abs(lhs._ub)); MachineInt d_ub = rhs._lb.is_min() ? max_int : max(abs(rhs._lb), abs(rhs._ub)) - one; MachineInt ub = min(n_ub, d_ub); ikos_assert(ub.is_non_negative()); if (lhs._lb.is_negative()) { if (lhs._ub.is_strictly_positive()) { return Interval(-ub, ub); } else { return Interval(-ub, zero); } } else { return Interval(zero, ub); } } else { // Unsigned remainder // [a, b] % [c, d] <= b // [a, b] % [c, d] <= d - 1 // [a, b] % [c, d] >= 0 MachineInt zero = MachineInt::zero(lhs.bit_width(), lhs.sign()); MachineInt one(1, lhs.bit_width(), lhs.sign()); MachineInt ub = min(lhs._ub, rhs._ub - one); return Interval(zero, ub); } } } /// \brief Left shift with wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline Interval shl(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // meet(rhs, [0, bit_width-1]) Interval constraint(MachineInt::zero(lhs.bit_width(), lhs.sign()), MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign())); Interval shift = rhs.meet(constraint); if (shift.is_bottom()) { // Invalid operand return shift; } // [a, b] << [c, d] = [a, b] * [1 << c, 1 << d] numeric::ZInterval coeff(ZBound(1 << shift._lb.to_z_number()), ZBound(1 << shift._ub.to_z_number())); return Interval::from_z_interval(lhs.to_z_interval() * coeff, lhs.bit_width(), lhs.sign(), Interval::WrapTag{}); } } /// \brief Left shift without wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline Interval shl_no_wrap(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // meet(rhs, [0, bit_width-1]) Interval constraint(MachineInt::zero(lhs.bit_width(), lhs.sign()), MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign())); Interval shift = rhs.meet(constraint); if (shift.is_bottom()) { // Invalid operand return shift; } // [a, b] << [c, d] = [a, b] * [1 << c, 1 << d] numeric::ZInterval coeff(ZBound(1 << shift._lb.to_z_number()), ZBound(1 << shift._ub.to_z_number())); return Interval::from_z_interval(lhs.to_z_interval() * coeff, lhs.bit_width(), lhs.sign(), Interval::TruncTag{}); } } /// \brief Logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Interval lshr(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // meet(rhs, [0, bit_width-1]) Interval constraint(MachineInt::zero(lhs.bit_width(), lhs.sign()), MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign())); Interval shift = rhs.meet(constraint); if (shift.is_bottom()) { // Invalid operand return shift; } if (lhs.sign() == Signed) { // Signed logical shift right return lshr(lhs.sign_cast(Unsigned), shift.sign_cast(Unsigned)) .sign_cast(Signed); } else { // Unsigned logical shift right // [a, b] >> [c, d] \in [a >> d, b >> c] return Interval(lshr(lhs._lb, shift._ub), lshr(lhs._ub, shift._lb)); } } } /// \brief Exact logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Interval lshr_exact(const Interval& lhs, const Interval& rhs) { return lshr(lhs, rhs); } /// \brief Arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Interval ashr(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // meet(rhs, [0, bit_width-1]) Interval constraint(MachineInt::zero(lhs.bit_width(), lhs.sign()), MachineInt(lhs.bit_width() - 1, lhs.bit_width(), lhs.sign())); Interval shift = rhs.meet(constraint); if (shift.is_bottom()) { // Invalid operand return shift; } if (lhs.sign() == Unsigned) { // Unsigned arithmetic shift right return ashr(lhs.sign_cast(Signed), shift.sign_cast(Signed)) .sign_cast(Unsigned); } else { // Signed arithmetic shift right if (lhs.contains(MachineInt::zero(lhs.bit_width(), lhs.sign()))) { Interval l(lhs._lb, MachineInt(-1, lhs.bit_width(), lhs.sign())); Interval u(MachineInt(1, lhs.bit_width(), lhs.sign()), lhs._ub); return ashr(l, shift) .join(ashr(u, shift)) .join(Interval(MachineInt::zero(lhs.bit_width(), lhs.sign()))); } else { // [a, b] >> [c, d] \in [min(a >> c, a >> d, b >> c, b >> d), // max(a >> c, a >> d, b >> c, b >> d)] MachineInt ll = ashr(lhs._lb, shift._lb); MachineInt lu = ashr(lhs._lb, shift._ub); MachineInt ul = ashr(lhs._ub, shift._lb); MachineInt uu = ashr(lhs._ub, shift._ub); return Interval(min(min(min(ll, lu), ul), uu), max(max(max(ll, lu), ul), uu)); } } } } /// \brief Exact arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline Interval ashr_exact(const Interval& lhs, const Interval& rhs) { return ashr(lhs, rhs); } /// \brief Bitwise AND inline Interval and_(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { boost::optional< MachineInt > l = lhs.singleton(); boost::optional< MachineInt > r = rhs.singleton(); if (l && r) { // [l, l] & [r, r] = [l & r, l & r] return Interval(and_(*l, *r)); } else if ((l && (*l).is_zero()) || (r && (*r).is_zero())) { // [a, b] & 0 = 0 return Interval(MachineInt::zero(lhs.bit_width(), lhs.sign())); } else if (l && (*l).all_ones()) { // 0b11..11 & [a, b] = [a, b] return rhs; } else if (r && (*r).all_ones()) { // [a, b] & 0b11..11 = [a, b] return lhs; } else if (lhs.sign() == Signed) { // Signed AND return and_(lhs.sign_cast(Unsigned), rhs.sign_cast(Unsigned)) .sign_cast(Signed); } else { // Unsigned AND // [a, b] & [c, d] <= [c, d] & b <= b // [a, b] & [c, d] <= [a, b] & d <= d // [a, b] & [c, d] >= 0 MachineInt zero = MachineInt::zero(lhs.bit_width(), lhs.sign()); MachineInt ub = min(lhs._ub, rhs._ub); return Interval(zero, ub); } } } /// \brief Bitwise OR inline Interval or_(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { boost::optional< MachineInt > l = lhs.singleton(); boost::optional< MachineInt > r = rhs.singleton(); if (l && r) { // [l, l] | [r, r] = [l | r, l | r] return Interval(or_(*l, *r)); } else if ((l && (*l).all_ones()) || (r && (*r).all_ones())) { // 0b11..11 | [a, b] = 0b11..11 return Interval(MachineInt::all_ones(lhs.bit_width(), lhs.sign())); } else if (l && (*l).is_zero()) { // 0 | [a, b] = [a, b] return rhs; } else if (r && (*r).is_zero()) { // [a, b] | 0 = [a, b] return lhs; } else if (lhs.sign() == Signed) { // Signed OR return or_(lhs.sign_cast(Unsigned), rhs.sign_cast(Unsigned)) .sign_cast(Signed); } else { // Unsigned OR uint64_t lead_zeros = std::min(lhs._ub.leading_zeros(), rhs._ub.leading_zeros()); ikos_assert(lead_zeros < lhs.bit_width()); MachineInt zero = MachineInt::zero(lhs.bit_width(), lhs.sign()); MachineInt ub = lshr(MachineInt::all_ones(lhs.bit_width(), lhs.sign()), MachineInt(lead_zeros, lhs.bit_width(), lhs.sign())); return Interval(zero, ub); } } } /// \brief Bitwise XOR inline Interval xor_(const Interval& lhs, const Interval& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { boost::optional< MachineInt > l = lhs.singleton(); boost::optional< MachineInt > r = rhs.singleton(); if (l && r) { // [l, l] ^ [r, r] = [l ^ r, l ^ r] return Interval(xor_(*l, *r)); } else if (l && (*l).is_zero()) { // 0 ^ [a, b] = [a, b] return rhs; } else if (r && (*r).is_zero()) { // [a, b] ^ 0 = [a, b] return lhs; } else if (lhs.sign() == Signed) { // Signed XOR return xor_(lhs.sign_cast(Unsigned), rhs.sign_cast(Unsigned)) .sign_cast(Signed); } else { // Unsigned XOR uint64_t lead_zeros = std::min(lhs._ub.leading_zeros(), rhs._ub.leading_zeros()); ikos_assert(lead_zeros < lhs.bit_width()); MachineInt zero = MachineInt::zero(lhs.bit_width(), lhs.sign()); MachineInt ub = lshr(MachineInt::all_ones(lhs.bit_width(), lhs.sign()), MachineInt(lead_zeros, lhs.bit_width(), lhs.sign())); return Interval(zero, ub); } } } /// @} /// \name Input / Output /// @{ /// \brief Write an interval on a stream inline std::ostream& operator<<(std::ostream& o, const Interval& interval) { interval.dump(o); return o; } /// @} } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/machine_int/interval_congruence.hpp000066400000000000000000000646351473507761200312430ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief IntervalCongruence class for machine integers * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { namespace machine_int { /// \brief Machine integer Interval-Congruence abstract value /// /// This is implemented as a pair of interval and congruence abstract value. class IntervalCongruence final : public core::AbstractDomain< IntervalCongruence > { private: /// Use a pair (machine_int::Interval, numeric::ZCongruence) /// /// machine_int::Congruence is just a wrapper for numeric::ZCongruence. /// For performance reasons, it is better to use a numeric::ZCongruence here, /// This way the normalization is only done once. public: /// \brief Interval on unlimited precision integers using ZInterval = numeric::Interval< ZNumber >; /// \brief Congruence on unlimited precision integers using ZCongruence = numeric::Congruence< ZNumber >; /// \brief Interval-congruence on unlimited precision integers using ZIntervalCongruence = numeric::IntervalCongruence< ZNumber >; private: Interval _i; ZCongruence _c; /// \brief Reduce the interval-congruence /// /// Let (i, c) be a pair of interval and congruence /// if (c.is_bottom() || i.is_bottom()) (bottom(), bottom()); /// if (c = 0Z+a and a notin i) (bottom(), bottom()); /// if (c = 0Z+a) ([a,a] , c); /// if (i=[a,b] and R(c,a) > L(c,b)) (bottom(), bottom()); /// if (i=[a,b] and R(c,a) = L(c,b)) ([R(c,a), R(c,b)], R(c,a)) /// else (i=[a,b]) ([R(c,a), L(c,b)], c); void reduce() { if (this->_c.is_bottom()) { this->_i.set_to_bottom(); return; } if (this->_i.is_bottom()) { this->_c.set_to_bottom(); return; } if (this->_c.is_top()) { // congruence is top boost::optional< MachineInt > n = this->_i.singleton(); if (n) { // interval is a singleton this->_c = ZCongruence(n->to_z_number()); } return; } ZNumber lb = this->_i.lb().to_z_number(); ZNumber ub = this->_i.ub().to_z_number(); if (this->_c.modulus() == 0) { // congruence is a singleton, refine the interval if (!(lb <= this->_c.residue() && this->_c.residue() <= ub)) { this->set_to_bottom(); } else { this->_i = Interval( MachineInt(this->_c.residue(), this->bit_width(), this->sign())); } return; } // refine lower and upper bounds of the interval using congruences ikos_assert(this->_c.modulus() > 0); ZNumber x = Congruence::r(this->_c, lb); ZNumber y = Congruence::l(this->_c, ub); if (x > y) { this->set_to_bottom(); } else if (x == y) { this->_i = Interval(MachineInt(x, this->bit_width(), this->sign())); this->_c = ZCongruence(x); } else { this->_i = Interval(MachineInt(x, this->bit_width(), this->sign()), MachineInt(y, this->bit_width(), this->sign())); } } /// \brief Wrap a congruence in Z to the given bit-width and signedness static ZCongruence wrap(const ZCongruence& c, uint64_t bit_width, Signedness sign) { return Congruence::wrap(c, bit_width, sign); } private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top interval-congruence for the given bit-width and /// signedness IntervalCongruence(TopTag, uint64_t bit_width, Signedness sign) : _i(Interval::top(bit_width, sign)), _c(ZCongruence::top()) {} /// \brief Create the bottom interval-congruence for the given bit-width and /// signedness IntervalCongruence(BottomTag, uint64_t bit_width, Signedness sign) : _i(Interval::bottom(bit_width, sign)), _c(ZCongruence::bottom()) {} public: /// \brief Create the top interval-congruence for the given bit-width and /// signedness static IntervalCongruence top(uint64_t bit_width, Signedness sign) { return IntervalCongruence(TopTag{}, bit_width, sign); } /// \brief Create the bottom interval-congruence for the given bit-width and /// signedness static IntervalCongruence bottom(uint64_t bit_width, Signedness sign) { return IntervalCongruence(BottomTag{}, bit_width, sign); } /// \brief Create the interval-congruence ([n, n], 0Z+n) explicit IntervalCongruence(const MachineInt& n) : _i(n), _c(n.to_z_number()) {} /// \brief Create the interval-congruence (i, c) IntervalCongruence(const Interval& i, const Congruence& c) : _i(i), _c(c.to_z_congruence()) { assert_compatible(i, c); this->reduce(); } /// \brief Create the interval-congruence (i, c) IntervalCongruence(Interval i, ZCongruence c) : _i(std::move(i)), _c(std::move(c)) { this->reduce(); } /// \brief Create the interval-congruence (i, T) explicit IntervalCongruence(Interval i) : _i(std::move(i)), _c(ZCongruence::top()) { this->reduce(); } /// \brief Create the interval-congruence (T, c) explicit IntervalCongruence(const Congruence& c) : _i(Interval::top(c.bit_width(), c.sign())), _c(c.to_z_congruence()) { this->reduce(); } /// \brief Copy constructor IntervalCongruence(const IntervalCongruence&) = default; /// \brief Move constructor IntervalCongruence(IntervalCongruence&&) = default; /// \brief Copy assignment operator IntervalCongruence& operator=(const IntervalCongruence&) = default; /// \brief Move assignment operator IntervalCongruence& operator=(IntervalCongruence&&) noexcept = default; /// \brief Destructor ~IntervalCongruence() override = default; /// \brief Return the bit width of the interval-congruence uint64_t bit_width() const { return this->_i.bit_width(); } /// \brief Return the signedness the interval-congruence Signedness sign() const { return this->_i.sign(); } bool is_signed() const { return this->sign() == Signed; } bool is_unsigned() const { return this->sign() == Unsigned; } /// \brief Return the interval const Interval& interval() const { return this->_i; } /// \brief Return the congruence Congruence congruence() const { return Congruence(this->_c, this->bit_width(), this->sign(), Congruence::NormalizedTag{}); } /// \brief Return the lower bound const MachineInt& lb() const { ikos_assert(!this->is_bottom()); return this->_i.lb(); } /// \brief Return the upper bound const MachineInt& ub() const { ikos_assert(!this->is_bottom()); return this->_i.ub(); } /// \brief Return the modulus const ZNumber& modulus() const { ikos_assert(!this->is_bottom()); return this->_c.modulus(); } /// \brief Return the residue const ZNumber& residue() const { ikos_assert(!this->is_bottom()); return this->_c.residue(); } void normalize() override { // Already performed by the reduction } bool is_bottom() const override { return this->_c.is_bottom(); // Correct because of reduction } bool is_top() const override { return this->_i.is_top() && this->_c.is_top(); } /// \brief Return true if the interval-congruence is 0 bool is_zero() const { return this->_i.is_zero(); // Correct because of normalization } void set_to_bottom() override { this->_i.set_to_bottom(); this->_c.set_to_bottom(); } void set_to_top() override { this->_i.set_to_top(); this->_c.set_to_top(); } bool leq(const IntervalCongruence& other) const override { assert_compatible(*this, other); return this->_i.leq(other._i) && this->_c.leq(other._c); } bool equals(const IntervalCongruence& other) const override { assert_compatible(*this, other); return this->_i.equals(other._i) && this->_c.equals(other._c); } IntervalCongruence join(const IntervalCongruence& other) const override { assert_compatible(*this, other); return IntervalCongruence(this->_i.join(other._i), this->_c.join(other._c)); } void join_with(const IntervalCongruence& other) override { assert_compatible(*this, other); this->_i.join_with(other._i); this->_c.join_with(other._c); this->reduce(); } IntervalCongruence widening(const IntervalCongruence& other) const override { assert_compatible(*this, other); return IntervalCongruence(this->_i.widening(other._i), this->_c.widening(other._c)); } void widen_with(const IntervalCongruence& other) override { assert_compatible(*this, other); this->_i.widen_with(other._i); this->_c.widen_with(other._c); this->reduce(); } IntervalCongruence widening_threshold(const IntervalCongruence& other, const MachineInt& threshold) const { assert_compatible(*this, other); return IntervalCongruence(this->_i.widening_threshold(other._i, threshold), this->_c.widening(other._c)); } void widen_threshold_with(const IntervalCongruence& other, const MachineInt& threshold) { assert_compatible(*this, other); this->_i.widen_threshold_with(other._i, threshold); this->_c.widen_with(other._c); this->reduce(); } IntervalCongruence meet(const IntervalCongruence& other) const override { assert_compatible(*this, other); return IntervalCongruence(this->_i.meet(other._i), this->_c.meet(other._c)); } void meet_with(const IntervalCongruence& other) override { assert_compatible(*this, other); this->_i.meet_with(other._i); this->_c.meet_with(other._c); this->reduce(); } IntervalCongruence narrowing(const IntervalCongruence& other) const override { assert_compatible(*this, other); return IntervalCongruence(this->_i.narrowing(other._i), this->_c.narrowing(other._c)); } void narrow_with(const IntervalCongruence& other) override { assert_compatible(*this, other); this->_i.narrow_with(other._i); this->_c.narrow_with(other._c); this->reduce(); } IntervalCongruence narrowing_threshold(const IntervalCongruence& other, const MachineInt& threshold) const { assert_compatible(*this, other); return IntervalCongruence(this->_i.narrowing_threshold(other._i, threshold), this->_c.narrowing(other._c)); } void narrow_threshold_with(const IntervalCongruence& other, const MachineInt& threshold) { assert_compatible(*this, other); this->_i.narrow_threshold_with(other._i, threshold); this->_c.narrow_with(other._c); this->reduce(); } /// \name Unary Operators /// @{ /// \brief Truncate the interval-congruence to the given bit width IntervalCongruence trunc(uint64_t bit_width) const { ikos_assert(this->bit_width() > bit_width); return IntervalCongruence(this->_i.trunc(bit_width), wrap(this->_c, bit_width, this->sign())); } /// \brief Extend the interval-congruence to the given bit width IntervalCongruence ext(uint64_t bit_width) const { ikos_assert(this->bit_width() < bit_width); return IntervalCongruence(this->_i.ext(bit_width), this->_c); } /// \brief Change the interval-congruence sign (bitcast) IntervalCongruence sign_cast(Signedness sign) const { ikos_assert(this->sign() != sign); return IntervalCongruence(this->_i.sign_cast(sign), wrap(this->_c, this->bit_width(), sign)); } /// \brief Cast the interval-congruence to the given bit width and sign /// /// This is equivalent to trunc()/ext() + sign_cast() (in this specific order) IntervalCongruence cast(uint64_t bit_width, Signedness sign) const { return IntervalCongruence(this->_i.cast(bit_width, sign), wrap(this->_c, bit_width, sign)); } /// @} /// \name Conversion Functions /// @{ /// \brief Return the interval as a ZInterval ZInterval to_z_interval() const { return this->_i.to_z_interval(); } /// \brief Return the congruence as a ZCongruence const ZCongruence& to_z_congruence() const { return this->_c; } /// \brief Return the interval-congruence as a ZIntervalCongruence ZIntervalCongruence to_z_interval_congruence() const { return ZIntervalCongruence(this->_i.to_z_interval(), this->_c); } struct WrapTag {}; struct TruncTag {}; /// \brief Convert a ZIntervalCongruence to a machine integer /// interval-congruence /// /// Note that it wraps. /// /// For instance: /// from_z_congruence([255, 256], 1Z, 8, Unsigned, WrapTag{}) = Top static IntervalCongruence from_z_interval_congruence( const ZIntervalCongruence& ic, uint64_t bit_width, Signedness sign, WrapTag) { if (ic.is_bottom()) { return bottom(bit_width, sign); } return IntervalCongruence(Interval::from_z_interval(ic.interval(), bit_width, sign, Interval::WrapTag{}), wrap(ic.congruence(), bit_width, sign)); } /// \brief Convert a ZIntervalCongruence to a machine integer /// interval-congruence /// /// Note that it truncates. /// /// For instance: /// from_z_congruence([255, 256], 1Z, 8, Unsigned, WrapTag{}) = [255, 255] static IntervalCongruence from_z_interval_congruence( const ZIntervalCongruence& ic, uint64_t bit_width, Signedness sign, TruncTag) { if (ic.is_bottom()) { return bottom(bit_width, sign); } return IntervalCongruence(Interval::from_z_interval(ic.interval(), bit_width, sign, Interval::TruncTag{}), ic.congruence()); } /// @} /// \brief If the interval-congruence is a singleton, return its value, /// otherwise return boost::none boost::optional< MachineInt > singleton() const { return this->_i.singleton(); // correct because of normalization } /// \brief Return true if the interval-congruence contains n bool contains(const MachineInt& n) const { return this->_i.contains(n) && this->_c.contains(n.to_z_number()); } void dump(std::ostream& o) const override { o << "("; this->_i.dump(o); o << ", "; this->_c.dump(o); o << ")"; } static std::string name() { return "interval-congruence"; } // Friends friend IntervalCongruence add(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence add_no_wrap(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence sub(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence sub_no_wrap(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence mul(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence mul_no_wrap(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence div(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence div_exact(const IntervalCongruence& lhs, const IntervalCongruence& rhs); friend IntervalCongruence rem(const IntervalCongruence& lhs, const IntervalCongruence& rhs); }; // end class IntervalCongruence /// \name Binary Operators /// @{ /// \brief Addition with wrapping inline IntervalCongruence add(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(add(lhs._i, rhs._i), IntervalCongruence::wrap(lhs._c + rhs._c, lhs.bit_width(), lhs.sign())); } } /// \brief Addition without wrapping inline IntervalCongruence add_no_wrap(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(add_no_wrap(lhs._i, rhs._i), lhs._c + rhs._c); } } /// \brief Substraction with wrapping inline IntervalCongruence sub(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(sub(lhs._i, rhs._i), IntervalCongruence::wrap(lhs._c - rhs._c, lhs.bit_width(), lhs.sign())); } } /// \brief Substraction without wrapping inline IntervalCongruence sub_no_wrap(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(sub_no_wrap(lhs._i, rhs._i), lhs._c - rhs._c); } } /// \brief Multiplication with wrapping inline IntervalCongruence mul(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(mul(lhs._i, rhs._i), IntervalCongruence::wrap(lhs._c * rhs._c, lhs.bit_width(), lhs.sign())); } } /// \brief Multiplication without wrapping inline IntervalCongruence mul_no_wrap(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(mul_no_wrap(lhs._i, rhs._i), lhs._c * rhs._c); } } /// \brief Division inline IntervalCongruence div(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // overflow is undefined behavior return IntervalCongruence(div(lhs._i, rhs._i), lhs._c / rhs._c); } } /// \brief Exact division inline IntervalCongruence div_exact(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { // overflow is undefined behavior return IntervalCongruence(div_exact(lhs._i, rhs._i), lhs._c / rhs._c); } } /// \brief Remainder inline IntervalCongruence rem(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(rem(lhs._i, rhs._i), lhs._c % rhs._c); } } /// \brief Left shift with wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline IntervalCongruence shl(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(shl(lhs.interval(), rhs.interval()), shl(lhs.congruence(), rhs.congruence())); } } /// \brief Left shift without wrapping /// /// The right hand side has to be between 0 and bit_width - 1 inline IntervalCongruence shl_no_wrap(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(shl_no_wrap(lhs.interval(), rhs.interval()), shl_no_wrap(lhs.congruence(), rhs.congruence())); } } /// \brief Logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline IntervalCongruence lshr(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(lshr(lhs.interval(), rhs.interval()), lshr(lhs.congruence(), rhs.congruence())); } } /// \brief Exact logical shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline IntervalCongruence lshr_exact(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(lshr_exact(lhs.interval(), rhs.interval()), lshr_exact(lhs.congruence(), rhs.congruence())); } } /// \brief Arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline IntervalCongruence ashr(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(ashr(lhs.interval(), rhs.interval()), ashr(lhs.congruence(), rhs.congruence())); } } /// \brief Exact arithmetic shift right /// /// The right hand side has to be between 0 and bit_width - 1 inline IntervalCongruence ashr_exact(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(ashr_exact(lhs.interval(), rhs.interval()), ashr_exact(lhs.congruence(), rhs.congruence())); } } /// \brief Bitwise AND inline IntervalCongruence and_(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(and_(lhs.interval(), rhs.interval()), and_(lhs.congruence(), rhs.congruence())); } } /// \brief Bitwise OR inline IntervalCongruence or_(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(or_(lhs.interval(), rhs.interval()), or_(lhs.congruence(), rhs.congruence())); } } /// \brief Bitwise XOR inline IntervalCongruence xor_(const IntervalCongruence& lhs, const IntervalCongruence& rhs) { assert_compatible(lhs, rhs); if (lhs.is_bottom()) { return lhs; } else if (rhs.is_bottom()) { return rhs; } else { return IntervalCongruence(xor_(lhs.interval(), rhs.interval()), xor_(lhs.congruence(), rhs.congruence())); } } /// @} /// \name Input / Output /// @{ /// \brief Write an interval-congruence on a stream inline std::ostream& operator<<(std::ostream& o, const IntervalCongruence& iv) { iv.dump(o); return o; } /// @} } // end namespace machine_int } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/nullity.hpp000066400000000000000000000133601473507761200244160ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Nullity abstract value * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Nullity abstract value /// /// This is either top, bottom, non-null or null. class Nullity final : public core::AbstractDomain< Nullity > { private: enum Kind : unsigned { BottomKind = 0, NullKind = 1, NonNullKind = 2, TopKind = 3 }; private: Kind _kind = TopKind; private: /// \brief Private constructor explicit Nullity(Kind kind) : _kind(kind) {} public: /// \brief Return the top nullity value static Nullity top() { return Nullity(TopKind); } /// \brief Return the bottom nullity value static Nullity bottom() { return Nullity(BottomKind); } /// \brief Return the non-null nullity value static Nullity non_null() { return Nullity(NonNullKind); } /// \brief Return the null nullity value static Nullity null() { return Nullity(NullKind); } /// \brief Copy constructor Nullity(const Nullity&) noexcept = default; /// \brief Move constructor Nullity(Nullity&&) noexcept = default; /// \brief Copy assignment operator Nullity& operator=(const Nullity&) noexcept = default; /// \brief Move assignment operator Nullity& operator=(Nullity&&) noexcept = default; /// \brief Destructor ~Nullity() override = default; void normalize() override {} bool is_bottom() const override { return this->_kind == BottomKind; } bool is_top() const override { return this->_kind == TopKind; } /// \brief Return true if this is the non-null nullity value bool is_non_null() const { return this->_kind == NonNullKind; } /// \brief Return true if this is the null nullity value bool is_null() const { return this->_kind == NullKind; } void set_to_bottom() override { this->_kind = BottomKind; } void set_to_top() override { this->_kind = TopKind; } /// \brief Set the nullity value to non-null void set_to_non_null() { this->_kind = NonNullKind; } /// \brief Set the nullity value to null void set_to_null() { this->_kind = NullKind; } bool leq(const Nullity& other) const override { switch (this->_kind) { case BottomKind: return true; case TopKind: return other._kind == TopKind; case NullKind: return other._kind == NullKind || other._kind == TopKind; case NonNullKind: return other._kind == NonNullKind || other._kind == TopKind; default: ikos_unreachable("unreachable"); } } bool equals(const Nullity& other) const override { return this->_kind == other._kind; } void join_with(const Nullity& other) override { this->_kind = static_cast< Kind >(static_cast< unsigned >(this->_kind) | static_cast< unsigned >(other._kind)); } void widen_with(const Nullity& other) override { this->join_with(other); } void meet_with(const Nullity& other) override { this->_kind = static_cast< Kind >(static_cast< unsigned >(this->_kind) & static_cast< unsigned >(other._kind)); } void narrow_with(const Nullity& other) override { this->meet_with(other); } void dump(std::ostream& o) const override { switch (this->_kind) { case BottomKind: { o << "⊥"; break; } case NullKind: { o << "N"; break; } case NonNullKind: { o << "NN"; break; } case TopKind: { o << "T"; break; } default: { ikos_unreachable("unreachable"); } } } static std::string name() { return "nullity"; } }; // end class Nullity } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/numeric/000077500000000000000000000000001473507761200236445ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/numeric/congruence.hpp000066400000000000000000000616271473507761200265210ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Congruence value for the congruence domain * * Author: Alexandre C. D. Wimmers * * Contributors: Jorge A. Navas * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Congruence abstract value template < typename Number > class Congruence {}; /// \brief Congruence abstract value /// /// This is either bottom, or aZ + b. /// /// Note that top is represented as 1Z + 0. template <> class Congruence< ZNumber > final : public core::AbstractDomain< Congruence< ZNumber > > { public: using NumberT = ZNumber; private: bool _is_bottom; ZNumber _a; ZNumber _b; // Invariant: !_is_bottom => _a >= 0 // Invariant: !_is_bottom && _a != 0 => 0 <= _b < _a // Invariant: _is_bottom => _a == _b == 0 private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top congruence 1Z + 0 explicit Congruence(TopTag) : _is_bottom(false), _a(1), _b(0) {} /// \brief Create the bottom congruence explicit Congruence(BottomTag) : _is_bottom(true), _a(0), _b(0) {} /// \brief Reduce the congruence void reduce() { ikos_assert(this->_a >= 0); // if a != 0: 0 <= b < a if (this->_a != 0) { this->_b = mod(this->_b, this->_a); } } public: /// \brief Create the congruence 1Z + 0 static Congruence top() { return Congruence(TopTag{}); } /// \brief Create the bottom congruence static Congruence bottom() { return Congruence(BottomTag{}); } /// \brief Create the congruence 0Z + n explicit Congruence(int n) : _is_bottom(false), _a(0), _b(n) {} /// \brief Create the congruence 0Z + n explicit Congruence(ZNumber n) : _is_bottom(false), _a(0), _b(std::move(n)) {} /// \brief Create the congruence aZ + b Congruence(ZNumber a, ZNumber b) : _is_bottom(false), _a(std::move(a)), _b(std::move(b)) { this->reduce(); } /// \brief Copy constructor Congruence(const Congruence&) = default; /// \brief Move constructor Congruence(Congruence&&) = default; /// \brief Copy assignment operator Congruence& operator=(const Congruence&) = default; /// \brief Move assignment operator Congruence& operator=(Congruence&&) noexcept = default; /// \brief Destructor ~Congruence() override = default; /// \brief Return the modulus const ZNumber& modulus() const { ikos_assert(!this->is_bottom()); return this->_a; } /// \brief Return the residue const ZNumber& residue() const { ikos_assert(!this->is_bottom()); return this->_b; } void normalize() override { // Already performed by reduction } bool is_bottom() const override { return this->_is_bottom; } bool is_top() const override { return this->_a == 1; } /// \brief Return true if the congruence is 0Z + 0 bool is_zero() const { return !this->_is_bottom && this->_a == 0 && this->_b == 0; } void set_to_bottom() override { this->_is_bottom = true; this->_a = 0; this->_b = 0; } void set_to_top() override { this->_is_bottom = false; this->_a = 1; this->_b = 0; } bool leq(const Congruence& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else if (this->_a == 0 && other._a == 0) { return this->_b == other._b; } else if (this->_a == 0) { return mod(this->_b, other._a) == other._b; } else if (other._a == 0) { return false; } else { return mod(this->_a, other._a) == 0 && mod(this->_b, other._a) == other._b; } } bool equals(const Congruence& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_a == other._a && this->_b == other._b; } } Congruence join(const Congruence& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return Congruence(gcd(this->_a, other._a, abs(this->_b - other._b)), min(this->_b, other._b)); } } void join_with(const Congruence& other) override { this->operator=(this->join(other)); } Congruence widening(const Congruence& other) const override { // equivalent to join, domain is flat return this->join(other); } void widen_with(const Congruence& other) override { // equivalent to join, domain is flat this->join_with(other); } Congruence widening_threshold(const Congruence& other, const ZNumber& /*threshold*/) const { // equivalent to join, domain is flat return this->join(other); } void widen_threshold_with(const Congruence& other, const ZNumber& /*threshold*/) { // equivalent to join, domain is flat this->join_with(other); } Congruence meet(const Congruence& other) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } // Note: lcm has meaning only if both a and o.a are not 0 if (this->_a == 0 && other._a == 0) { if (this->_b == other._b) { return *this; } else { return bottom(); } } else if (this->_a == 0) { if (mod(this->_b, other._a) == other._b) { return *this; } else { return bottom(); } } else if (other._a == 0) { if (mod(other._b, this->_a) == this->_b) { return other; } else { return bottom(); } } else { // pre: a and o.a != 0 ZNumber x; // gcd(a, o.a) ZNumber u; ZNumber v; gcd_extended(this->_a, other._a, x, u, v); if (mod(this->_b, x) == mod(other._b, x)) { // See http://www.dsi.unive.it/~avp/domains.pdf // See https://math.stackexchange.com/a/1644698 ZNumber lambda = (this->_b - other._b) / x; ZNumber sigma = this->_b - this->_a * u * lambda; return Congruence(lcm(this->_a, other._a), sigma); } else { return bottom(); } } } void meet_with(const Congruence& other) override { this->operator=(this->meet(other)); } Congruence narrowing(const Congruence& other) const override { // equivalent to meet, domain is flat return this->meet(other); } void narrow_with(const Congruence& other) override { // equivalent to meet, domain is flat this->meet_with(other); } Congruence narrowing_threshold(const Congruence& other, const ZNumber& /*threshold*/) const { // equivalent to meet, domain is flat return this->meet(other); } void narrow_threshold_with(const Congruence& other, const ZNumber& /*threshold*/) { // equivalent to meet, domain is flat this->meet_with(other); } /// \brief Unary minus Congruence operator-() const { if (this->is_bottom() || this->is_top()) { return *this; } else { return Congruence(this->_a, -this->_b); } } /// \brief Add a congruence void operator+=(const Congruence& other) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_a = gcd(this->_a, other._a); this->_b += other._b; this->reduce(); } } /// \brief Substract a congruence void operator-=(const Congruence& other) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_a = gcd(this->_a, other._a); this->_b -= other._b; this->reduce(); } } /// \brief If the congruence is a singleton 0Z + n, return n, otherwise return /// boost::none boost::optional< ZNumber > singleton() const { if (!this->is_bottom() && this->_a == 0) { return this->_b; } else { return boost::none; } } /// \brief Return true if the congruence contains n bool contains(int n) const { return this->contains(ZNumber(n)); } /// \brief Return true if the congruence contains n bool contains(const ZNumber& n) const { if (this->is_bottom()) { return false; } else if (this->_a == 0) { return n == this->_b; } else { return mod(n, this->_a) == this->_b; } } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; return; } if (this->_a == 0) { o << this->_b; return; } if (this->_b == 0) { o << this->_a << "Z"; } else { o << this->_a << "Z+" << this->_b; } } static std::string name() { return "congruence"; } }; // end class Congruence< ZNumber > /// \brief Add congruences inline Congruence< ZNumber > operator+(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else { return CongruenceT(gcd(lhs.modulus(), rhs.modulus()), lhs.residue() + rhs.residue()); } } /// \brief Add a congruence and a number inline Congruence< ZNumber > operator+(const Congruence< ZNumber >& lhs, const ZNumber& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom()) { return CongruenceT::bottom(); } else { return CongruenceT(lhs.modulus(), lhs.residue() + rhs); } } /// \brief Substract congruences inline Congruence< ZNumber > operator-(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else { return CongruenceT(gcd(lhs.modulus(), rhs.modulus()), lhs.residue() - rhs.residue()); } } /// \brief Substract a number inline Congruence< ZNumber > operator-(const Congruence< ZNumber >& lhs, const ZNumber& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom()) { return CongruenceT::bottom(); } else { return CongruenceT(lhs.modulus(), lhs.residue() - rhs); } } /// \brief Multiply congruences inline Congruence< ZNumber > operator*(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else { return CongruenceT(gcd(lhs.modulus() * rhs.modulus(), lhs.modulus() * rhs.residue(), rhs.modulus() * lhs.residue()), lhs.residue() * rhs.residue()); } } /// \brief Divide congruences inline Congruence< ZNumber > operator/(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else if (rhs.modulus() == 0 && rhs.residue() == 0) { return CongruenceT::bottom(); } else { // Stefan Bygde's paper "Static WCET analysis based on abstract // interpretation and counting of elements" provides a precise operator, // but it only works with positive numbers. // Special case: 0Z+0 / a'Z+b' if (lhs.modulus() == 0 && lhs.residue() == 0) { return CongruenceT(0); } // Special case: 0Z+b / 0Z+b' if (lhs.modulus() == 0 && rhs.modulus() == 0) { ikos_assert(rhs.residue() != 0); return CongruenceT(lhs.residue() / rhs.residue()); } // Special case: aZ+b / 0Z+b' // if b'|a and b'|b then abs(a/b')Z + b/b' if (rhs.modulus() == 0) { ikos_assert(rhs.residue() != 0); if (mod(lhs.modulus(), rhs.residue()) == 0 && mod(lhs.residue(), rhs.residue()) == 0) { return CongruenceT(abs(lhs.modulus() / rhs.residue()), lhs.residue() / rhs.residue()); } } // General case return CongruenceT::top(); } } /// \brief Signed remainder inline Congruence< ZNumber > operator%(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else if (rhs.modulus() == 0 && rhs.residue() == 0) { return CongruenceT::bottom(); } else { // Stefan Bygde's paper "Static WCET analysis based on abstract // interpretation and counting of elements" provides a precise operator, // but it only works with positive numbers. // Special case: 0Z+0 % a'Z+b' if (lhs.modulus() == 0 && lhs.residue() == 0) { return CongruenceT(0); } // Special case: 0Z+b % a'Z+b' if (lhs.modulus() == 0 && rhs.modulus() == 0) { ikos_assert(rhs.residue() != 0); return CongruenceT(lhs.residue() % rhs.residue()); } // Special case: aZ+b % 0Z+b' if (rhs.modulus() == 0) { ikos_assert(rhs.residue() != 0); if (mod(lhs.modulus(), rhs.residue()) == 0) { ZNumber n = lhs.residue() % rhs.residue(); ZNumber m = (lhs.residue() - lhs.modulus()) % rhs.residue(); return CongruenceT(n).join(CongruenceT(m)); } } // Special case: 0Z+b % a'Z+b' if (lhs.modulus() == 0) { ZNumber n = rhs.modulus() * ((abs(lhs.residue()) - rhs.residue()) / rhs.modulus()) + rhs.residue(); if (n <= 0) { return CongruenceT(lhs.residue()); } } // General case return CongruenceT(gcd(lhs.modulus(), rhs.modulus(), rhs.residue()), lhs.residue()); } } /// \brief Modulo inline Congruence< ZNumber > mod(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else if (rhs.modulus() == 0 && rhs.residue() == 0) { return CongruenceT::bottom(); } else { // Stefan Bygde's paper "Static WCET analysis based on abstract // interpretation and counting of elements" provides a precise operator, // but it only works with positive numbers. // Special case: mod(0Z+0, a'Z+b') if (lhs.modulus() == 0 && lhs.residue() == 0) { return CongruenceT(0); } // Special case: mod(aZ+b, 0Z+b'): // if b'|a then 0Z + mod(b, b') if (rhs.modulus() == 0) { ikos_assert(rhs.residue() != 0); if (mod(lhs.modulus(), rhs.residue()) == 0) { return CongruenceT(mod(lhs.residue(), rhs.residue())); } } // Special case: 0Z+b % a'Z+b' if (lhs.modulus() == 0 && lhs.residue() >= 0) { ZNumber n = rhs.modulus() * ((abs(lhs.residue()) - rhs.residue()) / rhs.modulus()) + rhs.residue(); if (n <= 0) { return CongruenceT(lhs.residue()); } } // General case return CongruenceT(gcd(lhs.modulus(), rhs.modulus(), rhs.residue()), lhs.residue()); } } /// \brief Left binary shift of congruences inline Congruence< ZNumber > operator<<(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else { if (rhs.modulus() == 0) { // aZ + b << 0Z + b' const ZNumber& b = rhs.residue(); if (b < 0) { // Invalid operand return CongruenceT::bottom(); } // aZ + b << 0Z + b' = (a*2^b')Z + b*2^b' ZNumber x = 1 << b; return CongruenceT(lhs.modulus() * x, lhs.residue() * x); } // aZ + b << a'Z + b' = (gcd(a, b * (2^a' - 1)))*(2^b')Z + b*(2^b') ZNumber x = 1 << rhs.residue(); ZNumber y = 1 << rhs.modulus(); ZNumber a = gcd(lhs.modulus(), lhs.residue() * (y - 1)) * x; ZNumber b = lhs.residue() * x; return CongruenceT(a, b); } } /// \brief Right binary shift of congruences inline Congruence< ZNumber > operator>>(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else { if (rhs.modulus() == 0) { // aZ + b >> 0Z + b' const ZNumber& b = rhs.residue(); if (b < 0) { // Invalid operand return CongruenceT::bottom(); } } if (lhs.is_zero() || rhs.is_zero()) { // 0 >> aZ + b // aZ + b >> 0 return lhs; } if (lhs.modulus() == 0 && rhs.modulus() == 0) { // 0Z + b >> 0Z + b' return CongruenceT(lhs.residue() >> rhs.residue()); } return CongruenceT::top(); } } /// \brief Bitwise AND of congruences inline Congruence< ZNumber > operator&(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else if (lhs.is_zero() || rhs.is_zero()) { return CongruenceT(0); } else if (lhs == CongruenceT(-1)) { return rhs; } else if (rhs == CongruenceT(-1)) { return lhs; } else if (lhs.modulus() == 0 && rhs.modulus() == 0) { return CongruenceT(lhs.residue() & rhs.residue()); } else { return CongruenceT::top(); } } /// \brief Bitwise OR of congruences inline Congruence< ZNumber > operator|(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else if (lhs == CongruenceT(-1) || rhs == CongruenceT(-1)) { return CongruenceT(-1); } else if (lhs.is_zero()) { return rhs; } else if (rhs.is_zero()) { return lhs; } else if (lhs.modulus() == 0 && rhs.modulus() == 0) { return CongruenceT(lhs.residue() | rhs.residue()); } else { return CongruenceT::top(); } } /// \brief Bitwise XOR of congruences inline Congruence< ZNumber > operator^(const Congruence< ZNumber >& lhs, const Congruence< ZNumber >& rhs) { using CongruenceT = Congruence< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return CongruenceT::bottom(); } else if (lhs.is_zero()) { return rhs; } else if (rhs.is_zero()) { return lhs; } else if (lhs.modulus() == 0 && rhs.modulus() == 0) { return CongruenceT(lhs.residue() ^ rhs.residue()); } else { return CongruenceT::top(); } } /// \brief Congruence on rationals /// /// We do not try to define the congruence domain on rationals. /// We instead implement this as the constant domain, for simplicity. template <> class Congruence< QNumber > final : public core::AbstractDomain< Congruence< QNumber > > { public: using NumberT = QNumber; private: QConstant _cst; public: static Congruence top() { return Congruence(QConstant::top()); } static Congruence bottom() { return Congruence(QConstant::bottom()); } explicit Congruence(int n) : _cst(n) {} explicit Congruence(QNumber n) : _cst(std::move(n)) {} explicit Congruence(QConstant cst) : _cst(std::move(cst)) {} Congruence(const QNumber&, const QNumber&) : _cst(QConstant::top()) {} Congruence(const Congruence&) = default; Congruence(Congruence&&) = default; Congruence& operator=(const Congruence&) = default; Congruence& operator=(Congruence&&) noexcept = default; ~Congruence() override = default; void normalize() override { this->_cst.normalize(); } bool is_bottom() const override { return this->_cst.is_bottom(); } bool is_top() const override { return this->_cst.is_top(); } bool is_zero() const { return this->_cst.is_zero(); } void set_to_bottom() override { this->_cst.set_to_bottom(); } void set_to_top() override { this->_cst.set_to_top(); } bool leq(const Congruence& other) const override { return this->_cst.leq(other._cst); } bool equals(const Congruence& other) const override { return this->_cst.equals(other._cst); } void join_with(const Congruence& other) override { this->_cst.join_with(other._cst); } void widen_with(const Congruence& other) override { this->_cst.widen_with(other._cst); } void widen_threshold_with(const Congruence& other, const QNumber& threshold) { this->_cst.widen_threshold_with(other._cst, threshold); } void meet_with(const Congruence& other) override { this->_cst.meet_with(other._cst); } void narrow_with(const Congruence& other) override { this->_cst.narrow_with(other._cst); } void narrow_threshold_with(const Congruence& other, const QNumber& threshold) { this->_cst.narrow_threshold_with(other._cst, threshold); } Congruence operator-() const { return Congruence(-this->_cst); } void operator+=(const Congruence& other) { this->_cst += other._cst; } void operator-=(const Congruence& other) { this->_cst -= other._cst; } const QConstant& to_constant() const { return this->_cst; } boost::optional< QNumber > singleton() const { return this->_cst.singleton(); } bool contains(int n) const { return this->_cst.contains(n); } bool contains(const QNumber& n) const { return this->_cst.contains(n); } void dump(std::ostream& o) const override { this->_cst.dump(o); } static std::string name() { return "congruence"; } }; // end class Congruence< QNumber > inline Congruence< QNumber > operator+(const Congruence< QNumber >& lhs, const Congruence< QNumber >& rhs) { return Congruence< QNumber >(lhs.to_constant() + rhs.to_constant()); } inline Congruence< QNumber > operator-(const Congruence< QNumber >& lhs, const Congruence< QNumber >& rhs) { return Congruence< QNumber >(lhs.to_constant() - rhs.to_constant()); } inline Congruence< QNumber > operator*(const Congruence< QNumber >& lhs, const Congruence< QNumber >& rhs) { return Congruence< QNumber >(lhs.to_constant() * rhs.to_constant()); } inline Congruence< QNumber > operator/(const Congruence< QNumber >& lhs, const Congruence< QNumber >& rhs) { return Congruence< QNumber >(lhs.to_constant() / rhs.to_constant()); } /// \brief Write a congruence on a stream template < typename Number > inline std::ostream& operator<<(std::ostream& o, const Congruence< Number >& congruence) { congruence.dump(o); return o; } /// \brief Congruence on unlimited precision integers using ZCongruence = Congruence< ZNumber >; /// \brief Congruence on unlimited precision rationals using QCongruence = Congruence< QNumber >; } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/numeric/constant.hpp000066400000000000000000000405501473507761200262120ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Constant abstract value * * Author: Arnaud J. Venet * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Constant abstract value /// /// This is either top, bottom or a constant. template < typename Number > class Constant final : public core::AbstractDomain< Constant< Number > > { public: using NumberT = Number; private: enum Kind { BottomKind, TopKind, NumberKind }; private: Kind _kind; Number _n; private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top constant explicit Constant(TopTag) : _kind(TopKind) {} /// \brief Create the bottom constant explicit Constant(BottomTag) : _kind(BottomKind) {} public: /// \brief Create the top constant static Constant top() { return Constant(TopTag{}); } /// \brief Create the bottom constant static Constant bottom() { return Constant(BottomTag{}); } /// \brief Create the constant n explicit Constant(int n) : _kind(NumberKind), _n(n) {} /// \brief Create the constant n explicit Constant(Number n) : _kind(NumberKind), _n(std::move(n)) {} /// \brief Copy constructor Constant(const Constant&) noexcept( std::is_nothrow_copy_constructible< Number >::value) = default; /// \brief Move constructor Constant(Constant&&) noexcept( std::is_nothrow_move_constructible< Number >::value) = default; /// \brief Copy assignment operator Constant& operator=(const Constant&) noexcept( std::is_nothrow_copy_assignable< Number >::value) = default; /// \brief Move assignment operator Constant& operator=(Constant&&) noexcept( std::is_nothrow_move_assignable< Number >::value) = default; /// \brief Destructor ~Constant() override = default; void normalize() override {} bool is_bottom() const override { return this->_kind == BottomKind; } bool is_top() const override { return this->_kind == TopKind; } /// \brief Return true if the constant is a number bool is_number() const { return this->_kind == NumberKind; } /// \brief Return true if the congruence is 0Z + 0 bool is_zero() const { return this->_kind == NumberKind && this->_n == 0; } void set_to_bottom() override { this->_kind = BottomKind; } void set_to_top() override { this->_kind = TopKind; } bool leq(const Constant& other) const override { switch (this->_kind) { case BottomKind: return true; case TopKind: return other._kind == TopKind; case NumberKind: return other._kind == TopKind || (other._kind == NumberKind && this->_n == other._n); default: ikos_unreachable("unreachable"); } } bool equals(const Constant& other) const override { if (this->_kind == NumberKind) { return other._kind == NumberKind && this->_n == other._n; } else { return this->_kind == other._kind; } } Constant join(const Constant& other) const override { if (this->is_bottom() || other.is_top()) { return other; } else if (this->is_top() || other.is_bottom()) { return *this; } else if (this->_n == other._n) { return *this; } else { return top(); } } void join_with(const Constant& other) override { this->operator=(this->join(other)); } Constant widening(const Constant& other) const override { // equivalent to join, domain is flat return this->join(other); } void widen_with(const Constant& other) override { // equivalent to join, domain is flat this->join_with(other); } Constant widening_threshold(const Constant& other, const Number& /*threshold*/) const { // equivalent to join, domain is flat return this->join(other); } void widen_threshold_with(const Constant& other, const Number& /*threshold*/) { // equivalent to join, domain is flat this->join_with(other); } Constant meet(const Constant& other) const override { if (this->is_bottom() || other.is_top()) { return *this; } else if (this->is_top() || other.is_bottom()) { return other; } else if (this->_n == other._n) { return *this; } else { return bottom(); } } void meet_with(const Constant& other) override { this->operator=(this->meet(other)); } Constant narrowing(const Constant& other) const override { // equivalent to meet, domain is flat return this->meet(other); } void narrow_with(const Constant& other) override { // equivalent to meet, domain is flat this->meet_with(other); } Constant narrowing_threshold(const Constant& other, const Number& /*threshold*/) const { // equivalent to meet, domain is flat return this->meet(other); } void narrow_threshold_with(const Constant& other, const Number& /*threshold*/) { // equivalent to meet, domain is flat this->meet_with(other); } /// \brief Unary minus Constant operator-() const { if (this->is_number()) { return Constant(-this->_n); } else { return *this; } } /// \brief Add constants void operator+=(const Constant& other) { if (this->is_bottom() || this->is_top()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (other.is_top()) { this->set_to_top(); } else { this->_n += other._n; } } /// \brief Substract constants void operator-=(const Constant& other) { if (this->is_bottom() || this->is_top()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (other.is_top()) { this->set_to_top(); } else { this->_n -= other._n; } } /// \brief If the constant in a number n, return n, otherwise return /// boost::none boost::optional< Number > number() const { if (this->is_number()) { return this->_n; } else { return boost::none; } } /// \brief If the constant in a singleton n, return n, otherwise return /// boost::none boost::optional< Number > singleton() const { return this->number(); } /// \brief Return true if the constant contains n bool contains(int n) const { return this->is_top() || (this->is_number() && this->_n == n); } /// \brief Return true if the constant contains n bool contains(const Number& n) const { return this->is_top() || (this->is_number() && this->_n == n); } void dump(std::ostream& o) const override { switch (this->_kind) { case BottomKind: { o << "⊥"; break; } case TopKind: { o << "T"; break; } case NumberKind: { o << this->_n; break; } } } static std::string name() { return "constant"; } // Friends template < typename T > friend Constant< T > operator+(const Constant< T >& lhs, const Constant< T >& rhs); template < typename T > friend Constant< T > operator-(const Constant< T >& lhs, const Constant< T >& rhs); template < typename T > friend Constant< T > operator*(const Constant< T >& lhs, const Constant< T >& rhs); template < typename T > friend Constant< T > operator/(const Constant< T >& lhs, const Constant< T >& rhs); friend Constant< ZNumber > operator%(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs); friend Constant< ZNumber > mod(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs); friend Constant< ZNumber > operator<<(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs); friend Constant< ZNumber > operator>>(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs); friend Constant< ZNumber > operator&(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs); friend Constant< ZNumber > operator|(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs); friend Constant< ZNumber > operator^(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs); }; // end class Constant /// \brief Add constants template < typename Number > inline Constant< Number > operator+(const Constant< Number >& lhs, const Constant< Number >& rhs) { using ConstantT = Constant< Number >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n + rhs._n); } } /// \brief Substract constants template < typename Number > inline Constant< Number > operator-(const Constant< Number >& lhs, const Constant< Number >& rhs) { using ConstantT = Constant< Number >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n - rhs._n); } } /// \brief Multiply constants template < typename Number > inline Constant< Number > operator*(const Constant< Number >& lhs, const Constant< Number >& rhs) { using ConstantT = Constant< Number >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (lhs.is_zero() || rhs.is_zero()) { return ConstantT(0); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n * rhs._n); } } /// \brief Divide constants template < typename Number > inline Constant< Number > operator/(const Constant< Number >& lhs, const Constant< Number >& rhs) { using ConstantT = Constant< Number >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (rhs.is_zero()) { return ConstantT::bottom(); } else if (lhs.is_zero()) { return ConstantT(0); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n / rhs._n); } } /// \brief Remainder of constants inline Constant< ZNumber > operator%(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs) { using ConstantT = Constant< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (rhs.is_zero()) { return ConstantT::bottom(); } else if (lhs.is_zero()) { return ConstantT(0); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n % rhs._n); } } /// \brief Modulo of constants inline Constant< ZNumber > mod(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs) { using ConstantT = Constant< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (rhs.is_zero()) { return ConstantT::bottom(); } else if (lhs.is_zero()) { return ConstantT(0); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(mod(lhs._n, rhs._n)); } } /// \brief Left binary shift of constants inline Constant< ZNumber > operator<<(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs) { using ConstantT = Constant< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (rhs.is_number() && rhs._n < 0) { return ConstantT::bottom(); } else if (lhs.is_zero()) { return ConstantT(0); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n << rhs._n); } } /// \brief Right binary shift of constants inline Constant< ZNumber > operator>>(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs) { using ConstantT = Constant< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (rhs.is_number() && rhs._n < 0) { return ConstantT::bottom(); } else if (lhs.is_zero()) { return ConstantT(0); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n >> rhs._n); } } /// \brief Bitwise AND of constants inline Constant< ZNumber > operator&(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs) { using ConstantT = Constant< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (lhs.is_zero() || rhs.is_zero()) { return ConstantT(0); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n & rhs._n); } } /// \brief Bitwise OR of constants inline Constant< ZNumber > operator|(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs) { using ConstantT = Constant< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (lhs == ConstantT(-1) || rhs == ConstantT(-1)) { return ConstantT(-1); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n | rhs._n); } } /// \brief Bitwise XOR of constants inline Constant< ZNumber > operator^(const Constant< ZNumber >& lhs, const Constant< ZNumber >& rhs) { using ConstantT = Constant< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return ConstantT::bottom(); } else if (lhs.is_top() || rhs.is_top()) { return ConstantT::top(); } else { return ConstantT(lhs._n ^ rhs._n); } } /// \brief Write a constant on a stream template < typename Number > inline std::ostream& operator<<(std::ostream& o, const Constant< Number >& cst) { cst.dump(o); return o; } /// \brief Constant on unlimited precision integers using ZConstant = Constant< ZNumber >; /// \brief Constant on unlimited precision rationals using QConstant = Constant< QNumber >; } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/numeric/gauge.hpp000066400000000000000000001327001473507761200254500ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief GaugeBound and Gauge classes * * Based on Arnaud Venet's paper: The Gauge Domain: Scalable Analysis of * Linear Inequality Invariants, in CAV, 129-154, 2012. * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Gauge bound /// /// This is either -oo, +oo or a linear expression of the non-negative loop /// counters (e.g, `1 + 2*i + 3*j`) template < typename Number, typename VariableRef > class GaugeBound { public: using BoundT = Bound< Number >; using VariableExpressionT = VariableExpression< Number, VariableRef >; using LinearExpressionT = LinearExpression< Number, VariableRef >; private: using Coefficients = PatriciaTreeMap< VariableRef, Number >; private: bool _is_infinite; Number _cst; Coefficients _coeffs; /* Invariants: * _is_infinite => _cst in {-1, 1} and _coeffs.empty() */ private: /// \brief Private constructor GaugeBound(bool is_infinite, Number cst, Coefficients coeffs) : _is_infinite(is_infinite), _cst(std::move(cst)), _coeffs(std::move(coeffs)) { if (this->_is_infinite) { this->_coeffs.clear(); this->_cst = (this->_cst >= 0) ? 1 : -1; } } /// \brief Private constructor GaugeBound(bool is_infinite, int cst, Coefficients coeffs) : _is_infinite(is_infinite), _cst(cst), _coeffs(std::move(coeffs)) { if (this->_is_infinite) { this->_coeffs.clear(); this->_cst = (cst >= 0) ? 1 : -1; } } public: /// \brief Return +oo static GaugeBound plus_infinity() { return GaugeBound(true, 1, Coefficients()); } /// \brief Return -oo static GaugeBound minus_infinity() { return GaugeBound(true, -1, Coefficients()); } /// \brief Create the gauge bound `n` explicit GaugeBound(int n) : _is_infinite(false), _cst(n) {} /// \brief Create the gauge bound `n` explicit GaugeBound(Number n) : _is_infinite(false), _cst(std::move(n)) {} /// \brief Create the gauge bound `1*v` explicit GaugeBound(VariableRef v) : _is_infinite(false), _cst(0) { this->_coeffs.insert_or_assign(v, Number(1)); } /// \brief Create a gauge bound from bound `b` explicit GaugeBound(const BoundT& b) : _is_infinite(b.is_infinite()) { if (b.is_plus_infinity()) { this->_cst = 1; } else if (b.is_minus_infinity()) { this->_cst = -1; } else { this->_cst = *b.number(); } } /// \brief Create the gauge bound `n*v` GaugeBound(int n, VariableRef v) : _is_infinite(false), _cst(0) { this->_coeffs.insert_or_assign(v, Number(n)); } /// \brief Create the gauge bound `n*v` GaugeBound(const Number& n, VariableRef v) : _is_infinite(false), _cst(0) { this->_coeffs.insert_or_assign(v, n); } /// \brief Copy constructor GaugeBound(const GaugeBound&) noexcept( std::is_nothrow_copy_constructible< Number >::value) = default; /// \brief Move constructor GaugeBound(GaugeBound&&) noexcept( std::is_nothrow_move_constructible< Number >::value) = default; /// \brief Assign a number GaugeBound& operator=(int n) { this->_is_infinite = false; this->_cst = n; this->_coeffs.clear(); return *this; } /// \brief Assign a number GaugeBound& operator=(Number n) { this->_is_infinite = false; this->_n = std::move(n); this->_coeffs.clear(); return *this; } /// \brief Copy assignment operator GaugeBound& operator=(const GaugeBound&) noexcept( std::is_nothrow_copy_assignable< Number >::value) = default; /// \brief Move assignment operator GaugeBound& operator=(GaugeBound&&) noexcept( std::is_nothrow_move_assignable< Number >::value) = default; /// \brief Destructor ~GaugeBound() = default; /// \brief Return true if the bound is infinite bool is_infinite() const { return this->_is_infinite; } /// \brief Return true if the bound is finite bool is_finite() const { return !this->_is_infinite; } /// \brief Return true if the bound is plus infinity bool is_plus_infinity() const { return this->_is_infinite && this->_cst == 1; } /// \brief Return true if the bound is minus infinity bool is_minus_infinity() const { return this->_is_infinite && this->_cst == -1; } /// \brief Return true if the bound is a constant bool is_constant() const { return !this->_is_infinite && this->_coeffs.empty(); } /// \brief Return the constant const Number& constant() const { ikos_assert(this->is_finite()); return this->_cst; } /// \brief Return the number of coefficients std::size_t num_coeffs() const { ikos_assert(this->is_finite()); return this->_coeffs.size(); } /// \brief Return the coefficient for the variable `v` Number coeff(VariableRef v) const { ikos_assert(this->is_finite()); boost::optional< const Number& > c = this->_coeffs.at(v); if (c) { return *c; } else { return Number(0); } } /// \brief Return the sum of the coefficients Number sum_coeffs() const { ikos_assert(this->is_finite()); Number r(0); for (auto it = this->_coeffs.begin(), et = this->_coeffs.end(); it != et; ++it) { r += it->second; } return r; } /// \brief Return the gauge bound as a numeric bound or boost::none boost::optional< BoundT > to_bound() const { if (this->_is_infinite) { if (this->_cst == 1) { return BoundT::plus_infinity(); } else { return BoundT::minus_infinity(); } } else if (this->_coeffs.empty()) { return BoundT(this->_cst); } else { return boost::none; } } private: /// \brief Apply a binary operator on coefficients template < typename BinaryOp > static typename BinaryOp::ResultType apply_binary_operation( const Coefficients& c1, const Coefficients& c2, const BinaryOp& op) { return c1.binary_operation(c2, op); } /// \brief Apply an unary operator on coefficients template < typename UnaryOp > static Coefficients apply_unary_operation(Coefficients c, const UnaryOp& op) { c.transform(op); return c; } /// \brief Join separated coefficient trees static Coefficients join_separated(const Coefficients& c1, const Coefficients& c2) { return c1.join(c2, [](const Number&, const Number&) { ikos_unreachable("trees are not separated"); return boost::optional< Number >(boost::none); }); } private: /// \brief Add binary operator struct NumberAdd { boost::optional< Number > operator()(const Number& x, const Number& y) const { return x + y; } }; /// \brief Negate binary operator struct GaugeBoundNeg { boost::optional< Number > operator()(VariableRef, const Number& x) const { return -x; } }; public: /// \brief Unary minus GaugeBound operator-() const { return GaugeBound(this->_is_infinite, -this->_cst, apply_unary_operation(this->_coeffs, GaugeBoundNeg{})); } private: /// \brief Add binary operator struct GaugeBoundAdd { using ResultType = Coefficients; bool has_equals() const { return false; } Coefficients equals(const Coefficients&) const { ikos_unreachable("unreachable"); return Coefficients(); } Coefficients left(const Coefficients& c) const { return c; } Coefficients right(const Coefficients& c) const { return c; } Coefficients left_with_right_leaf(Coefficients c, VariableRef v, const Number& n) const { c.update_or_insert(NumberAdd{}, v, n); return c; } Coefficients right_with_left_leaf(Coefficients c, VariableRef v, const Number& n) const { c.update_or_insert(NumberAdd{}, v, n); return c; } Coefficients merge(const Coefficients& l, const Coefficients& r) const { return join_separated(l, r); } }; public: /// \brief Add a number GaugeBound operator+(const Number& n) const { if (this->is_finite()) { return GaugeBound(false, this->_cst + n, this->_coeffs); } else { return *this; } } /// \brief Add gauge bounds GaugeBound operator+(const GaugeBound& other) const { if (this->is_finite() && other.is_finite()) { return GaugeBound(false, this->_cst + other._cst, apply_binary_operation(this->_coeffs, other._coeffs, GaugeBoundAdd{})); } else if (this->is_finite() && other.is_infinite()) { return other; } else if (this->is_infinite() && other.is_finite()) { return *this; } else if (this->_cst == other._cst) { return *this; } else { ikos_unreachable("undefined operation -oo + +oo"); } } /// \brief Add gauge bounds GaugeBound& operator+=(const GaugeBound& other) { return this->operator=(this->operator+(other)); } private: /// \brief Sub binary operator struct GaugeBoundSub { using ResultType = Coefficients; bool has_equals() const { return true; } Coefficients equals(const Coefficients&) const { return Coefficients(); // x - x } Coefficients left(const Coefficients& c) const { return c; } Coefficients right(const Coefficients& c) const { return apply_unary_operation(c, GaugeBoundNeg{}); } Coefficients left_with_right_leaf(Coefficients c, VariableRef v, const Number& n) const { c.update_or_insert(NumberAdd{}, v, -n); return c; } Coefficients right_with_left_leaf(Coefficients c, VariableRef v, const Number& n) const { c.transform(GaugeBoundNeg{}); c.update_or_insert(NumberAdd{}, v, n); return c; } Coefficients merge(const Coefficients& l, const Coefficients& r) const { return join_separated(l, r); } }; public: /// \brief Substract a number GaugeBound operator-(const Number& n) const { if (this->is_finite()) { return GaugeBound(false, this->_cst - n, this->_coeffs); } else { return *this; } } /// \brief Substract bounds GaugeBound operator-(const GaugeBound& other) const { if (this->is_finite() && other.is_finite()) { return GaugeBound(false, this->_cst - other._cst, apply_binary_operation(this->_coeffs, other._coeffs, GaugeBoundSub{})); } else if (this->is_finite() && other.is_infinite()) { return other.operator-(); } else if (this->is_infinite() && other.is_finite()) { return *this; } else if (this->_cst == -other._cst) { return *this; } else { ikos_unreachable("undefined operation +oo - +oo"); } } /// \brief Substract bounds GaugeBound& operator-=(const GaugeBound& other) { return this->operator=(this->operator-(other)); } private: /// \brief Multiplication by a constant struct GaugeBoundMul { Number c; boost::optional< Number > operator()(VariableRef, const Number& x) const { return x * c; } }; public: /// \brief Multiply by a number GaugeBound operator*(const Number& c) const { if (c == 0) { return GaugeBound(0); } else if (this->is_finite()) { return GaugeBound(false, this->_cst * c, apply_unary_operation(this->_coeffs, GaugeBoundMul{c})); } else { return GaugeBound(true, this->_cst * c, Coefficients()); } } /// \brief Multiply by a constant GaugeBound& operator*=(const Number& c) { return this->operator=(this->operator*(c)); } private: /// \brief Compare bounds struct GaugeBoundLeq { using ResultType = bool; bool has_equals() const { return true; } bool equals(const Coefficients&) const { return true; // x <= x } bool left(const Coefficients& c) const { return std::all_of(c.begin(), c.end(), [](const auto& binding) { return binding.second <= 0; }); } bool right(const Coefficients& c) const { return std::all_of(c.begin(), c.end(), [](const auto& binding) { return 0 <= binding.second; }); } bool left_with_right_leaf(const Coefficients& c, VariableRef v, const Number& n) const { if (!c.at(v)) { if (!(0 <= n)) { return false; } } return std::all_of(c.begin(), c.end(), [v, n](const auto& binding) { if (binding.first == v) { return binding.second <= n; } else { return binding.second <= 0; } }); } bool right_with_left_leaf(const Coefficients& c, VariableRef v, const Number& n) const { if (!c.at(v)) { if (!(n <= 0)) { return false; } } return std::all_of(c.begin(), c.end(), [v, n](const auto& binding) { if (binding.first == v) { return n <= binding.second; } else { return 0 <= binding.second; } }); } bool merge(bool l, bool r) const { return l && r; } }; /// \brief Compare bounds struct GaugeBoundGeq { using ResultType = bool; bool has_equals() const { return true; } bool equals(const Coefficients&) const { return true; // x >= x } bool left(const Coefficients& c) const { return std::all_of(c.begin(), c.end(), [](const auto& binding) { return binding.second >= 0; }); } bool right(const Coefficients& c) const { return std::all_of(c.begin(), c.end(), [](const auto& binding) { return 0 >= binding.second; }); } bool left_with_right_leaf(const Coefficients& c, VariableRef v, const Number& n) const { if (!c.at(v)) { if (!(0 >= n)) { return false; } } return std::all_of(c.begin(), c.end(), [v, n](const auto& binding) { if (binding.first == v) { return binding.second >= n; } else { return binding.second >= 0; } }); } bool right_with_left_leaf(const Coefficients& c, VariableRef v, const Number& n) const { if (!c.at(v)) { if (!(n >= 0)) { return false; } } return std::all_of(c.begin(), c.end(), [v, n](const auto& binding) { if (binding.first == v) { return n >= binding.second; } else { return 0 >= binding.second; } }); } bool merge(bool l, bool r) const { return l && r; } }; /// \brief Compare bounds struct GaugeBoundEq { using ResultType = bool; bool has_equals() const { return true; } bool equals(const Coefficients&) const { return true; // x == x } bool left(const Coefficients& c) const { return std::all_of(c.begin(), c.end(), [](const auto& binding) { return binding.second == 0; }); } bool right(const Coefficients& c) const { return std::all_of(c.begin(), c.end(), [](const auto& binding) { return 0 == binding.second; }); } bool left_with_right_leaf(const Coefficients& c, VariableRef v, const Number& n) const { if (!c.at(v)) { if (n != 0) { return false; } } return std::all_of(c.begin(), c.end(), [v, n](const auto& binding) { if (binding.first == v) { return binding.second == n; } else { return binding.second == 0; } }); } bool right_with_left_leaf(const Coefficients& c, VariableRef v, const Number& n) const { if (!c.at(v)) { if (n != 0) { return false; } } return std::all_of(c.begin(), c.end(), [v, n](const auto& binding) { if (binding.first == v) { return n == binding.second; } else { return 0 == binding.second; } }); } bool merge(bool l, bool r) const { return l && r; } }; public: /// \brief Lower or equal comparison bool operator<=(const GaugeBound& other) const { if (this->_is_infinite && other._is_infinite) { return this->_cst <= other._cst; } else if (this->_is_infinite) { return this->_cst < 0; } else if (other._is_infinite) { return other._cst > 0; } else { return this->_cst <= other._cst && apply_binary_operation(this->_coeffs, other._coeffs, GaugeBoundLeq{}); } } /// \brief Greater or equal comparison bool operator>=(const GaugeBound& other) const { if (this->_is_infinite && other._is_infinite) { return this->_cst >= other._cst; } else if (this->_is_infinite) { return this->_cst > 0; } else if (other._is_infinite) { return other._cst < 0; } else { return this->_cst >= other._cst && apply_binary_operation(this->_coeffs, other._coeffs, GaugeBoundGeq{}); } } /// \brief Lower comparison bool operator<(const GaugeBound& other) const { return !this->operator>=(other); } /// \brief Greater comparison bool operator>(const GaugeBound& other) const { return !this->operator<=(other); } /// \brief Equal comparison bool operator==(const GaugeBound& other) const { return this->_is_infinite == other._is_infinite && this->_cst == other._cst && apply_binary_operation(this->_coeffs, other._coeffs, GaugeBoundEq{}); } /// \brief Not equal comparison bool operator!=(const GaugeBound& other) const { return !this->operator==(other); } private: /// \brief Min with 0 struct MinZero { boost::optional< Number > operator()(VariableRef, const Number& x) const { return min(x, Number(0)); } }; /// \brief Min with 0 if it is not `u` struct MinZeroIfNot { VariableRef u; boost::optional< Number > operator()(VariableRef v, const Number& x) const { if (u == v) { return x; } return min(x, Number(0)); } }; /// \brief Min binary operator struct GaugeBoundMin { using ResultType = Coefficients; bool has_equals() const { return true; } Coefficients equals(const Coefficients& c) const { return c; // min(x, x) } Coefficients left(const Coefficients& c) const { return apply_unary_operation(c, MinZero{}); } Coefficients right(const Coefficients& c) const { return apply_unary_operation(c, MinZero{}); } Coefficients tree_with_leaf(Coefficients c, VariableRef v, const Number& x) const { auto y = c.at(v); if (y) { c.insert_or_assign(v, min(x, *y)); } else { c.insert_or_assign(v, min(x, Number(0))); } return apply_unary_operation(c, MinZeroIfNot{v}); } Coefficients left_with_right_leaf(Coefficients c, VariableRef v, const Number& x) const { return tree_with_leaf(c, v, x); } Coefficients right_with_left_leaf(Coefficients c, VariableRef v, const Number& x) const { return tree_with_leaf(c, v, x); } Coefficients merge(const Coefficients& l, const Coefficients& r) const { return join_separated(l, r); } }; public: /// \brief Return the min of the given bounds, as defined in the paper friend GaugeBound min(const GaugeBound& x, const GaugeBound& y) { if (x.is_infinite() || y.is_infinite()) { return (x <= y) ? x : y; } else { return GaugeBound(false, min(x._cst, y._cst), apply_binary_operation(x._coeffs, y._coeffs, GaugeBoundMin{})); } } /// \brief Return the min of the given bounds, as defined in the paper friend GaugeBound min(const GaugeBound& x, const GaugeBound& y, const GaugeBound& z) { return min(x, min(y, z)); } /// \brief Return the min of the given bounds, as defined in the paper friend GaugeBound min(const GaugeBound& x, const GaugeBound& y, const GaugeBound& z, const GaugeBound& t) { return min(min(x, y), min(z, t)); } private: /// \brief Max with 0 struct MaxZero { boost::optional< Number > operator()(VariableRef, const Number& x) const { return max(x, Number(0)); } }; /// \brief Max with 0 if it is not `u` struct MaxZeroIfNot { VariableRef u; boost::optional< Number > operator()(VariableRef v, const Number& x) const { if (u == v) { return x; } return max(x, Number(0)); } }; /// \brief Max binary operator struct GaugeBoundMax { using ResultType = Coefficients; bool has_equals() const { return true; } Coefficients equals(const Coefficients& c) const { return c; } Coefficients left(const Coefficients& c) const { return apply_unary_operation(c, MaxZero{}); } Coefficients right(const Coefficients& c) const { return apply_unary_operation(c, MaxZero{}); } Coefficients tree_with_leaf(Coefficients c, VariableRef v, const Number& x) const { auto y = c.at(v); if (y) { c.insert_or_assign(v, max(x, *y)); } else { c.insert_or_assign(v, max(x, Number(0))); } return apply_unary_operation(c, MaxZeroIfNot{v}); } Coefficients left_with_right_leaf(Coefficients c, VariableRef v, const Number& x) const { return tree_with_leaf(c, v, x); } Coefficients right_with_left_leaf(Coefficients c, VariableRef v, const Number& x) const { return tree_with_leaf(c, v, x); } Coefficients merge(const Coefficients& l, const Coefficients& r) const { return join_separated(l, r); } }; public: /// \brief Return the max of the given bounds, as defined in the paper friend GaugeBound max(const GaugeBound& x, const GaugeBound& y) { if (x.is_infinite() || y.is_infinite()) { return (x <= y) ? y : x; } else { return GaugeBound(false, max(x._cst, y._cst), apply_binary_operation(x._coeffs, y._coeffs, GaugeBoundMax{})); } } /// \brief Return the max of the given bounds, as defined in the paper friend GaugeBound max(const GaugeBound& x, const GaugeBound& y, const GaugeBound& z) { return max(x, max(y, z)); } /// \brief Return the max of the given bounds, as defined in the paper friend GaugeBound max(const GaugeBound& x, const GaugeBound& y, const GaugeBound& z, const GaugeBound& t) { return max(max(x, y), max(z, t)); } /// \brief Return the gauge bound as a linear expression LinearExpressionT lin_expr() const { ikos_assert(this->is_finite()); LinearExpressionT e(this->_cst); for (auto it = this->_coeffs.begin(), et = this->_coeffs.end(); it != et; ++it) { e.add(it->second, it->first); } return e; } /// \brief Write the gauge bound on a stream void dump(std::ostream& o) const { if (this->is_plus_infinity()) { o << "+oo"; } else if (this->is_minus_infinity()) { o << "-oo"; } else { bool first = true; for (auto it = this->_coeffs.begin(), et = this->_coeffs.end(); it != et; ++it) { const Number& c = it->second; const VariableRef& v = it->first; if (c == 0) { continue; } else if (c > 0 && !first) { o << "+"; } if (c == -1) { o << "-"; } else if (c != 1) { o << c; } DumpableTraits< VariableRef >::dump(o, v); first = false; } if (this->_cst > 0 && !first) { o << "+"; } if (this->_cst != 0 || first) { o << this->_cst; } } } }; // end class GaugeBound /// \brief Write a bound on a stream template < typename Number, typename VariableRef > inline std::ostream& operator<<( std::ostream& o, const GaugeBound< Number, VariableRef >& bound) { bound.dump(o); return o; } /// \brief Gauge abstract value /// /// This is implemented as a pair of gauge bounds template < typename Number, typename VariableRef > class Gauge final : public core::AbstractDomain< Gauge< Number, VariableRef > > { public: using BoundT = Bound< Number >; using GaugeBoundT = GaugeBound< Number, VariableRef >; using ConstantT = Constant< Number >; using IntervalT = Interval< Number >; private: // Lower bound GaugeBoundT _lb; // Upper bound GaugeBoundT _ub; // Invariant: _lb > _ub <=> _lb = 1 && _ub = 0 <=> is_bottom() private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top gauge [-oo, +oo] explicit Gauge(TopTag) : _lb(GaugeBoundT::minus_infinity()), _ub(GaugeBoundT::plus_infinity()) {} /// \brief Create the bottom gauge explicit Gauge(BottomTag) : _lb(1), _ub(0) {} public: /// \brief Create the gauge [-oo, +oo] static Gauge top() { return Gauge(TopTag{}); } /// \brief Create the bottom gauge static Gauge bottom() { return Gauge(BottomTag{}); } /// \brief Create the gauge [n, n] explicit Gauge(int n) : _lb(n), _ub(n) {} /// \brief Create the gauge [n, n] explicit Gauge(const Number& n) : _lb(n), _ub(n) {} /// \brief Create the gauge [b, b] explicit Gauge(const GaugeBoundT& b) : _lb(b), _ub(b) { ikos_assert(!b.is_infinite()); } /// \brief Create the gauge [lb, ub] /// /// If lb > ub, the gauge is bottom. Gauge(GaugeBoundT lb, GaugeBoundT ub) : _lb(std::move(lb)), _ub(std::move(ub)) { if (this->_lb > this->_ub) { this->_lb = 1; this->_ub = 0; } } /// \brief Create a gauge from an interval explicit Gauge(const IntervalT& i) : _lb(1), _ub(0) { if (!i.is_bottom()) { this->_lb = GaugeBoundT(i.lb()); this->_ub = GaugeBoundT(i.ub()); } } /// \brief Copy constructor Gauge(const Gauge&) noexcept( std::is_nothrow_copy_constructible< Number >::value) = default; /// \brief Move constructor Gauge(Gauge&&) noexcept(std::is_nothrow_move_constructible< Number >::value) = default; /// \brief Copy assignment operator Gauge& operator=(const Gauge&) noexcept( std::is_nothrow_copy_assignable< Number >::value) = default; /// \brief Move assignment operator Gauge& operator=(Gauge&&) noexcept( std::is_nothrow_move_assignable< Number >::value) = default; /// \brief Destructor ~Gauge() override = default; /// \brief Return the lower bound const GaugeBoundT& lb() const { ikos_assert(!this->is_bottom()); return this->_lb; } /// \brief Return the upper bound const GaugeBoundT& ub() const { ikos_assert(!this->is_bottom()); return this->_ub; } void normalize() override {} bool is_bottom() const override { return this->_lb > this->_ub; } bool is_top() const override { return this->_lb.is_infinite() && this->_ub.is_infinite(); } void set_to_bottom() override { this->_lb = 1; this->_ub = 0; } void set_to_top() override { this->_lb = GaugeBoundT::minus_infinity(); this->_ub = GaugeBoundT::plus_infinity(); } bool leq(const Gauge& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return other._lb <= this->_lb && this->_ub <= other._ub; } } bool equals(const Gauge& other) const override { if (is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_lb == other._lb && this->_ub == other._ub; } } Gauge join(const Gauge& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return Gauge(min(this->_lb, other._lb), max(this->_ub, other._ub)); } } void join_with(const Gauge& other) override { this->operator=(this->join(other)); } /// \brief Meet /// /// Implementation based on X. Wu, L. Chen and J. Wang's paper: An Abstract /// Domain to Infer Symbolic Ranges over Nonnegative Parameters. /// /// It uses a heuristic because, in general, the greatest lower bound /// cannot be defined. Gauge meet(const Gauge& other) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { // lower bound GaugeBoundT lb = GaugeBoundT::minus_infinity(); if (other._lb <= this->_lb) { lb = this->_lb; } else if (this->_lb <= other._lb) { lb = other._lb; } else { // no order, use a heuristic lb = (this->_lb.constant() + this->_lb.sum_coeffs() >= other._lb.constant() + other._lb.sum_coeffs()) ? this->_lb : other._lb; } // upper bound GaugeBoundT ub = GaugeBoundT::plus_infinity(); if (this->_ub <= other._ub) { ub = this->_ub; } else if (other._ub <= this->_ub) { ub = other._ub; } else { // no order, use a heuristic ub = (this->_ub.constant() + this->_ub.sum_coeffs() <= other._ub.constant() + other._ub.sum_coeffs()) ? this->_ub : other._ub; } if (lb.is_infinite() || ub.is_infinite() || (lb.is_constant() && ub.is_constant())) { // in that case, it is safe to use [lb, ub] return Gauge(lb, ub); } else { // use max(lb, ub) so that the gauge is not empty return Gauge(lb, max(lb, ub)); } } } void meet_with(const Gauge& other) override { this->operator=(this->meet(other)); } /// \brief Unary minus Gauge operator-() const { if (this->is_bottom()) { return bottom(); } else { return Gauge(-this->_ub, -this->_lb); } } /// \brief Add gauges Gauge operator+(const Gauge& other) const { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { return Gauge(this->_lb + other._lb, this->_ub + other._ub); } } /// \brief Add gauges Gauge& operator+=(const Gauge& other) { return this->operator=(this->operator+(other)); } /// \brief Substract gauges Gauge operator-(const Gauge& other) const { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { return Gauge(this->_lb - other._ub, this->_ub - other._lb); } } /// \brief Substract gauges Gauge& operator-=(const Gauge& other) { return this->operator=(this->operator-(other)); } /// \brief Multiply by a constant Gauge operator*(const Number& c) const { if (this->is_bottom()) { return bottom(); } else if (c >= 0) { return Gauge(this->_lb * c, this->_ub * c); } else { return Gauge(this->_ub * c, this->_lb * c); } } /// \brief Multiply by an interval Gauge operator*(const IntervalT& i) const { if (this->is_bottom() || i.is_bottom()) { return bottom(); } else if (i.is_top()) { return top(); } else if (i.lb().is_infinite()) { // i = [-oo, u] Number u = *i.ub().number(); if (this->_lb >= GaugeBoundT(0)) { return Gauge(GaugeBoundT::minus_infinity(), max(this->_lb * u, this->_ub * u)); } else if (this->_ub <= GaugeBoundT(0)) { return Gauge(min(this->_lb * u, this->_ub * u), GaugeBoundT::plus_infinity()); } else { return top(); } } else if (i.ub().is_infinite()) { // i = [l, +oo] Number l = *i.lb().number(); if (this->_lb >= GaugeBoundT(0)) { return Gauge(min(this->_lb * l, this->_ub * l), GaugeBoundT::plus_infinity()); } else if (this->_ub <= GaugeBoundT(0)) { return Gauge(GaugeBoundT::minus_infinity(), max(this->_lb * l, this->_ub * l)); } else { return top(); } } else { Number l = *i.lb().number(); Number u = *i.ub().number(); GaugeBoundT ll = this->_lb * l; GaugeBoundT lu = this->_lb * u; GaugeBoundT ul = this->_ub * l; GaugeBoundT uu = this->_ub * u; return Gauge(min(ll, lu, ul, uu), max(ll, lu, ul, uu)); } } /// \brief Forget a counter variable Gauge forget(VariableRef v) const { if (!this->is_bottom() && ((this->_lb.is_finite() && this->_lb.coeff(v) != 0) || (this->_ub.is_finite() && this->_ub.coeff(v) != 0))) { return top(); } else { return *this; } } /// \brief Coalesce operation, as described in the paper /// /// Note that the definition of coalesce() in Arnaud's paper is wrong because /// coefficients can be negative. Gauge coalesce(VariableRef v, const Number& l, const BoundT& u) const { if (this->is_bottom()) { return bottom(); } else { GaugeBoundT lb = this->_lb; if (this->_lb.is_finite()) { Number lb_v = this->_lb.coeff(v); if (lb_v > 0) { lb = this->_lb + lb_v * l + GaugeBoundT(-lb_v, v); } else if (lb_v < 0) { if (u.is_finite()) { lb = this->_lb + lb_v * (*u.number()) + GaugeBoundT(-lb_v, v); } else { lb = GaugeBoundT::minus_infinity(); } } } GaugeBoundT ub = this->_ub; if (this->_ub.is_finite()) { Number ub_v = this->_ub.coeff(v); if (ub_v > 0) { if (u.is_finite()) { ub = this->_ub + ub_v * (*u.number()) + GaugeBoundT(-ub_v, v); } else { ub = GaugeBoundT::plus_infinity(); } } else if (ub_v < 0) { ub = this->_ub + ub_v * l + GaugeBoundT(-ub_v, v); } } return Gauge(lb, ub); } } /// \brief Increment counter, as described in the paper /// /// Note that there is a typo in the paper, it should be: /// [min(a_0 - k*a_j, b_0 - k*b_j) + ..; max(a_0 - k*a_j, b_0 - k*_bj) + ...] Gauge counter_incr(VariableRef v, const Number& k) const { if (this->is_bottom()) { return bottom(); } else if (this->_lb.is_finite() && this->_ub.is_finite()) { Number lb_new_cst = this->_lb.constant() - k * this->_lb.coeff(v); Number ub_new_cst = this->_ub.constant() - k * this->_ub.coeff(v); return Gauge(this->_lb - this->_lb.constant() + min(lb_new_cst, ub_new_cst), this->_ub - this->_ub.constant() + max(lb_new_cst, ub_new_cst)); } else if (this->_lb.is_finite()) { return Gauge(this->_lb - k * this->_lb.coeff(v), GaugeBoundT::plus_infinity()); } else if (this->_ub.is_finite()) { return Gauge(GaugeBoundT::minus_infinity(), this->_ub - k * this->_ub.coeff(v)); } else { return top(); } } private: /// \brief Division with rounding towards -oo static Number div_round_low(Number num, Number den) { if (den < 0) { num = -num; den = -den; } Number q = num / den; Number r = num % den; if (r == 0 || num > 0) { return q; } else { return q - 1; } } /// \brief Division with rounding towards +oo static Number div_round_up(Number num, Number den) { if (den < 0) { num = -num; den = -den; } Number q = num / den; Number r = num % den; if (r == 0 || num < 0) { return q; } else { return q + 1; } } public: /// \brief Widening by linear interpolation /// /// \f$G \nabla^{k}_{u,v} G'\f$ in Arnaud's paper Gauge widening_interpol(const Gauge& other, VariableRef k, const Number& u, const ConstantT& v) const { ikos_assert(ConstantT(u) != v); if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { bool lb_is_finite = this->_lb.is_finite() && other._lb.is_finite(); bool ub_is_finite = this->_ub.is_finite() && other._ub.is_finite(); Number lb_slope; Number ub_slope; if (v.is_number()) { Number v_num = *v.number(); if (lb_is_finite) { lb_slope = div_round_low((other._lb.constant() + other._lb.coeff(k) * v_num) - (this->_lb.constant() + this->_lb.coeff(k) * u), v_num - u); } if (ub_is_finite) { ub_slope = div_round_up((other._ub.constant() + other._ub.coeff(k) * v_num) - (this->_ub.constant() + this->_ub.coeff(k) * u), v_num - u); } } else { if (lb_is_finite) { lb_slope = other._lb.coeff(k); } if (ub_is_finite) { ub_slope = other._ub.coeff(k); } } Number lb_new_cst; Number ub_new_cst; if (lb_is_finite) { lb_new_cst = this->_lb.constant() + this->_lb.coeff(k) * u - lb_slope * u; if (v.is_top()) { lb_new_cst = min(lb_new_cst, other._lb.constant()); } } if (ub_is_finite) { ub_new_cst = this->_ub.constant() + this->_ub.coeff(k) * u - ub_slope * u; if (v.is_top()) { ub_new_cst = max(ub_new_cst, other._ub.constant()); } } GaugeBoundT lb = min(this->_lb, other._lb); GaugeBoundT ub = max(this->_ub, other._ub); if (lb_is_finite && ub_is_finite) { lb += GaugeBoundT(min(lb_new_cst, ub_new_cst) - lb.constant()) + GaugeBoundT(min(lb_slope, ub_slope) - lb.coeff(k), k); ub += GaugeBoundT(max(lb_new_cst, ub_new_cst) - ub.constant()) + GaugeBoundT(max(lb_slope, ub_slope) - ub.coeff(k), k); } else if (lb_is_finite) { lb += GaugeBoundT(lb_new_cst - lb.constant()) + GaugeBoundT(lb_slope - lb.coeff(k), k); } else if (ub_is_finite) { ub += GaugeBoundT(ub_new_cst - ub.constant()) + GaugeBoundT(ub_slope - ub.coeff(k), k); } return Gauge(lb, ub); } } /// \brief Interval-like widening /// /// \f$\nabla_{I}\f$ in Arnaud's paper Gauge widening_interval(const Gauge& other) const { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return Gauge(this->_lb <= other._lb ? this->_lb : GaugeBoundT::minus_infinity(), other._ub <= this->_ub ? this->_ub : GaugeBoundT::plus_infinity()); } } /// \brief Interval-like widening with a threshold Gauge widening_interval_threshold(const Gauge& other, const Number& threshold) const { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { GaugeBoundT th = GaugeBoundT(threshold); GaugeBoundT lb = this->_lb; if (other._lb < this->_lb) { if (th <= other._lb) { lb = th; } else { lb = GaugeBoundT::minus_infinity(); } } GaugeBoundT ub = this->_ub; if (other._ub > this->_ub) { if (th >= other._ub) { ub = th; } else { ub = GaugeBoundT::plus_infinity(); } } return Gauge(lb, ub); } } /// \brief Widening /// /// Default to interval-like widening Gauge widening(const Gauge& other) const override { return this->widening_interval(other); } void widen_with(const Gauge& other) override { this->operator=(this->widening(other)); } Gauge narrowing(const Gauge& other) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { GaugeBoundT lb = this->_lb.is_infinite() ? other._lb : this->_lb; GaugeBoundT ub = this->_ub.is_infinite() ? other._ub : this->_ub; if (lb.is_infinite() || ub.is_infinite() || (lb.is_constant() && ub.is_constant())) { // in that case, it is safe to use [lb, ub] return Gauge(lb, ub); } else { // use max(lb, ub) so that the gauge is not empty return Gauge(lb, max(lb, ub)); } } } void narrow_with(const Gauge& other) override { this->operator=(this->narrowing(other)); } /// \brief Interval-like narrowing with a threshold Gauge narrowing_interval_threshold(const Gauge& other, const Number& threshold) const { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { GaugeBoundT th = GaugeBoundT(threshold); GaugeBoundT lb = this->_lb.is_infinite() || this->_lb == th ? other._lb : this->_lb; GaugeBoundT ub = this->_ub.is_infinite() || this->_ub == th ? other._ub : this->_ub; if (lb.is_infinite() || ub.is_infinite() || (lb.is_constant() && ub.is_constant())) { // in that case, it is safe to use [lb, ub] return Gauge(lb, ub); } else { // use max(lb, ub) so that the gauge is not empty return Gauge(lb, max(lb, ub)); } } } /// \brief If the gauge is a singleton [n, n], return n, otherwise return /// boost::none boost::optional< GaugeBoundT > singleton() const { if (!this->is_bottom() && this->_lb == this->_ub) { return this->_lb; } else { return boost::none; } } /// \brief Convert the gauge to an interval /// /// Return boost::none if one of the bound contains a variable. boost::optional< IntervalT > interval() const { if (this->is_bottom()) { return IntervalT::bottom(); } else { boost::optional< BoundT > lb = this->_lb.to_bound(); boost::optional< BoundT > ub = this->_ub.to_bound(); if (lb && ub) { return IntervalT(*lb, *ub); } else { return boost::none; } } } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "[" << this->_lb << ", " << this->_ub << "]"; } } static std::string name() { return "gauge"; } }; // end class Gauge /// \brief Write a gauge on a stream template < typename Number, typename VariableRef > inline std::ostream& operator<<(std::ostream& o, const Gauge< Number, VariableRef >& gauge) { gauge.dump(o); return o; } } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/numeric/interval.hpp000066400000000000000000000601041473507761200262020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Interval class * * Author: Arnaud J. Venet * * Contributors: * * Alexandre C. D. Wimmers * * Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Interval abstract value /// /// Implemented as a pair of bounds template < typename Number > class Interval final : public core::AbstractDomain< Interval< Number > > { public: using NumberT = Number; using BoundT = Bound< Number >; private: // Lower bound BoundT _lb; // Upper bound BoundT _ub; // Invariant: is_bottom() <=> _lb = 1 && _ub = 0 private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top interval [-oo, +oo] explicit Interval(TopTag) : _lb(BoundT::minus_infinity()), _ub(BoundT::plus_infinity()) {} /// \brief Create the bottom interval explicit Interval(BottomTag) : _lb(1), _ub(0) {} public: /// \brief Create the interval [-oo, +oo] static Interval top() { return Interval(TopTag{}); } /// \brief Create the bottom interval static Interval bottom() { return Interval(BottomTag{}); } /// \brief Create the interval [n, n] explicit Interval(int n) : _lb(n), _ub(n) {} /// \brief Create the interval [n, n] explicit Interval(const Number& n) : _lb(n), _ub(n) {} /// \brief Create the interval [b, b] explicit Interval(const BoundT& b) : _lb(b), _ub(b) { ikos_assert(!b.is_infinite()); } /// \brief Create the interval [lb, ub] /// /// If lb > ub, the interval is bottom. Interval(BoundT lb, BoundT ub) : _lb(std::move(lb)), _ub(std::move(ub)) { ikos_assert(this->_lb.is_finite() || this->_ub.is_finite() || this->_lb != this->_ub); if (this->_lb > this->_ub) { this->_lb = 1; this->_ub = 0; } } /// \brief Copy constructor Interval(const Interval&) noexcept( std::is_nothrow_copy_constructible< Number >::value) = default; /// \brief Move constructor Interval(Interval&&) noexcept( std::is_nothrow_move_constructible< Number >::value) = default; /// \brief Copy assignment operator Interval& operator=(const Interval&) noexcept( std::is_nothrow_copy_assignable< Number >::value) = default; /// \brief Move assignment operator Interval& operator=(Interval&&) noexcept( std::is_nothrow_move_assignable< Number >::value) = default; /// \brief Destructor ~Interval() override = default; /// \brief Return the lower bound const BoundT& lb() const { ikos_assert(!this->is_bottom()); return this->_lb; } /// \brief Return the upper bound const BoundT& ub() const { ikos_assert(!this->is_bottom()); return this->_ub; } void normalize() override {} bool is_bottom() const override { return this->_lb > this->_ub; } bool is_top() const override { return this->_lb.is_infinite() && this->_ub.is_infinite(); } /// \brief Return true if the interval is [0, 0] bool is_zero() const { return this->_lb == 0 && this->_ub == 0; } void set_to_bottom() override { this->_lb = 1; this->_ub = 0; } void set_to_top() override { this->_lb = BoundT::minus_infinity(); this->_ub = BoundT::plus_infinity(); } /// \brief Return the interval [-oo, ub] Interval lower_half_line() const { ikos_assert(!this->is_bottom()); return Interval(BoundT::minus_infinity(), this->_ub); } /// \brief Return the interval [lb, +oo] Interval upper_half_line() const { ikos_assert(!this->is_bottom()); return Interval(this->_lb, BoundT::plus_infinity()); } bool leq(const Interval& other) const override { if (this->is_bottom()) { return true; } else if (other.is_bottom()) { return false; } else { return other._lb <= this->_lb && this->_ub <= other._ub; } } bool equals(const Interval& other) const override { if (this->is_bottom()) { return other.is_bottom(); } else if (other.is_bottom()) { return false; } else { return this->_lb == other._lb && this->_ub == other._ub; } } Interval join(const Interval& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return Interval(min(this->_lb, other._lb), max(this->_ub, other._ub)); } } void join_with(const Interval& other) override { this->operator=(this->join(other)); } Interval widening(const Interval& other) const override { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { return Interval(other._lb < this->_lb ? BoundT::minus_infinity() : this->_lb, this->_ub < other._ub ? BoundT::plus_infinity() : this->_ub); } } void widen_with(const Interval& other) override { this->operator=(this->widening(other)); } Interval widening_threshold(const Interval& other, const Number& threshold) const { if (this->is_bottom()) { return other; } else if (other.is_bottom()) { return *this; } else { BoundT th = BoundT(threshold); BoundT lb = this->_lb; if (other._lb < this->_lb) { if (th <= other._lb) { lb = th; } else { lb = BoundT::minus_infinity(); } } BoundT ub = this->_ub; if (other._ub > this->_ub) { if (th >= other._ub) { ub = th; } else { ub = BoundT::plus_infinity(); } } return Interval(lb, ub); } } void widen_threshold_with(const Interval& other, const Number& threshold) { this->operator=(this->widening_threshold(other, threshold)); } Interval meet(const Interval& other) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { return Interval(max(this->_lb, other._lb), min(this->_ub, other._ub)); } } void meet_with(const Interval& other) override { this->operator=(this->meet(other)); } Interval narrowing(const Interval& other) const override { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { return Interval(this->_lb.is_infinite() ? other._lb : this->_lb, this->_ub.is_infinite() ? other._ub : this->_ub); } } void narrow_with(const Interval& other) override { this->operator=(this->narrowing(other)); } Interval narrowing_threshold(const Interval& other, const Number& threshold) const { if (this->is_bottom() || other.is_bottom()) { return bottom(); } else { return Interval(this->_lb.is_infinite() || this->_lb == BoundT(threshold) ? other._lb : this->_lb, this->_ub.is_infinite() || this->_ub == BoundT(threshold) ? other._ub : this->_ub); } } void narrow_threshold_with(const Interval& other, const Number& threshold) { this->operator=(this->narrowing_threshold(other, threshold)); } /// \brief Unary minus Interval operator-() const { if (this->is_bottom()) { return bottom(); } else { return Interval(-this->_ub, -this->_lb); } } /// \brief Add an interval void operator+=(const Interval& other) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_lb += other._lb; this->_ub += other._ub; } } /// \brief Substract an interval void operator-=(const Interval& other) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else { this->_lb -= other._ub; this->_ub -= other._lb; } } /// \brief Helper for mod([a, b], n) /// /// If mod([a, b], n) is equivalent to [a, b] - x, returns x /// Otherwise, returns boost::none. boost::optional< Number > mod_to_sub(const Number& n) { ikos_assert_msg(n != 0, "division by zero"); if (this->_lb.is_infinite() || this->_ub.is_infinite()) { return boost::none; } ZNumber lb = *this->_lb.number(); ZNumber ub = *this->_ub.number(); ZNumber mod_lb = mod(lb, n); ZNumber mod_ub = mod(ub, n); if (mod_ub - mod_lb != ub - lb) { return boost::none; } return lb - mod_lb; } /// \brief If the interval is a singleton [n, n], return n, otherwise return /// boost::none boost::optional< Number > singleton() const { if (this->_lb.is_finite() && this->_lb == this->_ub) { return this->_lb.number(); } else { return boost::none; } } /// \brief Return true if the interval contains n bool contains(int n) const { return this->contains(Number(n)); } /// \brief Return true if the interval contains n bool contains(Number n) const { if (this->is_bottom()) { return false; } else { BoundT b(std::move(n)); return this->_lb <= b && b <= this->_ub; } } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else { o << "[" << this->_lb << ", " << this->_ub << "]"; } } static std::string name() { return "interval"; } }; // end class Interval /// \brief Add intervals template < typename Number > inline Interval< Number > operator+(const Interval< Number >& lhs, const Interval< Number >& rhs) { using IntervalT = Interval< Number >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { return IntervalT(lhs.lb() + rhs.lb(), lhs.ub() + rhs.ub()); } } /// \brief Substract intervals template < typename Number > inline Interval< Number > operator-(const Interval< Number >& lhs, const Interval< Number >& rhs) { using IntervalT = Interval< Number >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { return IntervalT(lhs.lb() - rhs.ub(), lhs.ub() - rhs.lb()); } } /// \brief Multiply intervals template < typename Number > inline Interval< Number > operator*(const Interval< Number >& lhs, const Interval< Number >& rhs) { using BoundT = Bound< Number >; using IntervalT = Interval< Number >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { BoundT ll = lhs.lb() * rhs.lb(); BoundT lu = lhs.lb() * rhs.ub(); BoundT ul = lhs.ub() * rhs.lb(); BoundT uu = lhs.ub() * rhs.ub(); return IntervalT(min(ll, lu, ul, uu), max(ll, lu, ul, uu)); } } /// \brief Divide intervals inline Interval< ZNumber > operator/(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { if (rhs.contains(0)) { IntervalT l(rhs.lb(), BoundT(-1)); IntervalT u(BoundT(1), rhs.ub()); return (lhs / l).join(lhs / u); } else if (lhs.contains(0)) { IntervalT l(lhs.lb(), BoundT(-1)); IntervalT u(BoundT(1), lhs.ub()); return (l / rhs).join(u / rhs).join(IntervalT(0)); } else { // Neither the dividend nor the divisor contains 0 BoundT ll = lhs.lb() / rhs.lb(); BoundT lu = lhs.lb() / rhs.ub(); BoundT ul = lhs.ub() / rhs.lb(); BoundT uu = lhs.ub() / rhs.ub(); return IntervalT(min(ll, lu, ul, uu), max(ll, lu, ul, uu)); } } } /// \brief Divide intervals inline Interval< QNumber > operator/(const Interval< QNumber >& lhs, const Interval< QNumber >& rhs) { using BoundT = Bound< QNumber >; using IntervalT = Interval< QNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { boost::optional< QNumber > d = rhs.singleton(); if (d && *d == 0) { // [_, _] / 0 = ⊥ return IntervalT::bottom(); } else if (rhs.contains(0)) { boost::optional< QNumber > n = lhs.singleton(); if (n && *n == 0) { // 0 / [_, _] = 0 return IntervalT(0); } else { return IntervalT::top(); } } else { BoundT ll = lhs.lb() / rhs.lb(); BoundT lu = lhs.lb() / rhs.ub(); BoundT ul = lhs.ub() / rhs.lb(); BoundT uu = lhs.ub() / rhs.ub(); return IntervalT(min(ll, lu, ul, uu), max(ll, lu, ul, uu)); } } } /// \brief Remainder of intervals inline Interval< ZNumber > operator%(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { boost::optional< ZNumber > n = lhs.singleton(); boost::optional< ZNumber > d = rhs.singleton(); if (d && *d == 0) { // [_, _] % 0 = ⊥ return IntervalT::bottom(); } else if (n && d) { // [n, n] % [d, d] = [n % d, n % d] return IntervalT(*n % *d); } else { // [a, b] % [c, d] <= max(abs(a), abs(b)) // [a, b] % [c, d] <= max(abs(c), abs(d)) - 1 BoundT zero(0); BoundT n_ub = max(abs(lhs.lb()), abs(lhs.ub())); BoundT d_ub = max(abs(rhs.lb()), abs(rhs.ub())) - BoundT(1); BoundT ub = min(n_ub, d_ub); if (lhs.lb() < zero) { if (lhs.ub() > zero) { return IntervalT(-ub, ub); } else { return IntervalT(-ub, zero); } } else { return IntervalT(zero, ub); } } } } /// \brief Modulo of intervals inline Interval< ZNumber > mod(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { boost::optional< ZNumber > n = lhs.singleton(); boost::optional< ZNumber > d = rhs.singleton(); if (d && *d == 0) { // mod([_, _], 0) = ⊥ return IntervalT::bottom(); } else if (n && d) { // mod([n, n], [d, d]) = [mod(n, d), mod(n, d)] return IntervalT(mod(*n, *d)); } else if (d && lhs.lb().is_finite() && lhs.ub().is_finite()) { // mod([lb, ub], d) ZNumber lb = *lhs.lb().number(); ZNumber ub = *lhs.ub().number(); ZNumber mod_lb = mod(lb, *d); ZNumber mod_ub = mod(ub, *d); if (mod_ub - mod_lb == ub - lb) { return IntervalT(BoundT(mod_lb), BoundT(mod_ub)); } else { return IntervalT(BoundT(0), BoundT(abs(*d) - 1)); } } else { // mod([a, b], [c, d]) <= max(abs(c), abs(d)) - 1 BoundT ub = max(abs(rhs.lb()), abs(rhs.ub())) - BoundT(1); return IntervalT(BoundT(0), ub); } } } /// \brief Left binary shift of intervals inline Interval< ZNumber > operator<<(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { // rhs >= 0 IntervalT shift = rhs.meet(IntervalT(BoundT(0), BoundT::plus_infinity())); if (shift.is_bottom()) { // Invalid operand return IntervalT::bottom(); } // [a, b] << [c, d] = [a, b] * [1 << c, 1 << d] IntervalT coeff(BoundT(1 << *shift.lb().number()), shift.ub().is_finite() ? BoundT(1 << *shift.ub().number()) : BoundT::plus_infinity()); return lhs * coeff; } } /// \brief Right binary shift of intervals inline Interval< ZNumber > operator>>(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { // rhs >= 0 IntervalT shift = rhs.meet(IntervalT(BoundT(0), BoundT::plus_infinity())); if (shift.is_bottom()) { // Invalid operand return IntervalT::bottom(); } if (lhs.contains(0)) { IntervalT l(lhs.lb(), BoundT(-1)); IntervalT u(BoundT(1), lhs.ub()); return (l >> rhs).join(u >> rhs).join(IntervalT(0)); } else { // [a, b] >> [c, d] \in [min(a >> c, a >> d, b >> c, b >> d), // max(a >> c, a >> d, b >> c, b >> d)] BoundT ll = lhs.lb() >> shift.lb(); BoundT lu = lhs.lb() >> shift.ub(); BoundT ul = lhs.ub() >> shift.lb(); BoundT uu = lhs.ub() >> shift.ub(); return IntervalT(min(ll, lu, ul, uu), max(ll, lu, ul, uu)); } } } /// \brief Bitwise AND of intervals inline Interval< ZNumber > operator&(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { boost::optional< ZNumber > l = lhs.singleton(); boost::optional< ZNumber > r = rhs.singleton(); if (l && r) { // [l, l] & [r, r] = [l & r, l & r] return IntervalT(*l & *r); } else if ((l && *l == 0) || (r && *r == 0)) { // [a, b] & 0 = 0 return IntervalT(0); } else if (l && *l == -1) { // -1 & [a, b] = [a, b] return rhs; } else if (r && *r == -1) { // [a, b] & -1 = [a, b] return lhs; } else { if (lhs.lb() >= BoundT(0) && rhs.lb() >= BoundT(0)) { // [a, b] & [c, d] <= [c, d] & b <= b // [a, b] & [c, d] <= [a, b] & d <= d return IntervalT(BoundT(0), min(lhs.ub(), rhs.ub())); } else if (lhs.lb() >= BoundT(0)) { return IntervalT(BoundT(0), lhs.ub()); } else if (rhs.lb() >= BoundT(0)) { return IntervalT(BoundT(0), rhs.ub()); } else { return IntervalT::top(); } } } } /// \brief Bitwise OR of intervals inline Interval< ZNumber > operator|(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { boost::optional< ZNumber > l = lhs.singleton(); boost::optional< ZNumber > r = rhs.singleton(); if (l && r) { // [l, l] | [r, r] = [l | r, l | r] return IntervalT(*l | *r); } else if ((l && *l == -1) || (r && *r == -1)) { // -1 | [a, b] = -1 return IntervalT(-1); } else if (l && *l == 0) { // 0 | [a, b] = [a, b] return rhs; } else if (r && *r == 0) { // [a, b] | 0 = [a, b] return lhs; } else { if (lhs.lb() >= BoundT(0) && lhs.ub().is_finite() && rhs.lb() >= BoundT(0) && rhs.ub().is_finite()) { ZNumber m = max(*lhs.ub().number(), *rhs.ub().number()); ZNumber ub = (m + 1).next_power_of_2() - 1; return IntervalT(BoundT(0), BoundT(ub)); } else { return IntervalT::top(); } } } } /// \brief Bitwise XOR of intervals inline Interval< ZNumber > operator^(const Interval< ZNumber >& lhs, const Interval< ZNumber >& rhs) { using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; if (lhs.is_bottom() || rhs.is_bottom()) { return IntervalT::bottom(); } else { boost::optional< ZNumber > l = lhs.singleton(); boost::optional< ZNumber > r = rhs.singleton(); if (l && r) { // [l, l] ^ [r, r] = [l ^ r, l ^ r] return IntervalT(*l ^ *r); } else if (l && *l == 0) { // 0 ^ [a, b] = [a, b] return rhs; } else if (r && *r == 0) { // [a, b] ^ 0 = [a, b] return lhs; } else { if (lhs.lb() >= BoundT(0) && lhs.ub().is_finite() && rhs.lb() >= BoundT(0) && rhs.ub().is_finite()) { ZNumber m = max(*lhs.ub().number(), *rhs.ub().number()); ZNumber ub = (m + 1).next_power_of_2() - 1; return IntervalT(BoundT(0), BoundT(ub)); } else { return IntervalT::top(); } } } } /// \brief Write an interval on a stream template < typename Number > inline std::ostream& operator<<(std::ostream& o, const Interval< Number >& interval) { interval.dump(o); return o; } /// \brief Return the constraint system: i.lb() <= e <= i.ub() template < typename Number, typename VariableRef > inline LinearConstraintSystem< Number, VariableRef > within_interval( const LinearExpression< Number, VariableRef >& e, const Interval< Number >& i) { LinearConstraintSystem< Number, VariableRef > csts; if (i.is_bottom()) { csts.add(LinearConstraint< Number, VariableRef >::contradiction()); } else { boost::optional< Number > lb = i.lb().number(); boost::optional< Number > ub = i.ub().number(); if (lb && ub && *lb == *ub) { csts.add(e == *ub); } else { if (lb) { csts.add(e >= *lb); } if (ub) { csts.add(e <= *ub); } } } return csts; } /// \brief Return the constraint system: i.lb() <= v <= i.ub() template < typename Number, typename VariableRef > inline LinearConstraintSystem< Number, VariableRef > within_interval( VariableExpression< Number, VariableRef > v, const Interval< Number >& i) { return within_interval(LinearExpression< Number, VariableRef >(v), i); } /// \brief Return the constraint system: i.lb() <= v <= i.ub() template < typename Number, typename VariableRef > inline LinearConstraintSystem< Number, VariableRef > within_interval( VariableRef v, const Interval< Number >& i) { return within_interval(LinearExpression< Number, VariableRef >(v), i); } /// \brief Interval on unlimited precision integers using ZInterval = Interval< ZNumber >; /// \brief Interval on unlimited precision rationals using QInterval = Interval< QNumber >; } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/numeric/interval_congruence.hpp000066400000000000000000000465351473507761200304260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief IntervalCongruence class * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { namespace numeric { /// \brief Interval-Congruence abstract value template < typename Number > class IntervalCongruence {}; /// \brief Interval-Congruence abstract value /// /// This is implemented as a pair of interval and congruence abstract value. template <> class IntervalCongruence< ZNumber > final : public core::AbstractDomain< IntervalCongruence< ZNumber > > { public: using NumberT = ZNumber; using BoundT = Bound< ZNumber >; using IntervalT = Interval< ZNumber >; using CongruenceT = Congruence< ZNumber >; private: IntervalT _i; CongruenceT _c; private: /// \brief r(c, a) is the smallest element of c greater or equal than a static ZNumber r(const CongruenceT& c, const ZNumber& a) { ikos_assert(!c.is_bottom() && c.modulus() != 0); return a + mod(c.residue() - a, c.modulus()); } /// \brief l(c, a) is the greatest element of c smaller or equal than a static ZNumber l(const CongruenceT& c, const ZNumber& a) { ikos_assert(!c.is_bottom() && c.modulus() != 0); return a - mod(a - c.residue(), c.modulus()); } /// \brief Reduction /// /// Let (i, c) be a pair of interval and congruence /// if (c.is_bottom() || i.is_bottom()) (bottom(), bottom()); /// if (c = 0Z+a and a notin i) (bottom(), bottom()); /// if (c = 0Z+a) ([a,a] , c); /// if (i=[a,b] and r(c,a) > l(c,b)) (bottom(), bottom()); /// if (i=[a,b]) ([r(c,a), l(c,b)], c); /// if (i=[a,+oo]) ([r(c,a), +oo], c); /// if (i=[-oo,b]) ([-oo, l(c,b)], c); /// otherwise (i,c) void reduce() { if (this->_c.is_bottom()) { this->_i.set_to_bottom(); return; } if (this->_i.is_bottom()) { this->_c.set_to_bottom(); return; } if (this->_c.is_top()) { // congruence is top and interval is a singleton boost::optional< ZNumber > n = this->_i.singleton(); if (n) { this->_c = CongruenceT(*n); } return; } if (this->_c.modulus() == 0) { // congruence is a singleton, so we refine the interval if (!this->_i.contains(this->_c.residue())) { this->_i.set_to_bottom(); this->_c.set_to_bottom(); } else { this->_i = IntervalT(this->_c.residue()); } return; } // refine lower and upper bounds of the interval using congruences const BoundT& lb = this->_i.lb(); const BoundT& ub = this->_i.ub(); if (lb.is_finite() && ub.is_finite()) { ZNumber x = r(this->_c, *lb.number()); ZNumber y = l(this->_c, *ub.number()); if (x > y) { this->_i.set_to_bottom(); this->_c.set_to_bottom(); } else if (x == y) { this->_i = IntervalT(x); this->_c = CongruenceT(x); } else { this->_i = IntervalT(BoundT(x), BoundT(y)); } } else if (lb.is_finite()) { ZNumber x = r(this->_c, *lb.number()); this->_i = IntervalT(BoundT(x), ub); } else if (ub.is_finite()) { ZNumber y = l(this->_c, *ub.number()); this->_i = IntervalT(lb, BoundT(y)); } } private: struct TopTag {}; struct BottomTag {}; /// \brief Create the top interval-congruence explicit IntervalCongruence(TopTag) : _i(IntervalT::top()), _c(CongruenceT::top()) {} /// \brief Create the bottom interval-congruence explicit IntervalCongruence(BottomTag) : _i(IntervalT::bottom()), _c(CongruenceT::bottom()) {} public: /// \brief Create the top interval-congruence static IntervalCongruence top() { return IntervalCongruence(TopTag{}); } /// \brief Create the bottom interval-congruence static IntervalCongruence bottom() { return IntervalCongruence(BottomTag{}); } /// \brief Create the interval-congruence ([n, n], 0Z+n) explicit IntervalCongruence(int n) : _i(n), _c(n) {} /// \brief Create the interval-congruence ([n, n], 0Z+n) explicit IntervalCongruence(const ZNumber& n) : _i(n), _c(n) {} /// \brief Create the interval-congruence (i, c) IntervalCongruence(IntervalT i, CongruenceT c) : _i(std::move(i)), _c(std::move(c)) { this->reduce(); } /// \brief Create the interval-congruence (i, T) explicit IntervalCongruence(IntervalT i) : _i(std::move(i)), _c(CongruenceT::top()) { this->reduce(); } /// \brief Create the interval-congruence (T, c) explicit IntervalCongruence(CongruenceT c) : _i(IntervalT::top()), _c(std::move(c)) { this->reduce(); } /// \brief Copy constructor IntervalCongruence(const IntervalCongruence&) = default; /// \brief Move constructor IntervalCongruence(IntervalCongruence&&) = default; /// \brief Copy assignment operator IntervalCongruence& operator=(const IntervalCongruence&) = default; /// \brief Move assignment operator IntervalCongruence& operator=(IntervalCongruence&&) noexcept = default; /// \brief Destructor ~IntervalCongruence() override = default; /// \brief Return the interval const IntervalT& interval() const { return this->_i; } /// \brief Return the congruence const CongruenceT& congruence() const { return this->_c; } void normalize() override { // Already performed by the reduction } bool is_bottom() const override { return this->_c.is_bottom(); // Correct because of reduction } bool is_top() const override { return this->_i.is_top() && this->_c.is_top(); } void set_to_bottom() override { this->_i.set_to_bottom(); this->_c.set_to_bottom(); } void set_to_top() override { this->_i.set_to_top(); this->_c.set_to_top(); } bool leq(const IntervalCongruence& other) const override { return this->_i.leq(other._i) && this->_c.leq(other._c); } bool equals(const IntervalCongruence& other) const override { return this->_i.equals(other._i) && this->_c.equals(other._c); } IntervalCongruence join(const IntervalCongruence& other) const override { return IntervalCongruence(this->_i.join(other._i), this->_c.join(other._c)); } void join_with(const IntervalCongruence& other) override { this->_i.join_with(other._i); this->_c.join_with(other._c); this->reduce(); } IntervalCongruence widening(const IntervalCongruence& other) const override { return IntervalCongruence(this->_i.widening(other._i), this->_c.widening(other._c)); } void widen_with(const IntervalCongruence& other) override { this->_i.widen_with(other._i); this->_c.widen_with(other._c); this->reduce(); } IntervalCongruence widening_threshold(const IntervalCongruence& other, const ZNumber& threshold) const { return IntervalCongruence(this->_i.widening_threshold(other._i, threshold), this->_c.widening_threshold(other._c, threshold)); } void widen_threshold_with(const IntervalCongruence& other, const ZNumber& threshold) { this->_i.widen_threshold_with(other._i, threshold); this->_c.widen_threshold_with(other._c, threshold); this->reduce(); } IntervalCongruence meet(const IntervalCongruence& other) const override { return IntervalCongruence(this->_i.meet(other._i), this->_c.meet(other._c)); } void meet_with(const IntervalCongruence& other) override { this->_i.meet_with(other._i); this->_c.meet_with(other._c); this->reduce(); } IntervalCongruence narrowing(const IntervalCongruence& other) const override { return IntervalCongruence(this->_i.narrowing(other._i), this->_c.narrowing(other._c)); } void narrow_with(const IntervalCongruence& other) override { this->_i.narrow_with(other._i); this->_c.narrow_with(other._c); this->reduce(); } IntervalCongruence narrowing_threshold(const IntervalCongruence& other, const ZNumber& threshold) const { return IntervalCongruence(this->_i.narrowing_threshold(other._i, threshold), this->_c.narrowing_threshold(other._c, threshold)); } void narrow_threshold_with(const IntervalCongruence& other, const ZNumber& threshold) { this->_i.narrow_threshold_with(other._i, threshold); this->_c.narrow_threshold_with(other._c, threshold); this->reduce(); } /// \brief Unary minus IntervalCongruence operator-() const { return IntervalCongruence(-this->_i, -this->_c); } /// \brief Add interval-congruences void operator+=(const IntervalCongruence& other) { this->_i += other._i; this->_c += other._c; this->reduce(); } /// \brief If the interval-congruence is a singleton, return its value, /// otherwise return boost::none boost::optional< ZNumber > singleton() const { return this->_c.singleton(); // correct because of reduction } /// \brief Return true if the interval-congruence contains n bool contains(int n) const { return this->_i.contains(n) && this->_c.contains(n); } /// \brief Return true if the interval-congruence contains n bool contains(const ZNumber& n) const { return this->_i.contains(n) && this->_c.contains(n); } void dump(std::ostream& o) const override { o << "(" << this->_i << ", " << this->_c << ")"; } static std::string name() { return "interval-congruence"; } }; // end class IntervalCongruence< ZNumber > /// \brief Add interval-congruences inline IntervalCongruence< ZNumber > operator+( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() + rhs.interval(), lhs.congruence() + rhs.congruence()); } /// \brief Substract interval-congruences inline IntervalCongruence< ZNumber > operator-( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() - rhs.interval(), lhs.congruence() - rhs.congruence()); } /// \brief Multiply interval-congruences inline IntervalCongruence< ZNumber > operator*( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() * rhs.interval(), lhs.congruence() * rhs.congruence()); } /// \brief Divide interval-congruences inline IntervalCongruence< ZNumber > operator/( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() / rhs.interval(), lhs.congruence() / rhs.congruence()); } /// \brief Remainder of interval-congruences inline IntervalCongruence< ZNumber > operator%( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() % rhs.interval(), lhs.congruence() % rhs.congruence()); } /// \brief Modulo of interval-congruences inline IntervalCongruence< ZNumber > mod( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(mod(lhs.interval(), rhs.interval()), mod(lhs.congruence(), rhs.congruence())); } /// \brief Left binary shift of interval-congruences inline IntervalCongruence< ZNumber > operator<<( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() << rhs.interval(), lhs.congruence() << rhs.congruence()); } /// \brief Right binary shift of interval-congruences inline IntervalCongruence< ZNumber > operator>>( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() >> rhs.interval(), lhs.congruence() >> rhs.congruence()); } /// \brief Bitwise AND of interval-congruences inline IntervalCongruence< ZNumber > operator&( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() & rhs.interval(), lhs.congruence() & rhs.congruence()); } /// \brief Bitwise OR of interval-congruences inline IntervalCongruence< ZNumber > operator|( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() | rhs.interval(), lhs.congruence() | rhs.congruence()); } /// \brief Bitwise XOR of interval-congruences inline IntervalCongruence< ZNumber > operator^( const IntervalCongruence< ZNumber >& lhs, const IntervalCongruence< ZNumber >& rhs) { return IntervalCongruence< ZNumber >(lhs.interval() ^ rhs.interval(), lhs.congruence() ^ rhs.congruence()); } /// \brief Interval-Congruence abstract value on rationals /// /// The congruence domain on rationals is just a wrapper of the constant domain. /// We instead implement this as the interval domain alone. template <> class IntervalCongruence< QNumber > final : public core::AbstractDomain< IntervalCongruence< QNumber > > { public: using NumberT = QNumber; private: QInterval _i; public: static IntervalCongruence top() { return IntervalCongruence(QInterval::top()); } static IntervalCongruence bottom() { return IntervalCongruence(QInterval::bottom()); } explicit IntervalCongruence(int n) : _i(n) {} explicit IntervalCongruence(const QNumber& n) : _i(n) {} IntervalCongruence(QInterval i, const QCongruence&) : _i(std::move(i)) {} explicit IntervalCongruence(QInterval i) : _i(std::move(i)) {} explicit IntervalCongruence(const QCongruence&) : _i(QInterval::top()) {} IntervalCongruence(const IntervalCongruence&) = default; IntervalCongruence(IntervalCongruence&&) = default; IntervalCongruence& operator=(const IntervalCongruence&) = default; IntervalCongruence& operator=(IntervalCongruence&&) = default; ~IntervalCongruence() override = default; const QInterval& interval() const { return this->_i; } QCongruence congruence() const { return QCongruence::top(); } void normalize() override {} bool is_bottom() const override { return this->_i.is_bottom(); } bool is_top() const override { return this->_i.is_top(); } void set_to_bottom() override { this->_i.set_to_bottom(); } void set_to_top() override { this->_i.set_to_top(); } bool leq(const IntervalCongruence& other) const override { return this->_i.leq(other._i); } bool equals(const IntervalCongruence& other) const override { return this->_i.equals(other._i); } void join_with(const IntervalCongruence& other) override { this->_i.join_with(other._i); } void widen_with(const IntervalCongruence& other) override { this->_i.widen_with(other._i); } void widen_threshold_with(const IntervalCongruence& other, const QNumber& threshold) { this->_i.widen_threshold_with(other._i, threshold); } void meet_with(const IntervalCongruence& other) override { this->_i.meet_with(other._i); } void narrow_with(const IntervalCongruence& other) override { this->_i.narrow_with(other._i); } IntervalCongruence operator-() const { return IntervalCongruence(-this->_i); } void operator+=(const IntervalCongruence& other) { this->_i += other._i; } boost::optional< QNumber > singleton() const { return this->_i.singleton(); } bool contains(int n) const { return this->_i.contains(n); } bool contains(const QNumber& n) const { return this->_i.contains(n); } void dump(std::ostream& o) const override { this->_i.dump(o); } static std::string name() { return "interval-congruence"; } }; // end class IntervalCongruence< QNumber > inline IntervalCongruence< QNumber > operator+( const IntervalCongruence< QNumber >& lhs, const IntervalCongruence< QNumber >& rhs) { return IntervalCongruence< QNumber >(lhs.interval() + rhs.interval()); } inline IntervalCongruence< QNumber > operator-( const IntervalCongruence< QNumber >& lhs, const IntervalCongruence< QNumber >& rhs) { return IntervalCongruence< QNumber >(lhs.interval() - rhs.interval()); } inline IntervalCongruence< QNumber > operator*( const IntervalCongruence< QNumber >& lhs, const IntervalCongruence< QNumber >& rhs) { return IntervalCongruence< QNumber >(lhs.interval() * rhs.interval()); } inline IntervalCongruence< QNumber > operator/( const IntervalCongruence< QNumber >& lhs, const IntervalCongruence< QNumber >& rhs) { return IntervalCongruence< QNumber >(lhs.interval() / rhs.interval()); } /// \brief Write an interval-congruence on a stream template < typename Number > inline std::ostream& operator<<(std::ostream& o, const IntervalCongruence< Number >& ic) { ic.dump(o); return o; } } // end namespace numeric } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/pointer/000077500000000000000000000000001473507761200236625ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/pointer/pointer.hpp000066400000000000000000000262751473507761200260670ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer abstract value * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { /// \brief Pointer abstract value /// /// The pointer abstraction holds: /// * An uninitialized abstract value /// * A nullity abstract value /// * A points-to set of memory locations pointed by the pointer /// * An interval representing the offset template < typename MemoryLocationRef > class PointerAbsValue final : public core::AbstractDomain< PointerAbsValue< MemoryLocationRef > > { public: using PointsToSetT = PointsToSet< MemoryLocationRef >; using MachineIntInterval = machine_int::Interval; private: /// \brief Uninitialized Uninitialized _uninitialized; /// \brief Nullity Nullity _nullity; /// \brief Set of memory locations (i.e, addresses) pointed by the pointer PointsToSetT _points_to; /// \brief Offset interval MachineIntInterval _offset; private: /// \brief Reduce the pointer abstract value void reduce() { if (this->_uninitialized.is_bottom()) { this->set_to_bottom(); } else if (this->_uninitialized.is_uninitialized()) { this->set_to_uninitialized(); } else if (this->_nullity.is_bottom()) { this->set_to_bottom(); } else if (this->_nullity.is_null()) { this->set_to_null(); } else if (this->_points_to.is_bottom()) { this->set_to_bottom(); } else if (this->_points_to.is_empty()) { this->set_to_bottom(); } else if (this->_offset.is_bottom()) { this->set_to_bottom(); } } public: /// \brief Create the top abstract value with the given bit-width and /// signedness for the offset static PointerAbsValue top(uint64_t bit_width, Signedness sign) { return PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSetT::top(), MachineIntInterval::top(bit_width, sign)); } /// \brief Create the bottom abstract value with the given bit-width and /// signedness for the offset static PointerAbsValue bottom(uint64_t bit_width, Signedness sign) { return PointerAbsValue(Uninitialized::bottom(), Nullity::bottom(), PointsToSetT::bottom(), MachineIntInterval::bottom(bit_width, sign)); } /// \brief Create the uninitialized pointer with the given bit-width and /// signedness for the offset static PointerAbsValue uninitialized(uint64_t bit_width, Signedness sign) { return PointerAbsValue(Uninitialized::uninitialized(), Nullity::bottom(), PointsToSetT::bottom(), MachineIntInterval::bottom(bit_width, sign)); } /// \brief Create the null pointer with the given bit-width and signedness for /// the offset static PointerAbsValue null(uint64_t bit_width, Signedness sign) { return PointerAbsValue(Uninitialized::initialized(), Nullity::null(), PointsToSetT::bottom(), MachineIntInterval::bottom(bit_width, sign)); } /// \brief Create the abstract value with the given points-to set, interval, /// nullity and uninitialized PointerAbsValue(Uninitialized uninitialized, Nullity nullity, PointsToSetT points_to, MachineIntInterval offset) : _uninitialized(std::move(uninitialized)), _nullity(std::move(nullity)), _points_to(std::move(points_to)), _offset(std::move(offset)) { this->reduce(); } /// \brief Copy constructor PointerAbsValue(const PointerAbsValue&) = default; /// \brief Move constructor PointerAbsValue(PointerAbsValue&&) noexcept = default; /// \brief Copy assignment operator PointerAbsValue& operator=(const PointerAbsValue&) = default; /// \brief Move assignment operator PointerAbsValue& operator=(PointerAbsValue&&) noexcept = default; /// \brief Destructor ~PointerAbsValue() override = default; /// \brief Return the uninitialized const Uninitialized& uninitialized() const { return this->_uninitialized; } /// \brief Return the nullity const Nullity& nullity() const { return this->_nullity; } /// \brief Return the points-to set const PointsToSetT& points_to() const { return this->_points_to; } /// \brief Return the interval offset const MachineIntInterval& offset() const { return this->_offset; } void normalize() override { // Already performed by the reduction } bool is_bottom() const override { return this->_uninitialized.is_bottom(); // Correct because of reduction } bool is_top() const override { return this->_uninitialized.is_top() && this->_nullity.is_top() && this->_points_to.is_top() && this->_offset.is_top(); } /// \brief Return true if the pointer is uninitialized bool is_uninitialized() const { return this->_uninitialized.is_uninitialized(); } /// \brief Return true if the pointer is null bool is_null() const { return this->_nullity.is_null(); } void set_to_bottom() override { this->_uninitialized.set_to_bottom(); this->_nullity.set_to_bottom(); this->_points_to.set_to_bottom(); this->_offset.set_to_bottom(); } void set_to_top() override { this->_uninitialized.set_to_top(); this->_nullity.set_to_top(); this->_points_to.set_to_top(); this->_offset.set_to_top(); } /// \brief Set the pointer to uninitialized void set_to_uninitialized() { this->_uninitialized.set_to_uninitialized(); this->_nullity.set_to_bottom(); this->_points_to.set_to_bottom(); this->_offset.set_to_bottom(); } /// \brief Set the pointer to null void set_to_null() { this->_uninitialized.set_to_initialized(); this->_nullity.set_to_null(); this->_points_to.set_to_bottom(); this->_offset.set_to_bottom(); } bool leq(const PointerAbsValue& other) const override { return this->_uninitialized.leq(other._uninitialized) && this->_nullity.leq(other._nullity) && this->_points_to.leq(other._points_to) && this->_offset.leq(other._offset); } bool equals(const PointerAbsValue& other) const override { return this->_uninitialized.equals(other._uninitialized) && this->_nullity.equals(other._nullity) && this->_points_to.equals(other._points_to) && this->_offset.equals(other._offset); } void join_with(const PointerAbsValue& other) override { this->_uninitialized.join_with(other._uninitialized); this->_nullity.join_with(other._nullity); this->_points_to.join_with(other._points_to); this->_offset.join_with(other._offset); this->reduce(); } void join_loop_with(const PointerAbsValue& other) override { this->_uninitialized.join_loop_with(other._uninitialized); this->_nullity.join_loop_with(other._nullity); this->_points_to.join_loop_with(other._points_to); this->_offset.join_loop_with(other._offset); this->reduce(); } void join_iter_with(const PointerAbsValue& other) override { this->_uninitialized.join_iter_with(other._uninitialized); this->_nullity.join_iter_with(other._nullity); this->_points_to.join_iter_with(other._points_to); this->_offset.join_iter_with(other._offset); this->reduce(); } void widen_with(const PointerAbsValue& other) override { this->_uninitialized.widen_with(other._uninitialized); this->_nullity.widen_with(other._nullity); this->_points_to.widen_with(other._points_to); this->_offset.widen_with(other._offset); this->reduce(); } void meet_with(const PointerAbsValue& other) override { this->_uninitialized.meet_with(other._uninitialized); this->_nullity.meet_with(other._nullity); this->_points_to.meet_with(other._points_to); this->_offset.meet_with(other._offset); this->reduce(); } void narrow_with(const PointerAbsValue& other) override { this->_uninitialized.narrow_with(other._uninitialized); this->_nullity.narrow_with(other._nullity); this->_points_to.narrow_with(other._points_to); this->_offset.narrow_with(other._offset); this->reduce(); } /// \brief Add an offset to the pointer void add_offset(const MachineIntInterval& offset) { this->_offset = add(this->_offset, offset); } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else if (this->is_uninitialized()) { o << "U"; } else if (this->is_null()) { o << "N"; } else { this->_points_to.dump(o); o << " + "; this->_offset.dump(o); o << ", "; this->_nullity.dump(o); o << ", "; this->_uninitialized.dump(o); } } static std::string name() { return "pointer abstraction"; } }; // end class PointerAbsValue /// \brief Write a pointer abstract value on a stream template < typename MemoryLocationRef > inline std::ostream& operator<<( std::ostream& o, const PointerAbsValue< MemoryLocationRef >& pointer) { pointer.dump(o); return o; } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/pointer/pointer_set.hpp000066400000000000000000000200071473507761200267250ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Pointer set abstract domain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace core { /// \brief Pointer set abstract domain /// /// The pointer set abstraction holds: /// * A points-to set of memory locations pointed by the pointers /// * An interval representing the offsets /// /// It does not handle null and uninitialized pointers. template < typename MemoryLocationRef > class PointerSet final : public core::AbstractDomain< PointerSet< MemoryLocationRef > > { public: using PointsToSetT = PointsToSet< MemoryLocationRef >; using PointerAbsValueT = PointerAbsValue< MemoryLocationRef >; using MachineIntInterval = machine_int::Interval; private: /// \brief Set of memory locations (i.e, addresses) pointed by the pointers PointsToSetT _points_to; /// \brief Offsets interval MachineIntInterval _offsets; private: /// \brief Reduce the pointer set void reduce() { if (this->_points_to.is_bottom() || this->_points_to.is_empty()) { this->_offsets.set_to_bottom(); } else if (this->_offsets.is_bottom()) { this->_points_to.set_to_bottom(); } } public: /// \brief Create the top pointer set with the given bit-width and signedness /// for the offsets static PointerSet top(uint64_t bit_width, Signedness sign) { return PointerSet(PointsToSetT::top(), MachineIntInterval::top(bit_width, sign)); } /// \brief Create the bottom pointer set with the given bit-width and /// signedness for the offsets static PointerSet bottom(uint64_t bit_width, Signedness sign) { return PointerSet(PointsToSetT::bottom(), MachineIntInterval::bottom(bit_width, sign)); } /// \brief Create the empty pointer set with the given bit-width and /// signedness for the offsets static PointerSet empty(uint64_t bit_width, Signedness sign) { return PointerSet(PointsToSetT::empty(), MachineIntInterval::bottom(bit_width, sign)); } /// \brief Create the pointer set with the given points-to set and interval PointerSet(PointsToSetT points_to, MachineIntInterval offsets) : _points_to(std::move(points_to)), _offsets(std::move(offsets)) { this->reduce(); } /// \brief Copy constructor PointerSet(const PointerSet&) = default; /// \brief Move constructor PointerSet(PointerSet&&) noexcept = default; /// \brief Copy assignment operator PointerSet& operator=(const PointerSet&) = default; /// \brief Move assignment operator PointerSet& operator=(PointerSet&&) noexcept = default; /// \brief Destructor ~PointerSet() override = default; /// \brief Return the uninitialized Uninitialized uninitialized() const { return Uninitialized::top(); } /// \brief Return the nullity Nullity nullity() const { return Nullity::top(); } /// \brief Return the points-to set const PointsToSetT& points_to() const { return this->_points_to; } /// \brief Return the interval offsets const MachineIntInterval& offsets() const { return this->_offsets; } void normalize() override { // Already performed by the reduction } bool is_bottom() const override { return this->_points_to.is_bottom(); // Correct because of reduction } bool is_top() const override { return this->_points_to.is_top() && this->_offsets.is_top(); } void set_to_bottom() override { this->_points_to.set_to_bottom(); this->_offsets.set_to_bottom(); } void set_to_top() override { this->_points_to.set_to_top(); this->_offsets.set_to_top(); } bool leq(const PointerSet& other) const override { return this->_points_to.leq(other._points_to) && this->_offsets.leq(other._offsets); } bool equals(const PointerSet& other) const override { return this->_points_to.equals(other._points_to) && this->_offsets.equals(other._offsets); } void join_with(const PointerSet& other) override { this->_points_to.join_with(other._points_to); this->_offsets.join_with(other._offsets); this->reduce(); } void join_loop_with(const PointerSet& other) override { this->_points_to.join_loop_with(other._points_to); this->_offsets.join_loop_with(other._offsets); this->reduce(); } void join_iter_with(const PointerSet& other) override { this->_points_to.join_iter_with(other._points_to); this->_offsets.join_iter_with(other._offsets); this->reduce(); } void widen_with(const PointerSet& other) override { this->_points_to.widen_with(other._points_to); this->_offsets.widen_with(other._offsets); this->reduce(); } void meet_with(const PointerSet& other) override { this->_points_to.meet_with(other._points_to); this->_offsets.meet_with(other._offsets); this->reduce(); } void narrow_with(const PointerSet& other) override { this->_points_to.narrow_with(other._points_to); this->_offsets.narrow_with(other._offsets); this->reduce(); } /// \brief Add a pointer abstract value in the set void add(const PointerAbsValueT& pointer) { this->_points_to.join_with(pointer.points_to()); this->_offsets.join_with(pointer.offset()); this->reduce(); } void dump(std::ostream& o) const override { if (this->is_bottom()) { o << "⊥"; } else if (this->is_top()) { o << "T"; } else if (this->_points_to.is_empty()) { o << "{}"; } else { this->_points_to.dump(o); o << " + "; this->_offsets.dump(o); } } static std::string name() { return "pointer set abstraction"; } }; // end class PointerSet /// \brief Write a pointer set on a stream template < typename MemoryLocationRef > inline std::ostream& operator<<( std::ostream& o, const PointerSet< MemoryLocationRef >& pointer_set) { pointer_set.dump(o); return o; } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/pointer/points_to_set.hpp000066400000000000000000000215411473507761200272670ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief PointsToSet class * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace core { /// \brief Represents a set of memory locations (i.e, addresses) template < typename MemoryLocationRef > class PointsToSet final : public core::AbstractDomain< PointsToSet< MemoryLocationRef > > { public: static_assert(IsMemoryLocation< MemoryLocationRef >::value, "MemoryLocationRef does not meet the requirements for memory " "location types"); private: enum Kind { BottomKind, TopKind, SetKind }; private: using PatriciaTreeSetT = PatriciaTreeSet< MemoryLocationRef >; public: using Iterator = typename PatriciaTreeSetT::Iterator; private: Kind _kind; PatriciaTreeSetT _set; private: struct TopTag {}; struct BottomTag {}; struct EmptyTag {}; /// \brief Create the top points-to set explicit PointsToSet(TopTag) : _kind(TopKind) {} /// \brief Create the bottom points-to set explicit PointsToSet(BottomTag) : _kind(BottomKind) {} /// \brief Create the empty points-to set explicit PointsToSet(EmptyTag) : _kind(SetKind) {} public: /// \brief Create the top points-to set static PointsToSet top() { return PointsToSet(TopTag{}); } /// \brief Create the bottom points-to set static PointsToSet bottom() { return PointsToSet(BottomTag{}); } /// \brief Create the empty points-to set static PointsToSet empty() { return PointsToSet(EmptyTag{}); } /// \brief Create the points-to set with the given memory locations PointsToSet(std::initializer_list< MemoryLocationRef > elements) : _kind(SetKind), _set(elements) {} /// \brief Copy constructor PointsToSet(const PointsToSet&) noexcept = default; /// \brief Move constructor PointsToSet(PointsToSet&&) noexcept = default; /// \brief Copy assignment operator PointsToSet& operator=(const PointsToSet&) noexcept = default; /// \brief Move assignment operator PointsToSet& operator=(PointsToSet&&) noexcept = default; /// \brief Destructor ~PointsToSet() override = default; /// \brief Return the number of memory locations in the points-to set std::size_t size() const { ikos_assert(this->_kind == SetKind); return this->_set.size(); } /// \brief Begin iterator over the memory locations Iterator begin() const { ikos_assert(this->_kind == SetKind); return this->_set.begin(); } /// \brief End iterator over the memory locations Iterator end() const { ikos_assert(this->_kind == SetKind); return this->_set.end(); } void normalize() override {} bool is_bottom() const override { return this->_kind == BottomKind; } bool is_top() const override { return this->_kind == TopKind; } /// \brief Return true if the points-to value is a set (not top or bottom) bool is_set() const { return this->_kind == SetKind; } /// \brief Return true if the points-to set is the empty set bool is_empty() const { return this->_kind == SetKind && this->_set.empty(); } void set_to_bottom() override { this->_kind = BottomKind; this->_set.clear(); } void set_to_top() override { this->_kind = TopKind; this->_set.clear(); } /// \brief Set the points-to set to the empty set void set_to_empty() { this->_kind = SetKind; this->_set.clear(); } bool leq(const PointsToSet& other) const override { switch (this->_kind) { case BottomKind: return true; case TopKind: return other._kind == TopKind; case SetKind: return other._kind == TopKind || (other._kind == SetKind && this->_set.is_subset_of(other._set)); default: ikos_unreachable("unreachable"); } } bool equals(const PointsToSet& other) const override { if (this->_kind == SetKind) { return other._kind == SetKind && this->_set.equals(other._set); } else { return this->_kind == other._kind; } } void join_with(const PointsToSet& other) override { if (this->is_top() || other.is_bottom()) { return; } else if (other.is_top()) { this->set_to_top(); } else if (this->is_bottom()) { this->operator=(other); } else { this->_set.join_with(other._set); } } void widen_with(const PointsToSet& other) override { this->join_with(other); } void meet_with(const PointsToSet& other) override { if (this->is_bottom() || other.is_top()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (this->is_top()) { this->operator=(other); } else { this->_set.intersect_with(other._set); } } void narrow_with(const PointsToSet& other) override { this->meet_with(other); } /// \brief Perform the set difference void difference_with(const PointsToSet& other) { if (this->is_bottom()) { return; } else if (other.is_bottom()) { this->set_to_bottom(); } else if (other.is_top()) { this->set_to_empty(); } else if (this->is_top()) { return; } else { this->_set.difference_with(other._set); } } /// \brief Perform the set difference PointsToSet difference(const PointsToSet& other) const { PointsToSet tmp(*this); tmp.difference_with(other); return tmp; } /// \brief Add a memory location in the points-to set void add(MemoryLocationRef m) { if (!this->is_set()) { return; } this->_set.insert(m); } /// \brief Remove a memory location from the points-to set void remove(MemoryLocationRef m) { if (!this->is_set()) { return; } this->_set.erase(m); } /// \brief If the points-to set is a singleton {m}, return m, otherwise return /// boost::none boost::optional< MemoryLocationRef > singleton() const { if (this->is_set() && this->_set.size() == 1) { return *this->_set.begin(); } else { return boost::none; } } /// \brief Return true if the points-to set contains m bool contains(MemoryLocationRef m) const { return this->is_top() || (this->is_set() && this->_set.contains(m)); } void dump(std::ostream& o) const override { switch (this->_kind) { case BottomKind: { o << "⊥"; break; } case TopKind: { o << "T"; break; } case SetKind: { this->_set.dump(o); break; } default: { ikos_unreachable("unreachable"); } } } static std::string name() { return "points-to set"; } }; // end class PointsToSet /// \brief Write a points-to set on a stream template < typename MemoryLocationRef > inline std::ostream& operator<<( std::ostream& o, const PointsToSet< MemoryLocationRef >& points_to) { points_to.dump(o); return o; } } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/include/ikos/core/value/uninitialized.hpp000066400000000000000000000142001473507761200255600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Uninitialized abstract value * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace core { /// \brief Uninitialized abstract value /// /// This is either top, bottom, initialized or uninitialized. class Uninitialized final : public core::AbstractDomain< Uninitialized > { private: enum Kind : unsigned { BottomKind = 0, InitializedKind = 1, UninitializedKind = 2, TopKind = 3 }; private: Kind _kind = TopKind; private: /// \brief Private constructor explicit Uninitialized(Kind kind) : _kind(kind) {} public: /// \brief Return the top uninitialized value static Uninitialized top() { return Uninitialized(TopKind); } /// \brief Return the bottom uninitialized value static Uninitialized bottom() { return Uninitialized(BottomKind); } /// \brief Return the initialized abstract value static Uninitialized initialized() { return Uninitialized(InitializedKind); } /// \brief Return the uninitialized abstract value static Uninitialized uninitialized() { return Uninitialized(UninitializedKind); } /// \brief Copy constructor Uninitialized(const Uninitialized&) noexcept = default; /// \brief Move constructor Uninitialized(Uninitialized&&) noexcept = default; /// \brief Copy assignment operator Uninitialized& operator=(const Uninitialized&) noexcept = default; /// \brief Move assignment operator Uninitialized& operator=(Uninitialized&&) noexcept = default; /// \brief Destructor ~Uninitialized() override = default; void normalize() override {} bool is_bottom() const override { return this->_kind == BottomKind; } bool is_top() const override { return this->_kind == TopKind; } /// \brief Return true if this is the initialized abstract value bool is_initialized() const { return this->_kind == InitializedKind; } /// \brief Return true if this is the uninitialized abstract value bool is_uninitialized() const { return this->_kind == UninitializedKind; } void set_to_bottom() override { this->_kind = BottomKind; } void set_to_top() override { this->_kind = TopKind; } /// \brief Set the uninitialized value to initialized void set_to_initialized() { this->_kind = InitializedKind; } /// \brief Set the uninitialized value to uninitialized void set_to_uninitialized() { this->_kind = UninitializedKind; } bool leq(const Uninitialized& other) const override { switch (this->_kind) { case BottomKind: return true; case TopKind: return other._kind == TopKind; case InitializedKind: return other._kind == InitializedKind || other._kind == TopKind; case UninitializedKind: return other._kind == UninitializedKind || other._kind == TopKind; default: ikos_unreachable("unreachable"); } } bool equals(const Uninitialized& other) const override { return this->_kind == other._kind; } void join_with(const Uninitialized& other) override { this->_kind = static_cast< Kind >(static_cast< unsigned >(this->_kind) | static_cast< unsigned >(other._kind)); } void widen_with(const Uninitialized& other) override { this->join_with(other); } void meet_with(const Uninitialized& other) override { this->_kind = static_cast< Kind >(static_cast< unsigned >(this->_kind) & static_cast< unsigned >(other._kind)); } void narrow_with(const Uninitialized& other) override { this->meet_with(other); } void dump(std::ostream& o) const override { switch (this->_kind) { case BottomKind: { o << "⊥"; break; } case InitializedKind: { o << "I"; break; } case UninitializedKind: { o << "U"; break; } case TopKind: { o << "T"; break; } default: { ikos_unreachable("unreachable"); } } } static std::string name() { return "uninitialized"; } }; // end class Uninitialized } // end namespace core } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/core/test/000077500000000000000000000000001473507761200165255ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/000077500000000000000000000000001473507761200175045ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/.clang-tidy000066400000000000000000000077641473507761200215560ustar00rootroot00000000000000Checks: '*,-cert-dcl03-c,-cert-err58-cpp,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-macro-usage,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-vararg,-fuchsia-default-arguments,-fuchsia-overloaded-operator,-fuchsia-statically-constructed-objects,-google-build-using-namespace,-google-readability-function-size,-google-runtime-references,-hicpp-function-size,-hicpp-no-array-decay,-hicpp-static-assert,-hicpp-vararg,-llvm-header-guard,-misc-non-private-member-variables-in-classes,-misc-static-assert,-readability-container-size-empty,-readability-else-after-return,-readability-function-size,-readability-magic-numbers,-readability-named-parameter' CheckOptions: - { key: readability-identifier-naming.NamespaceCase, value: lower_case } - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } - { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase } - { key: readability-identifier-naming.TypedefCase, value: CamelCase } - { key: readability-identifier-naming.ClassCase, value: CamelCase } - { key: readability-identifier-naming.StructCase, value: CamelCase } - { key: readability-identifier-naming.EnumCase, value: CamelCase } - { key: readability-identifier-naming.UnionCase, value: CamelCase } - { key: readability-identifier-naming.MemberCase, value: lower_case } - { key: readability-identifier-naming.PrivateMemberPrefix, value: _ } - { key: readability-identifier-naming.ProtectedMemberPrefix, value: _ } - { key: readability-identifier-naming.FunctionCase, value: lower_case } - { key: readability-identifier-naming.MethodCase, value: lower_case } - { key: readability-identifier-naming.VariableCase, value: lower_case } - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } - { key: readability-identifier-naming.StaticVariableCase, value: CamelCase } - { key: readability-identifier-naming.GlobalVariableCase, value: CamelCase } - { key: modernize-use-default-member-init.UseAssignment, value: 1 } # Reasons for disabling checks: # * cert-dcl03-c: It generates false positives with ikos_unreachable() # * cert-err58-cpp: It generates warnings in Boost.Test # * cppcoreguidelines-avoid-magic-numbers: We use 'magic' numbers in tests # * cppcoreguidelines-macro-usage: We use macros in tests # * cppcoreguidelines-non-private-member-variables-in-classes: It generates warnings for protected members of classes # * cppcoreguidelines-pro-bounds-array-to-pointer-decay: It generates warnings for ikos_assert_msg() # * cppcoreguidelines-pro-type-vararg: It generates warnings in Boost.Test # * fuchsia-default-arguments: We allow default arguments # * fuchsia-overloaded-operator: We allow overloads of operators # * fuchsia-statically-constructed-objects: We allow static objects # * google-build-using-namespace: We allow 'using namespace' in tests # * google-readability-function-size: We allow long functions in tests # * google-runtime-references: We allow output parameters as reference # * hicpp-function-size: We allow long functions in tests # * hicpp-no-array-decay: It generates warnings for ikos_assert_msg() # * hicpp-static-assert: It generates false positives with ikos_unreachable() # * hicpp-vararg: It generates warnings in Boost.Test # * llvm-header-guard: We use #pragma once # * misc-non-private-member-variables-in-classes: It generates warnings for public members of structures # * misc-static-assert: It generates false positives with ikos_unreachable() # * readability-container-size-empty: Accept `x.size() == 0` checks in tests # * readability-else-after-return: We allow else after return # * readability-function-size: We allow long functions in tests # * readability-magic-numbers: We use 'magic' numbers in tests # * readability-named-parameter: We allow unnamed parameters NASA-SW-VnV-ikos-1d98c65/core/test/unit/CMakeLists.txt000066400000000000000000000053501473507761200222470ustar00rootroot00000000000000include(AddFlagUtils) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compiler_flag(OPTIONAL "WNO_EXIT_TIME_DESTRUCTORS" "-Wno-exit-time-destructors") add_compiler_flag(OPTIONAL "WNO_GLOBAL_CONSTRUCTORS" "-Wno-global-constructors") add_compiler_flag(OPTIONAL "WNO_DISABLED_MACRO_EXPANSION" "-Wno-disabled-macro-expansion") add_compiler_flag(OPTIONAL "WNO_USED_BUT_MARKED_UNUSED" "-Wno-used-but-marked-unused") endif() function(add_unit_test) string(REPLACE ";" "-" test_name "${ARGV}") string(REPLACE ";" "/" test_path "${ARGV}") set(test_build_target "test-core-${test_name}") add_executable(${test_build_target} "${test_path}.cpp") target_link_libraries(${test_build_target} ${GMPXX_LIB} ${GMP_LIB} ${Boost_LIBRARIES}) if (APRON_FOUND) target_link_libraries(${test_build_target} ${APRON_LIBRARIES}) endif() add_dependencies(build-core-tests ${test_build_target}) add_test(NAME "core-${test_name}" COMMAND ${test_build_target}) endfunction() add_unit_test(adt patricia_tree map) add_unit_test(adt patricia_tree set) add_unit_test(number z_number) add_unit_test(number q_number) add_unit_test(number machine_int) add_unit_test(value numeric constant) add_unit_test(value numeric interval) add_unit_test(value numeric congruence) add_unit_test(value numeric gauge) add_unit_test(value machine_int interval) add_unit_test(value machine_int constant) add_unit_test(value machine_int congruence) add_unit_test(value machine_int interval_congruence) add_unit_test(domain discrete_domain) add_unit_test(domain numeric constant) add_unit_test(domain numeric interval) add_unit_test(domain numeric congruence) add_unit_test(domain numeric interval_congruence) add_unit_test(domain numeric dbm) add_unit_test(domain numeric octagon) add_unit_test(domain numeric gauge) add_unit_test(domain numeric gauge_interval_congruence) add_unit_test(domain numeric union) add_unit_test(domain numeric var_packing_domain) add_unit_test(domain numeric var_packing_dbm) add_unit_test(domain numeric var_packing_dbm_congruence) if (APRON_FOUND) add_unit_test(domain numeric apron interval) add_unit_test(domain numeric apron polka_polyhedra) add_unit_test(domain numeric apron ppl_linear_congruences) add_unit_test(domain numeric apron pkgrid_polyhedra_lin_congruences) endif() add_unit_test(domain machine_int interval) add_unit_test(domain machine_int congruence) add_unit_test(domain machine_int interval_congruence) add_unit_test(domain machine_int numeric_domain_adapter) add_unit_test(domain machine_int polymorphic_domain) add_unit_test(domain pointer solver) add_unit_test(domain nullity separate_domain) add_unit_test(domain uninitialized separate_domain) add_unit_test(domain memory partitioning) add_unit_test(example muzq) add_unit_test(fixpoint wpo) NASA-SW-VnV-ikos-1d98c65/core/test/unit/adt/000077500000000000000000000000001473507761200202545ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/adt/patricia_tree/000077500000000000000000000000001473507761200230675ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/adt/patricia_tree/map.cpp000066400000000000000000000165351473507761200243620ustar00rootroot00000000000000/******************************************************************************* * * Tests for PatriciaTreeMap * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_patricia_tree_map #define BOOST_TEST_DYN_LINK #include #include #include BOOST_AUTO_TEST_CASE(test_patricia_tree_map) { using Index = ikos::core::Index; using Map = ikos::core::PatriciaTreeMap< Index, std::string >; Map m; // test insert_or_assign BOOST_CHECK(m.empty()); BOOST_CHECK(m.size() == 0); BOOST_CHECK(!m.at(1)); m.insert_or_assign(1, "hello"); BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 1); { auto x = m.at(1); BOOST_CHECK(!!x); BOOST_CHECK(*x == "hello"); } { auto x = m.at(2); BOOST_CHECK(!x); } m.insert_or_assign(2, "world"); BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 2); { auto x = m.at(1); BOOST_CHECK(!!x); BOOST_CHECK(*x == "hello"); } { auto x = m.at(2); BOOST_CHECK(!!x); BOOST_CHECK(*x == "world"); } { auto x = m.at(3); BOOST_CHECK(!x); } m.insert_or_assign(1, "bye"); BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 2); { auto x = m.at(1); BOOST_CHECK(!!x); BOOST_CHECK(*x == "bye"); } { auto x = m.at(2); BOOST_CHECK(!!x); BOOST_CHECK(*x == "world"); } { auto x = m.at(3); BOOST_CHECK(!x); } // insert 50, 51, ..., 99 for (std::size_t i = 50; i < 100; i++) { m.insert_or_assign(i, std::to_string(i)); } BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 52); // insert 3, 4, ..., 49 for (std::size_t i = 3; i < 50; i++) { m.insert_or_assign(i, std::to_string(i)); } BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 99); { auto x = m.at(1); BOOST_CHECK(!!x); BOOST_CHECK(*x == "bye"); } { auto x = m.at(2); BOOST_CHECK(!!x); BOOST_CHECK(*x == "world"); } for (std::size_t i = 3; i < 100; i++) { auto x = m.at(i); BOOST_CHECK(!!x); BOOST_CHECK(*x == std::to_string(i)); } { auto x = m.at(0); BOOST_CHECK(!x); } { auto x = m.at(100); BOOST_CHECK(!x); } // test erase m.erase(0); BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 99); m.erase(1); BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 98); { auto x = m.at(1); BOOST_CHECK(!x); } { auto x = m.at(2); BOOST_CHECK(!!x); BOOST_CHECK(*x == "world"); } for (std::size_t i = 3; i < 100; i++) { auto x = m.at(i); BOOST_CHECK(!!x); BOOST_CHECK(*x == std::to_string(i)); } // erase 2, 3, ..., 99 for (std::size_t i = 2; i < 100; i++) { m.erase(i); } BOOST_CHECK(m.empty()); BOOST_CHECK(m.size() == 0); // test clear m.insert_or_assign(1, "hello"); m.insert_or_assign(2, "world"); BOOST_CHECK(!m.empty()); BOOST_CHECK(m.size() == 2); m.clear(); BOOST_CHECK(m.empty()); BOOST_CHECK(m.size() == 0); // test begin/end m.clear(); m.insert_or_assign(1, "hello"); { auto it = m.begin(); BOOST_CHECK((it != m.end())); BOOST_CHECK(it->first == 1); BOOST_CHECK(it->second == "hello"); ++it; BOOST_CHECK((it == m.end())); } m.insert_or_assign(2, "world"); const std::array< std::pair< Index, std::string >, 2 > tab = { {{2, "world"}, {1, "hello"}}}; BOOST_CHECK(std::equal(m.begin(), m.end(), std::begin(tab), std::end(tab))); // insert 50, 51, ..., 99 for (std::size_t i = 50; i < 100; i++) { m.insert_or_assign(i, std::to_string(i)); } // insert 3, 4, ..., 49 for (std::size_t i = 3; i < 50; i++) { m.insert_or_assign(i, std::to_string(i)); } BOOST_CHECK(std::distance(m.begin(), m.end()) == 99); // test transform m.clear(); m.insert_or_assign(1, "hello"); m.insert_or_assign(2, "world"); m.transform([](Index, const std::string& s) { return s.substr(0, 1); }); const std::array< std::pair< Index, std::string >, 2 > tab2 = { {{2, "w"}, {1, "h"}}}; BOOST_CHECK(std::equal(m.begin(), m.end(), std::begin(tab2), std::end(tab2))); // test leq Map m1; Map m2; m1.insert_or_assign(1, "hello"); m1.insert_or_assign(2, "world"); m2.insert_or_assign(1, "zzzzz"); BOOST_CHECK(m1.leq(m2, std::less<>())); BOOST_CHECK(!m2.leq(m1, std::less<>())); m2.insert_or_assign(3, "test"); BOOST_CHECK(!m1.leq(m2, std::less<>())); // test equals m1.clear(); m2.clear(); BOOST_CHECK(m1.equals(m2, std::equal_to<>())); m1.insert_or_assign(1, "hello"); BOOST_CHECK(!m1.equals(m2, std::equal_to<>())); m2.insert_or_assign(1, "hello"); BOOST_CHECK(m1.equals(m2, std::equal_to<>())); m1.insert_or_assign(2, "a"); m2.insert_or_assign(2, "b"); BOOST_CHECK(!m1.equals(m2, std::equal_to<>())); // test join m1.clear(); m1.insert_or_assign(1, "hello"); m1.insert_or_assign(2, "world"); m2.clear(); m2.insert_or_assign(1, "zzzzz"); m = m1.join(m2, std::plus<>()); const std::array< std::pair< Index, std::string >, 2 > tab3 = { {{2, "world"}, {1, "hellozzzzz"}}}; BOOST_CHECK(std::equal(m.begin(), m.end(), std::begin(tab3), std::end(tab3))); // test intersect m1.clear(); m1.insert_or_assign(1, "hello"); m1.insert_or_assign(2, "world"); m2.clear(); m2.insert_or_assign(1, "zzzzz"); m = m1.intersect(m2, std::plus<>()); const std::array< std::pair< Index, std::string >, 1 > tab4 = { {{1, "hellozzzzz"}}}; BOOST_CHECK(std::equal(m.begin(), m.end(), std::begin(tab4), std::end(tab4))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/adt/patricia_tree/set.cpp000066400000000000000000000122631473507761200243720ustar00rootroot00000000000000/******************************************************************************* * * Tests for PatriciaTreeSet * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_patricia_tree_set #define BOOST_TEST_DYN_LINK #include #include #include BOOST_AUTO_TEST_CASE(test_patricia_tree_set) { using Index = ikos::core::Index; using Set = ikos::core::PatriciaTreeSet< Index >; Set s; // test insert BOOST_CHECK(s.empty()); BOOST_CHECK(s.size() == 0); BOOST_CHECK(!s.contains(1)); s.insert(1); BOOST_CHECK(!s.empty()); BOOST_CHECK(s.size() == 1); BOOST_CHECK(s.contains(1)); BOOST_CHECK(!s.contains(2)); s.insert(2); BOOST_CHECK(!s.empty()); BOOST_CHECK(s.size() == 2); BOOST_CHECK(s.contains(1)); BOOST_CHECK(s.contains(2)); BOOST_CHECK(!s.contains(3)); // insert 50, 51, ..., 99 for (std::size_t i = 50; i < 100; i++) { s.insert(i); } BOOST_CHECK(!s.empty()); BOOST_CHECK(s.size() == 52); // insert 3, 4, ..., 49 for (std::size_t i = 3; i < 50; i++) { s.insert(i); } BOOST_CHECK(!s.empty()); BOOST_CHECK(s.size() == 99); BOOST_CHECK(s.contains(1)); BOOST_CHECK(s.contains(2)); for (std::size_t i = 3; i < 100; i++) { BOOST_CHECK(s.contains(i)); } BOOST_CHECK(!s.contains(0)); BOOST_CHECK(!s.contains(100)); // test erase s.erase(0); BOOST_CHECK(!s.empty()); BOOST_CHECK(s.size() == 99); s.erase(1); BOOST_CHECK(!s.empty()); BOOST_CHECK(s.size() == 98); BOOST_CHECK(!s.contains(1)); BOOST_CHECK(s.contains(2)); for (std::size_t i = 3; i < 100; i++) { BOOST_CHECK(s.contains(i)); } // erase 2, 3, ..., 99 for (std::size_t i = 2; i < 100; i++) { s.erase(i); } BOOST_CHECK(s.empty()); BOOST_CHECK(s.size() == 0); // test clear s.insert(1); s.insert(2); BOOST_CHECK(!s.empty()); BOOST_CHECK(s.size() == 2); s.clear(); BOOST_CHECK(s.empty()); BOOST_CHECK(s.size() == 0); // test begin/end s.clear(); s.insert(1); { auto it = s.begin(); BOOST_CHECK((it != s.end())); BOOST_CHECK(*it == 1); ++it; BOOST_CHECK((it == s.end())); } s.insert(2); BOOST_CHECK(s.equals(Set({1, 2}))); // insert 50, 51, ..., 99 for (std::size_t i = 50; i < 100; i++) { s.insert(i); } // insert 3, 4, ..., 49 for (std::size_t i = 3; i < 50; i++) { s.insert(i); } BOOST_CHECK(std::distance(s.begin(), s.end()) == 99); // test leq Set s1; Set s2; s1.insert(1); s2.insert(1); s2.insert(2); BOOST_CHECK(s1.is_subset_of(s2)); BOOST_CHECK(!s2.is_subset_of(s1)); s1.insert(3); BOOST_CHECK(!s1.is_subset_of(s2)); // test equals s1.clear(); s2.clear(); BOOST_CHECK(s1.equals(s2)); s1.insert(1); BOOST_CHECK(!s1.equals(s2)); s2.insert(1); BOOST_CHECK(s1.equals(s2)); s1.insert(2); s2.insert(2); BOOST_CHECK(s1.equals(s2)); // test join s1.clear(); s1.insert(1); s1.insert(2); s2.clear(); s2.insert(1); BOOST_CHECK(s1.equals(s1.join(s2))); s1.clear(); s1.insert(2); s2.clear(); s2.insert(1); BOOST_CHECK(s1.join(s2).equals(Set({1, 2}))); // test intersect s1.clear(); s1.insert(1); s1.insert(2); s2.clear(); s2.insert(1); BOOST_CHECK(s1.intersect(s2).equals(Set({1}))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/000077500000000000000000000000001473507761200207535ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/discrete_domain.cpp000066400000000000000000000256571473507761200246270ustar00rootroot00000000000000/******************************************************************************* * * Tests for DiscreteDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_discrete_domain #define BOOST_TEST_DYN_LINK #include #include #include #include using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using DiscreteDomain = ikos::core::DiscreteDomain< Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(DiscreteDomain::top().is_top()); BOOST_CHECK(!DiscreteDomain::top().is_bottom()); BOOST_CHECK(!DiscreteDomain::bottom().is_top()); BOOST_CHECK(DiscreteDomain::bottom().is_bottom()); auto inv = DiscreteDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.add(x); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(iterators) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); DiscreteDomain inv = DiscreteDomain::bottom(); BOOST_CHECK((inv.begin() == inv.end())); inv.add(x); std::array< Variable, 1 > tab = {{x}}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab), std::end(tab), [](const Variable& a, const Variable& b) { return a == b; })); inv.add(y); std::array< Variable, 2 > tab2 = {{y, x}}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab2), std::end(tab2), [](const Variable& a, const Variable& b) { return a == b; })); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = DiscreteDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(DiscreteDomain::bottom().leq(DiscreteDomain::top())); BOOST_CHECK(DiscreteDomain::bottom().leq(DiscreteDomain::bottom())); BOOST_CHECK(!DiscreteDomain::top().leq(DiscreteDomain::bottom())); BOOST_CHECK(DiscreteDomain::top().leq(DiscreteDomain::top())); DiscreteDomain inv1{x}; BOOST_CHECK(inv1.leq(DiscreteDomain::top())); BOOST_CHECK(!inv1.leq(DiscreteDomain::bottom())); DiscreteDomain inv2{x, y}; BOOST_CHECK(inv2.leq(DiscreteDomain::top())); BOOST_CHECK(!inv2.leq(DiscreteDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); DiscreteDomain inv3{y}; BOOST_CHECK(inv3.leq(DiscreteDomain::top())); BOOST_CHECK(!inv3.leq(DiscreteDomain::bottom())); BOOST_CHECK(!inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); BOOST_CHECK(inv3.leq(inv2)); BOOST_CHECK(!inv2.leq(inv3)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!DiscreteDomain::bottom().equals(DiscreteDomain::top())); BOOST_CHECK(DiscreteDomain::bottom().equals(DiscreteDomain::bottom())); BOOST_CHECK(!DiscreteDomain::top().equals(DiscreteDomain::bottom())); BOOST_CHECK(DiscreteDomain::top().equals(DiscreteDomain::top())); DiscreteDomain inv1{x}; BOOST_CHECK(!inv1.equals(DiscreteDomain::top())); BOOST_CHECK(!inv1.equals(DiscreteDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); DiscreteDomain inv2{y}; BOOST_CHECK(!inv2.equals(DiscreteDomain::top())); BOOST_CHECK(!inv2.equals(DiscreteDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); DiscreteDomain inv3{x, y}; BOOST_CHECK(!inv3.equals(DiscreteDomain::top())); BOOST_CHECK(!inv3.equals(DiscreteDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK((DiscreteDomain::bottom().join(DiscreteDomain::top()) == DiscreteDomain::top())); BOOST_CHECK((DiscreteDomain::bottom().join(DiscreteDomain::bottom()) == DiscreteDomain::bottom())); BOOST_CHECK((DiscreteDomain::top().join(DiscreteDomain::top()) == DiscreteDomain::top())); BOOST_CHECK((DiscreteDomain::top().join(DiscreteDomain::bottom()) == DiscreteDomain::top())); DiscreteDomain inv1{x}; BOOST_CHECK((inv1.join(DiscreteDomain::top()) == DiscreteDomain::top())); BOOST_CHECK((inv1.join(DiscreteDomain::bottom()) == inv1)); BOOST_CHECK((DiscreteDomain::top().join(inv1) == DiscreteDomain::top())); BOOST_CHECK((DiscreteDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); DiscreteDomain inv2{y}; DiscreteDomain inv3{x, y}; BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); DiscreteDomain inv4{y, z}; BOOST_CHECK((inv4.join(inv3) == DiscreteDomain{x, y, z})); BOOST_CHECK((inv3.join(inv4) == DiscreteDomain{x, y, z})); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK((DiscreteDomain::bottom().meet(DiscreteDomain::top()) == DiscreteDomain::bottom())); BOOST_CHECK((DiscreteDomain::bottom().meet(DiscreteDomain::bottom()) == DiscreteDomain::bottom())); BOOST_CHECK((DiscreteDomain::top().meet(DiscreteDomain::top()) == DiscreteDomain::top())); BOOST_CHECK((DiscreteDomain::top().meet(DiscreteDomain::bottom()) == DiscreteDomain::bottom())); DiscreteDomain inv1{x}; BOOST_CHECK((inv1.meet(DiscreteDomain::top()) == inv1)); BOOST_CHECK( (inv1.meet(DiscreteDomain::bottom()) == DiscreteDomain::bottom())); BOOST_CHECK((DiscreteDomain::top().meet(inv1) == inv1)); BOOST_CHECK( (DiscreteDomain::bottom().meet(inv1) == DiscreteDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); DiscreteDomain inv2{y}; BOOST_CHECK((inv1.meet(inv2) == DiscreteDomain::bottom())); BOOST_CHECK((inv2.meet(inv1) == DiscreteDomain::bottom())); DiscreteDomain inv3{x, y}; BOOST_CHECK((inv1.meet(inv3) == inv1)); BOOST_CHECK((inv3.meet(inv1) == inv1)); BOOST_CHECK((inv2.meet(inv3) == inv2)); BOOST_CHECK((inv3.meet(inv2) == inv2)); DiscreteDomain inv4{y, z}; BOOST_CHECK((inv3.meet(inv4) == inv2)); BOOST_CHECK((inv4.meet(inv3) == inv2)); } BOOST_AUTO_TEST_CASE(difference) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK((DiscreteDomain::bottom().difference(DiscreteDomain::top()) == DiscreteDomain::bottom())); BOOST_CHECK((DiscreteDomain::bottom().difference(DiscreteDomain::bottom()) == DiscreteDomain::bottom())); BOOST_CHECK((DiscreteDomain::top().difference(DiscreteDomain::top()) == DiscreteDomain::bottom())); BOOST_CHECK((DiscreteDomain::top().difference(DiscreteDomain::bottom()) == DiscreteDomain::top())); DiscreteDomain inv1{x}; BOOST_CHECK( (inv1.difference(DiscreteDomain::top()) == DiscreteDomain::bottom())); BOOST_CHECK((inv1.difference(DiscreteDomain::bottom()) == inv1)); BOOST_CHECK( (DiscreteDomain::top().difference(inv1) == DiscreteDomain::top())); BOOST_CHECK( (DiscreteDomain::bottom().difference(inv1) == DiscreteDomain::bottom())); BOOST_CHECK((inv1.difference(inv1) == DiscreteDomain::bottom())); DiscreteDomain inv2{y}; BOOST_CHECK((inv1.difference(inv2) == inv1)); BOOST_CHECK((inv2.difference(inv1) == inv2)); DiscreteDomain inv3{x, y}; BOOST_CHECK((inv1.difference(inv3) == DiscreteDomain::bottom())); BOOST_CHECK((inv3.difference(inv1) == inv2)); BOOST_CHECK((inv2.difference(inv3) == DiscreteDomain::bottom())); BOOST_CHECK((inv3.difference(inv2) == inv1)); DiscreteDomain inv4{y, z}; BOOST_CHECK((inv3.difference(inv4) == inv1)); BOOST_CHECK((inv4.difference(inv3) == DiscreteDomain{z})); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = DiscreteDomain::top(); BOOST_CHECK(inv.is_top()); inv.add(x); BOOST_CHECK(inv.is_top()); inv = DiscreteDomain::bottom(); inv.add(x); BOOST_CHECK((inv == DiscreteDomain{x})); inv.add(y); BOOST_CHECK((inv == DiscreteDomain{x, y})); } BOOST_AUTO_TEST_CASE(remove_) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = DiscreteDomain::top(); BOOST_CHECK(inv.is_top()); inv.remove(x); BOOST_CHECK(inv.is_top()); inv = DiscreteDomain{x, y}; inv.remove(x); BOOST_CHECK((inv == DiscreteDomain{y})); inv.remove(y); BOOST_CHECK((inv == DiscreteDomain::bottom())); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/machine_int/000077500000000000000000000000001473507761200232315ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/machine_int/congruence.cpp000066400000000000000000000444621473507761200260770ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::CongruenceDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_int_congruence_domain #define BOOST_TEST_DYN_LINK #include #include #include #include using Int = ikos::core::MachineInt; using Congruence = ikos::core::machine_int::Congruence; using ikos::core::Signed; using ikos::core::Unsigned; using ikos::core::machine_int::BinaryOperator; using ikos::core::machine_int::Predicate; using ikos::core::machine_int::UnaryOperator; using VariableFactory = ikos::core::example::machine_int::VariableFactory; using Variable = VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< Int, Variable >; using LinearExpr = ikos::core::LinearExpression< Int, Variable >; using CongruenceDomain = ikos::core::machine_int::CongruenceDomain< Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK(CongruenceDomain::top().is_top()); BOOST_CHECK(!CongruenceDomain::top().is_bottom()); BOOST_CHECK(!CongruenceDomain::bottom().is_top()); BOOST_CHECK(CongruenceDomain::bottom().is_bottom()); auto inv = CongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence(Int(1, 32, Signed))); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence::bottom(32, Signed)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = CongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); BOOST_CHECK(CongruenceDomain::bottom().leq(CongruenceDomain::top())); BOOST_CHECK(CongruenceDomain::bottom().leq(CongruenceDomain::bottom())); BOOST_CHECK(!CongruenceDomain::top().leq(CongruenceDomain::bottom())); BOOST_CHECK(CongruenceDomain::top().leq(CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(Int(0, 32, Signed))); BOOST_CHECK(inv1.leq(CongruenceDomain::top())); BOOST_CHECK(!inv1.leq(CongruenceDomain::bottom())); auto inv2 = CongruenceDomain::top(); inv2.set(x, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv2.leq(CongruenceDomain::top())); BOOST_CHECK(!inv2.leq(CongruenceDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = CongruenceDomain::top(); inv3.set(x, Congruence(Int(0, 32, Signed))); inv3.set(y, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv3.leq(CongruenceDomain::top())); BOOST_CHECK(!inv3.leq(CongruenceDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = CongruenceDomain::top(); inv4.set(x, Congruence(Int(0, 32, Signed))); inv4.set(y, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv4.leq(CongruenceDomain::top())); BOOST_CHECK(!inv4.leq(CongruenceDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = CongruenceDomain::top(); inv5.set(x, Congruence(Int(0, 32, Signed))); inv5.set(y, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv5.set(z, Congruence(Int(3, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv5.leq(CongruenceDomain::top())); BOOST_CHECK(!inv5.leq(CongruenceDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK(!CongruenceDomain::bottom().equals(CongruenceDomain::top())); BOOST_CHECK(CongruenceDomain::bottom().equals(CongruenceDomain::bottom())); BOOST_CHECK(!CongruenceDomain::top().equals(CongruenceDomain::bottom())); BOOST_CHECK(CongruenceDomain::top().equals(CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(Int(0, 32, Signed))); BOOST_CHECK(!inv1.equals(CongruenceDomain::top())); BOOST_CHECK(!inv1.equals(CongruenceDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = CongruenceDomain::top(); inv2.set(x, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(!inv2.equals(CongruenceDomain::top())); BOOST_CHECK(!inv2.equals(CongruenceDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = CongruenceDomain::top(); inv3.set(x, Congruence(Int(0, 32, Signed))); inv3.set(y, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(!inv3.equals(CongruenceDomain::top())); BOOST_CHECK(!inv3.equals(CongruenceDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((CongruenceDomain::bottom().join(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().join(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().join(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().join(CongruenceDomain::bottom()) == CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(Int(1, 32, Signed))); BOOST_CHECK((inv1.join(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((inv1.join(CongruenceDomain::bottom()) == inv1)); BOOST_CHECK((CongruenceDomain::top().join(inv1) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(Int(3, 32, Signed))); inv3.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = CongruenceDomain::top(); inv4.set(x, Congruence(Int(3, 32, Signed))); inv4.set(y, Congruence(Int(4, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((CongruenceDomain::bottom().widening(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().widening( CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().widening(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().widening(CongruenceDomain::bottom()) == CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(Int(1, 32, Signed))); BOOST_CHECK( (inv1.widening(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((inv1.widening(CongruenceDomain::bottom()) == inv1)); BOOST_CHECK( (CongruenceDomain::top().widening(inv1) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(Int(3, 32, Signed))); inv3.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv3)); auto inv4 = CongruenceDomain::top(); inv4.set(x, Congruence(Int(3, 32, Signed))); inv4.set(y, Congruence(Int(4, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv4.widening(inv2) == inv2)); BOOST_CHECK((inv2.widening(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((CongruenceDomain::bottom().meet(CongruenceDomain::top()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::bottom().meet(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().meet(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().meet(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.meet(CongruenceDomain::top()) == inv1)); BOOST_CHECK( (inv1.meet(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().meet(inv1) == inv1)); BOOST_CHECK( (CongruenceDomain::bottom().meet(inv1) == CongruenceDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); inv3.set(x, Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((CongruenceDomain::bottom().narrowing(CongruenceDomain::top()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::bottom().narrowing( CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().narrowing(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().narrowing(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.narrowing(CongruenceDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((CongruenceDomain::bottom().narrowing(inv1) == CongruenceDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); inv3.set(x, Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); BOOST_CHECK((inv1.narrowing(inv2) == inv3)); BOOST_CHECK((inv2.narrowing(inv1) == inv3)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); auto inv1 = CongruenceDomain::top(); auto inv2 = CongruenceDomain::top(); inv1.assign(x, Int(0, 32, Signed)); inv2.set(x, Congruence(Int(0, 32, Signed))); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, Int(0, 32, Signed)); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv1.assign(y, x); BOOST_CHECK(inv1.to_congruence(y) == Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv1.set_to_top(); inv1.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv1.set(y, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); LinearExpr e(Int(1, 32, Signed)); e.add(Int(2, 32, Signed), x); e.add(Int(-3, 32, Signed), y); inv1.assign(z, e); BOOST_CHECK(inv1.to_congruence(z) == Congruence(Int(4, 32, Signed), Int(2, 32, Signed))); } BOOST_AUTO_TEST_CASE(unary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 6, Signed)); Variable z(vfac.get("z", 8, Signed)); Variable w(vfac.get("w", 8, Unsigned)); auto inv = CongruenceDomain::top(); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(85, 8, Signed))); inv.apply(UnaryOperator::Trunc, y, x); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(21, 6, Signed))); inv.apply(UnaryOperator::Ext, z, y); BOOST_CHECK(inv.to_congruence(z) == Congruence(Int(21, 8, Signed))); inv.apply(UnaryOperator::SignCast, w, z); BOOST_CHECK(inv.to_congruence(w) == Congruence(Int(21, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(binary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 8, Signed)); Variable z(vfac.get("z", 8, Signed)); auto inv = CongruenceDomain::top(); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(85, 8, Signed))); inv.apply(BinaryOperator::Add, y, x, Int(43, 8, Signed)); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(-128, 8, Signed))); inv.apply(BinaryOperator::SubNoWrap, z, y, Int(1, 8, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_var) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv.set(y, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); } BOOST_AUTO_TEST_CASE(add_int) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv.add(Predicate::EQ, x, Int(7, 32, Signed)); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(7, 32, Signed))); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv.set(x, Congruence::bottom(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = CongruenceDomain::top(); inv.refine(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv.refine(x, Congruence(Int(4, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); inv.set(y, Congruence(Int(3, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(3, 32, Signed), Int(1, 32, Signed))); inv.forget(x); BOOST_CHECK(inv.to_congruence(x) == Congruence::top(32, Signed)); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(3, 32, Signed), Int(1, 32, Signed))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv.set(y, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); LinearExpr e1(Int(1, 32, Signed)); e1.add(Int(2, 32, Signed), x); BOOST_CHECK(inv.to_congruence(e1) == Congruence(Int(4, 32, Signed), Int(3, 32, Signed))); LinearExpr e2(Int(1, 32, Signed)); e2.add(Int(2, 32, Signed), x); e2.add(Int(-3, 32, Signed), y); BOOST_CHECK(inv.to_congruence(e2) == Congruence(Int(4, 32, Signed), Int(2, 32, Signed))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/machine_int/interval.cpp000066400000000000000000000500071473507761200255630ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::IntervalDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_int_interval_domain #define BOOST_TEST_DYN_LINK #include #include #include #include using Int = ikos::core::MachineInt; using Interval = ikos::core::machine_int::Interval; using ikos::core::Signed; using ikos::core::Unsigned; using ikos::core::machine_int::BinaryOperator; using ikos::core::machine_int::Predicate; using ikos::core::machine_int::UnaryOperator; using VariableFactory = ikos::core::example::machine_int::VariableFactory; using Variable = VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< Int, Variable >; using LinearExpr = ikos::core::LinearExpression< Int, Variable >; using IntervalDomain = ikos::core::machine_int::IntervalDomain< Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK(IntervalDomain::top().is_top()); BOOST_CHECK(!IntervalDomain::top().is_bottom()); BOOST_CHECK(!IntervalDomain::bottom().is_top()); BOOST_CHECK(IntervalDomain::bottom().is_bottom()); auto inv = IntervalDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(Int(1, 32, Signed))); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom(32, Signed)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = IntervalDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); BOOST_CHECK(IntervalDomain::bottom().leq(IntervalDomain::top())); BOOST_CHECK(IntervalDomain::bottom().leq(IntervalDomain::bottom())); BOOST_CHECK(!IntervalDomain::top().leq(IntervalDomain::bottom())); BOOST_CHECK(IntervalDomain::top().leq(IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(inv1.leq(IntervalDomain::top())); BOOST_CHECK(!inv1.leq(IntervalDomain::bottom())); auto inv2 = IntervalDomain::top(); inv2.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv2.leq(IntervalDomain::top())); BOOST_CHECK(!inv2.leq(IntervalDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = IntervalDomain::top(); inv3.set(x, Interval(Int(0, 32, Signed))); inv3.set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv3.leq(IntervalDomain::top())); BOOST_CHECK(!inv3.leq(IntervalDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = IntervalDomain::top(); inv4.set(x, Interval(Int(0, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv4.leq(IntervalDomain::top())); BOOST_CHECK(!inv4.leq(IntervalDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = IntervalDomain::top(); inv5.set(x, Interval(Int(0, 32, Signed))); inv5.set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv5.set(z, Interval(Int::min(32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv5.leq(IntervalDomain::top())); BOOST_CHECK(!inv5.leq(IntervalDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK(!IntervalDomain::bottom().equals(IntervalDomain::top())); BOOST_CHECK(IntervalDomain::bottom().equals(IntervalDomain::bottom())); BOOST_CHECK(!IntervalDomain::top().equals(IntervalDomain::bottom())); BOOST_CHECK(IntervalDomain::top().equals(IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(!inv1.equals(IntervalDomain::top())); BOOST_CHECK(!inv1.equals(IntervalDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = IntervalDomain::top(); inv2.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv2.equals(IntervalDomain::top())); BOOST_CHECK(!inv2.equals(IntervalDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = IntervalDomain::top(); inv3.set(x, Interval(Int(0, 32, Signed))); inv3.set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv3.equals(IntervalDomain::top())); BOOST_CHECK(!inv3.equals(IntervalDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((IntervalDomain::bottom().join(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().join(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().join(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().join(IntervalDomain::bottom()) == IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((inv1.join(IntervalDomain::bottom()) == inv1)); BOOST_CHECK((IntervalDomain::top().join(inv1) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = IntervalDomain::top(); inv4.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((IntervalDomain::bottom().widening(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().widening(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().widening(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().widening(IntervalDomain::bottom()) == IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((inv1.widening(IntervalDomain::bottom()) == inv1)); BOOST_CHECK((IntervalDomain::top().widening(inv1) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv3.set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((IntervalDomain::bottom().meet(IntervalDomain::top()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::bottom().meet(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().meet(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().meet(IntervalDomain::bottom()) == IntervalDomain::bottom())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.meet(IntervalDomain::top()) == inv1)); BOOST_CHECK( (inv1.meet(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().meet(inv1) == inv1)); BOOST_CHECK( (IntervalDomain::bottom().meet(inv1) == IntervalDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = IntervalDomain::top(); auto inv5 = IntervalDomain::top(); inv4.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed))); inv5.set(x, Interval(Int(0, 32, Signed))); inv5.set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((IntervalDomain::bottom().narrowing(IntervalDomain::top()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::bottom().narrowing(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().narrowing(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().narrowing(IntervalDomain::bottom()) == IntervalDomain::bottom())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK((inv1.narrowing(IntervalDomain::top()) == inv1)); BOOST_CHECK( (inv1.narrowing(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK( (IntervalDomain::bottom().narrowing(inv1) == IntervalDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); auto inv1 = IntervalDomain::top(); auto inv2 = IntervalDomain::top(); inv1.assign(x, Int(0, 32, Signed)); inv2.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, Int(0, 32, Signed)); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.set_to_top(); inv1.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.set(y, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); LinearExpr e(Int(1, 32, Signed)); e.add(Int(2, 32, Signed), x); e.add(Int(-3, 32, Signed), y); inv1.assign(z, e); BOOST_CHECK(inv1.to_interval(z) == Interval(Int(-7, 32, Signed), Int(0, 32, Signed))); } BOOST_AUTO_TEST_CASE(unary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 6, Signed)); Variable z(vfac.get("z", 8, Signed)); Variable w(vfac.get("w", 8, Unsigned)); auto inv = IntervalDomain::top(); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(85, 8, Signed))); inv.apply(UnaryOperator::Trunc, y, x); BOOST_CHECK(inv.to_interval(y) == Interval(Int(21, 6, Signed))); inv.apply(UnaryOperator::Ext, z, y); BOOST_CHECK(inv.to_interval(z) == Interval(Int(21, 8, Signed))); inv.apply(UnaryOperator::SignCast, w, z); BOOST_CHECK(inv.to_interval(w) == Interval(Int(21, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(binary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 8, Signed)); Variable z(vfac.get("z", 8, Signed)); auto inv = IntervalDomain::top(); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(85, 8, Signed))); inv.apply(BinaryOperator::Add, y, x, Int(43, 8, Signed)); BOOST_CHECK(inv.to_interval(y) == Interval(Int(-128, 8, Signed))); inv.apply(BinaryOperator::SubNoWrap, z, y, Int(1, 8, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_var) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain::top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(-4, 32, Signed), Int(0, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(0, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(0, 32, Signed))); inv.add(Predicate::NE, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.add(Predicate::GT, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(1, 32, Signed), Int(3, 32, Signed))); inv.add(Predicate::LE, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); inv.add(Predicate::LT, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.add(Predicate::GE, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); inv.set_to_top(); inv.set(y, Interval(Int::min(32, Signed))); inv.add(Predicate::LT, x, y); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_int) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain::top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::EQ, x, Int(1, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed))); inv.add(Predicate::NE, x, Int(1, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::GT, x, Int(2, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::LE, x, Int(3, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(3, 32, Signed))); inv.add(Predicate::EQ, x, Int(2, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(Predicate::GT, y, Int::max(32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(Predicate::LT, y, Int::min(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = IntervalDomain::top(); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(x, Interval::bottom(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = IntervalDomain::top(); inv.refine(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.refine(x, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain::top(); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top(32, Signed)); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain::top(); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); LinearExpr e1(Int(1, 32, Signed)); e1.add(Int(2, 32, Signed), x); BOOST_CHECK(inv.to_interval(e1) == Interval(Int(3, 32, Signed), Int(5, 32, Signed))); LinearExpr e2(Int(1, 32, Signed)); e2.add(Int(2, 32, Signed), x); e2.add(Int(-3, 32, Signed), y); BOOST_CHECK(inv.to_interval(e2) == Interval(Int(-9, 32, Signed), Int(-4, 32, Signed))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/machine_int/interval_congruence.cpp000066400000000000000000000613351473507761200300010ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::IntervalCongruenceDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_int_interval_congruence_domain #define BOOST_TEST_DYN_LINK #include #include #include #include using Int = ikos::core::MachineInt; using Interval = ikos::core::machine_int::Interval; using Congruence = ikos::core::machine_int::Congruence; using IntervalCongruence = ikos::core::machine_int::IntervalCongruence; using ikos::core::Signed; using ikos::core::Unsigned; using ikos::core::machine_int::BinaryOperator; using ikos::core::machine_int::Predicate; using ikos::core::machine_int::UnaryOperator; using VariableFactory = ikos::core::example::machine_int::VariableFactory; using Variable = VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< Int, Variable >; using LinearExpr = ikos::core::LinearExpression< Int, Variable >; using IntervalCongruenceDomain = ikos::core::machine_int::IntervalCongruenceDomain< Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK(IntervalCongruenceDomain::top().is_top()); BOOST_CHECK(!IntervalCongruenceDomain::top().is_bottom()); BOOST_CHECK(!IntervalCongruenceDomain::bottom().is_top()); BOOST_CHECK(IntervalCongruenceDomain::bottom().is_bottom()); auto inv = IntervalCongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, IntervalCongruence(Int(1, 32, Signed))); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, IntervalCongruence::bottom(32, Signed)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = IntervalCongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); BOOST_CHECK( IntervalCongruenceDomain::bottom().leq(IntervalCongruenceDomain::top())); BOOST_CHECK(IntervalCongruenceDomain::bottom().leq( IntervalCongruenceDomain::bottom())); BOOST_CHECK( !IntervalCongruenceDomain::top().leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK( IntervalCongruenceDomain::top().leq(IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Int(0, 32, Signed))); BOOST_CHECK(inv1.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv1.leq(IntervalCongruenceDomain::bottom())); auto inv2 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Interval(Int(0, 32, Signed), Int(10, 32, Signed)), Congruence(Int(2, 32, Signed), Int(0, 32, Signed)))); BOOST_CHECK(inv2.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv2.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = IntervalCongruenceDomain::top(); inv3.set(x, IntervalCongruence(Int(0, 32, Signed))); inv3.set(y, IntervalCongruence(Interval::top(32, Signed), Congruence(Int(2, 32, Signed), Int(0, 32, Signed)))); BOOST_CHECK(inv3.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv3.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = IntervalCongruenceDomain::top(); inv4.set(x, IntervalCongruence(Int(0, 32, Signed))); inv4.set(y, IntervalCongruence(Interval::top(32, Signed), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK(inv4.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv4.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = IntervalCongruenceDomain::top(); inv5.set(x, IntervalCongruence(Int(0, 32, Signed))); inv5.set(y, IntervalCongruence(Interval(Int(0, 32, Signed), Int(4, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); inv5.set(z, IntervalCongruence( Congruence(Int(3, 32, Signed), Int(0, 32, Signed)))); BOOST_CHECK(inv5.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv5.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK(!IntervalCongruenceDomain::bottom().equals( IntervalCongruenceDomain::top())); BOOST_CHECK(IntervalCongruenceDomain::bottom().equals( IntervalCongruenceDomain::bottom())); BOOST_CHECK(!IntervalCongruenceDomain::top().equals( IntervalCongruenceDomain::bottom())); BOOST_CHECK( IntervalCongruenceDomain::top().equals(IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Int(0, 32, Signed))); BOOST_CHECK(!inv1.equals(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv1.equals(IntervalCongruenceDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence( Congruence(Int(2, 32, Signed), Int(0, 32, Signed)))); BOOST_CHECK(!inv2.equals(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv2.equals(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = IntervalCongruenceDomain::top(); inv3.set(x, IntervalCongruence(Int(0, 32, Signed))); inv3.set(y, IntervalCongruence( Interval(Int(0, 32, Signed), Int(2, 32, Signed)))); BOOST_CHECK(!inv3.equals(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv3.equals(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((IntervalCongruenceDomain::bottom().join( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().join( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK( (IntervalCongruenceDomain::top().join(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().join( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Int(1, 32, Signed))); BOOST_CHECK((inv1.join(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((inv1.join(IntervalCongruenceDomain::bottom()) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::top().join(inv1) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Int(3, 32, Signed))); inv3.set(x, IntervalCongruence(Interval(Int(0, 32, Signed), Int(3, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = IntervalCongruenceDomain::top(); inv4.set(x, IntervalCongruence(Int(3, 32, Signed))); inv4.set(y, IntervalCongruence( Interval(Int(1, 32, Signed), Int(4, 32, Signed)))); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((IntervalCongruenceDomain::bottom().widening( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().widening( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().widening( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().widening( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((inv1.widening(IntervalCongruenceDomain::bottom()) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::top().widening(inv1) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Int(3, 32, Signed))); inv3.set(x, IntervalCongruence(Interval(Int(0, 32, Signed), Int::max(32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK((inv1.widening(inv2) == inv3)); auto inv4 = IntervalCongruenceDomain::top(); inv4.set(x, IntervalCongruence(Int(3, 32, Signed))); inv4.set(y, IntervalCongruence( Interval(Int(1, 32, Signed), Int(4, 32, Signed)))); BOOST_CHECK((inv4.widening(inv2) == inv2)); BOOST_CHECK((inv2.widening(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((IntervalCongruenceDomain::bottom().meet( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::bottom().meet( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK( (IntervalCongruenceDomain::top().meet(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().meet( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Interval(Int(1, 32, Signed), Int(13, 32, Signed)), Congruence(Int(6, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK((inv1.meet(IntervalCongruenceDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().meet(inv1) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::bottom().meet(inv1) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Interval(Int(7, 32, Signed), Int::max(32, Signed)), Congruence(Int(8, 32, Signed), Int(7, 32, Signed)))); inv3.set(x, IntervalCongruence(Int(7, 32, Signed))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((IntervalCongruenceDomain::bottom().narrowing( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::bottom().narrowing( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().narrowing( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().narrowing( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Interval(Int(1, 32, Signed), Int(13, 32, Signed)), Congruence(Int(6, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK((inv1.narrowing(IntervalCongruenceDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::bottom().narrowing(inv1) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Interval(Int(7, 32, Signed), Int::max(32, Signed)), Congruence(Int(8, 32, Signed), Int(7, 32, Signed)))); inv3.set(x, IntervalCongruence(Int(7, 32, Signed))); BOOST_CHECK((inv1.narrowing(inv2) == inv3)); BOOST_CHECK((inv2.narrowing(inv1) == inv3)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); auto inv1 = IntervalCongruenceDomain::top(); auto inv2 = IntervalCongruenceDomain::top(); inv1.assign(x, Int(0, 32, Signed)); inv2.set(x, IntervalCongruence(Int(0, 32, Signed))); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, Int(0, 32, Signed)); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, IntervalCongruence(Interval(Int(1, 32, Signed), Int(5, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); inv1.assign(y, x); BOOST_CHECK( inv1.to_interval_congruence(y) == IntervalCongruence(Interval(Int(1, 32, Signed), Int(5, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); inv1.set_to_top(); inv1.set(x, IntervalCongruence(Interval(Int(1, 32, Signed), Int(13, 32, Signed)), Congruence(Int(6, 32, Signed), Int(1, 32, Signed)))); inv1.set(y, IntervalCongruence(Interval(Int(7, 32, Signed), Int(15, 32, Signed)), Congruence(Int(8, 32, Signed), Int(7, 32, Signed)))); LinearExpr e(Int(1, 32, Signed)); e.add(Int(2, 32, Signed), x); e.add(Int(-3, 32, Signed), y); inv1.assign(z, e); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Int(-42, 32, Signed), Int(6, 32, Signed)), Congruence(Int(4, 32, Signed), Int(2, 32, Signed)))); } BOOST_AUTO_TEST_CASE(unary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 6, Signed)); Variable z(vfac.get("z", 8, Signed)); Variable w(vfac.get("w", 8, Unsigned)); auto inv = IntervalCongruenceDomain::top(); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Int(85, 8, Signed))); inv.apply(UnaryOperator::Trunc, y, x); BOOST_CHECK(inv.to_interval_congruence(y) == IntervalCongruence(Int(21, 6, Signed))); inv.apply(UnaryOperator::Ext, z, y); BOOST_CHECK(inv.to_interval_congruence(z) == IntervalCongruence(Int(21, 8, Signed))); inv.apply(UnaryOperator::SignCast, w, z); BOOST_CHECK(inv.to_interval_congruence(w) == IntervalCongruence(Int(21, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(binary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 8, Signed)); Variable z(vfac.get("z", 8, Signed)); auto inv = IntervalCongruenceDomain::top(); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Int(85, 8, Signed))); inv.apply(BinaryOperator::Add, y, x, Int(43, 8, Signed)); BOOST_CHECK(inv.to_interval_congruence(y) == IntervalCongruence(Int(-128, 8, Signed))); inv.apply(BinaryOperator::SubNoWrap, z, y, Int(1, 8, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_var) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalCongruenceDomain::top(); inv.set(x, IntervalCongruence(Interval(Int(7, 32, Signed), Int(13, 32, Signed)), Congruence(Int(6, 32, Signed), Int(1, 32, Signed)))); inv.set(y, IntervalCongruence(Interval::top(32, Signed), Congruence(Int(8, 32, Signed), Int(7, 32, Signed)))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Int(7, 32, Signed))); BOOST_CHECK(inv.to_interval_congruence(y) == IntervalCongruence(Int(7, 32, Signed))); } BOOST_AUTO_TEST_CASE(add_int) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = IntervalCongruenceDomain::top(); inv.set(x, IntervalCongruence(Interval::top(32, Signed), Congruence(Int(6, 32, Signed), Int(1, 32, Signed)))); inv.add(Predicate::EQ, x, Int(7, 32, Signed)); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Int(7, 32, Signed))); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = IntervalCongruenceDomain::top(); inv.set(x, IntervalCongruence(Interval(Int(3, 32, Signed), Int(11, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK( inv.to_interval_congruence(x) == IntervalCongruence(Interval(Int(3, 32, Signed), Int(11, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); inv.set(x, IntervalCongruence::bottom(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = IntervalCongruenceDomain::top(); inv.set(x, IntervalCongruence(Interval(Int(6, 32, Signed), Int(11, 32, Signed)), Congruence(Int(5, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK( inv.to_interval_congruence(x) == IntervalCongruence(Interval(Int(6, 32, Signed), Int(11, 32, Signed)), Congruence(Int(5, 32, Signed), Int(1, 32, Signed)))); inv.refine(x, IntervalCongruence( Interval(Int(7, 32, Signed), Int(10, 32, Signed)))); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalCongruenceDomain::top(); inv.set(x, IntervalCongruence(Interval(Int(0, 32, Signed), Int(10, 32, Signed)), Congruence(Int(2, 32, Signed), Int(0, 32, Signed)))); inv.set(y, IntervalCongruence(Interval(Int(1, 32, Signed), Int(11, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); BOOST_CHECK( inv.to_interval_congruence(x) == IntervalCongruence(Interval(Int(0, 32, Signed), Int(10, 32, Signed)), Congruence(Int(2, 32, Signed), Int(0, 32, Signed)))); BOOST_CHECK( inv.to_interval_congruence(y) == IntervalCongruence(Interval(Int(1, 32, Signed), Int(11, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); inv.forget(x); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence::top(32, Signed)); BOOST_CHECK( inv.to_interval_congruence(y) == IntervalCongruence(Interval(Int(1, 32, Signed), Int(11, 32, Signed)), Congruence(Int(2, 32, Signed), Int(1, 32, Signed)))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalCongruenceDomain::top(); inv.set(x, IntervalCongruence(Interval(Int(7, 32, Signed), Int(13, 32, Signed)), Congruence(Int(6, 32, Signed), Int(1, 32, Signed)))); inv.set(y, IntervalCongruence(Interval(Int(7, 32, Signed), Int(15, 32, Signed)), Congruence(Int(8, 32, Signed), Int(7, 32, Signed)))); LinearExpr e1(Int(1, 32, Signed)); e1.add(Int(2, 32, Signed), x); BOOST_CHECK( inv.to_interval_congruence(e1) == IntervalCongruence(Interval(Int(15, 32, Signed), Int(27, 32, Signed)), Congruence(Int(4, 32, Signed), Int(3, 32, Signed)))); LinearExpr e2(Int(1, 32, Signed)); e2.add(Int(2, 32, Signed), x); e2.add(Int(-3, 32, Signed), y); BOOST_CHECK( inv.to_interval_congruence(e2) == IntervalCongruence(Interval(Int(-30, 32, Signed), Int(6, 32, Signed)), Congruence(Int(4, 32, Signed), Int(2, 32, Signed)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/machine_int/numeric_domain_adapter.cpp000066400000000000000000000604551473507761200304400ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::NumericDomainAdapter * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_numeric_domain_adapter #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using Int = ikos::core::MachineInt; using Interval = ikos::core::machine_int::Interval; using ikos::core::Signed; using ikos::core::Unsigned; using ikos::core::machine_int::BinaryOperator; using ikos::core::machine_int::Predicate; using ikos::core::machine_int::UnaryOperator; using VariableFactory = ikos::core::example::machine_int::VariableFactory; using Variable = VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< Int, Variable >; using LinearExpr = ikos::core::LinearExpression< Int, Variable >; // Machine integer abstract domain based on the numeric interval domain using NumericIntervalDomain = ikos::core::numeric::IntervalDomain< ZNumber, Variable >; using IntervalDomain = ikos::core::machine_int::NumericDomainAdapter< Variable, NumericIntervalDomain >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK(IntervalDomain(NumericIntervalDomain::top()).is_top()); BOOST_CHECK(!IntervalDomain(NumericIntervalDomain::top()).is_bottom()); BOOST_CHECK(!IntervalDomain(NumericIntervalDomain::bottom()).is_top()); BOOST_CHECK(IntervalDomain(NumericIntervalDomain::bottom()).is_bottom()); auto inv = IntervalDomain(NumericIntervalDomain::top()); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(Int(1, 32, Signed))); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom(32, Signed)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = IntervalDomain(NumericIntervalDomain::top()); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); BOOST_CHECK(IntervalDomain(NumericIntervalDomain::bottom()) .leq(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(IntervalDomain(NumericIntervalDomain::bottom()) .leq(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(!IntervalDomain(NumericIntervalDomain::top()) .leq(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(IntervalDomain(NumericIntervalDomain::top()) .leq(IntervalDomain(NumericIntervalDomain::top()))); auto inv1 = IntervalDomain(NumericIntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(inv1.leq(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv1.leq(IntervalDomain(NumericIntervalDomain::bottom()))); auto inv2 = IntervalDomain(NumericIntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv2.leq(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv2.leq(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = IntervalDomain(NumericIntervalDomain::top()); inv3.set(x, Interval(Int(0, 32, Signed))); inv3.set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv3.leq(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv3.leq(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = IntervalDomain(NumericIntervalDomain::top()); inv4.set(x, Interval(Int(0, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv4.leq(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv4.leq(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = IntervalDomain(NumericIntervalDomain::top()); inv5.set(x, Interval(Int(0, 32, Signed))); inv5.set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv5.set(z, Interval(Int::min(32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv5.leq(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv5.leq(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK(!IntervalDomain(NumericIntervalDomain::bottom()) .equals(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(IntervalDomain(NumericIntervalDomain::bottom()) .equals(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(!IntervalDomain(NumericIntervalDomain::top()) .equals(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(IntervalDomain(NumericIntervalDomain::top()) .equals(IntervalDomain(NumericIntervalDomain::top()))); auto inv1 = IntervalDomain(NumericIntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(!inv1.equals(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv1.equals(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = IntervalDomain(NumericIntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv2.equals(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv2.equals(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = IntervalDomain(NumericIntervalDomain::top()); inv3.set(x, Interval(Int(0, 32, Signed))); inv3.set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv3.equals(IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK(!inv3.equals(IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()) .join(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()) .join(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()) .join(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()) .join(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::top()))); auto inv1 = IntervalDomain(NumericIntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK( (inv1.join(IntervalDomain(NumericIntervalDomain::bottom())) == inv1)); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()).join(inv1) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK( (IntervalDomain(NumericIntervalDomain::bottom()).join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = IntervalDomain(NumericIntervalDomain::top()); auto inv3 = IntervalDomain(NumericIntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = IntervalDomain(NumericIntervalDomain::top()); inv4.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()) .widening(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()) .widening(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()) .widening(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()) .widening(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::top()))); auto inv1 = IntervalDomain(NumericIntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK( (inv1.widening(IntervalDomain(NumericIntervalDomain::bottom())) == inv1)); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()).widening(inv1) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK( (IntervalDomain(NumericIntervalDomain::bottom()).widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = IntervalDomain(NumericIntervalDomain::top()); auto inv3 = IntervalDomain(NumericIntervalDomain::top()); inv2.set(x, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv3.set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK((inv3.leq(inv1.widening(inv2)))); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()) .meet(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()) .meet(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()) .meet(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()) .meet(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); auto inv1 = IntervalDomain(NumericIntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK( (inv1.meet(IntervalDomain(NumericIntervalDomain::top())) == inv1)); BOOST_CHECK((inv1.meet(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK( (IntervalDomain(NumericIntervalDomain::top()).meet(inv1) == inv1)); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()).meet(inv1) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = IntervalDomain(NumericIntervalDomain::top()); auto inv3 = IntervalDomain(NumericIntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = IntervalDomain(NumericIntervalDomain::top()); auto inv5 = IntervalDomain(NumericIntervalDomain::top()); inv4.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed))); inv5.set(x, Interval(Int(0, 32, Signed))); inv5.set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::bottom()) .narrowing(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK( (IntervalDomain(NumericIntervalDomain::bottom()) .narrowing(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK((IntervalDomain(NumericIntervalDomain::top()) .narrowing(IntervalDomain(NumericIntervalDomain::top())) == IntervalDomain(NumericIntervalDomain::top()))); BOOST_CHECK( (IntervalDomain(NumericIntervalDomain::top()) .narrowing(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); auto inv1 = IntervalDomain(NumericIntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK( (inv1.narrowing(IntervalDomain(NumericIntervalDomain::top())) == inv1)); BOOST_CHECK( (inv1.narrowing(IntervalDomain(NumericIntervalDomain::bottom())) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK( (IntervalDomain(NumericIntervalDomain::top()).narrowing(inv1) == inv1)); BOOST_CHECK( (IntervalDomain(NumericIntervalDomain::bottom()).narrowing(inv1) == IntervalDomain(NumericIntervalDomain::bottom()))); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = IntervalDomain(NumericIntervalDomain::top()); auto inv3 = IntervalDomain(NumericIntervalDomain::top()); inv2.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.narrowing(inv2) == inv1)); // imprecise but sound BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); auto inv1 = IntervalDomain(NumericIntervalDomain::top()); auto inv2 = IntervalDomain(NumericIntervalDomain::top()); inv1.assign(x, Int(0, 32, Signed)); inv2.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, Int(0, 32, Signed)); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.set_to_top(); inv1.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.set(y, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); LinearExpr e(Int(1, 32, Signed)); e.add(Int(2, 32, Signed), x); e.add(Int(-3, 32, Signed), y); inv1.assign(z, e); BOOST_CHECK(inv1.to_interval(z) == Interval(Int(-7, 32, Signed), Int(0, 32, Signed))); } BOOST_AUTO_TEST_CASE(unary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 6, Signed)); Variable z(vfac.get("z", 8, Signed)); Variable w(vfac.get("w", 8, Unsigned)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(85, 8, Signed))); inv.apply(UnaryOperator::Trunc, y, x); BOOST_CHECK(inv.to_interval(y) == Interval(Int(21, 6, Signed))); inv.apply(UnaryOperator::Ext, z, y); BOOST_CHECK(inv.to_interval(z) == Interval(Int(21, 8, Signed))); inv.apply(UnaryOperator::SignCast, w, z); BOOST_CHECK(inv.to_interval(w) == Interval(Int(21, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(binary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 8, Signed)); Variable z(vfac.get("z", 8, Signed)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(85, 8, Signed))); inv.apply(BinaryOperator::Add, y, x, Int(43, 8, Signed)); BOOST_CHECK(inv.to_interval(y) == Interval(Int(-128, 8, Signed))); inv.apply(BinaryOperator::SubNoWrap, z, y, Int(1, 8, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_var) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(-4, 32, Signed), Int(0, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(0, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(0, 32, Signed))); inv.add(Predicate::NE, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.add(Predicate::GT, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(1, 32, Signed), Int(3, 32, Signed))); inv.add(Predicate::LE, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); inv.add(Predicate::LT, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.add(Predicate::GE, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); inv.set_to_top(); inv.set(x, Interval::top(32, Signed)); inv.set(y, Interval(Int::min(32, Signed))); inv.add(Predicate::LT, x, y); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_int) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::EQ, x, Int(1, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed))); inv.add(Predicate::NE, x, Int(1, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::GT, x, Int(2, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::LE, x, Int(3, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(3, 32, Signed))); inv.add(Predicate::EQ, x, Int(2, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(y, Interval::top(32, Signed)); inv.add(Predicate::GT, y, Int::max(32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(y, Interval::top(32, Signed)); inv.add(Predicate::LT, y, Int::min(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(x, Interval::bottom(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.refine(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.refine(x, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top(32, Signed)); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = IntervalDomain(NumericIntervalDomain::top()); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); LinearExpr e1(Int(1, 32, Signed)); e1.add(Int(2, 32, Signed), x); BOOST_CHECK(inv.to_interval(e1) == Interval(Int(3, 32, Signed), Int(5, 32, Signed))); LinearExpr e2(Int(1, 32, Signed)); e2.add(Int(2, 32, Signed), x); e2.add(Int(-3, 32, Signed), y); BOOST_CHECK(inv.to_interval(e2) == Interval(Int(-9, 32, Signed), Int(-4, 32, Signed))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/machine_int/polymorphic_domain.cpp000066400000000000000000001116261473507761200276400ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::PolymorphicDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_int_polymorphic_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include #include using Int = ikos::core::MachineInt; using Interval = ikos::core::machine_int::Interval; using Congruence = ikos::core::machine_int::Congruence; using ikos::core::Signed; using ikos::core::Unsigned; using ikos::core::machine_int::BinaryOperator; using ikos::core::machine_int::Predicate; using ikos::core::machine_int::UnaryOperator; using VariableFactory = ikos::core::example::machine_int::VariableFactory; using Variable = VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< Int, Variable >; using LinearExpr = ikos::core::LinearExpression< Int, Variable >; using PolymorphicDomain = ikos::core::machine_int::PolymorphicDomain< Variable >; using IntervalDomain = ikos::core::machine_int::IntervalDomain< Variable >; using CongruenceDomain = ikos::core::machine_int::CongruenceDomain< Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK(PolymorphicDomain(IntervalDomain::top()).is_top()); BOOST_CHECK(!PolymorphicDomain(IntervalDomain::top()).is_bottom()); BOOST_CHECK(!PolymorphicDomain(IntervalDomain::bottom()).is_top()); BOOST_CHECK(PolymorphicDomain(IntervalDomain::bottom()).is_bottom()); { auto inv = PolymorphicDomain(IntervalDomain::top()); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(Int(1, 32, Signed))); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom(32, Signed)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence(Int(1, 32, Signed))); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence::bottom(32, Signed)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; { auto inv = PolymorphicDomain(IntervalDomain::top()); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); BOOST_CHECK(PolymorphicDomain(IntervalDomain::bottom()) .leq(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(PolymorphicDomain(IntervalDomain::bottom()) .leq(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(!PolymorphicDomain(IntervalDomain::top()) .leq(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(PolymorphicDomain(IntervalDomain::top()) .leq(PolymorphicDomain(IntervalDomain::top()))); { auto inv1 = PolymorphicDomain(IntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(inv1.leq(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv1.leq(PolymorphicDomain(IntervalDomain::bottom()))); auto inv2 = PolymorphicDomain(IntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv2.leq(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv2.leq(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = PolymorphicDomain(IntervalDomain::top()); inv3.set(x, Interval(Int(0, 32, Signed))); inv3.set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv3.leq(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv3.leq(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = PolymorphicDomain(IntervalDomain::top()); inv4.set(x, Interval(Int(0, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv4.leq(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv4.leq(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = PolymorphicDomain(IntervalDomain::top()); inv5.set(x, Interval(Int(0, 32, Signed))); inv5.set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv5.set(z, Interval(Int::min(32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv5.leq(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv5.leq(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } { auto inv1 = PolymorphicDomain(CongruenceDomain::top()); inv1.set(x, Congruence(Int(0, 32, Signed))); BOOST_CHECK(inv1.leq(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv1.leq(PolymorphicDomain(CongruenceDomain::bottom()))); auto inv2 = PolymorphicDomain(CongruenceDomain::top()); inv2.set(x, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv2.leq(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv2.leq(PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = PolymorphicDomain(CongruenceDomain::top()); inv3.set(x, Congruence(Int(0, 32, Signed))); inv3.set(y, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv3.leq(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv3.leq(PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = PolymorphicDomain(CongruenceDomain::top()); inv4.set(x, Congruence(Int(0, 32, Signed))); inv4.set(y, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv4.leq(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv4.leq(PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = PolymorphicDomain(CongruenceDomain::top()); inv5.set(x, Congruence(Int(0, 32, Signed))); inv5.set(y, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv5.set(z, Congruence(Int(3, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv5.leq(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv5.leq(PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK(!PolymorphicDomain(IntervalDomain::bottom()) .equals(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(PolymorphicDomain(IntervalDomain::bottom()) .equals(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(!PolymorphicDomain(IntervalDomain::top()) .equals(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(PolymorphicDomain(IntervalDomain::top()) .equals(PolymorphicDomain(IntervalDomain::top()))); { auto inv1 = PolymorphicDomain(IntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(!inv1.equals(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv1.equals(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = PolymorphicDomain(IntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv2.equals(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv2.equals(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = PolymorphicDomain(IntervalDomain::top()); inv3.set(x, Interval(Int(0, 32, Signed))); inv3.set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv3.equals(PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK(!inv3.equals(PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } { auto inv1 = PolymorphicDomain(CongruenceDomain::top()); inv1.set(x, Congruence(Int(0, 32, Signed))); BOOST_CHECK(!inv1.equals(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv1.equals(PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = PolymorphicDomain(CongruenceDomain::top()); inv2.set(x, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(!inv2.equals(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv2.equals(PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = PolymorphicDomain(CongruenceDomain::top()); inv3.set(x, Congruence(Int(0, 32, Signed))); inv3.set(y, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(!inv3.equals(PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK(!inv3.equals(PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .join(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .join(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .join(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .join(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::top()))); { auto inv1 = PolymorphicDomain(IntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK( (inv1.join(PolymorphicDomain(IntervalDomain::bottom())) == inv1)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()).join(inv1) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK( (PolymorphicDomain(IntervalDomain::bottom()).join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = PolymorphicDomain(IntervalDomain::top()); auto inv3 = PolymorphicDomain(IntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = PolymorphicDomain(IntervalDomain::top()); inv4.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } { auto inv1 = PolymorphicDomain(CongruenceDomain::top()); inv1.set(x, Congruence(Int(1, 32, Signed))); BOOST_CHECK((inv1.join(PolymorphicDomain(CongruenceDomain::top())) == PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK( (inv1.join(PolymorphicDomain(CongruenceDomain::bottom())) == inv1)); BOOST_CHECK( (PolymorphicDomain(PolymorphicDomain(CongruenceDomain::top())) .join(inv1) == PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK( (PolymorphicDomain(CongruenceDomain::bottom()).join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = PolymorphicDomain(CongruenceDomain::top()); auto inv3 = PolymorphicDomain(CongruenceDomain::top()); inv2.set(x, Congruence(Int(3, 32, Signed))); inv3.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = PolymorphicDomain(CongruenceDomain::top()); inv4.set(x, Congruence(Int(3, 32, Signed))); inv4.set(y, Congruence(Int(4, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .widening(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .widening(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .widening(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .widening(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::top()))); { auto inv1 = PolymorphicDomain(IntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK( (inv1.widening(PolymorphicDomain(IntervalDomain::bottom())) == inv1)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()).widening(inv1) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK( (PolymorphicDomain(IntervalDomain::bottom()).widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = PolymorphicDomain(IntervalDomain::top()); auto inv3 = PolymorphicDomain(IntervalDomain::top()); inv2.set(x, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv3.set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } { auto inv1 = PolymorphicDomain(CongruenceDomain::top()); inv1.set(x, Congruence(Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(PolymorphicDomain(CongruenceDomain::top())) == PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK( (inv1.widening(PolymorphicDomain(CongruenceDomain::bottom())) == inv1)); BOOST_CHECK((PolymorphicDomain(CongruenceDomain::top()).widening(inv1) == PolymorphicDomain(CongruenceDomain::top()))); BOOST_CHECK( (PolymorphicDomain(CongruenceDomain::bottom()).widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = PolymorphicDomain(CongruenceDomain::top()); auto inv3 = PolymorphicDomain(CongruenceDomain::top()); inv2.set(x, Congruence(Int(3, 32, Signed))); inv3.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv3)); auto inv4 = PolymorphicDomain(CongruenceDomain::top()); inv4.set(x, Congruence(Int(3, 32, Signed))); inv4.set(y, Congruence(Int(4, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv4.widening(inv2) == inv2)); BOOST_CHECK((inv2.widening(inv4) == inv2)); } } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .meet(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .meet(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .meet(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .meet(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); { auto inv1 = PolymorphicDomain(IntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.meet(PolymorphicDomain(IntervalDomain::top())) == inv1)); BOOST_CHECK((inv1.meet(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()).meet(inv1) == inv1)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()).meet(inv1) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = PolymorphicDomain(IntervalDomain::top()); auto inv3 = PolymorphicDomain(IntervalDomain::top()); inv2.set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = PolymorphicDomain(IntervalDomain::top()); auto inv5 = PolymorphicDomain(IntervalDomain::top()); inv4.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv4.set(y, Interval(Int(0, 32, Signed))); inv5.set(x, Interval(Int(0, 32, Signed))); inv5.set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } { auto inv1 = PolymorphicDomain(CongruenceDomain::top()); inv1.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK( (inv1.meet(PolymorphicDomain(CongruenceDomain::top())) == inv1)); BOOST_CHECK((inv1.meet(PolymorphicDomain(CongruenceDomain::bottom())) == PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK( (PolymorphicDomain(CongruenceDomain::top()).meet(inv1) == inv1)); BOOST_CHECK((PolymorphicDomain(CongruenceDomain::bottom()).meet(inv1) == PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = PolymorphicDomain(CongruenceDomain::top()); auto inv3 = PolymorphicDomain(CongruenceDomain::top()); inv2.set(x, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); inv3.set(x, Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); } } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .narrowing(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()) .narrowing(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .narrowing(PolymorphicDomain(IntervalDomain::top())) == PolymorphicDomain(IntervalDomain::top()))); BOOST_CHECK((PolymorphicDomain(IntervalDomain::top()) .narrowing(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); { auto inv1 = PolymorphicDomain(IntervalDomain::top()); inv1.set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK( (inv1.narrowing(PolymorphicDomain(IntervalDomain::top())) == inv1)); BOOST_CHECK((inv1.narrowing(PolymorphicDomain(IntervalDomain::bottom())) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK( (PolymorphicDomain(IntervalDomain::top()).narrowing(inv1) == inv1)); BOOST_CHECK((PolymorphicDomain(IntervalDomain::bottom()).narrowing(inv1) == PolymorphicDomain(IntervalDomain::bottom()))); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = PolymorphicDomain(IntervalDomain::top()); auto inv3 = PolymorphicDomain(IntervalDomain::top()); inv2.set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } { auto inv1 = PolymorphicDomain(CongruenceDomain::top()); inv1.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK( (inv1.narrowing(PolymorphicDomain(CongruenceDomain::top())) == inv1)); BOOST_CHECK( (inv1.narrowing(PolymorphicDomain(CongruenceDomain::bottom())) == PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK( (PolymorphicDomain(CongruenceDomain::top()).narrowing(inv1) == inv1)); BOOST_CHECK( (PolymorphicDomain(CongruenceDomain::bottom()).narrowing(inv1) == PolymorphicDomain(CongruenceDomain::bottom()))); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = PolymorphicDomain(CongruenceDomain::top()); auto inv3 = PolymorphicDomain(CongruenceDomain::top()); inv2.set(x, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); inv3.set(x, Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); BOOST_CHECK((inv1.narrowing(inv2) == inv3)); BOOST_CHECK((inv2.narrowing(inv1) == inv3)); } } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); Variable z(vfac.get("z", 32, Signed)); { auto inv1 = PolymorphicDomain(IntervalDomain::top()); auto inv2 = PolymorphicDomain(IntervalDomain::top()); inv1.assign(x, Int(0, 32, Signed)); inv2.set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, Int(0, 32, Signed)); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.set_to_top(); inv1.set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.set(y, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); LinearExpr e(Int(1, 32, Signed)); e.add(Int(2, 32, Signed), x); e.add(Int(-3, 32, Signed), y); inv1.assign(z, e); BOOST_CHECK(inv1.to_interval(z) == Interval(Int(-7, 32, Signed), Int(0, 32, Signed))); } { auto inv1 = PolymorphicDomain(CongruenceDomain::top()); auto inv2 = PolymorphicDomain(CongruenceDomain::top()); inv1.assign(x, Int(0, 32, Signed)); inv2.set(x, Congruence(Int(0, 32, Signed))); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, Int(0, 32, Signed)); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv1.assign(y, x); BOOST_CHECK(inv1.to_congruence(y) == Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv1.set_to_top(); inv1.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv1.set(y, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); LinearExpr e(Int(1, 32, Signed)); e.add(Int(2, 32, Signed), x); e.add(Int(-3, 32, Signed), y); inv1.assign(z, e); BOOST_CHECK(inv1.to_congruence(z) == Congruence(Int(4, 32, Signed), Int(2, 32, Signed))); } } BOOST_AUTO_TEST_CASE(unary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 6, Signed)); Variable z(vfac.get("z", 8, Signed)); Variable w(vfac.get("w", 8, Unsigned)); { auto inv = PolymorphicDomain(IntervalDomain::top()); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(85, 8, Signed))); inv.apply(UnaryOperator::Trunc, y, x); BOOST_CHECK(inv.to_interval(y) == Interval(Int(21, 6, Signed))); inv.apply(UnaryOperator::Ext, z, y); BOOST_CHECK(inv.to_interval(z) == Interval(Int(21, 8, Signed))); inv.apply(UnaryOperator::SignCast, w, z); BOOST_CHECK(inv.to_interval(w) == Interval(Int(21, 8, Unsigned))); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(85, 8, Signed))); inv.apply(UnaryOperator::Trunc, y, x); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(21, 6, Signed))); inv.apply(UnaryOperator::Ext, z, y); BOOST_CHECK(inv.to_congruence(z) == Congruence(Int(21, 8, Signed))); inv.apply(UnaryOperator::SignCast, w, z); BOOST_CHECK(inv.to_congruence(w) == Congruence(Int(21, 8, Unsigned))); } } BOOST_AUTO_TEST_CASE(binary_apply) { VariableFactory vfac; Variable x(vfac.get("x", 8, Signed)); Variable y(vfac.get("y", 8, Signed)); Variable z(vfac.get("z", 8, Signed)); { auto inv = PolymorphicDomain(IntervalDomain::top()); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(85, 8, Signed))); inv.apply(BinaryOperator::Add, y, x, Int(43, 8, Signed)); BOOST_CHECK(inv.to_interval(y) == Interval(Int(-128, 8, Signed))); inv.apply(BinaryOperator::SubNoWrap, z, y, Int(1, 8, Signed)); BOOST_CHECK(inv.is_bottom()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(85, 8, Signed))); inv.apply(BinaryOperator::Add, y, x, Int(43, 8, Signed)); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(-128, 8, Signed))); inv.apply(BinaryOperator::SubNoWrap, z, y, Int(1, 8, Signed)); BOOST_CHECK(inv.is_bottom()); } } BOOST_AUTO_TEST_CASE(add_var) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); { auto inv = PolymorphicDomain(IntervalDomain::top()); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(-4, 32, Signed), Int(0, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(0, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(0, 32, Signed))); inv.add(Predicate::NE, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.add(Predicate::GT, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(1, 32, Signed), Int(3, 32, Signed))); inv.add(Predicate::LE, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); inv.add(Predicate::LT, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.add(Predicate::GE, x, y); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); inv.set_to_top(); inv.set(y, Interval(Int::min(32, Signed))); inv.add(Predicate::LT, x, y); BOOST_CHECK(inv.is_bottom()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv.set(y, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); inv.add(Predicate::EQ, x, y); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(24, 32, Signed), Int(7, 32, Signed))); } } BOOST_AUTO_TEST_CASE(add_int) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); { auto inv = PolymorphicDomain(IntervalDomain::top()); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::EQ, x, Int(1, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed))); inv.add(Predicate::NE, x, Int(1, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::GT, x, Int(2, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.add(Predicate::LE, x, Int(3, 32, Signed)); BOOST_CHECK(inv.to_interval(x) == Interval(Int(3, 32, Signed))); inv.add(Predicate::EQ, x, Int(2, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(Predicate::GT, y, Int::max(32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(Predicate::LT, y, Int::min(32, Signed)); BOOST_CHECK(inv.is_bottom()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv.add(Predicate::EQ, x, Int(7, 32, Signed)); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(7, 32, Signed))); } } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); { auto inv = PolymorphicDomain(IntervalDomain::top()); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(x, Interval::bottom(32, Signed)); BOOST_CHECK(inv.is_bottom()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.set(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv.set(x, Congruence::bottom(32, Signed)); BOOST_CHECK(inv.is_bottom()); } } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); { auto inv = PolymorphicDomain(IntervalDomain::top()); inv.refine(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.refine(x, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.is_bottom()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.refine(x, Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(2, 32, Signed), Int(1, 32, Signed))); inv.refine(x, Congruence(Int(4, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv.is_bottom()); } } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); { auto inv = PolymorphicDomain(IntervalDomain::top()); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top(32, Signed)); BOOST_CHECK(inv.to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.forget(y); BOOST_CHECK(inv.is_top()); } { auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.set(x, Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); inv.set(y, Congruence(Int(3, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv.to_congruence(x) == Congruence(Int(2, 32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(3, 32, Signed), Int(1, 32, Signed))); inv.forget(x); BOOST_CHECK(inv.to_congruence(x) == Congruence::top(32, Signed)); BOOST_CHECK(inv.to_congruence(y) == Congruence(Int(3, 32, Signed), Int(1, 32, Signed))); inv.forget(y); BOOST_CHECK(inv.is_top()); } } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = PolymorphicDomain(IntervalDomain::top()); inv.set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); LinearExpr e1(Int(1, 32, Signed)); e1.add(Int(2, 32, Signed), x); BOOST_CHECK(inv.to_interval(e1) == Interval(Int(3, 32, Signed), Int(5, 32, Signed))); LinearExpr e2(Int(1, 32, Signed)); e2.add(Int(2, 32, Signed), x); e2.add(Int(-3, 32, Signed), y); BOOST_CHECK(inv.to_interval(e2) == Interval(Int(-9, 32, Signed), Int(-4, 32, Signed))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x", 32, Signed)); Variable y(vfac.get("y", 32, Signed)); auto inv = PolymorphicDomain(CongruenceDomain::top()); inv.set(x, Congruence(Int(6, 32, Signed), Int(1, 32, Signed))); inv.set(y, Congruence(Int(8, 32, Signed), Int(7, 32, Signed))); LinearExpr e1(Int(1, 32, Signed)); e1.add(Int(2, 32, Signed), x); BOOST_CHECK(inv.to_congruence(e1) == Congruence(Int(4, 32, Signed), Int(3, 32, Signed))); LinearExpr e2(Int(1, 32, Signed)); e2.add(Int(2, 32, Signed), x); e2.add(Int(-3, 32, Signed), y); BOOST_CHECK(inv.to_congruence(e2) == Congruence(Int(4, 32, Signed), Int(2, 32, Signed))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/memory/000077500000000000000000000000001473507761200222635ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/memory/partitioning.cpp000066400000000000000000000626411473507761200255070ustar00rootroot00000000000000/******************************************************************************* * * Tests for memory::PartitioningDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_memory_partitioning_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include #include #include #include #include using Int = ikos::core::MachineInt; using Interval = ikos::core::machine_int::Interval; using ikos::core::Signed; using ikos::core::Unsigned; using ikos::core::machine_int::BinaryOperator; using ikos::core::machine_int::Predicate; using ikos::core::machine_int::UnaryOperator; using VariableFactory = ikos::core::example::scalar::VariableFactory; using Variable = VariableFactory::VariableRef; using MemoryFactory = ikos::core::example::MemoryFactory; using MemoryLocation = MemoryFactory::MemoryLocationRef; using VariableExpr = ikos::core::VariableExpression< Int, Variable >; using LinearExpr = ikos::core::LinearExpression< Int, Variable >; using IntervalDomain = ikos::core::machine_int::IntervalDomain< Variable >; using UninitializedDomain = ikos::core::uninitialized::SeparateDomain< Variable >; using ScalarDomain = ikos::core::scalar::MachineIntDomain< Variable, MemoryLocation, UninitializedDomain, IntervalDomain >; using MemoryDomain = ikos::core::memory::DummyDomain< Variable, MemoryLocation, ScalarDomain >; using PartitioningDomain = ikos::core::memory:: PartitioningDomain< Variable, MemoryLocation, MemoryDomain >; static PartitioningDomain make_top() { return PartitioningDomain(MemoryDomain( ScalarDomain(UninitializedDomain::top(), IntervalDomain::top()))); } static PartitioningDomain make_bottom() { return PartitioningDomain(MemoryDomain( ScalarDomain(UninitializedDomain::bottom(), IntervalDomain::bottom()))); } BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); BOOST_CHECK(make_top().is_top()); BOOST_CHECK(!make_top().is_bottom()); BOOST_CHECK(!make_bottom().is_top()); BOOST_CHECK(make_bottom().is_bottom()); auto inv = make_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.int_set(x, Interval(Int(1, 32, Signed))); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.partitioning_set_variable(x); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.int_set(x, Interval::bottom(32, Signed)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.partitioning_set_variable(x); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); auto inv1 = make_top(); inv1.int_assign(x, Int(1, 32, Signed)); inv1.partitioning_set_variable(x); auto inv2 = make_top(); inv2.int_assign(x, Int(3, 32, Signed)); inv2.partitioning_set_variable(x); auto inv3 = inv1.join(inv2); BOOST_CHECK(!inv3.is_top()); BOOST_CHECK(!inv3.is_bottom()); inv3.int_add(Predicate::EQ, x, Int(2, 32, Signed)); BOOST_CHECK(!inv3.is_top()); BOOST_CHECK(inv3.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { auto inv = make_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); Variable z(vfac.get_int("z", 32, Signed)); BOOST_CHECK(make_bottom().leq(make_top())); BOOST_CHECK(make_bottom().leq(make_bottom())); BOOST_CHECK(!make_top().leq(make_bottom())); BOOST_CHECK(make_top().leq(make_top())); auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(inv1.leq(make_top())); BOOST_CHECK(!inv1.leq(make_bottom())); auto inv2 = make_top(); inv2.int_set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv2.leq(make_top())); BOOST_CHECK(!inv2.leq(make_bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = make_top(); inv3.int_set(x, Interval(Int(0, 32, Signed))); inv3.int_set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(inv3.leq(make_top())); BOOST_CHECK(!inv3.leq(make_bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = make_top(); inv4.int_set(x, Interval(Int(0, 32, Signed))); inv4.int_set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv4.leq(make_top())); BOOST_CHECK(!inv4.leq(make_bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = make_top(); inv5.int_set(x, Interval(Int(0, 32, Signed))); inv5.int_set(y, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv5.int_set(z, Interval(Int::min(32, Signed), Int(0, 32, Signed))); BOOST_CHECK(inv5.leq(make_top())); BOOST_CHECK(!inv5.leq(make_bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); auto inv6 = make_top(); inv6.int_set(x, Interval(Int(1, 32, Signed), Int(9, 32, Signed))); inv6.partitioning_set_variable(x); auto inv7 = make_top(); inv7.int_set(x, Interval(Int(-9, 32, Signed), Int(-1, 32, Signed))); inv7.partitioning_set_variable(x); auto inv8 = inv6.join(inv7); auto inv9 = inv8; inv9.int_refine(x, Interval(Int(-3, 32, Signed), Int(3, 32, Signed))); BOOST_CHECK(inv8.leq(make_top())); BOOST_CHECK(!inv8.leq(make_bottom())); BOOST_CHECK(!inv8.leq(inv9)); BOOST_CHECK(inv9.leq(inv8)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); BOOST_CHECK(!make_bottom().equals(make_top())); BOOST_CHECK(make_bottom().equals(make_bottom())); BOOST_CHECK(!make_top().equals(make_bottom())); BOOST_CHECK(make_top().equals(make_top())); auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK(!inv1.equals(make_top())); BOOST_CHECK(!inv1.equals(make_bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = make_top(); inv2.int_set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv2.equals(make_top())); BOOST_CHECK(!inv2.equals(make_bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = make_top(); inv3.int_set(x, Interval(Int(0, 32, Signed))); inv3.int_set(y, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK(!inv3.equals(make_top())); BOOST_CHECK(!inv3.equals(make_bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); BOOST_CHECK((make_bottom().join(make_top()) == make_top())); BOOST_CHECK((make_bottom().join(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().join(make_top()) == make_top())); BOOST_CHECK((make_top().join(make_bottom()) == make_top())); auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(make_top()) == make_top())); BOOST_CHECK((inv1.join(make_bottom()) == inv1)); BOOST_CHECK((make_top().join(inv1) == make_top())); BOOST_CHECK((make_bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = make_top(); auto inv3 = make_top(); inv2.int_set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.int_set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = make_top(); inv4.int_set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv4.int_set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); auto inv5 = make_top(); inv5.int_set(x, Interval(Int(1, 32, Signed), Int(9, 32, Signed))); inv5.int_set(y, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv5.partitioning_set_variable(x); auto inv6 = make_top(); inv6.int_set(x, Interval(Int(-9, 32, Signed), Int(-1, 32, Signed))); inv6.int_set(y, Interval(Int(4, 32, Signed), Int(5, 32, Signed))); inv6.partitioning_set_variable(x); BOOST_CHECK((inv5.join(inv6).int_to_interval(x) == Interval(Int(-9, 32, Signed), Int(9, 32, Signed)))); BOOST_CHECK((inv6.join(inv5).int_to_interval(x) == Interval(Int(-9, 32, Signed), Int(9, 32, Signed)))); BOOST_CHECK((inv5.join(inv6).int_to_interval(y) == Interval(Int(1, 32, Signed), Int(5, 32, Signed)))); BOOST_CHECK((inv6.join(inv5).int_to_interval(y) == Interval(Int(1, 32, Signed), Int(5, 32, Signed)))); auto inv7 = inv5.join(inv6); inv7.int_add(Predicate::LT, y, Int(4, 32, Signed)); BOOST_CHECK((inv7 == inv5)); auto inv8 = make_top(); inv8.int_set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv8.int_set(y, Interval(Int(7, 32, Signed), Int(8, 32, Signed))); inv8.partitioning_set_variable(x); BOOST_CHECK((inv5.join(inv6).join(inv8) == inv8.join(inv5.join(inv6)))); auto inv9 = inv5.join(inv6).join(inv8); inv9.int_add(Predicate::NE, x, Int(0, 32, Signed)); BOOST_CHECK((inv9.int_to_interval(x) == Interval(Int(-9, 32, Signed), Int(9, 32, Signed)))); BOOST_CHECK((inv9.int_to_interval(y) == Interval(Int(1, 32, Signed), Int(8, 32, Signed)))); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); BOOST_CHECK((make_bottom().widening(make_top()) == make_top())); BOOST_CHECK((make_bottom().widening(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().widening(make_top()) == make_top())); BOOST_CHECK((make_top().widening(make_bottom()) == make_top())); { auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.widening(make_top()) == make_top())); BOOST_CHECK((inv1.widening(make_bottom()) == inv1)); BOOST_CHECK((make_top().widening(inv1) == make_top())); BOOST_CHECK((make_bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = make_top(); auto inv3 = make_top(); inv2.int_set(x, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv3.int_set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } { auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv1.partitioning_set_variable(x); BOOST_CHECK((inv1.widening(make_top()) == make_top())); BOOST_CHECK((inv1.widening(make_bottom()) == inv1)); BOOST_CHECK((make_top().widening(inv1) == make_top())); BOOST_CHECK((make_bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = make_top(); auto inv3 = make_top(); inv2.int_set(x, Interval(Int(0, 32, Signed), Int(2, 32, Signed))); inv2.partitioning_set_variable(x); inv3.int_set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); inv3.partitioning_set_variable(x); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); BOOST_CHECK((make_bottom().meet(make_top()) == make_bottom())); BOOST_CHECK((make_bottom().meet(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().meet(make_top()) == make_top())); BOOST_CHECK((make_top().meet(make_bottom()) == make_bottom())); { auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.meet(make_top()) == inv1)); BOOST_CHECK((inv1.meet(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().meet(inv1) == inv1)); BOOST_CHECK((make_bottom().meet(inv1) == make_bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = make_top(); auto inv3 = make_top(); inv2.int_set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv3.int_set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = make_top(); auto inv5 = make_top(); inv4.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv4.int_set(y, Interval(Int(0, 32, Signed))); inv5.int_set(x, Interval(Int(0, 32, Signed))); inv5.int_set(y, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } { auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv1.partitioning_set_variable(x); BOOST_CHECK((inv1.meet(make_top()) == inv1)); BOOST_CHECK((inv1.meet(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().meet(inv1) == inv1)); BOOST_CHECK((make_bottom().meet(inv1) == make_bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = make_top(); auto inv3 = make_top(); inv2.int_set(x, Interval(Int(-1, 32, Signed), Int(0, 32, Signed))); inv2.partitioning_set_variable(x); inv3.int_set(x, Interval(Int(0, 32, Signed))); inv3.partitioning_set_variable(x); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = make_top(); auto inv5 = make_top(); inv4.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv4.int_set(y, Interval(Int(0, 32, Signed))); inv4.partitioning_set_variable(x); inv5.int_set(x, Interval(Int(0, 32, Signed))); inv5.int_set(y, Interval(Int(0, 32, Signed))); inv5.partitioning_set_variable(x); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); BOOST_CHECK((make_bottom().narrowing(make_top()) == make_bottom())); BOOST_CHECK((make_bottom().narrowing(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().narrowing(make_top()) == make_top())); BOOST_CHECK((make_top().narrowing(make_bottom()) == make_bottom())); { auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); BOOST_CHECK((inv1.narrowing(make_top()) == inv1)); BOOST_CHECK((inv1.narrowing(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().narrowing(inv1) == inv1)); BOOST_CHECK((make_bottom().narrowing(inv1) == make_bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = make_top(); inv2.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } { auto inv1 = make_top(); inv1.int_set(x, Interval(Int(0, 32, Signed), Int::max(32, Signed))); inv1.partitioning_set_variable(x); BOOST_CHECK((inv1.narrowing(make_top()) == inv1)); BOOST_CHECK((inv1.narrowing(make_bottom()) == make_bottom())); BOOST_CHECK((make_top().narrowing(inv1) == inv1)); BOOST_CHECK((make_bottom().narrowing(inv1) == make_bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = make_top(); inv2.int_set(x, Interval(Int(0, 32, Signed), Int(1, 32, Signed))); inv2.partitioning_set_variable(x); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); Variable z(vfac.get_int("z", 32, Signed)); auto inv1 = make_top(); auto inv2 = make_top(); inv1.int_assign(x, Int(0, 32, Signed)); inv2.int_set(x, Interval(Int(0, 32, Signed))); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.int_assign(x, Int(0, 32, Signed)); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.int_set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.int_assign(y, x); BOOST_CHECK(inv1.int_to_interval(y) == Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.set_to_top(); inv1.int_set(x, Interval(Int(-1, 32, Signed), Int(1, 32, Signed))); inv1.int_set(y, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); LinearExpr e(Int(1, 32, Signed)); e.add(Int(2, 32, Signed), x); e.add(Int(-3, 32, Signed), y); inv1.int_assign(z, e); BOOST_CHECK(inv1.int_to_interval(z) == Interval(Int(-7, 32, Signed), Int(0, 32, Signed))); } BOOST_AUTO_TEST_CASE(unary_apply) { VariableFactory vfac; Variable x(vfac.get_int("x", 8, Signed)); Variable y(vfac.get_int("y", 6, Signed)); Variable z(vfac.get_int("z", 8, Signed)); Variable w(vfac.get_int("w", 8, Unsigned)); auto inv = make_top(); inv.int_assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(85, 8, Signed))); inv.int_apply(UnaryOperator::Trunc, y, x); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(21, 6, Signed))); inv.int_apply(UnaryOperator::Ext, z, y); BOOST_CHECK(inv.int_to_interval(z) == Interval(Int(21, 8, Signed))); inv.int_apply(UnaryOperator::SignCast, w, z); BOOST_CHECK(inv.int_to_interval(w) == Interval(Int(21, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(binary_apply) { VariableFactory vfac; Variable x(vfac.get_int("x", 8, Signed)); Variable y(vfac.get_int("y", 8, Signed)); Variable z(vfac.get_int("z", 8, Signed)); auto inv = make_top(); inv.int_assign(x, Int(85, 8, Signed)); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(85, 8, Signed))); inv.int_apply(BinaryOperator::Add, y, x, Int(43, 8, Signed)); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(-128, 8, Signed))); inv.int_apply(BinaryOperator::SubNoWrap, z, y, Int(1, 8, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_var) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); auto inv = make_top(); inv.int_set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.int_set(y, Interval(Int(-4, 32, Signed), Int(0, 32, Signed))); inv.int_add(Predicate::EQ, x, y); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(0, 32, Signed))); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(0, 32, Signed))); inv.int_add(Predicate::NE, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.int_set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.int_set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.int_add(Predicate::GT, x, y); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(2, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(1, 32, Signed), Int(3, 32, Signed))); inv.int_add(Predicate::LE, x, y); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(2, 32, Signed), Int(3, 32, Signed))); inv.int_add(Predicate::LT, x, y); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(2, 32, Signed))); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(3, 32, Signed))); inv.int_add(Predicate::EQ, x, y); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.int_set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.int_set(y, Interval(Int(1, 32, Signed), Int(5, 32, Signed))); inv.int_add(Predicate::GE, x, y); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(1, 32, Signed), Int(4, 32, Signed))); inv.set_to_top(); inv.int_set(y, Interval(Int::min(32, Signed))); inv.int_add(Predicate::LT, x, y); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(add_int) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); auto inv = make_top(); inv.int_set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.int_add(Predicate::EQ, x, Int(1, 32, Signed)); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(1, 32, Signed))); inv.int_add(Predicate::NE, x, Int(1, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.int_set(x, Interval(Int(0, 32, Signed), Int(4, 32, Signed))); inv.int_add(Predicate::GT, x, Int(2, 32, Signed)); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.int_add(Predicate::LE, x, Int(3, 32, Signed)); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(3, 32, Signed))); inv.int_add(Predicate::EQ, x, Int(2, 32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.int_add(Predicate::GT, y, Int::max(32, Signed)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.int_add(Predicate::LT, y, Int::min(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); auto inv = make_top(); inv.int_set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.int_set(x, Interval::bottom(32, Signed)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); auto inv = make_top(); inv.int_refine(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.int_refine(x, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); auto inv = make_top(); inv.int_set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.int_set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); BOOST_CHECK(inv.int_to_interval(x) == Interval(Int(1, 32, Signed), Int(2, 32, Signed))); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.int_forget(x); BOOST_CHECK(inv.int_to_interval(x) == Interval::top(32, Signed)); BOOST_CHECK(inv.int_to_interval(y) == Interval(Int(3, 32, Signed), Int(4, 32, Signed))); inv.int_forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get_int("x", 32, Signed)); Variable y(vfac.get_int("y", 32, Signed)); auto inv = make_top(); inv.int_set(x, Interval(Int(1, 32, Signed), Int(2, 32, Signed))); inv.int_set(y, Interval(Int(3, 32, Signed), Int(4, 32, Signed))); LinearExpr e1(Int(1, 32, Signed)); e1.add(Int(2, 32, Signed), x); BOOST_CHECK(inv.int_to_interval(e1) == Interval(Int(3, 32, Signed), Int(5, 32, Signed))); LinearExpr e2(Int(1, 32, Signed)); e2.add(Int(2, 32, Signed), x); e2.add(Int(-3, 32, Signed), y); BOOST_CHECK(inv.int_to_interval(e2) == Interval(Int(-9, 32, Signed), Int(-4, 32, Signed))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/nullity/000077500000000000000000000000001473507761200224535ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/nullity/separate_domain.cpp000066400000000000000000000151721473507761200263200ustar00rootroot00000000000000/******************************************************************************* * * Tests for NullityDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_nullity_domain #define BOOST_TEST_DYN_LINK #include #include #include #include using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using Nullity = ikos::core::Nullity; using NullityDomain = ikos::core::nullity::SeparateDomain< Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(NullityDomain::top().is_top()); BOOST_CHECK(!NullityDomain::top().is_bottom()); BOOST_CHECK(!NullityDomain::bottom().is_top()); BOOST_CHECK(NullityDomain::bottom().is_bottom()); auto inv = NullityDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.assign_null(x); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Nullity::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = NullityDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(NullityDomain::bottom().leq(NullityDomain::top())); BOOST_CHECK(NullityDomain::bottom().leq(NullityDomain::bottom())); BOOST_CHECK(!NullityDomain::top().leq(NullityDomain::bottom())); BOOST_CHECK(NullityDomain::top().leq(NullityDomain::top())); auto inv1 = NullityDomain::top(); inv1.set(x, Nullity::null()); BOOST_CHECK(inv1.leq(NullityDomain::top())); BOOST_CHECK(!inv1.leq(NullityDomain::bottom())); auto inv2 = NullityDomain::top(); inv2.set(x, Nullity::non_null()); BOOST_CHECK(inv2.leq(NullityDomain::top())); BOOST_CHECK(!inv2.leq(NullityDomain::bottom())); BOOST_CHECK(!inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = NullityDomain::top(); inv3.set(x, Nullity::null()); inv3.set(y, Nullity::non_null()); BOOST_CHECK(inv3.leq(NullityDomain::top())); BOOST_CHECK(!inv3.leq(NullityDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((NullityDomain::bottom().join(NullityDomain::top()) == NullityDomain::top())); BOOST_CHECK((NullityDomain::bottom().join(NullityDomain::bottom()) == NullityDomain::bottom())); BOOST_CHECK((NullityDomain::top().join(NullityDomain::top()) == NullityDomain::top())); BOOST_CHECK((NullityDomain::top().join(NullityDomain::bottom()) == NullityDomain::top())); auto inv1 = NullityDomain::top(); inv1.set(x, Nullity::null()); BOOST_CHECK((inv1.join(NullityDomain::top()) == NullityDomain::top())); BOOST_CHECK((inv1.join(NullityDomain::bottom()) == inv1)); BOOST_CHECK((NullityDomain::top().join(inv1) == NullityDomain::top())); BOOST_CHECK((NullityDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = NullityDomain::top(); inv2.set(x, Nullity::non_null()); BOOST_CHECK((inv1.join(inv2) == NullityDomain::top())); BOOST_CHECK((inv2.join(inv1) == NullityDomain::top())); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((NullityDomain::bottom().meet(NullityDomain::top()) == NullityDomain::bottom())); BOOST_CHECK((NullityDomain::bottom().meet(NullityDomain::bottom()) == NullityDomain::bottom())); BOOST_CHECK((NullityDomain::top().meet(NullityDomain::top()) == NullityDomain::top())); BOOST_CHECK((NullityDomain::top().meet(NullityDomain::bottom()) == NullityDomain::bottom())); auto inv1 = NullityDomain::top(); inv1.set(x, Nullity::null()); BOOST_CHECK((inv1.meet(NullityDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(NullityDomain::bottom()) == NullityDomain::bottom())); BOOST_CHECK((NullityDomain::top().meet(inv1) == inv1)); BOOST_CHECK((NullityDomain::bottom().meet(inv1) == NullityDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = NullityDomain::top(); inv2.set(x, Nullity::non_null()); BOOST_CHECK((inv1.meet(inv2) == NullityDomain::bottom())); BOOST_CHECK((inv2.meet(inv1) == NullityDomain::bottom())); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/000077500000000000000000000000001473507761200224155ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/apron/000077500000000000000000000000001473507761200235345ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/apron/interval.cpp000066400000000000000000000557251473507761200261020ustar00rootroot00000000000000/******************************************************************************* * * Tests for ApronDomain with Domain = Interval * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_apron_interval #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using ApronDomain = ikos::core::numeric:: ApronDomain< ikos::core::numeric::apron::Interval, ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(ApronDomain::top().is_top()); BOOST_CHECK(!ApronDomain::top().is_bottom()); BOOST_CHECK(!ApronDomain::bottom().is_top()); BOOST_CHECK(ApronDomain::bottom().is_bottom()); auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().leq(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().leq(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(ApronDomain::top())); BOOST_CHECK(!inv1.leq(ApronDomain::bottom())); auto inv2 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(ApronDomain::top())); BOOST_CHECK(!inv2.leq(ApronDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(ApronDomain::top())); BOOST_CHECK(!inv3.leq(ApronDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(ApronDomain::top())); BOOST_CHECK(!inv4.leq(ApronDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = ApronDomain::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(ApronDomain::top())); BOOST_CHECK(!inv5.leq(ApronDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!ApronDomain::bottom().equals(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().equals(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().equals(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().equals(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(ApronDomain::top())); BOOST_CHECK(!inv1.equals(ApronDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(ApronDomain::top())); BOOST_CHECK(!inv2.equals(ApronDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(ApronDomain::top())); BOOST_CHECK(!inv3.equals(ApronDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK( (ApronDomain::bottom().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((inv1.join(ApronDomain::bottom()) == inv1)); BOOST_CHECK((ApronDomain::top().join(inv1) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().widening(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((inv1.widening(ApronDomain::bottom()) == inv1)); BOOST_CHECK((ApronDomain::top().widening(inv1) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().meet(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().meet(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().meet(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().meet(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = ApronDomain::top(); auto inv5 = ApronDomain::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().narrowing(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().narrowing(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(0))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); // Check integer division with rounding towards zero inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(-1)); // Check rem inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(-2)); // Check mod inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(1)); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = ApronDomain::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(6), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(6), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(6), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(18), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(6), Bound(6))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(6), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(18), Bound(19))); inv.add(VariableExpr(x) >= VariableExpr(z)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); // Apron Interval cannot infer 4 <= x <= 7 BOOST_CHECK(inv.to_interval(x) == Interval(Bound(2), Bound(9))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(3), ZNumber(1)))); // Apron Interval cannot infer 4 <= x <= 7 BOOST_CHECK(inv.to_interval(x) == Interval(Bound(2), Bound(7))); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/apron/pkgrid_polyhedra_lin_congruences.cpp000066400000000000000000000666421473507761200330420ustar00rootroot00000000000000/******************************************************************************* * * Tests for ApronDomain with Domain = PkgridPolyhedraLinCongruences * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_apron_pkgrid_polyhedra_lin_congruences #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using ApronDomain = ikos::core::numeric::ApronDomain< ikos::core::numeric::apron::PkgridPolyhedraLinCongruences, ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(ApronDomain::top().is_top()); BOOST_CHECK(!ApronDomain::top().is_bottom()); BOOST_CHECK(!ApronDomain::bottom().is_top()); BOOST_CHECK(ApronDomain::bottom().is_bottom()); auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().leq(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().leq(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(ApronDomain::top())); BOOST_CHECK(!inv1.leq(ApronDomain::bottom())); auto inv2 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(ApronDomain::top())); BOOST_CHECK(!inv2.leq(ApronDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(ApronDomain::top())); BOOST_CHECK(!inv3.leq(ApronDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(ApronDomain::top())); BOOST_CHECK(!inv4.leq(ApronDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = ApronDomain::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(ApronDomain::top())); BOOST_CHECK(!inv5.leq(ApronDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1} <= {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1} <= {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1, y = 2} <= {x <= 1} inv2.add(VariableExpr(z) <= 4); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1, y = 2} <= {x <= 1, z <= 4} inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK(!inv1.leq(inv2)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!ApronDomain::bottom().equals(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().equals(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().equals(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().equals(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(ApronDomain::top())); BOOST_CHECK(!inv1.equals(ApronDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(ApronDomain::top())); BOOST_CHECK(!inv2.equals(ApronDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(ApronDomain::top())); BOOST_CHECK(!inv3.equals(ApronDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK( (ApronDomain::bottom().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((inv1.join(ApronDomain::bottom()) == inv1)); BOOST_CHECK((ApronDomain::top().join(inv1) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1} U {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1} U {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1, y = 2} U {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1, y = 2} U {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.set(x, Interval(Bound(-1), Bound(1))); inv3.add(VariableExpr(y) <= 3); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 1); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.join(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.join(inv2).to_interval(a) == Interval(Bound(4), Bound::plus_infinity()))); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().widening(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); // inv1 widen TOP gives {x = 0 mod 1}, and is not reduced to top. BOOST_CHECK((inv1.widening(ApronDomain::top()).to_congruence(x) == Congruence::top())); BOOST_CHECK((inv1.widening(ApronDomain::bottom()) == inv1)); // TOP widen inv1 gives {x = 0 mod 1}, and is not reduced to top. BOOST_CHECK((ApronDomain::top().widening(inv1).to_congruence(x) == Congruence::top())); BOOST_CHECK((ApronDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv3)); // a bit surprising, but sound. } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().meet(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().meet(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().meet(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().meet(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = ApronDomain::top(); auto inv5 = ApronDomain::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & top() inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK((inv1.meet(inv2) == ApronDomain::bottom())); // {x = 1} & {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1, y = 2} & {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.assign(x, 1); inv3.assign(y, 2); inv3.add(VariableExpr(z) <= 4); BOOST_CHECK((inv1.meet(inv2) == inv3)); // {x = 1, y = 2} & {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.assign(x, 1); inv3.add(VariableExpr(y) <= 2); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 4); inv3.assign(b, 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.meet(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); inv3.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.meet(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().narrowing(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().narrowing(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); // Check integer division with rounding towards zero inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(-1)); // Check rem inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(-2)); // Check mod inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(1)); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = ApronDomain::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(VariableExpr(x) >= 1); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); // Apron Pkgrid Polyhedra Lin Congruences might not infer 4 <= x <= 7 BOOST_CHECK(inv.to_interval(x) == Interval(Bound(2), Bound(9)) || inv.to_interval(x) == Interval(Bound(4), Bound(7))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(3), ZNumber(1)))); // Apron Pkgrid Polyhedra Lin Congruences might not infer 4 <= x <= 7 BOOST_CHECK(inv.to_interval(x) == Interval(Bound(2), Bound(7)) || inv.to_interval(x) == Interval(Bound(4), Bound(7))); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/apron/polka_polyhedra.cpp000066400000000000000000000657571473507761200274410ustar00rootroot00000000000000/******************************************************************************* * * Tests for ApronDomain with Domain = PolkaPolyhedra * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_apron_polka_polyhedra #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using ApronDomain = ikos::core::numeric::ApronDomain< ikos::core::numeric::apron::PolkaPolyhedra, ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(ApronDomain::top().is_top()); BOOST_CHECK(!ApronDomain::top().is_bottom()); BOOST_CHECK(!ApronDomain::bottom().is_top()); BOOST_CHECK(ApronDomain::bottom().is_bottom()); auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().leq(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().leq(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(ApronDomain::top())); BOOST_CHECK(!inv1.leq(ApronDomain::bottom())); auto inv2 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(ApronDomain::top())); BOOST_CHECK(!inv2.leq(ApronDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(ApronDomain::top())); BOOST_CHECK(!inv3.leq(ApronDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(ApronDomain::top())); BOOST_CHECK(!inv4.leq(ApronDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = ApronDomain::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(ApronDomain::top())); BOOST_CHECK(!inv5.leq(ApronDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1} <= {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1} <= {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1, y = 2} <= {x <= 1} inv2.add(VariableExpr(z) <= 4); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1, y = 2} <= {x <= 1, z <= 4} inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK(!inv1.leq(inv2)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!ApronDomain::bottom().equals(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().equals(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().equals(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().equals(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(ApronDomain::top())); BOOST_CHECK(!inv1.equals(ApronDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(ApronDomain::top())); BOOST_CHECK(!inv2.equals(ApronDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(ApronDomain::top())); BOOST_CHECK(!inv3.equals(ApronDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK( (ApronDomain::bottom().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((inv1.join(ApronDomain::bottom()) == inv1)); BOOST_CHECK((ApronDomain::top().join(inv1) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1} U {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1} U {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1, y = 2} U {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1, y = 2} U {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.set(x, Interval(Bound(-1), Bound(1))); inv3.add(VariableExpr(y) <= 3); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 1); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.join(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.join(inv2).to_interval(a) == Interval(Bound(4), Bound::plus_infinity()))); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().widening(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((inv1.widening(ApronDomain::bottom()) == inv1)); BOOST_CHECK((ApronDomain::top().widening(inv1) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv3)); // a bit surprising, but sound. } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().meet(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().meet(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().meet(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().meet(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = ApronDomain::top(); auto inv5 = ApronDomain::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & top() inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK((inv1.meet(inv2) == ApronDomain::bottom())); // {x = 1} & {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1, y = 2} & {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.assign(x, 1); inv3.assign(y, 2); inv3.add(VariableExpr(z) <= 4); BOOST_CHECK((inv1.meet(inv2) == inv3)); // {x = 1, y = 2} & {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.assign(x, 1); inv3.add(VariableExpr(y) <= 2); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 4); inv3.assign(b, 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.meet(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); inv3.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.meet(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().narrowing(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().narrowing(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); // Check integer division with rounding towards zero inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(-1)); // Check rem inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(-2)); // Check mod inv1.set(x, Interval(-5)); inv1.set(y, Interval(3)); BOOST_CHECK(!inv1.is_bottom()); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(1)); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = ApronDomain::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(VariableExpr(x) >= 1); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); // Apron Interval cannot infer 4 <= x <= 7 BOOST_CHECK(inv.to_interval(x) == Interval(Bound(2), Bound(9))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(3), ZNumber(1)))); // Apron Interval cannot infer 4 <= x <= 7 BOOST_CHECK(inv.to_interval(x) == Interval(Bound(2), Bound(7))); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/apron/ppl_linear_congruences.cpp000066400000000000000000000505331473507761200307660ustar00rootroot00000000000000/******************************************************************************* * * Tests for ApronDomain with Domain = PplLinearCongruences * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_apron_ppl_linear_congruences #define BOOST_TEST_DYN_LINK #include #include #include #include #include // TODO(marthaud): some tests are commented out, this is because we need to // improve to_interval() and to_congruence() methods in the ApronDomain to make // them pass. using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using ApronDomain = ikos::core::numeric::ApronDomain< ikos::core::numeric::apron::PplLinearCongruences, ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(ApronDomain::top().is_top()); BOOST_CHECK(!ApronDomain::top().is_bottom()); BOOST_CHECK(!ApronDomain::bottom().is_top()); BOOST_CHECK(ApronDomain::bottom().is_bottom()); auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = ApronDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().leq(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().leq(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().leq(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Congruence(0)); BOOST_CHECK(inv1.leq(ApronDomain::top())); BOOST_CHECK(!inv1.leq(ApronDomain::bottom())); auto inv2 = ApronDomain::top(); inv2.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(inv2.leq(ApronDomain::top())); BOOST_CHECK(!inv2.leq(ApronDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Congruence(0)); inv3.set(y, Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv3.leq(ApronDomain::top())); BOOST_CHECK(!inv3.leq(ApronDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Congruence(0)); inv4.set(y, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(inv4.leq(ApronDomain::top())); BOOST_CHECK(!inv4.leq(ApronDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = ApronDomain::top(); inv5.set(x, Congruence(0)); inv5.set(y, Congruence(ZNumber(2), ZNumber(0))); inv5.set(z, Congruence(ZNumber(4), ZNumber(0))); BOOST_CHECK(inv5.leq(ApronDomain::top())); BOOST_CHECK(!inv5.leq(ApronDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!ApronDomain::bottom().equals(ApronDomain::top())); BOOST_CHECK(ApronDomain::bottom().equals(ApronDomain::bottom())); BOOST_CHECK(!ApronDomain::top().equals(ApronDomain::bottom())); BOOST_CHECK(ApronDomain::top().equals(ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Congruence(0)); BOOST_CHECK(!inv1.equals(ApronDomain::top())); BOOST_CHECK(!inv1.equals(ApronDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = ApronDomain::top(); inv2.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(!inv2.equals(ApronDomain::top())); BOOST_CHECK(!inv2.equals(ApronDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = ApronDomain::top(); inv3.set(x, Congruence(0)); inv3.set(y, Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(!inv3.equals(ApronDomain::top())); BOOST_CHECK(!inv3.equals(ApronDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK( (ApronDomain::bottom().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK( (ApronDomain::top().join(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Congruence(1)); BOOST_CHECK((inv1.join(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((inv1.join(ApronDomain::bottom()) == inv1)); BOOST_CHECK((ApronDomain::top().join(inv1) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Congruence(3)); inv3.set(x, Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = ApronDomain::top(); inv4.set(x, Congruence(3)); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::bottom().widening(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().widening(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().widening(ApronDomain::bottom()) == ApronDomain::top())); auto inv1 = ApronDomain::top(); inv1.set(x, Congruence(1)); // inv1 widen TOP gives {x = 0 mod 1}, and is not reduced to top. BOOST_CHECK((inv1.widening(ApronDomain::top()).to_congruence(x) == Congruence::top())); BOOST_CHECK((inv1.widening(ApronDomain::bottom()) == inv1)); // TOP widen inv1 gives {x = 0 mod 1}, and is not reduced to top. BOOST_CHECK((ApronDomain::top().widening(inv1).to_congruence(x) == Congruence::top())); BOOST_CHECK((ApronDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); // auto inv2 = ApronDomain::top(); // auto inv3 = ApronDomain::top(); // inv2.set(x, Congruence(3)); // inv3.set(x, Congruence(ZNumber(2), ZNumber(1))); // BOOST_CHECK((inv1.widening(inv2) == inv3)); // BOOST_CHECK((inv2.widening(inv1) == inv3)); // auto inv4 = ApronDomain::top(); // inv4.set(x, Congruence(3)); // inv4.set(y, Interval(0)); // BOOST_CHECK((inv4.widening(inv2) == inv2)); // BOOST_CHECK((inv2.widening(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().meet(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().meet(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK((inv1.meet(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().meet(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().meet(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Congruence(ZNumber(3), ZNumber(1))); inv3.set(x, Congruence(ZNumber(6), ZNumber(4))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = ApronDomain::top(); auto inv5 = ApronDomain::top(); inv4.set(x, Congruence(ZNumber(2), ZNumber(0))); inv4.set(y, Interval(0)); inv5.set(x, Congruence(ZNumber(6), ZNumber(4))); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::top()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::bottom().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK( (ApronDomain::top().narrowing(ApronDomain::top()) == ApronDomain::top())); BOOST_CHECK((ApronDomain::top().narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); auto inv1 = ApronDomain::top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK((inv1.narrowing(ApronDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(ApronDomain::bottom()) == ApronDomain::bottom())); BOOST_CHECK((ApronDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((ApronDomain::bottom().narrowing(inv1) == ApronDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = ApronDomain::top(); auto inv3 = ApronDomain::top(); inv2.set(x, Congruence(ZNumber(3), ZNumber(1))); inv3.set(x, Congruence(ZNumber(6), ZNumber(4))); BOOST_CHECK((inv1.narrowing(inv2) == inv3)); BOOST_CHECK((inv2.narrowing(inv1) == inv3)); auto inv4 = ApronDomain::top(); auto inv5 = ApronDomain::top(); inv4.set(x, Congruence(ZNumber(2), ZNumber(0))); inv4.set(y, Interval(0)); inv5.set(x, Congruence(ZNumber(6), ZNumber(4))); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.narrowing(inv2) == inv5)); BOOST_CHECK((inv2.narrowing(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.assign(x, 0); inv2.set(x, Congruence(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); inv1.assign(y, x); // BOOST_CHECK(inv1.to_congruence(y) == Congruence(ZNumber(2), ZNumber(0))); inv1.set_to_top(); inv1.set(x, Congruence(ZNumber(3), ZNumber(0))); inv1.set(y, Congruence(ZNumber(3), ZNumber(1))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(3), ZNumber(1))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ApronDomain::top(); auto inv2 = ApronDomain::top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); inv1.set(y, Congruence(ZNumber(3), ZNumber(1))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mul, z, x, y); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(2), ZNumber(0))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Shl, z, x, y); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(4), ZNumber(0))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(2), ZNumber(1))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(2), ZNumber(1))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(6), ZNumber(0))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(16), ZNumber(0))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(3), ZNumber(2))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(3), ZNumber(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(12), ZNumber(4))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); // BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(56), ZNumber(8))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = ApronDomain::top(); inv.add(VariableExpr(x) == 1); // BOOST_CHECK(inv.to_congruence(x) == Congruence(1)); inv.add(VariableExpr(y) == 2 * VariableExpr(z) + 1); // BOOST_CHECK(inv.to_congruence(x) == Congruence(1)); // BOOST_CHECK(inv.to_congruence(y) == Congruence(ZNumber(2), ZNumber(1))); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ApronDomain::top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); inv.refine(x, Interval(Bound(2), Bound(5))); // BOOST_CHECK(inv.to_congruence(x) == Congruence(4)); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Congruence(ZNumber(2), ZNumber(1))); inv.set(y, Congruence(ZNumber(4), ZNumber(3))); // BOOST_CHECK(inv.to_congruence(x) == Congruence(ZNumber(2), ZNumber(1))); // BOOST_CHECK(inv.to_congruence(y) == Congruence(ZNumber(4), ZNumber(3))); inv.forget(x); BOOST_CHECK(inv.to_congruence(x) == Congruence::top()); // BOOST_CHECK(inv.to_congruence(y) == Congruence(ZNumber(4), ZNumber(3))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Congruence(1)); inv.set(y, Congruence(3)); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(3)); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(-6)); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ApronDomain::top(); inv.set(x, Congruence(ZNumber(3), ZNumber(0))); inv.set(y, Congruence(ZNumber(3), ZNumber(1))); // BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == // Congruence(ZNumber(6), ZNumber(1))); // BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + // 1) == Congruence(ZNumber(3), ZNumber(1))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/congruence.cpp000066400000000000000000000546011473507761200252570ustar00rootroot00000000000000/******************************************************************************* * * Tests for CongruenceDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_congruence_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using CongruenceDomain = ikos::core::numeric::CongruenceDomain< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(CongruenceDomain::top().is_top()); BOOST_CHECK(!CongruenceDomain::top().is_bottom()); BOOST_CHECK(!CongruenceDomain::bottom().is_top()); BOOST_CHECK(CongruenceDomain::bottom().is_bottom()); auto inv = CongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Congruence::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(iterators) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = CongruenceDomain::top(); BOOST_CHECK((inv.begin() == inv.end())); inv.set(x, Congruence(1)); std::array< std::pair< Variable, Congruence >, 1 > tab = { {{x, Congruence(1)}}}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab), std::end(tab))); inv.set(y, Congruence(ZNumber(2), ZNumber(0))); std::array< std::pair< Variable, Congruence >, 2 > tab2 = {{ {y, Congruence(ZNumber(2), ZNumber(0))}, {x, Congruence(1)}, }}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab2), std::end(tab2))); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = CongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK(CongruenceDomain::bottom().leq(CongruenceDomain::top())); BOOST_CHECK(CongruenceDomain::bottom().leq(CongruenceDomain::bottom())); BOOST_CHECK(!CongruenceDomain::top().leq(CongruenceDomain::bottom())); BOOST_CHECK(CongruenceDomain::top().leq(CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(0)); BOOST_CHECK(inv1.leq(CongruenceDomain::top())); BOOST_CHECK(!inv1.leq(CongruenceDomain::bottom())); auto inv2 = CongruenceDomain::top(); inv2.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(inv2.leq(CongruenceDomain::top())); BOOST_CHECK(!inv2.leq(CongruenceDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = CongruenceDomain::top(); inv3.set(x, Congruence(0)); inv3.set(y, Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv3.leq(CongruenceDomain::top())); BOOST_CHECK(!inv3.leq(CongruenceDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = CongruenceDomain::top(); inv4.set(x, Congruence(0)); inv4.set(y, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(inv4.leq(CongruenceDomain::top())); BOOST_CHECK(!inv4.leq(CongruenceDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = CongruenceDomain::top(); inv5.set(x, Congruence(0)); inv5.set(y, Congruence(ZNumber(2), ZNumber(0))); inv5.set(z, Congruence(ZNumber(4), ZNumber(0))); BOOST_CHECK(inv5.leq(CongruenceDomain::top())); BOOST_CHECK(!inv5.leq(CongruenceDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!CongruenceDomain::bottom().equals(CongruenceDomain::top())); BOOST_CHECK(CongruenceDomain::bottom().equals(CongruenceDomain::bottom())); BOOST_CHECK(!CongruenceDomain::top().equals(CongruenceDomain::bottom())); BOOST_CHECK(CongruenceDomain::top().equals(CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(0)); BOOST_CHECK(!inv1.equals(CongruenceDomain::top())); BOOST_CHECK(!inv1.equals(CongruenceDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = CongruenceDomain::top(); inv2.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(!inv2.equals(CongruenceDomain::top())); BOOST_CHECK(!inv2.equals(CongruenceDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = CongruenceDomain::top(); inv3.set(x, Congruence(0)); inv3.set(y, Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(!inv3.equals(CongruenceDomain::top())); BOOST_CHECK(!inv3.equals(CongruenceDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((CongruenceDomain::bottom().join(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().join(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().join(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().join(CongruenceDomain::bottom()) == CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(1)); BOOST_CHECK((inv1.join(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((inv1.join(CongruenceDomain::bottom()) == inv1)); BOOST_CHECK((CongruenceDomain::top().join(inv1) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(3)); inv3.set(x, Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = CongruenceDomain::top(); inv4.set(x, Congruence(3)); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((CongruenceDomain::bottom().widening(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().widening( CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().widening(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().widening(CongruenceDomain::bottom()) == CongruenceDomain::top())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(1)); BOOST_CHECK( (inv1.widening(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((inv1.widening(CongruenceDomain::bottom()) == inv1)); BOOST_CHECK( (CongruenceDomain::top().widening(inv1) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(3)); inv3.set(x, Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv3)); auto inv4 = CongruenceDomain::top(); inv4.set(x, Congruence(3)); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.widening(inv2) == inv2)); BOOST_CHECK((inv2.widening(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((CongruenceDomain::bottom().meet(CongruenceDomain::top()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::bottom().meet(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().meet(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().meet(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK((inv1.meet(CongruenceDomain::top()) == inv1)); BOOST_CHECK( (inv1.meet(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().meet(inv1) == inv1)); BOOST_CHECK( (CongruenceDomain::bottom().meet(inv1) == CongruenceDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(ZNumber(3), ZNumber(1))); inv3.set(x, Congruence(ZNumber(6), ZNumber(4))); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = CongruenceDomain::top(); auto inv5 = CongruenceDomain::top(); inv4.set(x, Congruence(ZNumber(2), ZNumber(0))); inv4.set(y, Interval(0)); inv5.set(x, Congruence(ZNumber(6), ZNumber(4))); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((CongruenceDomain::bottom().narrowing(CongruenceDomain::top()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::bottom().narrowing( CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().narrowing(CongruenceDomain::top()) == CongruenceDomain::top())); BOOST_CHECK((CongruenceDomain::top().narrowing(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); auto inv1 = CongruenceDomain::top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); BOOST_CHECK((inv1.narrowing(CongruenceDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(CongruenceDomain::bottom()) == CongruenceDomain::bottom())); BOOST_CHECK((CongruenceDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((CongruenceDomain::bottom().narrowing(inv1) == CongruenceDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = CongruenceDomain::top(); auto inv3 = CongruenceDomain::top(); inv2.set(x, Congruence(ZNumber(3), ZNumber(1))); inv3.set(x, Congruence(ZNumber(6), ZNumber(4))); BOOST_CHECK((inv1.narrowing(inv2) == inv3)); BOOST_CHECK((inv2.narrowing(inv1) == inv3)); auto inv4 = CongruenceDomain::top(); auto inv5 = CongruenceDomain::top(); inv4.set(x, Congruence(ZNumber(2), ZNumber(0))); inv4.set(y, Interval(0)); inv5.set(x, Congruence(ZNumber(6), ZNumber(4))); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.narrowing(inv2) == inv5)); BOOST_CHECK((inv2.narrowing(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = CongruenceDomain::top(); auto inv2 = CongruenceDomain::top(); inv1.assign(x, 0); inv2.set(x, Congruence(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); inv1.assign(y, x); BOOST_CHECK(inv1.to_congruence(y) == Congruence(ZNumber(2), ZNumber(0))); inv1.set_to_top(); inv1.set(x, Congruence(ZNumber(3), ZNumber(0))); inv1.set(y, Congruence(ZNumber(3), ZNumber(1))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(3), ZNumber(1))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = CongruenceDomain::top(); auto inv2 = CongruenceDomain::top(); inv1.set(x, Congruence(ZNumber(2), ZNumber(0))); inv1.set(y, Congruence(ZNumber(3), ZNumber(1))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(2), ZNumber(0))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(4), ZNumber(0))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(2), ZNumber(1))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(2), ZNumber(1))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(6), ZNumber(0))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(16), ZNumber(0))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(3), ZNumber(2))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(3), ZNumber(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(12), ZNumber(4))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence(ZNumber(56), ZNumber(8))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_congruence(z) == Congruence::top()); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = CongruenceDomain::top(); inv.add(VariableExpr(x) == 1); BOOST_CHECK(inv.to_congruence(x) == Congruence(1)); inv.add(VariableExpr(y) == 2 * VariableExpr(z) + 1); BOOST_CHECK(inv.to_congruence(x) == Congruence(1)); BOOST_CHECK(inv.to_congruence(y) == Congruence(ZNumber(2), ZNumber(1))); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = CongruenceDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_congruence(x) == Congruence::top()); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); BOOST_CHECK(inv.to_congruence(x) == Congruence(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_congruence(x) == Congruence(ZNumber(3), ZNumber(1))); inv.set_to_top(); inv.set(x, IntervalCongruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); BOOST_CHECK(inv.to_congruence(x) == Congruence(1)); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_congruence(x) == Congruence(ZNumber(3), ZNumber(1))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = CongruenceDomain::top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); inv.refine(x, Interval(Bound(2), Bound(5))); BOOST_CHECK(inv.to_congruence(x) == Congruence(4)); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(ZNumber(2), ZNumber(1))); inv.set(y, Congruence(ZNumber(4), ZNumber(3))); BOOST_CHECK(inv.to_congruence(x) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(y) == Congruence(ZNumber(4), ZNumber(3))); inv.forget(x); BOOST_CHECK(inv.to_congruence(x) == Congruence::top()); BOOST_CHECK(inv.to_congruence(y) == Congruence(ZNumber(4), ZNumber(3))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(1)); inv.set(y, Congruence(3)); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(3)); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(-6)); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(ZNumber(3), ZNumber(0))); inv.set(y, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(6), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence(ZNumber(3), ZNumber(1))); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = CongruenceDomain::top(); inv.set(x, Congruence(ZNumber(3), ZNumber(0))); inv.set(y, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Congruence(ZNumber(6), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Congruence(ZNumber(3), ZNumber(1)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/constant.cpp000066400000000000000000000500451473507761200247560ustar00rootroot00000000000000/******************************************************************************* * * Tests for ConstantDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_interval_domain #define BOOST_TEST_DYN_LINK #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Constant = ikos::core::numeric::ZConstant; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using ConstantDomain = ikos::core::numeric::ConstantDomain< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(ConstantDomain::top().is_top()); BOOST_CHECK(!ConstantDomain::top().is_bottom()); BOOST_CHECK(!ConstantDomain::bottom().is_top()); BOOST_CHECK(ConstantDomain::bottom().is_bottom()); auto inv = ConstantDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Constant(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Constant::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(iterators) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ConstantDomain::top(); BOOST_CHECK((inv.begin() == inv.end())); inv.set(x, Constant(1)); std::array< std::pair< Variable, Constant >, 1 > tab = {{{x, Constant(1)}}}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab), std::end(tab))); inv.set(y, Constant(2)); std::array< std::pair< Variable, Constant >, 2 > tab2 = {{ {y, Constant(2)}, {x, Constant(1)}, }}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab2), std::end(tab2))); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = ConstantDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(ConstantDomain::bottom().leq(ConstantDomain::top())); BOOST_CHECK(ConstantDomain::bottom().leq(ConstantDomain::bottom())); BOOST_CHECK(!ConstantDomain::top().leq(ConstantDomain::bottom())); BOOST_CHECK(ConstantDomain::top().leq(ConstantDomain::top())); auto inv1 = ConstantDomain::top(); inv1.set(x, Constant(0)); BOOST_CHECK(inv1.leq(ConstantDomain::top())); BOOST_CHECK(!inv1.leq(ConstantDomain::bottom())); auto inv2 = ConstantDomain::top(); inv2.set(x, Constant(1)); BOOST_CHECK(inv2.leq(ConstantDomain::top())); BOOST_CHECK(!inv2.leq(ConstantDomain::bottom())); BOOST_CHECK(!inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = ConstantDomain::top(); inv3.set(x, Constant(0)); inv3.set(y, Constant(1)); BOOST_CHECK(inv3.leq(ConstantDomain::top())); BOOST_CHECK(!inv3.leq(ConstantDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = ConstantDomain::top(); inv4.set(x, Constant(0)); inv4.set(y, Constant(2)); BOOST_CHECK(inv4.leq(ConstantDomain::top())); BOOST_CHECK(!inv4.leq(ConstantDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!ConstantDomain::bottom().equals(ConstantDomain::top())); BOOST_CHECK(ConstantDomain::bottom().equals(ConstantDomain::bottom())); BOOST_CHECK(!ConstantDomain::top().equals(ConstantDomain::bottom())); BOOST_CHECK(ConstantDomain::top().equals(ConstantDomain::top())); auto inv1 = ConstantDomain::top(); inv1.set(x, Constant(0)); BOOST_CHECK(!inv1.equals(ConstantDomain::top())); BOOST_CHECK(!inv1.equals(ConstantDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = ConstantDomain::top(); inv2.set(x, Constant(1)); BOOST_CHECK(!inv2.equals(ConstantDomain::top())); BOOST_CHECK(!inv2.equals(ConstantDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = ConstantDomain::top(); inv3.set(x, Constant(0)); inv3.set(y, Constant(1)); BOOST_CHECK(!inv3.equals(ConstantDomain::top())); BOOST_CHECK(!inv3.equals(ConstantDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((ConstantDomain::bottom().join(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::bottom().join(ConstantDomain::bottom()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::top().join(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::top().join(ConstantDomain::bottom()) == ConstantDomain::top())); auto inv1 = ConstantDomain::top(); inv1.set(x, Constant(0)); BOOST_CHECK((inv1.join(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((inv1.join(ConstantDomain::bottom()) == inv1)); BOOST_CHECK((ConstantDomain::top().join(inv1) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = ConstantDomain::top(); inv2.set(x, Constant(-1)); BOOST_CHECK((inv1.join(inv2) == ConstantDomain::top())); BOOST_CHECK((inv2.join(inv1) == ConstantDomain::top())); auto inv4 = ConstantDomain::top(); inv4.set(x, Constant(-1)); inv4.set(y, Constant(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((ConstantDomain::bottom().widening(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::bottom().widening(ConstantDomain::bottom()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::top().widening(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::top().widening(ConstantDomain::bottom()) == ConstantDomain::top())); auto inv1 = ConstantDomain::top(); inv1.set(x, Constant(0)); BOOST_CHECK((inv1.widening(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((inv1.widening(ConstantDomain::bottom()) == inv1)); BOOST_CHECK((ConstantDomain::top().widening(inv1) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = ConstantDomain::top(); inv2.set(x, Constant(-1)); BOOST_CHECK((inv1.widening(inv2) == ConstantDomain::top())); BOOST_CHECK((inv2.widening(inv1) == ConstantDomain::top())); auto inv4 = ConstantDomain::top(); inv4.set(x, Constant(-1)); inv4.set(y, Constant(0)); BOOST_CHECK((inv4.widening(inv2) == inv2)); BOOST_CHECK((inv2.widening(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((ConstantDomain::bottom().meet(ConstantDomain::top()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::bottom().meet(ConstantDomain::bottom()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::top().meet(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::top().meet(ConstantDomain::bottom()) == ConstantDomain::bottom())); auto inv1 = ConstantDomain::top(); inv1.set(x, Constant(0)); BOOST_CHECK((inv1.meet(ConstantDomain::top()) == inv1)); BOOST_CHECK( (inv1.meet(ConstantDomain::bottom()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::top().meet(inv1) == inv1)); BOOST_CHECK( (ConstantDomain::bottom().meet(inv1) == ConstantDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = ConstantDomain::top(); inv2.set(x, Constant(-1)); BOOST_CHECK((inv1.meet(inv2) == ConstantDomain::bottom())); BOOST_CHECK((inv2.meet(inv1) == ConstantDomain::bottom())); auto inv4 = ConstantDomain::top(); inv4.set(x, Constant(-1)); inv4.set(y, Constant(0)); BOOST_CHECK((inv4.meet(inv2) == inv4)); BOOST_CHECK((inv2.meet(inv4) == inv4)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((ConstantDomain::bottom().narrowing(ConstantDomain::top()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::bottom().narrowing(ConstantDomain::bottom()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::top().narrowing(ConstantDomain::top()) == ConstantDomain::top())); BOOST_CHECK((ConstantDomain::top().narrowing(ConstantDomain::bottom()) == ConstantDomain::bottom())); auto inv1 = ConstantDomain::top(); inv1.set(x, Constant(0)); BOOST_CHECK((inv1.narrowing(ConstantDomain::top()) == inv1)); BOOST_CHECK( (inv1.narrowing(ConstantDomain::bottom()) == ConstantDomain::bottom())); BOOST_CHECK((ConstantDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK( (ConstantDomain::bottom().narrowing(inv1) == ConstantDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = ConstantDomain::top(); inv2.set(x, Constant(-1)); BOOST_CHECK((inv1.narrowing(inv2) == ConstantDomain::bottom())); BOOST_CHECK((inv2.narrowing(inv1) == ConstantDomain::bottom())); auto inv4 = ConstantDomain::top(); inv4.set(x, Constant(-1)); inv4.set(y, Constant(0)); BOOST_CHECK((inv4.narrowing(inv2) == inv4)); BOOST_CHECK((inv2.narrowing(inv4) == inv4)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ConstantDomain::top(); auto inv2 = ConstantDomain::top(); inv1.assign(x, 0); inv2.set(x, Constant(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Constant(1)); inv1.assign(y, x); BOOST_CHECK(inv1.to_constant(y) == Constant(1)); inv1.set_to_top(); inv1.set(x, Constant(1)); inv1.set(y, Constant(2)); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_constant(z) == Constant(-3)); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = ConstantDomain::top(); auto inv2 = ConstantDomain::top(); inv1.set(x, Constant(2)); inv1.set(y, Constant(3)); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(5)); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(-1)); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(6)); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(0)); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(2)); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(2)); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(16)); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(0)); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(2)); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(3)); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_constant(z) == Constant(1)); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(5)); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(-1)); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(6)); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(0)); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(2)); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(2)); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(16)); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(0)); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(2)); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(3)); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_constant(z) == Constant(1)); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(7)); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(1)); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(12)); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(1)); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(1)); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(1)); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(32)); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(0)); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(0)); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(7)); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_constant(z) == Constant(7)); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ConstantDomain::top(); inv.add(VariableExpr(x) == 1); BOOST_CHECK(inv.to_constant(x) == Constant(1)); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ConstantDomain::top(); inv.set(x, Constant(1)); BOOST_CHECK(inv.to_constant(x) == Constant(1)); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_constant(x) == Constant::top()); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_constant(x) == Constant(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_constant(x) == Constant::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(1)); BOOST_CHECK(inv.to_constant(x) == Constant(1)); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_constant(x) == Constant::top()); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = ConstantDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.is_top()); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_top()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_constant(x) == Constant(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_constant(x) == Constant::top()); inv.set_to_top(); inv.refine(x, IntervalCongruence(1)); BOOST_CHECK(inv.to_constant(x) == Constant(1)); inv.set_to_top(); inv.refine(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_constant(x) == Constant::top()); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ConstantDomain::top(); inv.set(x, Constant(1)); inv.set(y, Constant(3)); BOOST_CHECK(inv.to_constant(x) == Constant(1)); BOOST_CHECK(inv.to_constant(y) == Constant(3)); inv.forget(x); BOOST_CHECK(inv.to_constant(x) == Constant::top()); BOOST_CHECK(inv.to_constant(y) == Constant(3)); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ConstantDomain::top(); inv.set(x, Constant(1)); inv.set(y, Constant(3)); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(3)); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(-6)); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ConstantDomain::top(); inv.set(x, Constant(1)); inv.set(y, Constant(3)); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(3)); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence(-6)); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = ConstantDomain::top(); inv.set(x, Constant(1)); inv.set(y, Constant(3)); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(3)); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(-6)); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/dbm.cpp000066400000000000000000000716531473507761200236770ustar00rootroot00000000000000/******************************************************************************* * * Tests for DBM * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_dbm #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using DBM = ikos::core::numeric::DBM< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(DBM::top().is_top()); BOOST_CHECK(!DBM::top().is_bottom()); BOOST_CHECK(!DBM::bottom().is_top()); BOOST_CHECK(DBM::bottom().is_bottom()); auto inv = DBM::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(VariableExpr(x) - VariableExpr(y) <= 1); inv.forget(x); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = DBM::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK(DBM::bottom().leq(DBM::top())); BOOST_CHECK(DBM::bottom().leq(DBM::bottom())); BOOST_CHECK(!DBM::top().leq(DBM::bottom())); BOOST_CHECK(DBM::top().leq(DBM::top())); auto inv1 = DBM::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(DBM::top())); BOOST_CHECK(!inv1.leq(DBM::bottom())); auto inv2 = DBM::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(DBM::top())); BOOST_CHECK(!inv2.leq(DBM::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = DBM::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(DBM::top())); BOOST_CHECK(!inv3.leq(DBM::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = DBM::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(DBM::top())); BOOST_CHECK(!inv4.leq(DBM::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = DBM::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(DBM::top())); BOOST_CHECK(!inv5.leq(DBM::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1} <= {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1} <= {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1, y = 2} <= {x <= 1} inv2.add(VariableExpr(z) <= 4); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1, y = 2} <= {x <= 1, z <= 4} inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK(!inv1.leq(inv2)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!DBM::bottom().equals(DBM::top())); BOOST_CHECK(DBM::bottom().equals(DBM::bottom())); BOOST_CHECK(!DBM::top().equals(DBM::bottom())); BOOST_CHECK(DBM::top().equals(DBM::top())); auto inv1 = DBM::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(DBM::top())); BOOST_CHECK(!inv1.equals(DBM::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = DBM::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(DBM::top())); BOOST_CHECK(!inv2.equals(DBM::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = DBM::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(DBM::top())); BOOST_CHECK(!inv3.equals(DBM::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((DBM::bottom().join(DBM::top()) == DBM::top())); BOOST_CHECK((DBM::bottom().join(DBM::bottom()) == DBM::bottom())); BOOST_CHECK((DBM::top().join(DBM::top()) == DBM::top())); BOOST_CHECK((DBM::top().join(DBM::bottom()) == DBM::top())); auto inv1 = DBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(DBM::top()) == DBM::top())); BOOST_CHECK((inv1.join(DBM::bottom()) == inv1)); BOOST_CHECK((DBM::top().join(inv1) == DBM::top())); BOOST_CHECK((DBM::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = DBM::top(); auto inv3 = DBM::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = DBM::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1} U {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1} U {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1, y = 2} U {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1, y = 2} U {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.set(x, Interval(Bound(-1), Bound(1))); inv3.add(VariableExpr(y) <= 3); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 1); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.join(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.join(inv2).to_interval(a) == Interval(Bound(4), Bound::plus_infinity()))); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((DBM::bottom().widening(DBM::top()) == DBM::top())); BOOST_CHECK((DBM::bottom().widening(DBM::bottom()) == DBM::bottom())); BOOST_CHECK((DBM::top().widening(DBM::top()) == DBM::top())); BOOST_CHECK((DBM::top().widening(DBM::bottom()) == DBM::top())); auto inv1 = DBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(DBM::top()) == DBM::top())); BOOST_CHECK((inv1.widening(DBM::bottom()) == inv1)); BOOST_CHECK((DBM::top().widening(inv1) == DBM::top())); BOOST_CHECK((DBM::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = DBM::top(); auto inv3 = DBM::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(widening_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((DBM::bottom().widening_threshold(DBM::top(), ZNumber(10)) == DBM::top())); BOOST_CHECK((DBM::bottom().widening_threshold(DBM::bottom(), ZNumber(10)) == DBM::bottom())); BOOST_CHECK( (DBM::top().widening_threshold(DBM::top(), ZNumber(10)) == DBM::top())); BOOST_CHECK((DBM::top().widening_threshold(DBM::bottom(), ZNumber(10)) == DBM::top())); auto inv1 = DBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening_threshold(DBM::top(), ZNumber(10)) == DBM::top())); BOOST_CHECK((inv1.widening_threshold(DBM::bottom(), ZNumber(10)) == inv1)); BOOST_CHECK((DBM::top().widening_threshold(inv1, ZNumber(10)) == DBM::top())); BOOST_CHECK((DBM::bottom().widening_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK((inv1.widening_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = DBM::top(); auto inv3 = DBM::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.widening_threshold(inv2, ZNumber(10)) == inv3)); BOOST_CHECK((inv2.widening_threshold(inv1, ZNumber(10)) == inv2)); auto inv4 = DBM::top(); auto inv5 = DBM::top(); auto inv6 = DBM::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv5.set(x, Interval(Bound(-2), Bound(0))); inv6.set(x, Interval(Bound(-10), Bound(0))); BOOST_CHECK((inv4.widening_threshold(inv5, ZNumber(10)) == inv6)); BOOST_CHECK((inv5.widening_threshold(inv4, ZNumber(10)) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((DBM::bottom().narrowing_threshold(DBM::top(), ZNumber(10)) == DBM::bottom())); BOOST_CHECK((DBM::bottom().narrowing_threshold(DBM::bottom(), ZNumber(10)) == DBM::bottom())); BOOST_CHECK( (DBM::top().narrowing_threshold(DBM::top(), ZNumber(10)) == DBM::top())); BOOST_CHECK((DBM::top().narrowing_threshold(DBM::bottom(), ZNumber(10)) == DBM::bottom())); auto inv1 = DBM::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing_threshold(DBM::top(), ZNumber(10)) == inv1)); BOOST_CHECK( (inv1.narrowing_threshold(DBM::bottom(), ZNumber(10)) == DBM::bottom())); BOOST_CHECK((DBM::top().narrowing_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK( (DBM::bottom().narrowing_threshold(inv1, ZNumber(10)) == DBM::bottom())); BOOST_CHECK((inv1.narrowing_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = DBM::top(); auto inv3 = DBM::top(); inv2.set(x, Interval(Bound(0), Bound(1))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv1.narrowing_threshold(inv3, ZNumber(10)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(20)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(5)) == inv3)); auto inv4 = DBM::top(); auto inv5 = DBM::top(); inv4.set(x, Interval(Bound(-10), Bound(0))); inv5.set(x, Interval(Bound(-1), Bound(0))); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(10)) == inv5)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(20)) == inv4)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(5)) == inv4)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((DBM::bottom().meet(DBM::top()) == DBM::bottom())); BOOST_CHECK((DBM::bottom().meet(DBM::bottom()) == DBM::bottom())); BOOST_CHECK((DBM::top().meet(DBM::top()) == DBM::top())); BOOST_CHECK((DBM::top().meet(DBM::bottom()) == DBM::bottom())); auto inv1 = DBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(DBM::top()) == inv1)); BOOST_CHECK((inv1.meet(DBM::bottom()) == DBM::bottom())); BOOST_CHECK((DBM::top().meet(inv1) == inv1)); BOOST_CHECK((DBM::bottom().meet(inv1) == DBM::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = DBM::top(); auto inv3 = DBM::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = DBM::top(); auto inv5 = DBM::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & top() inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK((inv1.meet(inv2) == DBM::bottom())); // {x = 1} & {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1, y = 2} & {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.assign(x, 1); inv3.assign(y, 2); inv3.add(VariableExpr(z) <= 4); BOOST_CHECK((inv1.meet(inv2) == inv3)); // {x = 1, y = 2} & {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.assign(x, 1); inv3.add(VariableExpr(y) <= 2); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 4); inv3.assign(b, 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.meet(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); inv3.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.meet(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((DBM::bottom().narrowing(DBM::top()) == DBM::bottom())); BOOST_CHECK((DBM::bottom().narrowing(DBM::bottom()) == DBM::bottom())); BOOST_CHECK((DBM::top().narrowing(DBM::top()) == DBM::top())); BOOST_CHECK((DBM::top().narrowing(DBM::bottom()) == DBM::bottom())); auto inv1 = DBM::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(DBM::top()) == inv1)); BOOST_CHECK((inv1.narrowing(DBM::bottom()) == DBM::bottom())); BOOST_CHECK((DBM::top().narrowing(inv1) == inv1)); BOOST_CHECK((DBM::bottom().narrowing(inv1) == DBM::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = DBM::top(); auto inv3 = DBM::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = DBM::top(); auto inv2 = DBM::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); inv1.normalize(); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); inv1.set_to_top(); inv1.assign(x, 7); inv1.add(VariableExpr(y) <= 3); inv1.add(VariableExpr(y) >= 1); inv1.assign(z, VariableExpr(x) + 2 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(10), Bound(14))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = DBM::top(); auto inv2 = DBM::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); inv1.normalize(); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); inv1.normalize(); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(0))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); inv1.normalize(); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = DBM::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); inv.normalize(); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); inv.normalize(); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); inv.normalize(); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.assign(x, 1); inv.add(VariableExpr(x) + VariableExpr(y) >= 0); inv.add(VariableExpr(x) - VariableExpr(y) >= 3); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = DBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = DBM::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, IntervalCongruence(Interval(Bound(7), Bound(10)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(7)); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = DBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = DBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = DBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = DBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/gauge.cpp000066400000000000000000001516151473507761200242220ustar00rootroot00000000000000/******************************************************************************* * * Tests for GaugeDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using ZBound = ikos::core::ZBound; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpression = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using ZConstant = ikos::core::numeric::ZConstant; using ZInterval = ikos::core::numeric::ZInterval; using GaugeBound = ikos::core::numeric::GaugeBound< ZNumber, Variable >; using Gauge = ikos::core::numeric::Gauge< ZNumber, Variable >; using GaugeSemiLattice = ikos::core::numeric::GaugeSemiLattice< ZNumber, Variable >; using GaugeDomain = ikos::core::numeric::GaugeDomain< ZNumber, Variable >; // NOLINTNEXTLINE(readability-identifier-naming) static VariableFactory vfac; // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l1 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l2 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l3 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l4 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l5 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l6 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l7 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l8 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l9 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l10 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l11 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l12 = GaugeSemiLattice::top(); // NOLINTNEXTLINE(readability-identifier-naming) static GaugeSemiLattice l13 = GaugeSemiLattice::top(); // initialization static bool init_unit_test() { boost::unit_test::framework::master_test_suite().p_name.value = "test_gauge_domain"; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); l1.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l2.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l2.set(y, Gauge(GaugeBound(i), GaugeBound(2, i))); l3.set(x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); l4.set(x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); l4.set(y, Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(3, i))); l5.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l5.set(y, Gauge(GaugeBound(2, k), GaugeBound(2, k))); l6.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l6.set(y, Gauge(GaugeBound(0), GaugeBound(2, i) + GaugeBound(2, k))); l7.set(x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); l7.set(y, Gauge(GaugeBound(-2), GaugeBound(3, i) + GaugeBound(2, k))); l8.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l8.set(y, Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(3, i))); l9.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l9.set(y, Gauge(GaugeBound(2, k), GaugeBound(2, i) + GaugeBound(2, k))); l10.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l10.set(y, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); l11.set(x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); l11.set(y, Gauge(GaugeBound(-2), GaugeBound::plus_infinity())); l12.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l12.set(y, Gauge(GaugeBound(1), GaugeBound(6))); l13.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l13.set(y, Gauge(GaugeBound(0), GaugeBound(6) + GaugeBound(2, k))); return true; } int main(int argc, char* argv[]) { return boost::unit_test::unit_test_main(&init_unit_test, argc, argv); } #define test_gauge_semilattice(inv, is_bottom_v, is_top_v) \ do { \ BOOST_CHECK((inv).is_bottom() == (is_bottom_v)); \ BOOST_CHECK((inv).is_top() == (is_top_v)); \ } while (0) BOOST_AUTO_TEST_CASE(gauge_semilattice_constructors) { test_gauge_semilattice(GaugeSemiLattice::bottom(), true, false); test_gauge_semilattice(GaugeSemiLattice::top(), false, true); test_gauge_semilattice(l1, false, false); test_gauge_semilattice(l2, false, false); test_gauge_semilattice(l3, false, false); test_gauge_semilattice(l4, false, false); test_gauge_semilattice(l5, false, false); test_gauge_semilattice(l6, false, false); test_gauge_semilattice(l7, false, false); test_gauge_semilattice(l8, false, false); test_gauge_semilattice(l9, false, false); test_gauge_semilattice(l10, false, false); test_gauge_semilattice(l11, false, false); test_gauge_semilattice(l12, false, false); test_gauge_semilattice(l13, false, false); } #define test_gauge_semilattice_leq(x, y, r) BOOST_CHECK((x).leq(y) == (r)) BOOST_AUTO_TEST_CASE(gauge_semilattice_leq) { test_gauge_semilattice_leq(GaugeSemiLattice::top(), GaugeSemiLattice::top(), true); test_gauge_semilattice_leq(GaugeSemiLattice::top(), GaugeSemiLattice::bottom(), false); test_gauge_semilattice_leq(GaugeSemiLattice::top(), l1, false); test_gauge_semilattice_leq(GaugeSemiLattice::top(), l2, false); test_gauge_semilattice_leq(GaugeSemiLattice::top(), l3, false); test_gauge_semilattice_leq(GaugeSemiLattice::top(), l4, false); test_gauge_semilattice_leq(GaugeSemiLattice::top(), l5, false); test_gauge_semilattice_leq(GaugeSemiLattice::bottom(), GaugeSemiLattice::top(), true); test_gauge_semilattice_leq(GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom(), true); test_gauge_semilattice_leq(GaugeSemiLattice::bottom(), l1, true); test_gauge_semilattice_leq(GaugeSemiLattice::bottom(), l2, true); test_gauge_semilattice_leq(GaugeSemiLattice::bottom(), l3, true); test_gauge_semilattice_leq(GaugeSemiLattice::bottom(), l4, true); test_gauge_semilattice_leq(GaugeSemiLattice::bottom(), l5, true); test_gauge_semilattice_leq(l1, GaugeSemiLattice::top(), true); test_gauge_semilattice_leq(l1, GaugeSemiLattice::bottom(), false); test_gauge_semilattice_leq(l1, l1, true); test_gauge_semilattice_leq(l1, l2, false); test_gauge_semilattice_leq(l1, l3, true); test_gauge_semilattice_leq(l1, l4, false); test_gauge_semilattice_leq(l1, l5, false); test_gauge_semilattice_leq(l2, GaugeSemiLattice::top(), true); test_gauge_semilattice_leq(l2, GaugeSemiLattice::bottom(), false); test_gauge_semilattice_leq(l2, l1, true); test_gauge_semilattice_leq(l2, l2, true); test_gauge_semilattice_leq(l2, l3, true); test_gauge_semilattice_leq(l2, l4, true); test_gauge_semilattice_leq(l2, l5, false); test_gauge_semilattice_leq(l3, GaugeSemiLattice::top(), true); test_gauge_semilattice_leq(l3, GaugeSemiLattice::bottom(), false); test_gauge_semilattice_leq(l3, l1, false); test_gauge_semilattice_leq(l3, l2, false); test_gauge_semilattice_leq(l3, l3, true); test_gauge_semilattice_leq(l3, l4, false); test_gauge_semilattice_leq(l3, l5, false); test_gauge_semilattice_leq(l4, GaugeSemiLattice::top(), true); test_gauge_semilattice_leq(l4, GaugeSemiLattice::bottom(), false); test_gauge_semilattice_leq(l4, l1, false); test_gauge_semilattice_leq(l4, l2, false); test_gauge_semilattice_leq(l4, l3, true); test_gauge_semilattice_leq(l4, l4, true); test_gauge_semilattice_leq(l4, l5, false); test_gauge_semilattice_leq(l5, GaugeSemiLattice::top(), true); test_gauge_semilattice_leq(l5, GaugeSemiLattice::bottom(), false); test_gauge_semilattice_leq(l5, l1, true); test_gauge_semilattice_leq(l5, l2, false); test_gauge_semilattice_leq(l5, l3, true); test_gauge_semilattice_leq(l5, l4, false); test_gauge_semilattice_leq(l5, l5, true); } #define test_gauge_semilattice_join(x, y, z) BOOST_CHECK(((x).join(y) == (z))) BOOST_AUTO_TEST_CASE(gauge_semilattice_join) { test_gauge_semilattice_join(GaugeSemiLattice::top(), GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::top(), GaugeSemiLattice::bottom(), GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::top(), l1, GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::top(), l2, GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::top(), l3, GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::top(), l4, GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::top(), l5, GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::bottom(), GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_join(GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_join(GaugeSemiLattice::bottom(), l1, l1); test_gauge_semilattice_join(GaugeSemiLattice::bottom(), l2, l2); test_gauge_semilattice_join(GaugeSemiLattice::bottom(), l3, l3); test_gauge_semilattice_join(GaugeSemiLattice::bottom(), l4, l4); test_gauge_semilattice_join(GaugeSemiLattice::bottom(), l5, l5); test_gauge_semilattice_join(l1, GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_join(l1, GaugeSemiLattice::bottom(), l1); test_gauge_semilattice_join(l1, l1, l1); test_gauge_semilattice_join(l1, l2, l1); test_gauge_semilattice_join(l1, l3, l3); test_gauge_semilattice_join(l1, l4, l3); test_gauge_semilattice_join(l1, l5, l1); test_gauge_semilattice_join(l2, GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_join(l2, GaugeSemiLattice::bottom(), l2); test_gauge_semilattice_join(l2, l1, l1); test_gauge_semilattice_join(l2, l2, l2); test_gauge_semilattice_join(l2, l3, l3); test_gauge_semilattice_join(l2, l4, l4); test_gauge_semilattice_join(l2, l5, l6); test_gauge_semilattice_join(l3, GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_join(l3, GaugeSemiLattice::bottom(), l3); test_gauge_semilattice_join(l3, l1, l3); test_gauge_semilattice_join(l3, l2, l3); test_gauge_semilattice_join(l3, l3, l3); test_gauge_semilattice_join(l3, l4, l3); test_gauge_semilattice_join(l3, l5, l3); test_gauge_semilattice_join(l4, GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_join(l4, GaugeSemiLattice::bottom(), l4); test_gauge_semilattice_join(l4, l1, l3); test_gauge_semilattice_join(l4, l2, l4); test_gauge_semilattice_join(l4, l3, l3); test_gauge_semilattice_join(l4, l4, l4); test_gauge_semilattice_join(l4, l5, l7); test_gauge_semilattice_join(l5, GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_join(l5, GaugeSemiLattice::bottom(), l5); test_gauge_semilattice_join(l5, l1, l1); test_gauge_semilattice_join(l5, l2, l6); test_gauge_semilattice_join(l5, l3, l3); test_gauge_semilattice_join(l5, l4, l7); test_gauge_semilattice_join(l5, l5, l5); } #define test_gauge_semilattice_meet(x, y, z) BOOST_CHECK(((x).meet(y) == (z))) BOOST_AUTO_TEST_CASE(gauge_semilattice_meet) { test_gauge_semilattice_meet(GaugeSemiLattice::top(), GaugeSemiLattice::top(), GaugeSemiLattice::top()); test_gauge_semilattice_meet(GaugeSemiLattice::top(), GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(GaugeSemiLattice::top(), l1, l1); test_gauge_semilattice_meet(GaugeSemiLattice::top(), l2, l2); test_gauge_semilattice_meet(GaugeSemiLattice::top(), l3, l3); test_gauge_semilattice_meet(GaugeSemiLattice::top(), l4, l4); test_gauge_semilattice_meet(GaugeSemiLattice::top(), l5, l5); test_gauge_semilattice_meet(GaugeSemiLattice::bottom(), GaugeSemiLattice::top(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(GaugeSemiLattice::bottom(), l1, GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(GaugeSemiLattice::bottom(), l2, GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(GaugeSemiLattice::bottom(), l3, GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(GaugeSemiLattice::bottom(), l4, GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(GaugeSemiLattice::bottom(), l5, GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(l1, GaugeSemiLattice::top(), l1); test_gauge_semilattice_meet(l1, GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(l1, l1, l1); test_gauge_semilattice_meet(l1, l2, l2); test_gauge_semilattice_meet(l1, l3, l1); test_gauge_semilattice_meet(l1, l4, l8); test_gauge_semilattice_meet(l1, l5, l5); test_gauge_semilattice_meet(l2, GaugeSemiLattice::top(), l2); test_gauge_semilattice_meet(l2, GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(l2, l1, l2); test_gauge_semilattice_meet(l2, l2, l2); test_gauge_semilattice_meet(l2, l3, l2); test_gauge_semilattice_meet(l2, l4, l2); test_gauge_semilattice_meet(l2, l5, l9); test_gauge_semilattice_meet(l3, GaugeSemiLattice::top(), l3); test_gauge_semilattice_meet(l3, GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(l3, l1, l1); test_gauge_semilattice_meet(l3, l2, l2); test_gauge_semilattice_meet(l3, l3, l3); test_gauge_semilattice_meet(l3, l4, l4); test_gauge_semilattice_meet(l3, l5, l5); test_gauge_semilattice_meet(l4, GaugeSemiLattice::top(), l4); test_gauge_semilattice_meet(l4, GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(l4, l1, l8); test_gauge_semilattice_meet(l4, l2, l2); test_gauge_semilattice_meet(l4, l3, l4); test_gauge_semilattice_meet(l4, l4, l4); test_gauge_semilattice_meet(l4, l5, l5); test_gauge_semilattice_meet(l5, GaugeSemiLattice::top(), l5); test_gauge_semilattice_meet(l5, GaugeSemiLattice::bottom(), GaugeSemiLattice::bottom()); test_gauge_semilattice_meet(l5, l1, l5); test_gauge_semilattice_meet(l5, l2, l5); test_gauge_semilattice_meet(l5, l3, l5); test_gauge_semilattice_meet(l5, l4, l5); test_gauge_semilattice_meet(l5, l5, l5); } static void test_gauge_semilattice_forget(GaugeSemiLattice x, const Variable& v, const GaugeSemiLattice& y) { x.forget(v); BOOST_CHECK((x == y)); } BOOST_AUTO_TEST_CASE(gauge_semilattice_forget) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_semilattice_forget(GaugeSemiLattice::top(), x, GaugeSemiLattice::top()); test_gauge_semilattice_forget(GaugeSemiLattice::bottom(), x, GaugeSemiLattice::bottom()); test_gauge_semilattice_forget(l1, x, GaugeSemiLattice::top()); test_gauge_semilattice_forget(l1, y, l1); test_gauge_semilattice_forget(l2, y, l1); test_gauge_semilattice_forget(l3, x, GaugeSemiLattice::top()); test_gauge_semilattice_forget(l4, y, l3); test_gauge_semilattice_forget(l5, y, l1); } static void test_gauge_semilattice_counter_incr(GaugeSemiLattice x, const Variable& v, int k, const GaugeSemiLattice& y) { x.counter_incr(v, ZNumber(k)); BOOST_CHECK((x == y)); } BOOST_AUTO_TEST_CASE(gauge_semilattice_counter_incr) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); test_gauge_semilattice_counter_incr(GaugeSemiLattice::top(), i, 1, GaugeSemiLattice::top()); test_gauge_semilattice_counter_incr(GaugeSemiLattice::bottom(), i, 1, GaugeSemiLattice::bottom()); // l1.counter_incr(i, 1) test_gauge_semilattice_counter_incr(l1, i, 1, l1); // l2.counter_incr(i, 1) GaugeSemiLattice l2_prime = l1; l2_prime.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l2_prime.set(y, Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(-1) + GaugeBound(2, i))); test_gauge_semilattice_counter_incr(l2, i, 1, l2_prime); // l3.counter_incr(i, 1) test_gauge_semilattice_counter_incr(l3, i, 1, l3); // l4.counter_incr(i, 1) auto l4_prime = GaugeSemiLattice::top(); l4_prime.set(x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); l4_prime.set(y, Gauge(GaugeBound(-3) + GaugeBound(i), GaugeBound(-3) + GaugeBound(3, i))); test_gauge_semilattice_counter_incr(l4, i, 1, l4_prime); // l5.counter_incr(i, 1) test_gauge_semilattice_counter_incr(l5, i, 1, l5); // l5.counter_incr(k, 2) auto l5_prime = GaugeSemiLattice::top(); l5_prime.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l5_prime.set(y, Gauge(GaugeBound(-4) + GaugeBound(2, k), GaugeBound(-4) + GaugeBound(2, k))); test_gauge_semilattice_counter_incr(l5, k, 2, l5_prime); // l6.counter_incr(i, 1) auto l6_prime = GaugeSemiLattice::top(); l6_prime.set(x, Gauge(GaugeBound(0), GaugeBound(1))); l6_prime.set(y, Gauge(GaugeBound(-2), GaugeBound(2, i) + GaugeBound(2, k))); test_gauge_semilattice_counter_incr(l6, i, 1, l6_prime); // l7.counter_incr(i, 1) auto l7_prime = GaugeSemiLattice::top(); l7_prime.set(x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); l7_prime.set(y, Gauge(GaugeBound(-3), GaugeBound(-2) + GaugeBound(3, i) + GaugeBound(2, k))); test_gauge_semilattice_counter_incr(l7, i, 1, l7_prime); } static void test_gauge_semilattice_counter_forget(GaugeSemiLattice x, const Variable& v, const GaugeSemiLattice& y) { x.counter_forget(v); BOOST_CHECK((x == y)); } static void test_gauge_semilattice_counter_forget(GaugeSemiLattice x, const Variable& v, const ZInterval& intv, const GaugeSemiLattice& y) { x.counter_forget(v, intv); BOOST_CHECK((x == y)); } BOOST_AUTO_TEST_CASE(gauge_semilattice_counter_forget) { Variable x(vfac.get("x")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); test_gauge_semilattice_counter_forget(GaugeSemiLattice::top(), x, GaugeSemiLattice::top()); test_gauge_semilattice_counter_forget(GaugeSemiLattice::bottom(), x, GaugeSemiLattice::bottom()); test_gauge_semilattice_counter_forget(l1, i, l1); test_gauge_semilattice_counter_forget(l2, i, l10); test_gauge_semilattice_counter_forget(l2, i, ZInterval(ZBound(1), ZBound(3)), l12); test_gauge_semilattice_counter_forget(l3, i, l3); test_gauge_semilattice_counter_forget(l4, i, l11); test_gauge_semilattice_counter_forget(l5, i, l5); test_gauge_semilattice_counter_forget(l5, k, l10); test_gauge_semilattice_counter_forget(l6, i, l10); test_gauge_semilattice_counter_forget(l6, i, ZInterval(ZBound(1), ZBound(3)), l13); test_gauge_semilattice_counter_forget(l6, i, ZInterval(ZBound(1), ZBound::plus_infinity()), l10); test_gauge_semilattice_counter_forget(l6, k, l10); test_gauge_semilattice_counter_forget(l7, i, l11); test_gauge_semilattice_counter_forget(l7, k, l11); } #define test_gauge_semilattice_get(x, v, y) BOOST_CHECK((x).get(v) == (y)) BOOST_AUTO_TEST_CASE(gauge_semilattice_get) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_semilattice_get(GaugeSemiLattice::top(), x, Gauge::top()); test_gauge_semilattice_get(GaugeSemiLattice::bottom(), x, Gauge::bottom()); test_gauge_semilattice_get(l1, x, Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_semilattice_get(l1, y, Gauge::top()); test_gauge_semilattice_get(l2, x, Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_semilattice_get(l3, x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_semilattice_get(l4, x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_semilattice_get(l5, x, Gauge(GaugeBound(0), GaugeBound(1))); } #define test_gauge_domain(d, is_bottom_v, is_top_v) \ do { \ BOOST_CHECK((d).is_bottom() == (is_bottom_v)); \ BOOST_CHECK((d).is_top() == (is_top_v)); \ } while (0) BOOST_AUTO_TEST_CASE(gauge_domain_constructors) { Variable x(vfac.get("x")); Variable i(vfac.get("i")); test_gauge_domain(GaugeDomain::bottom(), true, false); test_gauge_domain(GaugeDomain::top(), false, true); auto d = GaugeDomain::top(); d.set_to_top(); d.counter_init(i, ZNumber(0)); test_gauge_domain(d, false, false); d.set_to_top(); d.counter_init(i, ZNumber(0)); d.assign(x, 1); test_gauge_domain(d, false, false); } #define test_gauge_domain_get(x, v, y) BOOST_CHECK((x).to_gauge(v) == (y)) #define test_gauge_domain_to_interval(x, v, y) \ BOOST_CHECK((x).to_interval(v) == (y)) BOOST_AUTO_TEST_CASE(gauge_domain_assign) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); test_gauge_domain_get(GaugeDomain::bottom(), x, Gauge::bottom()); test_gauge_domain_to_interval(GaugeDomain::bottom(), x, ZInterval::bottom()); test_gauge_domain_get(GaugeDomain::top(), x, Gauge::top()); test_gauge_domain_to_interval(GaugeDomain::top(), x, ZInterval::top()); auto d = GaugeDomain::top(); d.counter_init(i, ZNumber(0)); test_gauge_domain_get(d, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d, i, ZInterval(ZBound(0), ZBound(0))); test_gauge_domain_get(d, x, Gauge::top()); test_gauge_domain_to_interval(d, x, ZInterval::top()); d.assign(x, 1); test_gauge_domain_get(d, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d, i, ZInterval(ZBound(0), ZBound(0))); test_gauge_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_gauge_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); d.assign(y, 2 * VariableExpression(i) + 1); test_gauge_domain_get(d, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d, i, ZInterval(ZBound(0), ZBound(0))); test_gauge_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_gauge_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, y, Gauge(GaugeBound(1) + GaugeBound(2, i))); test_gauge_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); d.counter_incr(i, ZNumber(1)); test_gauge_domain_get(d, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_gauge_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_gauge_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); d.counter_init(k, ZNumber(0)); test_gauge_domain_get(d, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, k, Gauge(GaugeBound(k))); test_gauge_domain_to_interval(d, k, ZInterval(ZBound(0), ZBound(0))); test_gauge_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_gauge_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_gauge_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); d.assign(z, 3 * VariableExpression(k) + 2 * VariableExpression(y)); test_gauge_domain_get(d, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, k, Gauge(GaugeBound(k))); test_gauge_domain_to_interval(d, k, ZInterval(ZBound(0), ZBound(0))); test_gauge_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_gauge_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_gauge_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, z, Gauge(GaugeBound(-2) + GaugeBound(4, i) + GaugeBound(3, k))); test_gauge_domain_to_interval(d, z, ZInterval(ZBound(2), ZBound(2))); d.counter_incr(k, ZNumber(1)); test_gauge_domain_get(d, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, k, Gauge(GaugeBound(k))); test_gauge_domain_to_interval(d, k, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_gauge_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_gauge_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); test_gauge_domain_get(d, z, Gauge(GaugeBound(-5) + GaugeBound(4, i) + GaugeBound(3, k))); test_gauge_domain_to_interval(d, z, ZInterval(ZBound(2), ZBound(2))); } BOOST_AUTO_TEST_CASE(gauge_domain_widening) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); auto d1 = GaugeDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 0); d1.assign(y, 1); test_gauge_domain_get(d1, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d1, i, ZInterval(0)); test_gauge_domain_get(d1, x, Gauge(0)); test_gauge_domain_to_interval(d1, x, ZInterval(0)); test_gauge_domain_get(d1, y, Gauge(1)); test_gauge_domain_to_interval(d1, y, ZInterval(1)); GaugeDomain d2 = d1; d2.counter_incr(i, ZNumber(1)); d2.assign(x, VariableExpression(x) + 2); d2.assign(y, VariableExpression(y) + 3); test_gauge_domain_get(d2, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d2, i, ZInterval(1)); test_gauge_domain_get(d2, x, Gauge(2)); test_gauge_domain_to_interval(d2, x, ZInterval(2)); test_gauge_domain_get(d2, y, Gauge(4)); test_gauge_domain_to_interval(d2, y, ZInterval(4)); GaugeDomain d3 = d1.widening(d2); test_gauge_domain_get(d3, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d3, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d3, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_gauge_domain_to_interval(d3, y, ZInterval(ZBound(1), ZBound::plus_infinity())); GaugeDomain d4 = d3; d4.assign(y, 3 * VariableExpression(i) + 2); GaugeDomain d5 = d3.widening(d4); test_gauge_domain_get(d5, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d5, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d5, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d5, x, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d5, y, Gauge(GaugeBound(1) + GaugeBound(3, i), GaugeBound::plus_infinity())); test_gauge_domain_to_interval(d5, y, ZInterval(ZBound(1), ZBound::plus_infinity())); } BOOST_AUTO_TEST_CASE(gauge_domain_widening_narrowing_threshold) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); auto d1 = GaugeDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 0); d1.assign(y, 1); GaugeDomain d2 = d1; d2.counter_incr(i, ZNumber(1)); d2.assign(x, VariableExpression(x) + 2); d2.assign(y, VariableExpression(y) + 3); GaugeDomain d3 = d1.widening_threshold(d2, ZNumber(10)); test_gauge_domain_get(d3, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound(10))); test_gauge_domain_get(d3, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound(20))); test_gauge_domain_get(d3, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_gauge_domain_to_interval(d3, y, ZInterval(ZBound(1), ZBound(31))); GaugeDomain d4 = d3; d4.add(VariableExpression(i) <= 5); d4 = d4.narrowing_threshold(d3, ZNumber(10)); test_gauge_domain_get(d4, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d4, i, ZInterval(ZBound(0), ZBound(5))); test_gauge_domain_get(d4, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d4, x, ZInterval(ZBound(0), ZBound(10))); test_gauge_domain_get(d4, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_gauge_domain_to_interval(d4, y, ZInterval(ZBound(1), ZBound(16))); } BOOST_AUTO_TEST_CASE(gauge_domain_add) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); auto d1 = GaugeDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 0); d1.assign(y, 1); d1.add(VariableExpression(i) <= 10); test_gauge_domain_get(d1, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d1, i, ZInterval(0)); test_gauge_domain_get(d1, x, Gauge(0)); test_gauge_domain_get(d1, y, Gauge(1)); GaugeDomain d2 = d1; d2.counter_incr(i, ZNumber(1)); d2.assign(x, VariableExpression(x) + 2); d2.assign(y, VariableExpression(y) + 3); d2.add(VariableExpression(i) <= 10); test_gauge_domain_get(d2, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d2, i, ZInterval(1)); test_gauge_domain_get(d2, x, Gauge(2)); test_gauge_domain_get(d2, y, Gauge(4)); GaugeDomain d3 = d1.widening(d2); d3.add(VariableExpression(i) <= 10); test_gauge_domain_get(d3, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound(10))); test_gauge_domain_get(d3, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound(20))); test_gauge_domain_get(d3, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_gauge_domain_to_interval(d3, y, ZInterval(ZBound(1), ZBound(31))); GaugeDomain d4 = d3; d4.add(VariableExpression(i) >= 11); test_gauge_domain_get(d4, i, Gauge::bottom()); GaugeDomain d5 = d3; d5.add(VariableExpression(i) == 10); test_gauge_domain_get(d5, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d5, i, ZInterval(10)); test_gauge_domain_get(d5, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d5, x, ZInterval(20)); test_gauge_domain_get(d5, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_gauge_domain_to_interval(d5, y, ZInterval(31)); GaugeDomain d6 = d3; d6.add(VariableExpression(i) != 10); test_gauge_domain_get(d6, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d6, i, ZInterval(ZBound(0), ZBound(9))); test_gauge_domain_get(d6, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d6, x, ZInterval(ZBound(0), ZBound(18))); test_gauge_domain_get(d6, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_gauge_domain_to_interval(d6, y, ZInterval(ZBound(1), ZBound(28))); } BOOST_AUTO_TEST_CASE(gauge_domain_forget) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); auto d1 = GaugeDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 0); d1.assign(y, 1); d1.add(VariableExpression(i) <= 10); GaugeDomain d2 = d1; d2.counter_incr(i, ZNumber(1)); d2.assign(x, VariableExpression(x) + 2); d2.assign(y, VariableExpression(y) + 3); d2.add(VariableExpression(i) <= 10); GaugeDomain d3 = d1.widening(d2); d3.add(VariableExpression(i) <= 10); d1.forget(i); test_gauge_domain_get(d1, i, Gauge::top()); test_gauge_domain_to_interval(d1, i, ZInterval::top()); test_gauge_domain_get(d1, x, Gauge(0)); test_gauge_domain_get(d1, y, Gauge(1)); d3.forget(y); test_gauge_domain_get(d3, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound(10))); test_gauge_domain_get(d3, x, Gauge(GaugeBound(2, i))); test_gauge_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound(20))); test_gauge_domain_get(d3, y, Gauge::top()); test_gauge_domain_to_interval(d3, y, ZInterval::top()); d3.forget(i); test_gauge_domain_get(d3, i, Gauge::top()); test_gauge_domain_to_interval(d3, i, ZInterval::top()); test_gauge_domain_get(d3, x, Gauge(GaugeBound(0), GaugeBound(20))); test_gauge_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound(20))); } BOOST_AUTO_TEST_CASE(gauge_domain_set) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto d1 = GaugeDomain::top(); d1.assign(x, 0); d1.assign(y, 1); d1.set(x, ZInterval::top()); test_gauge_domain_get(d1, x, Gauge::top()); test_gauge_domain_get(d1, y, Gauge(1)); d1.set(x, ZInterval(ZBound(1), ZBound(2))); test_gauge_domain_get(d1, x, Gauge(GaugeBound(1), GaugeBound(2))); test_gauge_domain_get(d1, y, Gauge(1)); d1.set(x, ZInterval(ZBound(1), ZBound::plus_infinity())); test_gauge_domain_get(d1, x, Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_gauge_domain_get(d1, y, Gauge(1)); d1.set(x, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_gauge_domain_get(d1, x, Gauge(GaugeBound::minus_infinity(), GaugeBound(1))); test_gauge_domain_get(d1, y, Gauge(1)); } BOOST_AUTO_TEST_CASE(gauge_domain_apply_var_var_var) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); Variable zero(vfac.get("zero")); Variable one(vfac.get("one")); Variable two(vfac.get("two")); auto d1 = GaugeDomain::top(); d1.assign(zero, 0); d1.assign(one, 1); d1.assign(two, 2); d1.counter_init(i, ZNumber(0)); d1.assign(x, 3); d1.assign(y, 2); d1.assign(z, 2); d1.assign(w, 16); test_gauge_domain_get(d1, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d1, i, ZInterval(0)); test_gauge_domain_get(d1, x, Gauge(3)); test_gauge_domain_to_interval(d1, x, ZInterval(3)); test_gauge_domain_get(d1, y, Gauge(2)); test_gauge_domain_to_interval(d1, y, ZInterval(2)); test_gauge_domain_get(d1, z, Gauge(2)); test_gauge_domain_to_interval(d1, z, ZInterval(2)); test_gauge_domain_get(d1, w, Gauge(16)); test_gauge_domain_to_interval(d1, w, ZInterval(16)); GaugeDomain d2 = d1; d2.apply(BinaryOperator::Add, x, x, two); d2.apply(BinaryOperator::Sub, y, y, one); d2.apply(BinaryOperator::Mul, z, z, two); d2.apply(BinaryOperator::Div, w, w, two); d2.apply(BinaryOperator::Add, k, i, one); test_gauge_domain_get(d2, x, Gauge(5)); test_gauge_domain_to_interval(d2, x, ZInterval(5)); test_gauge_domain_get(d2, y, Gauge(1)); test_gauge_domain_to_interval(d2, y, ZInterval(1)); test_gauge_domain_get(d2, z, Gauge(4)); test_gauge_domain_to_interval(d2, z, ZInterval(4)); test_gauge_domain_get(d2, w, Gauge(8)); test_gauge_domain_to_interval(d2, w, ZInterval(8)); test_gauge_domain_get(d2, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_gauge_domain_to_interval(d2, k, ZInterval(1)); d2.counter_incr(i, ZNumber(1)); test_gauge_domain_get(d2, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d2, i, ZInterval(1)); test_gauge_domain_get(d2, k, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d2, k, ZInterval(1)); GaugeDomain d3 = d1.widening(d2); test_gauge_domain_get(d3, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d3, k, Gauge::top()); test_gauge_domain_to_interval(d3, k, ZInterval::top()); test_gauge_domain_get(d3, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_gauge_domain_to_interval(d3, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_gauge_domain_get(d3, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d3, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_gauge_domain_get(d3, z, Gauge(GaugeBound(2) + GaugeBound(2, i))); test_gauge_domain_to_interval(d3, z, ZInterval(ZBound(2), ZBound::plus_infinity())); test_gauge_domain_get(d3, w, Gauge(GaugeBound(16) + GaugeBound(-8, i))); test_gauge_domain_to_interval(d3, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); GaugeDomain d4 = d3; d4.apply(BinaryOperator::Add, x, x, two); d4.apply(BinaryOperator::Sub, y, y, one); d4.apply(BinaryOperator::Mul, z, z, two); d4.apply(BinaryOperator::Div, w, w, two); d4.apply(BinaryOperator::Add, k, i, one); test_gauge_domain_get(d4, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_gauge_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_gauge_domain_get(d4, x, Gauge(GaugeBound(5) + GaugeBound(2, i))); test_gauge_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_gauge_domain_get(d4, y, Gauge(GaugeBound(1) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_gauge_domain_get(d4, z, Gauge(GaugeBound(4) + GaugeBound(4, i))); test_gauge_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_gauge_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_gauge_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); d4.counter_incr(i, ZNumber(1)); test_gauge_domain_get(d4, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d4, i, ZInterval(ZBound(1), ZBound::plus_infinity())); test_gauge_domain_get(d4, k, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_gauge_domain_get(d4, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_gauge_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_gauge_domain_get(d4, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_gauge_domain_get(d4, z, Gauge(GaugeBound(0) + GaugeBound(4, i))); test_gauge_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_gauge_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_gauge_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); GaugeDomain d5 = d3.join(d4); test_gauge_domain_get(d5, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d5, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d5, k, Gauge::top()); test_gauge_domain_to_interval(d5, k, ZInterval::top()); test_gauge_domain_get(d5, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_gauge_domain_to_interval(d5, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_gauge_domain_get(d5, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d5, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_gauge_domain_get(d5, z, Gauge(GaugeBound(2, i), GaugeBound(2) + GaugeBound(4, i))); test_gauge_domain_to_interval(d5, z, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d5, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(16))); test_gauge_domain_to_interval(d5, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); } BOOST_AUTO_TEST_CASE(gauge_domain_apply_var_var_num) { Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); auto d1 = GaugeDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 3); d1.assign(y, 2); d1.assign(z, 2); d1.assign(w, 16); test_gauge_domain_get(d1, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d1, i, ZInterval(0)); test_gauge_domain_get(d1, x, Gauge(3)); test_gauge_domain_to_interval(d1, x, ZInterval(3)); test_gauge_domain_get(d1, y, Gauge(2)); test_gauge_domain_to_interval(d1, y, ZInterval(2)); test_gauge_domain_get(d1, z, Gauge(2)); test_gauge_domain_to_interval(d1, z, ZInterval(2)); test_gauge_domain_get(d1, w, Gauge(16)); test_gauge_domain_to_interval(d1, w, ZInterval(16)); GaugeDomain d2 = d1; d2.apply(BinaryOperator::Add, x, x, ZNumber(2)); d2.apply(BinaryOperator::Sub, y, y, ZNumber(1)); d2.apply(BinaryOperator::Mul, z, z, ZNumber(2)); d2.apply(BinaryOperator::Div, w, w, ZNumber(2)); d2.apply(BinaryOperator::Add, k, i, ZNumber(1)); test_gauge_domain_get(d2, x, Gauge(5)); test_gauge_domain_to_interval(d2, x, ZInterval(5)); test_gauge_domain_get(d2, y, Gauge(1)); test_gauge_domain_to_interval(d2, y, ZInterval(1)); test_gauge_domain_get(d2, z, Gauge(4)); test_gauge_domain_to_interval(d2, z, ZInterval(4)); test_gauge_domain_get(d2, w, Gauge(8)); test_gauge_domain_to_interval(d2, w, ZInterval(8)); test_gauge_domain_get(d2, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_gauge_domain_to_interval(d2, k, ZInterval(1)); d2.counter_incr(i, ZNumber(1)); test_gauge_domain_get(d2, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d2, i, ZInterval(1)); test_gauge_domain_get(d2, k, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d2, k, ZInterval(1)); GaugeDomain d3 = d1.widening(d2); test_gauge_domain_get(d3, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d3, k, Gauge::top()); test_gauge_domain_to_interval(d3, k, ZInterval::top()); test_gauge_domain_get(d3, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_gauge_domain_to_interval(d3, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_gauge_domain_get(d3, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d3, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_gauge_domain_get(d3, z, Gauge(GaugeBound(2) + GaugeBound(2, i))); test_gauge_domain_to_interval(d3, z, ZInterval(ZBound(2), ZBound::plus_infinity())); test_gauge_domain_get(d3, w, Gauge(GaugeBound(16) + GaugeBound(-8, i))); test_gauge_domain_to_interval(d3, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); GaugeDomain d4 = d3; d4.apply(BinaryOperator::Add, x, x, ZNumber(2)); d4.apply(BinaryOperator::Sub, y, y, ZNumber(1)); d4.apply(BinaryOperator::Mul, z, z, ZNumber(2)); d4.apply(BinaryOperator::Div, w, w, ZNumber(2)); d4.apply(BinaryOperator::Add, k, i, ZNumber(1)); test_gauge_domain_get(d4, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_gauge_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_gauge_domain_get(d4, x, Gauge(GaugeBound(5) + GaugeBound(2, i))); test_gauge_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_gauge_domain_get(d4, y, Gauge(GaugeBound(1) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_gauge_domain_get(d4, z, Gauge(GaugeBound(4) + GaugeBound(4, i))); test_gauge_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_gauge_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_gauge_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); d4.counter_incr(i, ZNumber(1)); test_gauge_domain_get(d4, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d4, i, ZInterval(ZBound(1), ZBound::plus_infinity())); test_gauge_domain_get(d4, k, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_gauge_domain_get(d4, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_gauge_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_gauge_domain_get(d4, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_gauge_domain_get(d4, z, Gauge(GaugeBound(0) + GaugeBound(4, i))); test_gauge_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_gauge_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_gauge_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); GaugeDomain d5 = d3.join(d4); test_gauge_domain_get(d5, i, Gauge(GaugeBound(i))); test_gauge_domain_to_interval(d5, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d5, k, Gauge::top()); test_gauge_domain_to_interval(d5, k, ZInterval::top()); test_gauge_domain_get(d5, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_gauge_domain_to_interval(d5, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_gauge_domain_get(d5, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_gauge_domain_to_interval(d5, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_gauge_domain_get(d5, z, Gauge(GaugeBound(2, i), GaugeBound(2) + GaugeBound(4, i))); test_gauge_domain_to_interval(d5, z, ZInterval(ZBound(0), ZBound::plus_infinity())); test_gauge_domain_get(d5, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(16))); test_gauge_domain_to_interval(d5, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/gauge_interval_congruence.cpp000066400000000000000000000645121473507761200303350ustar00rootroot00000000000000/******************************************************************************* * * Tests for GaugeIntervalCongruenceDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_gauge_interval_congruence_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using ZBound = ikos::core::ZBound; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpression = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using ZConstant = ikos::core::numeric::ZConstant; using ZInterval = ikos::core::numeric::ZInterval; using GaugeBound = ikos::core::numeric::GaugeBound< ZNumber, Variable >; using Gauge = ikos::core::numeric::Gauge< ZNumber, Variable >; using GaugeSemiLattice = ikos::core::numeric::GaugeSemiLattice< ZNumber, Variable >; using GaugeIntervalCongruenceDomain = ikos::core::numeric::GaugeIntervalCongruenceDomain< ZNumber, Variable >; #define test_domain(d, is_bottom_v, is_top_v) \ do { \ BOOST_CHECK((d).is_bottom() == (is_bottom_v)); \ BOOST_CHECK((d).is_top() == (is_top_v)); \ } while (0) BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_constructors) { VariableFactory vfac; Variable x(vfac.get("x")); Variable i(vfac.get("i")); test_domain(GaugeIntervalCongruenceDomain::bottom(), true, false); test_domain(GaugeIntervalCongruenceDomain::top(), false, true); auto d = GaugeIntervalCongruenceDomain::top(); d.set_to_top(); d.counter_init(i, ZNumber(0)); test_domain(d, false, false); d.set_to_top(); d.counter_init(i, ZNumber(0)); d.assign(x, 1); test_domain(d, false, false); } #define test_domain_get(x, v, y) BOOST_CHECK((x).to_gauge(v) == (y)) #define test_domain_to_interval(x, v, y) BOOST_CHECK((x).to_interval(v) == (y)) BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); test_domain_get(GaugeIntervalCongruenceDomain::bottom(), x, Gauge::bottom()); test_domain_to_interval(GaugeIntervalCongruenceDomain::bottom(), x, ZInterval::bottom()); test_domain_get(GaugeIntervalCongruenceDomain::top(), x, Gauge::top()); test_domain_to_interval(GaugeIntervalCongruenceDomain::top(), x, ZInterval::top()); auto d = GaugeIntervalCongruenceDomain::top(); d.counter_init(i, ZNumber(0)); test_domain_get(d, i, Gauge(GaugeBound(i))); test_domain_to_interval(d, i, ZInterval(ZBound(0), ZBound(0))); test_domain_get(d, x, Gauge::top()); test_domain_to_interval(d, x, ZInterval::top()); d.assign(x, 1); test_domain_get(d, i, Gauge(GaugeBound(i))); test_domain_to_interval(d, i, ZInterval(ZBound(0), ZBound(0))); test_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); d.assign(y, 2 * VariableExpression(i) + 1); test_domain_get(d, i, Gauge(GaugeBound(i))); test_domain_to_interval(d, i, ZInterval(ZBound(0), ZBound(0))); test_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, y, Gauge(GaugeBound(1) + GaugeBound(2, i))); test_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); d.counter_incr(i, ZNumber(1)); test_domain_get(d, i, Gauge(GaugeBound(i))); test_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); d.counter_init(k, ZNumber(0)); test_domain_get(d, i, Gauge(GaugeBound(i))); test_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, k, Gauge(GaugeBound(k))); test_domain_to_interval(d, k, ZInterval(ZBound(0), ZBound(0))); test_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); d.assign(z, 3 * VariableExpression(k) + 2 * VariableExpression(y)); test_domain_get(d, i, Gauge(GaugeBound(i))); test_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, k, Gauge(GaugeBound(k))); test_domain_to_interval(d, k, ZInterval(ZBound(0), ZBound(0))); test_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, z, Gauge(GaugeBound(-2) + GaugeBound(4, i) + GaugeBound(3, k))); test_domain_to_interval(d, z, ZInterval(ZBound(2), ZBound(2))); d.counter_incr(k, ZNumber(1)); test_domain_get(d, i, Gauge(GaugeBound(i))); test_domain_to_interval(d, i, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, k, Gauge(GaugeBound(k))); test_domain_to_interval(d, k, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, x, Gauge(GaugeBound(1), GaugeBound(1))); test_domain_to_interval(d, x, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, y, Gauge(GaugeBound(-1) + GaugeBound(2, i))); test_domain_to_interval(d, y, ZInterval(ZBound(1), ZBound(1))); test_domain_get(d, z, Gauge(GaugeBound(-5) + GaugeBound(4, i) + GaugeBound(3, k))); test_domain_to_interval(d, z, ZInterval(ZBound(2), ZBound(2))); } BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_widening) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); auto d1 = GaugeIntervalCongruenceDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 0); d1.assign(y, 1); test_domain_get(d1, i, Gauge(GaugeBound(i))); test_domain_to_interval(d1, i, ZInterval(0)); test_domain_get(d1, x, Gauge(0)); test_domain_to_interval(d1, x, ZInterval(0)); test_domain_get(d1, y, Gauge(1)); test_domain_to_interval(d1, y, ZInterval(1)); GaugeIntervalCongruenceDomain d2 = d1; d2.counter_incr(i, ZNumber(1)); d2.assign(x, VariableExpression(x) + 2); d2.assign(y, VariableExpression(y) + 3); test_domain_get(d2, i, Gauge(GaugeBound(i))); test_domain_to_interval(d2, i, ZInterval(1)); test_domain_get(d2, x, Gauge(2)); test_domain_to_interval(d2, x, ZInterval(2)); test_domain_get(d2, y, Gauge(4)); test_domain_to_interval(d2, y, ZInterval(4)); GaugeIntervalCongruenceDomain d3 = d1.widening(d2); test_domain_get(d3, i, Gauge(GaugeBound(i))); test_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d3, x, Gauge(GaugeBound(2, i))); test_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d3, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_domain_to_interval(d3, y, ZInterval(ZBound(1), ZBound::plus_infinity())); GaugeIntervalCongruenceDomain d4 = d3; d4.assign(y, 3 * VariableExpression(i) + 2); GaugeIntervalCongruenceDomain d5 = d3.widening(d4); test_domain_get(d5, i, Gauge(GaugeBound(i))); test_domain_to_interval(d5, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d5, x, Gauge(GaugeBound(2, i))); test_domain_to_interval(d5, x, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d5, y, Gauge(GaugeBound(1) + GaugeBound(3, i), GaugeBound::plus_infinity())); test_domain_to_interval(d5, y, ZInterval(ZBound(1), ZBound::plus_infinity())); } BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); auto d1 = GaugeIntervalCongruenceDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 0); d1.assign(y, 1); d1.add(VariableExpression(i) <= 10); test_domain_get(d1, i, Gauge(GaugeBound(i))); test_domain_to_interval(d1, i, ZInterval(0)); test_domain_get(d1, x, Gauge(0)); test_domain_get(d1, y, Gauge(1)); GaugeIntervalCongruenceDomain d2 = d1; d2.counter_incr(i, ZNumber(1)); d2.assign(x, VariableExpression(x) + 2); d2.assign(y, VariableExpression(y) + 3); d2.add(VariableExpression(i) <= 10); test_domain_get(d2, i, Gauge(GaugeBound(i))); test_domain_to_interval(d2, i, ZInterval(1)); test_domain_get(d2, x, Gauge(2)); test_domain_get(d2, y, Gauge(4)); GaugeIntervalCongruenceDomain d3 = d1.widening(d2); d3.add(VariableExpression(i) <= 10); test_domain_get(d3, i, Gauge(GaugeBound(i))); test_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound(10))); test_domain_get(d3, x, Gauge(GaugeBound(2, i))); test_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound(20))); test_domain_get(d3, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_domain_to_interval(d3, y, ZInterval(ZBound(1), ZBound(31))); GaugeIntervalCongruenceDomain d4 = d3; d4.add(VariableExpression(i) >= 11); test_domain_get(d4, i, Gauge::bottom()); GaugeIntervalCongruenceDomain d5 = d3; d5.add(VariableExpression(i) == 10); test_domain_get(d5, i, Gauge(GaugeBound(i))); test_domain_to_interval(d5, i, ZInterval(10)); test_domain_get(d5, x, Gauge(GaugeBound(2, i))); test_domain_to_interval(d5, x, ZInterval(20)); test_domain_get(d5, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_domain_to_interval(d5, y, ZInterval(31)); GaugeIntervalCongruenceDomain d6 = d3; d6.add(VariableExpression(i) != 10); test_domain_get(d6, i, Gauge(GaugeBound(i))); test_domain_to_interval(d6, i, ZInterval(ZBound(0), ZBound(9))); test_domain_get(d6, x, Gauge(GaugeBound(2, i))); test_domain_to_interval(d6, x, ZInterval(ZBound(0), ZBound(18))); test_domain_get(d6, y, Gauge(GaugeBound(1) + GaugeBound(3, i))); test_domain_to_interval(d6, y, ZInterval(ZBound(1), ZBound(28))); } BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable i(vfac.get("i")); auto d1 = GaugeIntervalCongruenceDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 0); d1.assign(y, 1); d1.add(VariableExpression(i) <= 10); GaugeIntervalCongruenceDomain d2 = d1; d2.counter_incr(i, ZNumber(1)); d2.assign(x, VariableExpression(x) + 2); d2.assign(y, VariableExpression(y) + 3); d2.add(VariableExpression(i) <= 10); GaugeIntervalCongruenceDomain d3 = d1.widening(d2); d3.add(VariableExpression(i) <= 10); d1.forget(i); test_domain_get(d1, i, Gauge::top()); test_domain_to_interval(d1, i, ZInterval::top()); test_domain_get(d1, x, Gauge(0)); test_domain_get(d1, y, Gauge(1)); d3.forget(y); test_domain_get(d3, i, Gauge(GaugeBound(i))); test_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound(10))); test_domain_get(d3, x, Gauge(GaugeBound(2, i))); test_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound(20))); test_domain_get(d3, y, Gauge::top()); test_domain_to_interval(d3, y, ZInterval::top()); d3.forget(i); test_domain_get(d3, i, Gauge::top()); test_domain_to_interval(d3, i, ZInterval::top()); test_domain_get(d3, x, Gauge(GaugeBound(0), GaugeBound(20))); test_domain_to_interval(d3, x, ZInterval(ZBound(0), ZBound(20))); } BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_set) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto d1 = GaugeIntervalCongruenceDomain::top(); d1.assign(x, 0); d1.assign(y, 1); d1.set(x, ZInterval::top()); test_domain_get(d1, x, Gauge::top()); test_domain_get(d1, y, Gauge(1)); d1.set(x, ZInterval(ZBound(1), ZBound(2))); test_domain_get(d1, x, Gauge(GaugeBound(1), GaugeBound(2))); test_domain_get(d1, y, Gauge(1)); d1.set(x, ZInterval(ZBound(1), ZBound::plus_infinity())); test_domain_get(d1, x, Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_domain_get(d1, y, Gauge(1)); d1.set(x, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_domain_get(d1, x, Gauge(GaugeBound::minus_infinity(), GaugeBound(1))); test_domain_get(d1, y, Gauge(1)); } BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_apply_var_var_var) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); Variable zero(vfac.get("zero")); Variable one(vfac.get("one")); Variable two(vfac.get("two")); auto d1 = GaugeIntervalCongruenceDomain::top(); d1.assign(zero, 0); d1.assign(one, 1); d1.assign(two, 2); d1.counter_init(i, ZNumber(0)); d1.assign(x, 3); d1.assign(y, 2); d1.assign(z, 2); d1.assign(w, 16); test_domain_get(d1, i, Gauge(GaugeBound(i))); test_domain_to_interval(d1, i, ZInterval(0)); test_domain_get(d1, x, Gauge(3)); test_domain_to_interval(d1, x, ZInterval(3)); test_domain_get(d1, y, Gauge(2)); test_domain_to_interval(d1, y, ZInterval(2)); test_domain_get(d1, z, Gauge(2)); test_domain_to_interval(d1, z, ZInterval(2)); test_domain_get(d1, w, Gauge(16)); test_domain_to_interval(d1, w, ZInterval(16)); GaugeIntervalCongruenceDomain d2 = d1; d2.apply(BinaryOperator::Add, x, x, two); d2.apply(BinaryOperator::Sub, y, y, one); d2.apply(BinaryOperator::Mul, z, z, two); d2.apply(BinaryOperator::Div, w, w, two); d2.apply(BinaryOperator::Add, k, i, one); test_domain_get(d2, x, Gauge(5)); test_domain_to_interval(d2, x, ZInterval(5)); test_domain_get(d2, y, Gauge(1)); test_domain_to_interval(d2, y, ZInterval(1)); test_domain_get(d2, z, Gauge(4)); test_domain_to_interval(d2, z, ZInterval(4)); test_domain_get(d2, w, Gauge(8)); test_domain_to_interval(d2, w, ZInterval(8)); test_domain_get(d2, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_domain_to_interval(d2, k, ZInterval(1)); d2.counter_incr(i, ZNumber(1)); test_domain_get(d2, i, Gauge(GaugeBound(i))); test_domain_to_interval(d2, i, ZInterval(1)); test_domain_get(d2, k, Gauge(GaugeBound(i))); test_domain_to_interval(d2, k, ZInterval(1)); GaugeIntervalCongruenceDomain d3 = d1.widening(d2); test_domain_get(d3, i, Gauge(GaugeBound(i))); test_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d3, k, Gauge::top()); test_domain_to_interval(d3, k, ZInterval::top()); test_domain_get(d3, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_domain_to_interval(d3, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_domain_get(d3, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_domain_to_interval(d3, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_domain_get(d3, z, Gauge(GaugeBound(2) + GaugeBound(2, i))); test_domain_to_interval(d3, z, ZInterval(ZBound(2), ZBound::plus_infinity())); test_domain_get(d3, w, Gauge(GaugeBound(16) + GaugeBound(-8, i))); test_domain_to_interval(d3, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); GaugeIntervalCongruenceDomain d4 = d3; d4.apply(BinaryOperator::Add, x, x, two); d4.apply(BinaryOperator::Sub, y, y, one); d4.apply(BinaryOperator::Mul, z, z, two); d4.apply(BinaryOperator::Div, w, w, two); d4.apply(BinaryOperator::Add, k, i, one); test_domain_get(d4, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_domain_get(d4, x, Gauge(GaugeBound(5) + GaugeBound(2, i))); test_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_domain_get(d4, y, Gauge(GaugeBound(1) + GaugeBound(-1, i))); test_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_domain_get(d4, z, Gauge(GaugeBound(4) + GaugeBound(4, i))); test_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); d4.counter_incr(i, ZNumber(1)); test_domain_get(d4, i, Gauge(GaugeBound(i))); test_domain_to_interval(d4, i, ZInterval(ZBound(1), ZBound::plus_infinity())); test_domain_get(d4, k, Gauge(GaugeBound(i))); test_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_domain_get(d4, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_domain_get(d4, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_domain_get(d4, z, Gauge(GaugeBound(0) + GaugeBound(4, i))); test_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); GaugeIntervalCongruenceDomain d5 = d3.join(d4); test_domain_get(d5, i, Gauge(GaugeBound(i))); test_domain_to_interval(d5, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d5, k, Gauge::top()); test_domain_to_interval(d5, k, ZInterval::top()); test_domain_get(d5, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_domain_to_interval(d5, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_domain_get(d5, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_domain_to_interval(d5, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_domain_get(d5, z, Gauge(GaugeBound(2, i), GaugeBound(2) + GaugeBound(4, i))); test_domain_to_interval(d5, z, ZInterval(ZBound(2), ZBound::plus_infinity())); test_domain_get(d5, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(16))); test_domain_to_interval(d5, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); } BOOST_AUTO_TEST_CASE(gauge_interval_congruence_domain_apply_var_var_num) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); Variable i(vfac.get("i")); Variable k(vfac.get("k")); auto d1 = GaugeIntervalCongruenceDomain::top(); d1.counter_init(i, ZNumber(0)); d1.assign(x, 3); d1.assign(y, 2); d1.assign(z, 2); d1.assign(w, 16); test_domain_get(d1, i, Gauge(GaugeBound(i))); test_domain_to_interval(d1, i, ZInterval(0)); test_domain_get(d1, x, Gauge(3)); test_domain_to_interval(d1, x, ZInterval(3)); test_domain_get(d1, y, Gauge(2)); test_domain_to_interval(d1, y, ZInterval(2)); test_domain_get(d1, z, Gauge(2)); test_domain_to_interval(d1, z, ZInterval(2)); test_domain_get(d1, w, Gauge(16)); test_domain_to_interval(d1, w, ZInterval(16)); GaugeIntervalCongruenceDomain d2 = d1; d2.apply(BinaryOperator::Add, x, x, ZNumber(2)); d2.apply(BinaryOperator::Sub, y, y, ZNumber(1)); d2.apply(BinaryOperator::Mul, z, z, ZNumber(2)); d2.apply(BinaryOperator::Div, w, w, ZNumber(2)); d2.apply(BinaryOperator::Add, k, i, ZNumber(1)); test_domain_get(d2, x, Gauge(5)); test_domain_to_interval(d2, x, ZInterval(5)); test_domain_get(d2, y, Gauge(1)); test_domain_to_interval(d2, y, ZInterval(1)); test_domain_get(d2, z, Gauge(4)); test_domain_to_interval(d2, z, ZInterval(4)); test_domain_get(d2, w, Gauge(8)); test_domain_to_interval(d2, w, ZInterval(8)); test_domain_get(d2, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_domain_to_interval(d2, k, ZInterval(1)); d2.counter_incr(i, ZNumber(1)); test_domain_get(d2, i, Gauge(GaugeBound(i))); test_domain_to_interval(d2, i, ZInterval(1)); test_domain_get(d2, k, Gauge(GaugeBound(i))); test_domain_to_interval(d2, k, ZInterval(1)); GaugeIntervalCongruenceDomain d3 = d1.widening(d2); test_domain_get(d3, i, Gauge(GaugeBound(i))); test_domain_to_interval(d3, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d3, k, Gauge::top()); test_domain_to_interval(d3, k, ZInterval::top()); test_domain_get(d3, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_domain_to_interval(d3, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_domain_get(d3, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_domain_to_interval(d3, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_domain_get(d3, z, Gauge(GaugeBound(2) + GaugeBound(2, i))); test_domain_to_interval(d3, z, ZInterval(ZBound(2), ZBound::plus_infinity())); test_domain_get(d3, w, Gauge(GaugeBound(16) + GaugeBound(-8, i))); test_domain_to_interval(d3, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); GaugeIntervalCongruenceDomain d4 = d3; d4.apply(BinaryOperator::Add, x, x, ZNumber(2)); d4.apply(BinaryOperator::Sub, y, y, ZNumber(1)); d4.apply(BinaryOperator::Mul, z, z, ZNumber(2)); d4.apply(BinaryOperator::Div, w, w, ZNumber(2)); d4.apply(BinaryOperator::Add, k, i, ZNumber(1)); test_domain_get(d4, k, Gauge(GaugeBound(1) + GaugeBound(i))); test_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_domain_get(d4, x, Gauge(GaugeBound(5) + GaugeBound(2, i))); test_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_domain_get(d4, y, Gauge(GaugeBound(1) + GaugeBound(-1, i))); test_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_domain_get(d4, z, Gauge(GaugeBound(4) + GaugeBound(4, i))); test_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); d4.counter_incr(i, ZNumber(1)); test_domain_get(d4, i, Gauge(GaugeBound(i))); test_domain_to_interval(d4, i, ZInterval(ZBound(1), ZBound::plus_infinity())); test_domain_get(d4, k, Gauge(GaugeBound(i))); test_domain_to_interval(d4, k, ZInterval(ZBound(1), ZBound::plus_infinity())); test_domain_get(d4, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_domain_to_interval(d4, x, ZInterval(ZBound(5), ZBound::plus_infinity())); test_domain_get(d4, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_domain_to_interval(d4, y, ZInterval(ZBound::minus_infinity(), ZBound(1))); test_domain_get(d4, z, Gauge(GaugeBound(0) + GaugeBound(4, i))); test_domain_to_interval(d4, z, ZInterval(ZBound(4), ZBound::plus_infinity())); test_domain_get(d4, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(8))); test_domain_to_interval(d4, w, ZInterval(ZBound::minus_infinity(), ZBound(8))); GaugeIntervalCongruenceDomain d5 = d3.join(d4); test_domain_get(d5, i, Gauge(GaugeBound(i))); test_domain_to_interval(d5, i, ZInterval(ZBound(0), ZBound::plus_infinity())); test_domain_get(d5, k, Gauge::top()); test_domain_to_interval(d5, k, ZInterval::top()); test_domain_get(d5, x, Gauge(GaugeBound(3) + GaugeBound(2, i))); test_domain_to_interval(d5, x, ZInterval(ZBound(3), ZBound::plus_infinity())); test_domain_get(d5, y, Gauge(GaugeBound(2) + GaugeBound(-1, i))); test_domain_to_interval(d5, y, ZInterval(ZBound::minus_infinity(), ZBound(2))); test_domain_get(d5, z, Gauge(GaugeBound(2, i), GaugeBound(2) + GaugeBound(4, i))); test_domain_to_interval(d5, z, ZInterval(ZBound(2), ZBound::plus_infinity())); test_domain_get(d5, w, Gauge(GaugeBound::minus_infinity(), GaugeBound(16))); test_domain_to_interval(d5, w, ZInterval(ZBound::minus_infinity(), ZBound(16))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/interval.cpp000066400000000000000000000565231473507761200247600ustar00rootroot00000000000000/******************************************************************************* * * Tests for IntervalDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_interval_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using IntervalDomain = ikos::core::numeric::IntervalDomain< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(IntervalDomain::top().is_top()); BOOST_CHECK(!IntervalDomain::top().is_bottom()); BOOST_CHECK(!IntervalDomain::bottom().is_top()); BOOST_CHECK(IntervalDomain::bottom().is_bottom()); auto inv = IntervalDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(iterators) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalDomain::top(); BOOST_CHECK((inv.begin() == inv.end())); inv.set(x, Interval(1)); std::array< std::pair< Variable, Interval >, 1 > tab = {{{x, Interval(1)}}}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab), std::end(tab))); inv.set(y, Interval(Bound(1), Bound(2))); std::array< std::pair< Variable, Interval >, 2 > tab2 = {{ {y, Interval(Bound(1), Bound(2))}, {x, Interval(1)}, }}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab2), std::end(tab2))); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = IntervalDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK(IntervalDomain::bottom().leq(IntervalDomain::top())); BOOST_CHECK(IntervalDomain::bottom().leq(IntervalDomain::bottom())); BOOST_CHECK(!IntervalDomain::top().leq(IntervalDomain::bottom())); BOOST_CHECK(IntervalDomain::top().leq(IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(IntervalDomain::top())); BOOST_CHECK(!inv1.leq(IntervalDomain::bottom())); auto inv2 = IntervalDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(IntervalDomain::top())); BOOST_CHECK(!inv2.leq(IntervalDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = IntervalDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(IntervalDomain::top())); BOOST_CHECK(!inv3.leq(IntervalDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = IntervalDomain::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(IntervalDomain::top())); BOOST_CHECK(!inv4.leq(IntervalDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = IntervalDomain::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(IntervalDomain::top())); BOOST_CHECK(!inv5.leq(IntervalDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!IntervalDomain::bottom().equals(IntervalDomain::top())); BOOST_CHECK(IntervalDomain::bottom().equals(IntervalDomain::bottom())); BOOST_CHECK(!IntervalDomain::top().equals(IntervalDomain::bottom())); BOOST_CHECK(IntervalDomain::top().equals(IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(IntervalDomain::top())); BOOST_CHECK(!inv1.equals(IntervalDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = IntervalDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(IntervalDomain::top())); BOOST_CHECK(!inv2.equals(IntervalDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = IntervalDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(IntervalDomain::top())); BOOST_CHECK(!inv3.equals(IntervalDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((IntervalDomain::bottom().join(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().join(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().join(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().join(IntervalDomain::bottom()) == IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((inv1.join(IntervalDomain::bottom()) == inv1)); BOOST_CHECK((IntervalDomain::top().join(inv1) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = IntervalDomain::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((IntervalDomain::bottom().widening(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().widening(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().widening(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().widening(IntervalDomain::bottom()) == IntervalDomain::top())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((inv1.widening(IntervalDomain::bottom()) == inv1)); BOOST_CHECK((IntervalDomain::top().widening(inv1) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((IntervalDomain::bottom().meet(IntervalDomain::top()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::bottom().meet(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().meet(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().meet(IntervalDomain::bottom()) == IntervalDomain::bottom())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(IntervalDomain::top()) == inv1)); BOOST_CHECK( (inv1.meet(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().meet(inv1) == inv1)); BOOST_CHECK( (IntervalDomain::bottom().meet(inv1) == IntervalDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = IntervalDomain::top(); auto inv5 = IntervalDomain::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((IntervalDomain::bottom().narrowing(IntervalDomain::top()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::bottom().narrowing(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().narrowing(IntervalDomain::top()) == IntervalDomain::top())); BOOST_CHECK((IntervalDomain::top().narrowing(IntervalDomain::bottom()) == IntervalDomain::bottom())); auto inv1 = IntervalDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(IntervalDomain::top()) == inv1)); BOOST_CHECK( (inv1.narrowing(IntervalDomain::bottom()) == IntervalDomain::bottom())); BOOST_CHECK((IntervalDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK( (IntervalDomain::bottom().narrowing(inv1) == IntervalDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = IntervalDomain::top(); auto inv3 = IntervalDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = IntervalDomain::top(); auto inv2 = IntervalDomain::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = IntervalDomain::top(); auto inv2 = IntervalDomain::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(0))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = IntervalDomain::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) >= VariableExpr(z)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = IntervalDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = IntervalDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/interval_congruence.cpp000066400000000000000000000766731473507761200272000ustar00rootroot00000000000000/******************************************************************************* * * Tests for IntervalCongruenceDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_interval_congruence_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using IntervalCongruenceDomain = ikos::core::numeric::IntervalCongruenceDomain< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(IntervalCongruenceDomain::top().is_top()); BOOST_CHECK(!IntervalCongruenceDomain::top().is_bottom()); BOOST_CHECK(!IntervalCongruenceDomain::bottom().is_top()); BOOST_CHECK(IntervalCongruenceDomain::bottom().is_bottom()); auto inv = IntervalCongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, IntervalCongruence(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, IntervalCongruence::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(iterators) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalCongruenceDomain::top(); BOOST_CHECK((inv.begin() == inv.end())); inv.set(x, IntervalCongruence(1)); std::array< std::pair< Variable, IntervalCongruence >, 1 > tab = { {{x, IntervalCongruence(1)}}}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab), std::end(tab))); inv.set(y, IntervalCongruence(Interval(Bound(1), Bound(3)), Congruence(ZNumber(2), ZNumber(1)))); std::array< std::pair< Variable, IntervalCongruence >, 2 > tab2 = {{ {y, IntervalCongruence(Interval(Bound(1), Bound(3)), Congruence(ZNumber(2), ZNumber(1)))}, {x, IntervalCongruence(1)}, }}; BOOST_CHECK( std::equal(inv.begin(), inv.end(), std::begin(tab2), std::end(tab2))); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = IntervalCongruenceDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); BOOST_CHECK( IntervalCongruenceDomain::bottom().leq(IntervalCongruenceDomain::top())); BOOST_CHECK(IntervalCongruenceDomain::bottom().leq( IntervalCongruenceDomain::bottom())); BOOST_CHECK( !IntervalCongruenceDomain::top().leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK( IntervalCongruenceDomain::top().leq(IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(1)); BOOST_CHECK(inv1.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv1.leq(IntervalCongruenceDomain::bottom())); auto inv2 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Interval(Bound(-1), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv2.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv2.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = IntervalCongruenceDomain::top(); inv3.set(x, IntervalCongruence(1)); inv3.set(y, IntervalCongruence(Interval(Bound(-1), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv3.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv3.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = IntervalCongruenceDomain::top(); inv4.set(x, IntervalCongruence(0)); inv4.set(y, IntervalCongruence(Interval(Bound(1), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv4.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv4.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = IntervalCongruenceDomain::top(); inv5.set(x, IntervalCongruence(0)); inv5.set(y, IntervalCongruence(Interval(Bound(1), Bound(3)), Congruence(ZNumber(2), ZNumber(1)))); inv5.set(z, IntervalCongruence(Interval(Bound::minus_infinity(), Bound(0)), Congruence::top())); BOOST_CHECK(inv5.leq(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv5.leq(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!IntervalCongruenceDomain::bottom().equals( IntervalCongruenceDomain::top())); BOOST_CHECK(IntervalCongruenceDomain::bottom().equals( IntervalCongruenceDomain::bottom())); BOOST_CHECK(!IntervalCongruenceDomain::top().equals( IntervalCongruenceDomain::bottom())); BOOST_CHECK( IntervalCongruenceDomain::top().equals(IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(0)); BOOST_CHECK(!inv1.equals(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv1.equals(IntervalCongruenceDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Interval(Bound(-1), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(!inv2.equals(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv2.equals(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = IntervalCongruenceDomain::top(); inv3.set(x, IntervalCongruence(0)); inv3.set(y, IntervalCongruence(Interval(Bound(-1), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(!inv3.equals(IntervalCongruenceDomain::top())); BOOST_CHECK(!inv3.equals(IntervalCongruenceDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((IntervalCongruenceDomain::bottom().join( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().join( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK( (IntervalCongruenceDomain::top().join(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().join( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Interval(Bound(0), Bound(4)), Congruence(ZNumber(4), ZNumber(0)))); BOOST_CHECK((inv1.join(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((inv1.join(IntervalCongruenceDomain::bottom()) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::top().join(inv1) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Interval(Bound(-6), Bound(1)), Congruence(ZNumber(6), ZNumber(0)))); inv3.set(x, IntervalCongruence(Interval(Bound(-6), Bound(4)), Congruence(ZNumber(2), ZNumber(0)))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = IntervalCongruenceDomain::top(); inv4.set(x, IntervalCongruence(Interval(Bound(-6), Bound(1)), Congruence(ZNumber(6), ZNumber(0)))); inv4.set(y, IntervalCongruence(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((IntervalCongruenceDomain::bottom().widening( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().widening( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().widening( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().widening( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::top())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((inv1.widening(IntervalCongruenceDomain::bottom()) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::top().widening(inv1) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((IntervalCongruenceDomain::bottom().meet( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::bottom().meet( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK( (IntervalCongruenceDomain::top().meet(IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().meet( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Interval(Bound(0), Bound(4)), Congruence(ZNumber(4), ZNumber(0)))); BOOST_CHECK((inv1.meet(IntervalCongruenceDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().meet(inv1) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::bottom().meet(inv1) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, IntervalCongruence(Interval(Bound(-6), Bound(2)), Congruence(ZNumber(6), ZNumber(0)))); inv3.set(x, IntervalCongruence(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = IntervalCongruenceDomain::top(); auto inv5 = IntervalCongruenceDomain::top(); inv4.set(x, IntervalCongruence(Interval(Bound(0), Bound(4)), Congruence(ZNumber(4), ZNumber(0)))); inv4.set(y, IntervalCongruence(0)); inv5.set(x, IntervalCongruence(0)); inv5.set(y, IntervalCongruence(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((IntervalCongruenceDomain::bottom().narrowing( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::bottom().narrowing( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().narrowing( IntervalCongruenceDomain::top()) == IntervalCongruenceDomain::top())); BOOST_CHECK((IntervalCongruenceDomain::top().narrowing( IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); auto inv1 = IntervalCongruenceDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(IntervalCongruenceDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(IntervalCongruenceDomain::bottom()) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((IntervalCongruenceDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((IntervalCongruenceDomain::bottom().narrowing(inv1) == IntervalCongruenceDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = IntervalCongruenceDomain::top(); auto inv3 = IntervalCongruenceDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = IntervalCongruenceDomain::top(); auto inv2 = IntervalCongruenceDomain::top(); inv1.assign(x, 0); inv2.set(x, IntervalCongruence(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, IntervalCongruence(Interval(Bound(-1), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval_congruence(y) == IntervalCongruence(Interval(Bound(-1), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); inv1.set_to_top(); inv1.set(x, IntervalCongruence(Interval(Bound(-3), Bound(3)), Congruence(ZNumber(3), ZNumber(0)))); inv1.set(y, IntervalCongruence(Interval(Bound(-2), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-17), Bound(13)), Congruence(ZNumber(3), ZNumber(1)))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = IntervalCongruenceDomain::top(); auto inv2 = IntervalCongruenceDomain::top(); inv1.set(x, IntervalCongruence(Interval(Bound(-2), Bound(4)), Congruence(ZNumber(2), ZNumber(0)))); inv1.set(y, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-1), Bound(8)), Congruence::top())); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-6), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-8), Bound(16)), Congruence(ZNumber(2), ZNumber(0)))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-2), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-3), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-32), Bound(64)), Congruence(ZNumber(4), ZNumber(0)))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-1), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(2), ZNumber(1)))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-5), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-6), Bound(12)), Congruence(ZNumber(6), ZNumber(0)))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(1)), Congruence::top())); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-2), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-16), Bound(32)), Congruence(ZNumber(16), ZNumber(0)))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-1), Bound(0)), Congruence::top())); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(5), Bound(8)), Congruence(ZNumber(3), ZNumber(2)))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence(ZNumber(3), ZNumber(0)))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(4), Bound(16)), Congruence(ZNumber(12), ZNumber(4)))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(8), Bound(64)), Congruence(ZNumber(56), ZNumber(8)))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(7)), Congruence::top())); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(7)), Congruence::top())); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = IntervalCongruenceDomain::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) >= VariableExpr(z)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.apply(BinaryOperator::Mul, x, y, ZNumber(4)); BOOST_CHECK(inv.to_congruence(x) == Congruence(ZNumber(4), ZNumber(0))); inv.add(VariableExpr(x) <= 7); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(4)); inv.set_to_top(); inv.apply(BinaryOperator::Mul, x, y, ZNumber(4)); inv.add(VariableExpr(x) <= 3); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.apply(BinaryOperator::Mul, x, y, ZNumber(4)); inv.apply(BinaryOperator::Add, x, x, ZNumber(2)); inv.add(VariableExpr(x) <= 3); inv.add(VariableExpr(x) >= 2); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(2)); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = IntervalCongruenceDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(2)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Interval(Bound(1), Bound(2)), Congruence(ZNumber(3), ZNumber(1)))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = IntervalCongruenceDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); inv.set_to_top(); inv.refine(x, IntervalCongruence(1)); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Congruence(ZNumber(3), ZNumber(1)))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Interval(Bound(4), Bound(7)), Congruence(ZNumber(3), ZNumber(1)))); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalCongruenceDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalCongruenceDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalCongruenceDomain::top(); inv.set(x, Congruence(ZNumber(3), ZNumber(0))); inv.set(y, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(6), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence(ZNumber(3), ZNumber(1))); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = IntervalCongruenceDomain::top(); inv.refine(x, Interval(Bound(0), Bound(3))); inv.refine(y, Interval(Bound(4), Bound(7))); inv.refine(x, Congruence(ZNumber(3), ZNumber(0))); inv.refine(y, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(6), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-20), Bound(-5)), Congruence(ZNumber(3), ZNumber(1)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/octagon.cpp000066400000000000000000000246521473507761200245640ustar00rootroot00000000000000/******************************************************************************* * * Tests for Octagon * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_octagon_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using ZBound = ikos::core::Bound< ZNumber >; using ZInterval = ikos::core::numeric::Interval< ZNumber >; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Octagon = ikos::core::numeric::Octagon< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(test_1) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); auto inv = Octagon::top(); BOOST_CHECK(inv.is_top()); inv.assign(x, 0); inv.add(VariableExpr(w) == VariableExpr(x)); inv.apply(BinaryOperator::Add, x, x, ZNumber(1)); inv.add(VariableExpr(x) == VariableExpr(y)); inv.add(VariableExpr(x) <= VariableExpr(z)); inv.normalize(); BOOST_CHECK(inv.to_interval(x) == ZInterval(1)); BOOST_CHECK(inv.to_interval(y) == ZInterval(1)); BOOST_CHECK(inv.to_interval(z) == ZInterval(ZBound(1), ZBound::plus_infinity())); BOOST_CHECK(inv.to_interval(w) == ZInterval(0)); } BOOST_AUTO_TEST_CASE(test_2) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); auto inv = Octagon::top(); inv.add(VariableExpr(x) >= 0); inv.add(VariableExpr(y) >= VariableExpr(x)); inv.add(VariableExpr(z) == 11); inv.add(VariableExpr(z) >= VariableExpr(x) + 1); inv.add(VariableExpr(y) <= VariableExpr(z) - 1); inv.add(VariableExpr(w) == VariableExpr(y) + 1); inv.normalize(); BOOST_CHECK(inv.to_interval(x) == ZInterval(ZBound(0), ZBound(10))); BOOST_CHECK(inv.to_interval(y) == ZInterval(ZBound(0), ZBound(10))); BOOST_CHECK(inv.to_interval(z) == ZInterval(11)); BOOST_CHECK(inv.to_interval(w) == ZInterval(ZBound(1), ZBound(11))); } BOOST_AUTO_TEST_CASE(test_3) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); auto inv = Octagon::top(); inv.add(VariableExpr(x) == 0); inv.add(VariableExpr(y) == 10); inv.add(VariableExpr(z) >= VariableExpr(x)); inv.add(VariableExpr(z) <= VariableExpr(y) - 1); inv.assign(w, z); inv.normalize(); Octagon tmp1 = inv; tmp1.add(VariableExpr(z) <= -1); BOOST_CHECK(tmp1.is_bottom()); Octagon tmp2 = inv; tmp2.add(VariableExpr(w) <= -1); BOOST_CHECK(tmp2.is_bottom()); } BOOST_AUTO_TEST_CASE(test_4) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv1 = Octagon::top(); inv1.assign(x, 0); inv1.add(VariableExpr(x) <= VariableExpr(y) - 1); inv1.apply(BinaryOperator::Add, x, x, ZNumber(1)); Octagon inv2(inv1); inv2.add(VariableExpr(x) <= VariableExpr(y) - 1); inv2.apply(BinaryOperator::Add, x, x, ZNumber(1)); Octagon inv3 = inv1.join(inv2); BOOST_CHECK(inv3.to_interval(x) == ZInterval(ZBound(1), ZBound(2))); BOOST_CHECK(inv3.to_interval(y) == ZInterval(ZBound(1), ZBound::plus_infinity())); } BOOST_AUTO_TEST_CASE(test_5) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv1 = Octagon::top(); inv1.add(VariableExpr(y) >= 1); inv1.assign(x, 0); inv1.add(VariableExpr(x) <= VariableExpr(y) - 1); inv1.apply(BinaryOperator::Add, x, x, ZNumber(1)); Octagon inv2 = inv1; inv2.add(VariableExpr(x) <= VariableExpr(y) - 1); inv2.apply(BinaryOperator::Add, x, x, ZNumber(1)); Octagon inv3 = inv1.join(inv2); inv3.add(VariableExpr(x) <= VariableExpr(y) - 1); BOOST_CHECK(inv3.to_interval(x) == ZInterval(ZBound(1), ZBound(2))); BOOST_CHECK(inv3.to_interval(y) == ZInterval(ZBound(1), ZBound::plus_infinity())); } BOOST_AUTO_TEST_CASE(test_6) { VariableFactory vfac; // downsizing Variable vi(vfac.get("i")); Variable vn(vfac.get("n")); Variable tmp1(vfac.get("tmp1")); Variable tmp2(vfac.get("tmp2")); Variable tmp3(vfac.get("tmp3")); auto inv1 = Octagon::top(); inv1.add(VariableExpr(vn) >= 1); inv1.assign(vi, 0); inv1.add(VariableExpr(vi) <= VariableExpr(vn) - 1); inv1.apply(BinaryOperator::Add, vi, vi, ZNumber(1)); inv1.apply(BinaryOperator::Add, tmp1, vi, ZNumber(2)); inv1.apply(BinaryOperator::Add, tmp2, tmp1, ZNumber(2)); inv1.apply(BinaryOperator::Add, tmp3, tmp2, ZNumber(4)); inv1.forget(vi); BOOST_CHECK(inv1.to_interval(vi).is_top()); inv1.forget(vn); BOOST_CHECK(inv1.to_interval(vn).is_top()); inv1.forget(tmp3); BOOST_CHECK(inv1.to_interval(tmp3).is_top()); inv1.forget(tmp1); BOOST_CHECK(inv1.to_interval(tmp1).is_top()); } BOOST_AUTO_TEST_CASE(test_7) { VariableFactory vfac; Variable vj(vfac.get("j")); Variable vj1(vfac.get("j1")); auto inv = Octagon::top(); inv.add(VariableExpr(vj) >= 0); inv.add(VariableExpr(vj) <= 10); inv.add(VariableExpr(vj1) >= 1); inv.add(VariableExpr(vj1) <= 11); inv.add(VariableExpr(vj1) == VariableExpr(vj) + 1); inv.add(VariableExpr(vj) <= 9); BOOST_CHECK(inv.to_interval(vj) == ZInterval(ZBound(0), ZBound(9))); BOOST_CHECK(inv.to_interval(vj1) == ZInterval(ZBound(1), ZBound(11))); } BOOST_AUTO_TEST_CASE(test_8) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto s1 = Octagon::top(); s1.assign(x, 0); s1.assign(y, 0); // std::cout << "Loc 1: " << s1 << std::endl; Octagon s2 = s1; s2.apply(BinaryOperator::Add, x, x, ZNumber(1)); // std::cout << "Loc 2a (after x++): " << s2 << std::endl; // s2.apply(BinaryOperator::Add, y, y, ZNumber(1)); // std::cout << "Loc 2b (after y++): " << s2 << std::endl; Octagon s3 = s1.join(s2); // std::cout << "Loc 3, after join: " << s3 << std::endl; Octagon s4 = s3; s4.apply(BinaryOperator::Add, x, x, ZNumber(1)); // std::cout << "Loc 4a (after x++): " << s4 << std::endl; s4.apply(BinaryOperator::Add, y, y, ZNumber(1)); // std::cout << "Loc 4b (after y++): " << s4 << std::endl; Octagon s5 = s4.widening(s3); // std::cout << "Loc 5, after widening : " << s5 << std::endl; // TODO(marthaud): Add checks } BOOST_AUTO_TEST_CASE(test_9) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable n(vfac.get("n")); Variable tmp_x(vfac.get("tmp_x")); Variable tmp_y(vfac.get("tmp_y")); auto s1 = Octagon::top(); s1.assign(x, 0); s1.assign(y, 0); // std::cout << "Loc 1: " << s1 << std::endl; Octagon s2 = s1; s2.add(VariableExpr(x) <= VariableExpr(n)); // std::cout << "Loc 2: " << s2 << std::endl; Octagon s3 = s2; s3.apply(BinaryOperator::Add, tmp_x, x, ZNumber(1)); s3.apply(BinaryOperator::Add, tmp_y, y, ZNumber(1)); s3.assign(x, tmp_x); s3.assign(y, tmp_y); // std::cout << "Loc 3 tmp_x:=x+1, tmp_y:=y+1, x:=tmp_x, y:=tmp_y= " << s3 // << std::endl; Octagon s4 = s1.join(s3); // std::cout << "Loc 4: Loc 1 U Loc 3=" << s4 << std::endl; Octagon s5 = s4; s5.add(VariableExpr(x) <= VariableExpr(n)); // std::cout << "Loc 2': x<=n " << s5 << std::endl; Octagon s6 = s5; s6.apply(BinaryOperator::Add, tmp_x, x, ZNumber(1)); s6.apply(BinaryOperator::Add, tmp_y, y, ZNumber(1)); s6.assign(x, tmp_x); s6.assign(y, tmp_y); // std::cout << "Loc 3': tmp_x:=x+1, tmp_y:=y+1, x:=tmp_x, y:=tmp_y= " << s6 // << std::endl; Octagon s7 = s1.join(s6); // std::cout << "Loc 4': Loc 1 U Loc 3'=" << s7 << std::endl; Octagon s8 = s4.widening(s7); // std::cout << "Loc 4': Widening(Loc 4, Loc 4')=" << s8 << std::endl; Octagon s9 = s8; s9.add(VariableExpr(x) <= VariableExpr(n)); // std::cout << "Loc 2'': x<=n " << s9 << std::endl; Octagon s10 = s9; s10.apply(BinaryOperator::Add, tmp_x, x, ZNumber(1)); s10.apply(BinaryOperator::Add, tmp_y, y, ZNumber(1)); s10.assign(x, tmp_x); s10.assign(y, tmp_y); // std::cout << "Loc 3'': tmp_x:=x+1, tmp_y:=y+1, x:=tmp_x, y:=tmp_y= " << s10 // << std::endl; Octagon s11 = s1.join(s10); // std::cout << "Loc 4'': Loc 1 U Loc 3''=" << s11 << std::endl; Octagon s12 = s8.widening(s11); // std::cout << "Loc 4'': Widening(Loc 4', Loc 4'')=" << s12 << std::endl; // TODO(marthaud): Add checks } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/union.cpp000066400000000000000000000561761473507761200242700ustar00rootroot00000000000000/******************************************************************************* * * Tests for UnionDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_interval_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using IntervalDomain = ikos::core::numeric::IntervalDomain< ZNumber, Variable >; using UnionDomain = ikos::core::numeric::UnionDomain< ZNumber, Variable, IntervalDomain, 2 >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(UnionDomain::top().is_top()); BOOST_CHECK(!UnionDomain::top().is_bottom()); BOOST_CHECK(!UnionDomain::bottom().is_top()); BOOST_CHECK(UnionDomain::bottom().is_bottom()); auto inv = UnionDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.assign(x, 1); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = UnionDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK(UnionDomain::bottom().leq(UnionDomain::top())); BOOST_CHECK(UnionDomain::bottom().leq(UnionDomain::bottom())); BOOST_CHECK(!UnionDomain::top().leq(UnionDomain::bottom())); BOOST_CHECK(UnionDomain::top().leq(UnionDomain::top())); auto inv_a = UnionDomain::top(); auto inv_b = UnionDomain::top(); inv_a.assign(x, 1); BOOST_CHECK(inv_a.leq(inv_b)); inv_b.add(VariableExpr(x) <= 1); BOOST_CHECK(inv_a.leq(inv_b)); inv_b.set_to_top(); inv_b.add(VariableExpr(x) <= 0); BOOST_CHECK(!inv_a.leq(inv_b)); inv_a.assign(y, 2); inv_b.set_to_top(); inv_b.add(VariableExpr(x) <= 1); BOOST_CHECK(inv_a.leq(inv_b)); inv_b.add(VariableExpr(z) <= 4); BOOST_CHECK(!inv_a.leq(inv_b)); inv_a.set_to_top(); inv_b.set_to_top(); inv_a.assign(x, 1); inv_a.add(VariableExpr(y) <= 2); inv_a.assign(z, 3); inv_a.add(VariableExpr(a) >= 4); inv_a.assign(b, 5); inv_b.add(VariableExpr(y) <= 3); inv_b.add(VariableExpr(a) >= 1); inv_b.assign(z, 3); inv_b.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv_a.leq(inv_b)); inv_b.add(VariableExpr(a) >= 5); BOOST_CHECK(!inv_a.leq(inv_b)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!UnionDomain::bottom().equals(UnionDomain::top())); BOOST_CHECK(UnionDomain::bottom().equals(UnionDomain::bottom())); BOOST_CHECK(!UnionDomain::top().equals(UnionDomain::bottom())); BOOST_CHECK(UnionDomain::top().equals(UnionDomain::top())); auto inv1 = UnionDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(UnionDomain::top())); BOOST_CHECK(!inv1.equals(UnionDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = UnionDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(UnionDomain::top())); BOOST_CHECK(!inv2.equals(UnionDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = UnionDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(UnionDomain::top())); BOOST_CHECK(!inv3.equals(UnionDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK( (UnionDomain::bottom().join(UnionDomain::top()) == UnionDomain::top())); BOOST_CHECK((UnionDomain::bottom().join(UnionDomain::bottom()) == UnionDomain::bottom())); BOOST_CHECK( (UnionDomain::top().join(UnionDomain::top()) == UnionDomain::top())); BOOST_CHECK( (UnionDomain::top().join(UnionDomain::bottom()) == UnionDomain::top())); auto inv_a = UnionDomain::top(); auto inv_b = UnionDomain::top(); auto inv_c = UnionDomain::top(); inv_a.set_to_top(); inv_a.assign(x, 0); inv_b.set_to_top(); inv_b.assign(x, 2); inv_c = inv_a.join(inv_b); // {x = 0} U {x = 2} { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 1); BOOST_CHECK(inv.is_bottom()); } inv_a.set_to_top(); inv_a.assign(x, 4); inv_c = inv_c.join(inv_a); // ({x = 0} U {x = 2}) U {x = 4} { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 1); BOOST_CHECK(inv.is_bottom()); } { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 3); BOOST_CHECK(inv.is_bottom()); } inv_a.set_to_top(); inv_a.assign(x, 6); inv_b.set_to_top(); inv_b.assign(x, 8); inv_a = inv_a.join(inv_b); inv_b.set_to_top(); inv_b.assign(x, 10); inv_a = inv_b.join(inv_a); inv_c = inv_c.join(inv_a); // "(({x = 0} U {x = 2}) U {x = 4}) U ({x = 10} U ({x = 6} U {x = 8}))" BOOST_CHECK(inv_c.to_interval(x) == Interval(Bound(0), Bound(10))); { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 1); BOOST_CHECK(!inv.is_bottom()); } { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 3); BOOST_CHECK(inv.is_bottom()); } { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 5); BOOST_CHECK(inv.is_bottom()); } { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 7); BOOST_CHECK(!inv.is_bottom()); } inv_c.add(VariableExpr(x) >= 5); BOOST_CHECK(inv_c.to_interval(x) == Interval(Bound(6), Bound(10))); { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 7); BOOST_CHECK(!inv.is_bottom()); } { UnionDomain inv = inv_c; inv.add(VariableExpr(x) == 9); BOOST_CHECK(inv.is_bottom()); } inv_c.add(VariableExpr(x) <= 7); BOOST_CHECK(inv_c.to_interval(x) == Interval(Bound(6), Bound(7))); inv_c.add(VariableExpr(x) >= 8); BOOST_CHECK(inv_c.is_bottom()); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((UnionDomain::bottom().widening(UnionDomain::top()) == UnionDomain::top())); BOOST_CHECK((UnionDomain::bottom().widening(UnionDomain::bottom()) == UnionDomain::bottom())); BOOST_CHECK( (UnionDomain::top().widening(UnionDomain::top()) == UnionDomain::top())); BOOST_CHECK((UnionDomain::top().widening(UnionDomain::bottom()) == UnionDomain::top())); auto inv1 = UnionDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(UnionDomain::top()) == UnionDomain::top())); BOOST_CHECK((inv1.widening(UnionDomain::bottom()) == inv1)); BOOST_CHECK((UnionDomain::top().widening(inv1) == UnionDomain::top())); BOOST_CHECK((UnionDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = UnionDomain::top(); auto inv3 = UnionDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK((UnionDomain::bottom().meet(UnionDomain::top()) == UnionDomain::bottom())); BOOST_CHECK((UnionDomain::bottom().meet(UnionDomain::bottom()) == UnionDomain::bottom())); BOOST_CHECK( (UnionDomain::top().meet(UnionDomain::top()) == UnionDomain::top())); BOOST_CHECK((UnionDomain::top().meet(UnionDomain::bottom()) == UnionDomain::bottom())); auto inv_a = UnionDomain::top(); auto inv_b = UnionDomain::top(); inv_a.assign(x, 0); inv_b.assign(x, 10); inv_a.join_with(inv_b); inv_b.set_to_top(); inv_b.add(VariableExpr(x) <= 5); UnionDomain inv = inv_a.meet(inv_b); BOOST_CHECK(inv.to_interval(x) == Interval(0)); auto inv1 = UnionDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(UnionDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(UnionDomain::bottom()) == UnionDomain::bottom())); BOOST_CHECK((UnionDomain::top().meet(inv1) == inv1)); BOOST_CHECK((UnionDomain::bottom().meet(inv1) == UnionDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = UnionDomain::top(); auto inv3 = UnionDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = UnionDomain::top(); auto inv5 = UnionDomain::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((UnionDomain::bottom().narrowing(UnionDomain::top()) == UnionDomain::bottom())); BOOST_CHECK((UnionDomain::bottom().narrowing(UnionDomain::bottom()) == UnionDomain::bottom())); BOOST_CHECK( (UnionDomain::top().narrowing(UnionDomain::top()) == UnionDomain::top())); BOOST_CHECK((UnionDomain::top().narrowing(UnionDomain::bottom()) == UnionDomain::bottom())); auto inv1 = UnionDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(UnionDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(UnionDomain::bottom()) == UnionDomain::bottom())); BOOST_CHECK((UnionDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((UnionDomain::bottom().narrowing(inv1) == UnionDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = UnionDomain::top(); auto inv3 = UnionDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = UnionDomain::top(); auto inv2 = UnionDomain::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = UnionDomain::top(); auto inv2 = UnionDomain::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(0))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = UnionDomain::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) >= VariableExpr(z)); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); auto inv_a = UnionDomain::top(); auto inv_b = UnionDomain::top(); inv_a.assign(x, 0); inv_b.assign(x, 2); UnionDomain inv = inv_a.join(inv_b); inv.set(y, Interval(Bound(0), Bound(4))); inv.set(z, Interval(Bound::minus_infinity(), Bound(42))); inv.set(w, Interval(Bound(42), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(0), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(0), Bound(4))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound::minus_infinity(), Bound(42))); BOOST_CHECK(inv.to_interval(w) == Interval(Bound(42), Bound::plus_infinity())); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = UnionDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = UnionDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = UnionDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = UnionDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = UnionDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/var_packing_dbm.cpp000066400000000000000000000774071473507761200262460ustar00rootroot00000000000000/******************************************************************************* * * Tests for VarPackingDBM * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_var_packing_dbm #define BOOST_TEST_DYN_LINK #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using VarPackingDBM = ikos::core::numeric::VarPackingDBM< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(VarPackingDBM::top().is_top()); BOOST_CHECK(!VarPackingDBM::top().is_bottom()); BOOST_CHECK(!VarPackingDBM::bottom().is_top()); BOOST_CHECK(VarPackingDBM::bottom().is_bottom()); auto inv = VarPackingDBM::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(VariableExpr(x) - VariableExpr(y) <= 1); inv.forget(x); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = VarPackingDBM::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK(VarPackingDBM::bottom().leq(VarPackingDBM::top())); BOOST_CHECK(VarPackingDBM::bottom().leq(VarPackingDBM::bottom())); BOOST_CHECK(!VarPackingDBM::top().leq(VarPackingDBM::bottom())); BOOST_CHECK(VarPackingDBM::top().leq(VarPackingDBM::top())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(VarPackingDBM::top())); BOOST_CHECK(!inv1.leq(VarPackingDBM::bottom())); auto inv2 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(VarPackingDBM::top())); BOOST_CHECK(!inv2.leq(VarPackingDBM::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = VarPackingDBM::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(VarPackingDBM::top())); BOOST_CHECK(!inv3.leq(VarPackingDBM::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = VarPackingDBM::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(VarPackingDBM::top())); BOOST_CHECK(!inv4.leq(VarPackingDBM::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = VarPackingDBM::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(VarPackingDBM::top())); BOOST_CHECK(!inv5.leq(VarPackingDBM::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1} <= {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1} <= {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1, y = 2} <= {x <= 1} inv2.add(VariableExpr(z) <= 4); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1, y = 2} <= {x <= 1, z <= 4} inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK(!inv1.leq(inv2)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!VarPackingDBM::bottom().equals(VarPackingDBM::top())); BOOST_CHECK(VarPackingDBM::bottom().equals(VarPackingDBM::bottom())); BOOST_CHECK(!VarPackingDBM::top().equals(VarPackingDBM::bottom())); BOOST_CHECK(VarPackingDBM::top().equals(VarPackingDBM::top())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(VarPackingDBM::top())); BOOST_CHECK(!inv1.equals(VarPackingDBM::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(VarPackingDBM::top())); BOOST_CHECK(!inv2.equals(VarPackingDBM::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = VarPackingDBM::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(VarPackingDBM::top())); BOOST_CHECK(!inv3.equals(VarPackingDBM::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((VarPackingDBM::bottom().join(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::bottom().join(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().join(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::top().join(VarPackingDBM::bottom()) == VarPackingDBM::top())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((inv1.join(VarPackingDBM::bottom()) == inv1)); BOOST_CHECK((VarPackingDBM::top().join(inv1) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = VarPackingDBM::top(); auto inv3 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = VarPackingDBM::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1} U {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1} U {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1, y = 2} U {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1, y = 2} U {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.set(x, Interval(Bound(-1), Bound(1))); inv3.add(VariableExpr(y) <= 3); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 1); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.join(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.join(inv2).to_interval(a) == Interval(Bound(4), Bound::plus_infinity()))); inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 10); inv1.add((VariableExpr(z) - VariableExpr(y)) <= 10); inv2.set_to_top(); inv2.assign(y, 0); inv2.assign(z, 0); inv3.set_to_top(); inv3.add(VariableExpr(y) <= 10); inv3.add((VariableExpr(z) - VariableExpr(y)) <= 10); // {x = 1, y <= 10, z - y <= 10} U {y = 0, z = 0} BOOST_CHECK((inv1.join(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((VarPackingDBM::bottom().widening(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::bottom().widening(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().widening(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::top().widening(VarPackingDBM::bottom()) == VarPackingDBM::top())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((inv1.widening(VarPackingDBM::bottom()) == inv1)); BOOST_CHECK((VarPackingDBM::top().widening(inv1) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = VarPackingDBM::top(); auto inv3 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(widening_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((VarPackingDBM::bottom().widening_threshold(VarPackingDBM::top(), ZNumber(10)) == VarPackingDBM::top())); BOOST_CHECK( (VarPackingDBM::bottom().widening_threshold(VarPackingDBM::bottom(), ZNumber(10)) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().widening_threshold(VarPackingDBM::top(), ZNumber(10)) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::top().widening_threshold(VarPackingDBM::bottom(), ZNumber(10)) == VarPackingDBM::top())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening_threshold(VarPackingDBM::top(), ZNumber(10)) == VarPackingDBM::top())); BOOST_CHECK( (inv1.widening_threshold(VarPackingDBM::bottom(), ZNumber(10)) == inv1)); BOOST_CHECK((VarPackingDBM::top().widening_threshold(inv1, ZNumber(10)) == VarPackingDBM::top())); BOOST_CHECK( (VarPackingDBM::bottom().widening_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK((inv1.widening_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = VarPackingDBM::top(); auto inv3 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.widening_threshold(inv2, ZNumber(10)) == inv3)); BOOST_CHECK((inv2.widening_threshold(inv1, ZNumber(10)) == inv2)); auto inv4 = VarPackingDBM::top(); auto inv5 = VarPackingDBM::top(); auto inv6 = VarPackingDBM::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv5.set(x, Interval(Bound(-2), Bound(0))); inv6.set(x, Interval(Bound(-10), Bound(0))); BOOST_CHECK((inv4.widening_threshold(inv5, ZNumber(10)) == inv6)); BOOST_CHECK((inv5.widening_threshold(inv4, ZNumber(10)) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((VarPackingDBM::bottom().narrowing_threshold(VarPackingDBM::top(), ZNumber(10)) == VarPackingDBM::bottom())); BOOST_CHECK( (VarPackingDBM::bottom().narrowing_threshold(VarPackingDBM::bottom(), ZNumber(10)) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().narrowing_threshold(VarPackingDBM::top(), ZNumber(10)) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::top().narrowing_threshold(VarPackingDBM::bottom(), ZNumber(10)) == VarPackingDBM::bottom())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK( (inv1.narrowing_threshold(VarPackingDBM::top(), ZNumber(10)) == inv1)); BOOST_CHECK((inv1.narrowing_threshold(VarPackingDBM::bottom(), ZNumber(10)) == VarPackingDBM::bottom())); BOOST_CHECK( (VarPackingDBM::top().narrowing_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK((VarPackingDBM::bottom().narrowing_threshold(inv1, ZNumber(10)) == VarPackingDBM::bottom())); BOOST_CHECK((inv1.narrowing_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = VarPackingDBM::top(); auto inv3 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(0), Bound(1))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv1.narrowing_threshold(inv3, ZNumber(10)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(20)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(5)) == inv3)); auto inv4 = VarPackingDBM::top(); auto inv5 = VarPackingDBM::top(); inv4.set(x, Interval(Bound(-10), Bound(0))); inv5.set(x, Interval(Bound(-1), Bound(0))); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(10)) == inv5)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(20)) == inv4)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(5)) == inv4)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((VarPackingDBM::bottom().meet(VarPackingDBM::top()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::bottom().meet(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().meet(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::top().meet(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(VarPackingDBM::top()) == inv1)); BOOST_CHECK((inv1.meet(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().meet(inv1) == inv1)); BOOST_CHECK((VarPackingDBM::bottom().meet(inv1) == VarPackingDBM::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = VarPackingDBM::top(); auto inv3 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = VarPackingDBM::top(); auto inv5 = VarPackingDBM::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & top() inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK( (inv1.meet(inv2) == VarPackingDBM::bottom())); // {x = 1} & {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1, y = 2} & {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.assign(x, 1); inv3.assign(y, 2); inv3.add(VariableExpr(z) <= 4); BOOST_CHECK((inv1.meet(inv2) == inv3)); // {x = 1, y = 2} & {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.assign(x, 1); inv3.add(VariableExpr(y) <= 2); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 4); inv3.assign(b, 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.meet(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); inv3.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.meet(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((VarPackingDBM::bottom().narrowing(VarPackingDBM::top()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::bottom().narrowing(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().narrowing(VarPackingDBM::top()) == VarPackingDBM::top())); BOOST_CHECK((VarPackingDBM::top().narrowing(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); auto inv1 = VarPackingDBM::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(VarPackingDBM::top()) == inv1)); BOOST_CHECK( (inv1.narrowing(VarPackingDBM::bottom()) == VarPackingDBM::bottom())); BOOST_CHECK((VarPackingDBM::top().narrowing(inv1) == inv1)); BOOST_CHECK( (VarPackingDBM::bottom().narrowing(inv1) == VarPackingDBM::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = VarPackingDBM::top(); auto inv3 = VarPackingDBM::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = VarPackingDBM::top(); auto inv2 = VarPackingDBM::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); inv1.set_to_top(); inv1.assign(x, 7); inv1.add(VariableExpr(y) <= 3); inv1.add(VariableExpr(y) >= 1); inv1.assign(z, VariableExpr(x) + 2 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(10), Bound(14))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = VarPackingDBM::top(); auto inv2 = VarPackingDBM::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(0))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = VarPackingDBM::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.assign(x, 1); inv.add(VariableExpr(x) + VariableExpr(y) >= 0); inv.add(VariableExpr(x) - VariableExpr(y) >= 3); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = VarPackingDBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = VarPackingDBM::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, IntervalCongruence(Interval(Bound(7), Bound(10)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(7)); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); inv.set_to_top(); inv.add(VariableExpr(x) - VariableExpr(y) <= 1); inv.forget(x); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBM::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/var_packing_dbm_congruence.cpp000066400000000000000000001136511473507761200304460ustar00rootroot00000000000000/******************************************************************************* * * Tests for VarPackingDBMCongruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_var_packing_dbm_congruence #define BOOST_TEST_DYN_LINK #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using VarPackingDBMCongruence = ikos::core::numeric::VarPackingDBMCongruence< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(VarPackingDBMCongruence::top().is_top()); BOOST_CHECK(!VarPackingDBMCongruence::top().is_bottom()); BOOST_CHECK(!VarPackingDBMCongruence::bottom().is_top()); BOOST_CHECK(VarPackingDBMCongruence::bottom().is_bottom()); auto inv = VarPackingDBMCongruence::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(VariableExpr(x) - VariableExpr(y) <= 1); inv.forget(x); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = VarPackingDBMCongruence::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK( VarPackingDBMCongruence::bottom().leq(VarPackingDBMCongruence::top())); BOOST_CHECK( VarPackingDBMCongruence::bottom().leq(VarPackingDBMCongruence::bottom())); BOOST_CHECK( !VarPackingDBMCongruence::top().leq(VarPackingDBMCongruence::bottom())); BOOST_CHECK( VarPackingDBMCongruence::top().leq(VarPackingDBMCongruence::top())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv1.leq(VarPackingDBMCongruence::bottom())); auto inv2 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv2.leq(VarPackingDBMCongruence::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = VarPackingDBMCongruence::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv3.leq(VarPackingDBMCongruence::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = VarPackingDBMCongruence::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv4.leq(VarPackingDBMCongruence::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = VarPackingDBMCongruence::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv5.leq(VarPackingDBMCongruence::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1} <= {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1} <= {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1, y = 2} <= {x <= 1} inv2.add(VariableExpr(z) <= 4); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1, y = 2} <= {x <= 1, z <= 4} inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK(!inv1.leq(inv2)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!VarPackingDBMCongruence::bottom().equals( VarPackingDBMCongruence::top())); BOOST_CHECK(VarPackingDBMCongruence::bottom().equals( VarPackingDBMCongruence::bottom())); BOOST_CHECK(!VarPackingDBMCongruence::top().equals( VarPackingDBMCongruence::bottom())); BOOST_CHECK( VarPackingDBMCongruence::top().equals(VarPackingDBMCongruence::top())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv1.equals(VarPackingDBMCongruence::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv2.equals(VarPackingDBMCongruence::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = VarPackingDBMCongruence::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(VarPackingDBMCongruence::top())); BOOST_CHECK(!inv3.equals(VarPackingDBMCongruence::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK( (VarPackingDBMCongruence::bottom().join(VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK((VarPackingDBMCongruence::bottom().join( VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK( (VarPackingDBMCongruence::top().join(VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK( (VarPackingDBMCongruence::top().join(VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::top())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK((inv1.join(VarPackingDBMCongruence::bottom()) == inv1)); BOOST_CHECK((VarPackingDBMCongruence::top().join(inv1) == VarPackingDBMCongruence::top())); BOOST_CHECK((VarPackingDBMCongruence::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = VarPackingDBMCongruence::top(); auto inv3 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = VarPackingDBMCongruence::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1} U {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1} U {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1, y = 2} U {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1, y = 2} U {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.set(x, Interval(Bound(-1), Bound(1))); inv3.add(VariableExpr(y) <= 3); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 1); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.join(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.join(inv2).to_interval(a) == Interval(Bound(4), Bound::plus_infinity()))); inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 10); inv1.add((VariableExpr(z) - VariableExpr(y)) <= 10); inv2.set_to_top(); inv2.assign(y, 0); inv2.assign(z, 0); inv3.set_to_top(); inv3.add(VariableExpr(y) <= 10); inv3.add((VariableExpr(z) - VariableExpr(y)) <= 10); // {x = 1, y <= 10, z - y <= 10} U {y = 0, z = 0} BOOST_CHECK((inv1.join(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK( (VarPackingDBMCongruence::bottom().widening( VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK((VarPackingDBMCongruence::bottom().widening( VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK(( VarPackingDBMCongruence::top().widening(VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK((VarPackingDBMCongruence::top().widening( VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::top())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening(VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK((inv1.widening(VarPackingDBMCongruence::bottom()) == inv1)); BOOST_CHECK((VarPackingDBMCongruence::top().widening(inv1) == VarPackingDBMCongruence::top())); BOOST_CHECK((VarPackingDBMCongruence::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = VarPackingDBMCongruence::top(); auto inv3 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(widening_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK( (VarPackingDBMCongruence::bottom() .widening_threshold(VarPackingDBMCongruence::top(), ZNumber(10)) == VarPackingDBMCongruence::top())); BOOST_CHECK(( VarPackingDBMCongruence::bottom() .widening_threshold(VarPackingDBMCongruence::bottom(), ZNumber(10)) == VarPackingDBMCongruence::bottom())); BOOST_CHECK( (VarPackingDBMCongruence::top() .widening_threshold(VarPackingDBMCongruence::top(), ZNumber(10)) == VarPackingDBMCongruence::top())); BOOST_CHECK( (VarPackingDBMCongruence::top() .widening_threshold(VarPackingDBMCongruence::bottom(), ZNumber(10)) == VarPackingDBMCongruence::top())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK( (inv1.widening_threshold(VarPackingDBMCongruence::top(), ZNumber(10)) == VarPackingDBMCongruence::top())); BOOST_CHECK((inv1.widening_threshold(VarPackingDBMCongruence::bottom(), ZNumber(10)) == inv1)); BOOST_CHECK( (VarPackingDBMCongruence::top().widening_threshold(inv1, ZNumber(10)) == VarPackingDBMCongruence::top())); BOOST_CHECK(( VarPackingDBMCongruence::bottom().widening_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK((inv1.widening_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = VarPackingDBMCongruence::top(); auto inv3 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.widening_threshold(inv2, ZNumber(10)) == inv3)); BOOST_CHECK((inv2.widening_threshold(inv1, ZNumber(10)) == inv2)); auto inv4 = VarPackingDBMCongruence::top(); auto inv5 = VarPackingDBMCongruence::top(); auto inv6 = VarPackingDBMCongruence::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv5.set(x, Interval(Bound(-2), Bound(0))); inv6.set(x, Interval(Bound(-10), Bound(0))); BOOST_CHECK((inv4.widening_threshold(inv5, ZNumber(10)) == inv6)); BOOST_CHECK((inv5.widening_threshold(inv4, ZNumber(10)) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK( (VarPackingDBMCongruence::bottom() .narrowing_threshold(VarPackingDBMCongruence::top(), ZNumber(10)) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((VarPackingDBMCongruence::bottom() .narrowing_threshold(VarPackingDBMCongruence::bottom(), ZNumber(10)) == VarPackingDBMCongruence::bottom())); BOOST_CHECK( (VarPackingDBMCongruence::top() .narrowing_threshold(VarPackingDBMCongruence::top(), ZNumber(10)) == VarPackingDBMCongruence::top())); BOOST_CHECK((VarPackingDBMCongruence::top() .narrowing_threshold(VarPackingDBMCongruence::bottom(), ZNumber(10)) == VarPackingDBMCongruence::bottom())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing_threshold(VarPackingDBMCongruence::top(), ZNumber(10)) == inv1)); BOOST_CHECK((inv1.narrowing_threshold(VarPackingDBMCongruence::bottom(), ZNumber(10)) == VarPackingDBMCongruence::bottom())); BOOST_CHECK( (VarPackingDBMCongruence::top().narrowing_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK( (VarPackingDBMCongruence::bottom().narrowing_threshold(inv1, ZNumber(10)) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((inv1.narrowing_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = VarPackingDBMCongruence::top(); auto inv3 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(0), Bound(1))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv1.narrowing_threshold(inv3, ZNumber(10)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(20)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(5)) == inv3)); auto inv4 = VarPackingDBMCongruence::top(); auto inv5 = VarPackingDBMCongruence::top(); inv4.set(x, Interval(Bound(-10), Bound(0))); inv5.set(x, Interval(Bound(-1), Bound(0))); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(10)) == inv5)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(20)) == inv4)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(5)) == inv4)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK( (VarPackingDBMCongruence::bottom().meet(VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((VarPackingDBMCongruence::bottom().meet( VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK( (VarPackingDBMCongruence::top().meet(VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK( (VarPackingDBMCongruence::top().meet(VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(VarPackingDBMCongruence::top()) == inv1)); BOOST_CHECK((inv1.meet(VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((VarPackingDBMCongruence::top().meet(inv1) == inv1)); BOOST_CHECK((VarPackingDBMCongruence::bottom().meet(inv1) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = VarPackingDBMCongruence::top(); auto inv3 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = VarPackingDBMCongruence::top(); auto inv5 = VarPackingDBMCongruence::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & top() inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK((inv1.meet(inv2) == VarPackingDBMCongruence::bottom())); // {x = 1} & {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1, y = 2} & {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.assign(x, 1); inv3.assign(y, 2); inv3.add(VariableExpr(z) <= 4); BOOST_CHECK((inv1.meet(inv2) == inv3)); // {x = 1, y = 2} & {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.assign(x, 1); inv3.add(VariableExpr(y) <= 2); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 4); inv3.assign(b, 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.meet(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); inv3.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.meet(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((VarPackingDBMCongruence::bottom().narrowing( VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((VarPackingDBMCongruence::bottom().narrowing( VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK( (VarPackingDBMCongruence::top().narrowing( VarPackingDBMCongruence::top()) == VarPackingDBMCongruence::top())); BOOST_CHECK((VarPackingDBMCongruence::top().narrowing( VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); auto inv1 = VarPackingDBMCongruence::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(VarPackingDBMCongruence::top()) == inv1)); BOOST_CHECK((inv1.narrowing(VarPackingDBMCongruence::bottom()) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((VarPackingDBMCongruence::top().narrowing(inv1) == inv1)); BOOST_CHECK((VarPackingDBMCongruence::bottom().narrowing(inv1) == VarPackingDBMCongruence::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = VarPackingDBMCongruence::top(); auto inv3 = VarPackingDBMCongruence::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = VarPackingDBMCongruence::top(); auto inv2 = VarPackingDBMCongruence::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); inv1.set_to_top(); inv1.assign(x, 7); inv1.add(VariableExpr(y) <= 3); inv1.add(VariableExpr(y) >= 1); inv1.assign(z, VariableExpr(x) + 2 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(10), Bound(14))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = VarPackingDBMCongruence::top(); auto inv2 = VarPackingDBMCongruence::top(); inv1.set(x, IntervalCongruence(Interval(Bound(-2), Bound(4)), Congruence(ZNumber(2), ZNumber(0)))); inv1.set(y, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-1), Bound(8)), Congruence::top())); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-6), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-8), Bound(16)), Congruence(ZNumber(2), ZNumber(0)))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-2), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-3), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-32), Bound(64)), Congruence(ZNumber(4), ZNumber(0)))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-1), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(2), ZNumber(1)))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-5), Bound(1)), Congruence(ZNumber(2), ZNumber(1)))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-6), Bound(12)), Congruence(ZNumber(6), ZNumber(0)))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(1)), Congruence::top())); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-2), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-16), Bound(32)), Congruence(ZNumber(16), ZNumber(0)))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(-1), Bound(0)), Congruence::top())); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(5), Bound(8)), Congruence(ZNumber(3), ZNumber(2)))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence(ZNumber(3), ZNumber(0)))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(4), Bound(16)), Congruence(ZNumber(12), ZNumber(4)))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(3)), Congruence::top())); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(8), Bound(64)), Congruence(ZNumber(56), ZNumber(8)))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(2)), Congruence::top())); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(4)), Congruence::top())); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(7)), Congruence::top())); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK( inv1.to_interval_congruence(z) == IntervalCongruence(Interval(Bound(0), Bound(7)), Congruence::top())); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable w(vfac.get("w")); auto inv = VarPackingDBMCongruence::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.assign(x, 1); inv.add(VariableExpr(x) + VariableExpr(y) >= 0); inv.add(VariableExpr(x) - VariableExpr(y) >= 3); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.assign(y, VariableExpr(x) + 1); inv.assign(z, VariableExpr(y) + 1); inv.add(VariableExpr(x) <= 7); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(7))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(2), Bound(8))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(3), Bound(9))); inv.add(VariableExpr(x) == 4 * VariableExpr(w)); BOOST_CHECK(inv.to_interval(x) == Interval(4)); BOOST_CHECK(inv.to_interval(y) == Interval(5)); BOOST_CHECK(inv.to_interval(z) == Interval(6)); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = VarPackingDBMCongruence::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(2)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Interval(Bound(1), Bound(2)), Congruence(ZNumber(3), ZNumber(1)))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = VarPackingDBMCongruence::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); inv.set_to_top(); inv.refine(x, IntervalCongruence(1)); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Congruence(ZNumber(3), ZNumber(1)))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval_congruence(x) == IntervalCongruence(Interval(Bound(4), Bound(7)), Congruence(ZNumber(3), ZNumber(1)))); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBMCongruence::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); inv.set_to_top(); inv.add(VariableExpr(x) - VariableExpr(y) <= 1); inv.forget(x); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBMCongruence::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBMCongruence::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDBMCongruence::top(); inv.refine(x, Interval(Bound(0), Bound(3))); inv.refine(y, Interval(Bound(4), Bound(7))); inv.refine(x, Congruence(ZNumber(3), ZNumber(0))); inv.refine(y, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(1), Bound(7)), Congruence(ZNumber(6), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-20), Bound(-5)), Congruence(ZNumber(3), ZNumber(1)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/numeric/var_packing_domain.cpp000066400000000000000000001013401473507761200267330ustar00rootroot00000000000000/******************************************************************************* * * Tests for VarPackingDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_var_packing_domain #define BOOST_TEST_DYN_LINK #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using VariableExpr = ikos::core::VariableExpression< ZNumber, Variable >; using BinaryOperator = ikos::core::numeric::BinaryOperator; using Bound = ikos::core::ZBound; using Interval = ikos::core::numeric::ZInterval; using Congruence = ikos::core::numeric::ZCongruence; using IntervalCongruence = ikos::core::numeric::IntervalCongruence< ZNumber >; using DBM = ikos::core::numeric::DBM< ZNumber, Variable >; using VarPackingDomain = ikos::core::numeric::VarPackingDomain< ZNumber, Variable, DBM >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(VarPackingDomain::top().is_top()); BOOST_CHECK(!VarPackingDomain::top().is_bottom()); BOOST_CHECK(!VarPackingDomain::bottom().is_top()); BOOST_CHECK(VarPackingDomain::bottom().is_bottom()); auto inv = VarPackingDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval(1)); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Interval::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.add(VariableExpr(x) - VariableExpr(y) <= 1); inv.forget(x); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = VarPackingDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK(VarPackingDomain::bottom().leq(VarPackingDomain::top())); BOOST_CHECK(VarPackingDomain::bottom().leq(VarPackingDomain::bottom())); BOOST_CHECK(!VarPackingDomain::top().leq(VarPackingDomain::bottom())); BOOST_CHECK(VarPackingDomain::top().leq(VarPackingDomain::top())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(inv1.leq(VarPackingDomain::top())); BOOST_CHECK(!inv1.leq(VarPackingDomain::bottom())); auto inv2 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv2.leq(VarPackingDomain::top())); BOOST_CHECK(!inv2.leq(VarPackingDomain::bottom())); BOOST_CHECK(inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = VarPackingDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(inv3.leq(VarPackingDomain::top())); BOOST_CHECK(!inv3.leq(VarPackingDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); auto inv4 = VarPackingDomain::top(); inv4.set(x, Interval(0)); inv4.set(y, Interval(Bound(0), Bound(2))); BOOST_CHECK(inv4.leq(VarPackingDomain::top())); BOOST_CHECK(!inv4.leq(VarPackingDomain::bottom())); BOOST_CHECK(!inv3.leq(inv4)); BOOST_CHECK(!inv4.leq(inv3)); auto inv5 = VarPackingDomain::top(); inv5.set(x, Interval(0)); inv5.set(y, Interval(Bound(0), Bound(2))); inv5.set(z, Interval(Bound::minus_infinity(), Bound(0))); BOOST_CHECK(inv5.leq(VarPackingDomain::top())); BOOST_CHECK(!inv5.leq(VarPackingDomain::bottom())); BOOST_CHECK(!inv5.leq(inv3)); BOOST_CHECK(!inv3.leq(inv5)); BOOST_CHECK(inv5.leq(inv4)); BOOST_CHECK(!inv4.leq(inv5)); inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1} <= {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1} <= {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK(inv1.leq(inv2)); // {x = 1, y = 2} <= {x <= 1} inv2.add(VariableExpr(z) <= 4); BOOST_CHECK(!inv1.leq(inv2)); // not {x = 1, y = 2} <= {x <= 1, z <= 4} inv1.set_to_top(); inv2.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK(inv1.leq(inv2)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} <= {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK(!inv1.leq(inv2)); } BOOST_AUTO_TEST_CASE(equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(!VarPackingDomain::bottom().equals(VarPackingDomain::top())); BOOST_CHECK(VarPackingDomain::bottom().equals(VarPackingDomain::bottom())); BOOST_CHECK(!VarPackingDomain::top().equals(VarPackingDomain::bottom())); BOOST_CHECK(VarPackingDomain::top().equals(VarPackingDomain::top())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(0)); BOOST_CHECK(!inv1.equals(VarPackingDomain::top())); BOOST_CHECK(!inv1.equals(VarPackingDomain::bottom())); BOOST_CHECK(inv1.equals(inv1)); auto inv2 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv2.equals(VarPackingDomain::top())); BOOST_CHECK(!inv2.equals(VarPackingDomain::bottom())); BOOST_CHECK(!inv1.equals(inv2)); BOOST_CHECK(!inv2.equals(inv1)); auto inv3 = VarPackingDomain::top(); inv3.set(x, Interval(0)); inv3.set(y, Interval(Bound(-1), Bound(1))); BOOST_CHECK(!inv3.equals(VarPackingDomain::top())); BOOST_CHECK(!inv3.equals(VarPackingDomain::bottom())); BOOST_CHECK(!inv3.equals(inv1)); BOOST_CHECK(!inv1.equals(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((VarPackingDomain::bottom().join(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::bottom().join(VarPackingDomain::bottom()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::top().join(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::top().join(VarPackingDomain::bottom()) == VarPackingDomain::top())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.join(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((inv1.join(VarPackingDomain::bottom()) == inv1)); BOOST_CHECK((VarPackingDomain::top().join(inv1) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = VarPackingDomain::top(); auto inv3 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(Bound(-1), Bound(1))); BOOST_CHECK((inv1.join(inv2) == inv3)); BOOST_CHECK((inv2.join(inv1) == inv3)); auto inv4 = VarPackingDomain::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv4.set(y, Interval(0)); BOOST_CHECK((inv4.join(inv2) == inv2)); BOOST_CHECK((inv2.join(inv4) == inv2)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1} U {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1} U {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv2)); // {x = 1, y = 2} U {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.join(inv2) == inv3)); // {x = 1, y = 2} U {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.set(x, Interval(Bound(-1), Bound(1))); inv3.add(VariableExpr(y) <= 3); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 1); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.join(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} U {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.join(inv2).to_interval(a) == Interval(Bound(4), Bound::plus_infinity()))); inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 10); inv1.add((VariableExpr(z) - VariableExpr(y)) <= 10); inv2.set_to_top(); inv2.assign(y, 0); inv2.assign(z, 0); inv3.set_to_top(); inv3.add(VariableExpr(y) <= 10); inv3.add((VariableExpr(z) - VariableExpr(y)) <= 10); // {x = 1, y <= 10, z - y <= 10} U {y = 0, z = 0} BOOST_CHECK((inv1.join(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(widening) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((VarPackingDomain::bottom().widening(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::bottom().widening( VarPackingDomain::bottom()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::top().widening(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::top().widening(VarPackingDomain::bottom()) == VarPackingDomain::top())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK( (inv1.widening(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((inv1.widening(VarPackingDomain::bottom()) == inv1)); BOOST_CHECK( (VarPackingDomain::top().widening(inv1) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::bottom().widening(inv1) == inv1)); BOOST_CHECK((inv1.widening(inv1) == inv1)); auto inv2 = VarPackingDomain::top(); auto inv3 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.widening(inv2) == inv3)); BOOST_CHECK((inv2.widening(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(widening_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK( (VarPackingDomain::bottom().widening_threshold(VarPackingDomain::top(), ZNumber(10)) == VarPackingDomain::top())); BOOST_CHECK( (VarPackingDomain::bottom().widening_threshold(VarPackingDomain::bottom(), ZNumber(10)) == VarPackingDomain::bottom())); BOOST_CHECK( (VarPackingDomain::top().widening_threshold(VarPackingDomain::top(), ZNumber(10)) == VarPackingDomain::top())); BOOST_CHECK( (VarPackingDomain::top().widening_threshold(VarPackingDomain::bottom(), ZNumber(10)) == VarPackingDomain::top())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.widening_threshold(VarPackingDomain::top(), ZNumber(10)) == VarPackingDomain::top())); BOOST_CHECK((inv1.widening_threshold(VarPackingDomain::bottom(), ZNumber(10)) == inv1)); BOOST_CHECK((VarPackingDomain::top().widening_threshold(inv1, ZNumber(10)) == VarPackingDomain::top())); BOOST_CHECK( (VarPackingDomain::bottom().widening_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK((inv1.widening_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = VarPackingDomain::top(); auto inv3 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(0), Bound(2))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.widening_threshold(inv2, ZNumber(10)) == inv3)); BOOST_CHECK((inv2.widening_threshold(inv1, ZNumber(10)) == inv2)); auto inv4 = VarPackingDomain::top(); auto inv5 = VarPackingDomain::top(); auto inv6 = VarPackingDomain::top(); inv4.set(x, Interval(Bound(-1), Bound(0))); inv5.set(x, Interval(Bound(-2), Bound(0))); inv6.set(x, Interval(Bound(-10), Bound(0))); BOOST_CHECK((inv4.widening_threshold(inv5, ZNumber(10)) == inv6)); BOOST_CHECK((inv5.widening_threshold(inv4, ZNumber(10)) == inv5)); } BOOST_AUTO_TEST_CASE(narrowing_threshold) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK( (VarPackingDomain::bottom().narrowing_threshold(VarPackingDomain::top(), ZNumber(10)) == VarPackingDomain::bottom())); BOOST_CHECK(( VarPackingDomain::bottom().narrowing_threshold(VarPackingDomain::bottom(), ZNumber(10)) == VarPackingDomain::bottom())); BOOST_CHECK( (VarPackingDomain::top().narrowing_threshold(VarPackingDomain::top(), ZNumber(10)) == VarPackingDomain::top())); BOOST_CHECK( (VarPackingDomain::top().narrowing_threshold(VarPackingDomain::bottom(), ZNumber(10)) == VarPackingDomain::bottom())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK( (inv1.narrowing_threshold(VarPackingDomain::top(), ZNumber(10)) == inv1)); BOOST_CHECK( (inv1.narrowing_threshold(VarPackingDomain::bottom(), ZNumber(10)) == VarPackingDomain::bottom())); BOOST_CHECK( (VarPackingDomain::top().narrowing_threshold(inv1, ZNumber(10)) == inv1)); BOOST_CHECK( (VarPackingDomain::bottom().narrowing_threshold(inv1, ZNumber(10)) == VarPackingDomain::bottom())); BOOST_CHECK((inv1.narrowing_threshold(inv1, ZNumber(10)) == inv1)); auto inv2 = VarPackingDomain::top(); auto inv3 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); inv3.set(x, Interval(Bound(0), Bound(10))); BOOST_CHECK((inv1.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv1.narrowing_threshold(inv3, ZNumber(10)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(10)) == inv2)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(20)) == inv3)); BOOST_CHECK((inv3.narrowing_threshold(inv2, ZNumber(5)) == inv3)); auto inv4 = VarPackingDomain::top(); auto inv5 = VarPackingDomain::top(); inv4.set(x, Interval(Bound(-10), Bound(0))); inv5.set(x, Interval(Bound(-1), Bound(0))); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(10)) == inv5)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(20)) == inv4)); BOOST_CHECK((inv4.narrowing_threshold(inv5, ZNumber(5)) == inv4)); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); Variable a(vfac.get("a")); Variable b(vfac.get("b")); BOOST_CHECK((VarPackingDomain::bottom().meet(VarPackingDomain::top()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::bottom().meet(VarPackingDomain::bottom()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::top().meet(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::top().meet(VarPackingDomain::bottom()) == VarPackingDomain::bottom())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.meet(VarPackingDomain::top()) == inv1)); BOOST_CHECK( (inv1.meet(VarPackingDomain::bottom()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::top().meet(inv1) == inv1)); BOOST_CHECK( (VarPackingDomain::bottom().meet(inv1) == VarPackingDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = VarPackingDomain::top(); auto inv3 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(-1), Bound(0))); inv3.set(x, Interval(0)); BOOST_CHECK((inv1.meet(inv2) == inv3)); BOOST_CHECK((inv2.meet(inv1) == inv3)); auto inv4 = VarPackingDomain::top(); auto inv5 = VarPackingDomain::top(); inv4.set(x, Interval(Bound(0), Bound(1))); inv4.set(y, Interval(0)); inv5.set(x, Interval(0)); inv5.set(y, Interval(0)); BOOST_CHECK((inv4.meet(inv2) == inv5)); BOOST_CHECK((inv2.meet(inv4) == inv5)); inv1.set_to_top(); inv1.assign(x, 1); inv2.set_to_top(); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & top() inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1} & {x <= 1} inv2.set_to_top(); inv2.add(VariableExpr(x) <= 0); BOOST_CHECK( (inv1.meet(inv2) == VarPackingDomain::bottom())); // {x = 1} & {x <= 0} inv1.assign(y, 2); inv2.set_to_top(); inv2.add(VariableExpr(x) <= 1); BOOST_CHECK((inv1.meet(inv2) == inv1)); // {x = 1, y = 2} & {x <= 1} inv2.add(VariableExpr(z) <= 4); inv3.set_to_top(); inv3.assign(x, 1); inv3.assign(y, 2); inv3.add(VariableExpr(z) <= 4); BOOST_CHECK((inv1.meet(inv2) == inv3)); // {x = 1, y = 2} & {x <= 1, z <= 4} inv1.set_to_top(); inv1.assign(x, 1); inv1.add(VariableExpr(y) <= 2); inv1.assign(z, 3); inv1.add(VariableExpr(a) >= 4); inv1.assign(b, 5); inv2.set_to_top(); inv2.add(VariableExpr(y) <= 3); inv2.add(VariableExpr(a) >= 1); inv2.assign(z, 3); inv2.set(x, Interval(Bound(-1), Bound(1))); inv3.set_to_top(); inv3.assign(x, 1); inv3.add(VariableExpr(y) <= 2); inv3.assign(z, 3); inv3.add(VariableExpr(a) >= 4); inv3.assign(b, 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 1} BOOST_CHECK((inv1.meet(inv2) == inv3)); inv2.add(VariableExpr(a) >= 5); inv3.add(VariableExpr(a) >= 5); // {x = 1, y <= 2, z = 3, a >= 4, b = 5} & {-1 <= x <= 1, y <= 3, z = 3, a >= // 5} BOOST_CHECK((inv1.meet(inv2) == inv3)); } BOOST_AUTO_TEST_CASE(narrowing) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((VarPackingDomain::bottom().narrowing(VarPackingDomain::top()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::bottom().narrowing( VarPackingDomain::bottom()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::top().narrowing(VarPackingDomain::top()) == VarPackingDomain::top())); BOOST_CHECK((VarPackingDomain::top().narrowing(VarPackingDomain::bottom()) == VarPackingDomain::bottom())); auto inv1 = VarPackingDomain::top(); inv1.set(x, Interval(Bound(0), Bound::plus_infinity())); BOOST_CHECK((inv1.narrowing(VarPackingDomain::top()) == inv1)); BOOST_CHECK((inv1.narrowing(VarPackingDomain::bottom()) == VarPackingDomain::bottom())); BOOST_CHECK((VarPackingDomain::top().narrowing(inv1) == inv1)); BOOST_CHECK((VarPackingDomain::bottom().narrowing(inv1) == VarPackingDomain::bottom())); BOOST_CHECK((inv1.narrowing(inv1) == inv1)); auto inv2 = VarPackingDomain::top(); auto inv3 = VarPackingDomain::top(); inv2.set(x, Interval(Bound(0), Bound(1))); BOOST_CHECK((inv1.narrowing(inv2) == inv2)); BOOST_CHECK((inv2.narrowing(inv1) == inv2)); } BOOST_AUTO_TEST_CASE(assign) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); VarPackingDomain inv1 = VarPackingDomain::top(); VarPackingDomain inv2 = VarPackingDomain::top(); inv1.assign(x, 0); inv2.set(x, Interval(0)); BOOST_CHECK((inv1 == inv2)); inv1.set_to_bottom(); inv1.assign(x, 0); BOOST_CHECK(inv1.is_bottom()); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.assign(y, x); BOOST_CHECK(inv1.to_interval(y) == Interval(Bound(-1), Bound(1))); inv1.set_to_top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.assign(z, 2 * VariableExpr(x) - 3 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-7), Bound(0))); inv1.set_to_top(); inv1.assign(x, 7); inv1.add(VariableExpr(y) <= 3); inv1.add(VariableExpr(y) >= 1); inv1.assign(z, VariableExpr(x) + 2 * VariableExpr(y) + 1); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(10), Bound(14))); } BOOST_AUTO_TEST_CASE(apply) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv1 = VarPackingDomain::top(); auto inv2 = VarPackingDomain::top(); inv1.set(x, Interval(Bound(-1), Bound(1))); inv1.set(y, Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::Add, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Sub, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(0))); inv1.apply(BinaryOperator::Mul, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-2), Bound(2))); inv1.apply(BinaryOperator::Div, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Rem, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(4))); inv1.apply(BinaryOperator::Shr, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, y); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Sub, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-4), Bound(-2))); inv1.apply(BinaryOperator::Mul, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-3), Bound(3))); inv1.apply(BinaryOperator::Div, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(0))); inv1.apply(BinaryOperator::Rem, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(1))); inv1.apply(BinaryOperator::Mod, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Shl, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-8), Bound(8))); inv1.apply(BinaryOperator::Shr, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(-1), Bound(0))); inv1.apply(BinaryOperator::And, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(3))); inv1.apply(BinaryOperator::Or, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Xor, z, x, ZNumber(3)); BOOST_CHECK(inv1.to_interval(z) == Interval::top()); inv1.apply(BinaryOperator::Add, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(5), Bound(6))); inv1.apply(BinaryOperator::Sub, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(3))); inv1.apply(BinaryOperator::Mul, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(4), Bound(8))); inv1.apply(BinaryOperator::Div, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(2), Bound(4))); inv1.apply(BinaryOperator::Rem, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Mod, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(1))); inv1.apply(BinaryOperator::Shl, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(8), Bound(16))); inv1.apply(BinaryOperator::Shr, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(1), Bound(2))); inv1.apply(BinaryOperator::And, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(2))); inv1.apply(BinaryOperator::Or, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); inv1.apply(BinaryOperator::Xor, z, ZNumber(4), y); BOOST_CHECK(inv1.to_interval(z) == Interval(Bound(0), Bound(7))); } BOOST_AUTO_TEST_CASE(add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); auto inv = VarPackingDomain::top(); inv.add(VariableExpr(x) >= 1); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); inv.add(VariableExpr(y) >= VariableExpr(x) + 2); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); inv.add(2 * VariableExpr(x) + 3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(2 * VariableExpr(z) <= 4 * VariableExpr(y)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound::plus_infinity())); inv.add(VariableExpr(z) + VariableExpr(x) <= 20); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(9))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound::plus_infinity())); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(11), Bound(19))); inv.add(3 * VariableExpr(y) <= VariableExpr(z)); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(5), Bound(6))); BOOST_CHECK(inv.to_interval(z) == Interval(Bound(15), Bound(19))); inv.add(VariableExpr(x) == VariableExpr(y)); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.assign(x, 1); inv.add(VariableExpr(x) + VariableExpr(y) >= 0); inv.add(VariableExpr(x) - VariableExpr(y) >= 3); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = VarPackingDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.set(x, Interval::bottom()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.set(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.set(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.set(x, IntervalCongruence(Interval(Bound(1), Bound(4)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(4))); } BOOST_AUTO_TEST_CASE(refine) { VariableFactory vfac; Variable x(vfac.get("x")); auto inv = VarPackingDomain::top(); inv.refine(x, Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); inv.refine(x, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); inv.refine(x, Congruence(1)); BOOST_CHECK(inv.to_interval(x) == Interval(1)); inv.set_to_top(); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval::top()); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, Congruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(4), Bound(7))); inv.set_to_top(); inv.refine(x, Interval(Bound(2), Bound(9))); inv.refine(x, IntervalCongruence(Interval(Bound(7), Bound(10)), Congruence(ZNumber(3), ZNumber(1)))); BOOST_CHECK(inv.to_interval(x) == Interval(7)); } BOOST_AUTO_TEST_CASE(forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(x) == Interval(Bound(1), Bound(2))); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(x); BOOST_CHECK(inv.to_interval(x) == Interval::top()); BOOST_CHECK(inv.to_interval(y) == Interval(Bound(3), Bound(4))); inv.forget(y); BOOST_CHECK(inv.is_top()); inv.set_to_top(); inv.add(VariableExpr(x) - VariableExpr(y) <= 1); inv.forget(x); BOOST_CHECK(inv.is_top()); } BOOST_AUTO_TEST_CASE(to_interval) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) + 1) == Interval(Bound(3), Bound(5))); BOOST_CHECK(inv.to_interval(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Interval(Bound(-9), Bound(-4))); } BOOST_AUTO_TEST_CASE(to_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) + 1) == Congruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(inv.to_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == Congruence::top()); } BOOST_AUTO_TEST_CASE(to_interval_congruence) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); auto inv = VarPackingDomain::top(); inv.set(x, Interval(Bound(1), Bound(2))); inv.set(y, Interval(Bound(3), Bound(4))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) + 1) == IntervalCongruence(Interval(Bound(3), Bound(5)), Congruence(ZNumber(2), ZNumber(1)))); BOOST_CHECK(inv.to_interval_congruence(2 * VariableExpr(x) - 3 * VariableExpr(y) + 1) == IntervalCongruence(Interval(Bound(-9), Bound(-4)))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/pointer/000077500000000000000000000000001473507761200224335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/pointer/solver.cpp000066400000000000000000000307411473507761200244560ustar00rootroot00000000000000/******************************************************************************* * * Tests for pointer::ConstraintSystem * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_pointer_solver #define BOOST_TEST_DYN_LINK #include #include #include #include using ikos::core::Unsigned; using Int = ikos::core::MachineInt; using Interval = ikos::core::machine_int::Interval; using Nullity = ikos::core::Nullity; using Uninitialized = ikos::core::Uninitialized; using VariableFactory = ikos::core::example::VariableFactory; using Variable = VariableFactory::VariableRef; using MemoryFactory = ikos::core::example::VariableFactory; using MemLocation = MemoryFactory::VariableRef; using VarOperand = ikos::core::pointer::VariableOperand< Variable, MemLocation >; using AddrOperand = ikos::core::pointer::AddressOperand< Variable, MemLocation >; using Assign = ikos::core::pointer::AssignConstraint< Variable, MemLocation >; using Store = ikos::core::pointer::StoreConstraint< Variable, MemLocation >; using Load = ikos::core::pointer::LoadConstraint< Variable, MemLocation >; using PointerAbsValue = ikos::core::PointerAbsValue< MemLocation >; using PointsToSet = ikos::core::PointsToSet< MemLocation >; using ConstraintSystem = ikos::core::pointer::ConstraintSystem< Variable, MemLocation >; BOOST_AUTO_TEST_CASE(test_1) { // Sample function: // // int **f(int **p, int *q) { // int *tmp = q + 1; // *p = tmp; // return p; // } VariableFactory vfac; MemoryFactory memfac; Variable p(vfac.get("p")); Variable q(vfac.get("q")); Variable tmp(vfac.get("tmp")); MemLocation x(memfac.get("x")); MemLocation y(memfac.get("y")); ConstraintSystem s(64, Unsigned); // tmp = q + 1; s.add(Assign::create(tmp, VarOperand::create(q, Interval(Int(4, 64, Unsigned))))); // *p = tmp s.add(Store::create(p, VarOperand::create(tmp, Interval(Int(0, 64, Unsigned))))); // f(&x + [0, 4], &y + [8, 16]) s.add(Assign::create(p, AddrOperand::create(x, Interval(Int(0, 64, Unsigned), Int(4, 64, Unsigned))))); s.add(Assign::create(q, AddrOperand::create(y, Interval(Int(8, 64, Unsigned), Int(16, 64, Unsigned))))); s.solve(); BOOST_CHECK( s.get_pointer(p) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{x}, Interval(Int(0, 64, Unsigned), Int(4, 64, Unsigned)))); BOOST_CHECK( s.get_pointer(q) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{y}, Interval(Int(8, 64, Unsigned), Int(16, 64, Unsigned)))); BOOST_CHECK( s.get_pointer(tmp) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{y}, Interval(Int(12, 64, Unsigned), Int(20, 64, Unsigned)))); BOOST_CHECK( s.get_memory(x) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{y}, Interval(Int(12, 64, Unsigned), Int(20, 64, Unsigned)))); BOOST_CHECK(s.get_memory(y) == PointerAbsValue::bottom(64, Unsigned)); } BOOST_AUTO_TEST_CASE(test_2) { // int x, y; // int **p, *q; // q = &x; // p = &q; // *p = &y; // translated by llvm: // i32* x = alloca i32 // i32* y = alloca i32 // i32*** p = alloca i32** // i32** q = alloca i32* // store x, q // store q, p // tmp = load p // store y, tmp VariableFactory vfac; MemoryFactory memfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable p(vfac.get("p")); Variable q(vfac.get("q")); Variable tmp(vfac.get("tmp")); MemLocation mx(memfac.get("&x")); MemLocation my(memfac.get("&y")); MemLocation mp(memfac.get("&p")); MemLocation mq(memfac.get("&q")); ConstraintSystem s(64, Unsigned); Interval zero(Int(0, 64, Unsigned)); // i32* x = alloca i32 s.add(Assign::create(x, AddrOperand::create(mx, zero))); // i32* y = alloca i32 s.add(Assign::create(y, AddrOperand::create(my, zero))); // i32*** p = alloca i32** s.add(Assign::create(p, AddrOperand::create(mp, zero))); // i32** q = alloca i32* s.add(Assign::create(q, AddrOperand::create(mq, zero))); // store x, q s.add(Store::create(q, VarOperand::create(x, zero))); // store q, p s.add(Store::create(p, VarOperand::create(q, zero))); // tmp = load p s.add(Load::create(tmp, VarOperand::create(p, zero))); // store y, tmp s.add(Store::create(tmp, VarOperand::create(y, zero))); s.solve(); BOOST_CHECK(s.get_memory(mp) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{mq}, zero)); BOOST_CHECK(s.get_memory(mq) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{mx, my}, zero)); } BOOST_AUTO_TEST_CASE(test_3) { // Sample function: // global struct foo * x = null; //-- %main._0 = call noalias i8* @malloc(i64 8) nounwind, !dbg !18 // p0 = malloc(8); //-- %main._1 = bitcast i8* %main._0 to %struct.foo*, !dbg !18 // p1 = p0; //-- store %struct.foo* %main._1, %struct.foo** @x, align 8, !dbg !18 // *x = p1 //-- %main._4 = load %struct.foo** @x, align 8, !dbg !21 // p4 = *x; //-- %main._5 = getelementptr inbounds %struct.foo* %main._4, i32 0, i32 0, //! dbg !21 // p5 = p4 + 0; //-- store i32 5, i32* %main._5, align 4, !dbg !21 /*C*/ // *p5 = 5; // x->a = 5; //-- %main._6 = load %struct.foo** @x, align 8, !dbg !22 // p6 = *x; //-- %main._7 = load %struct.foo** @x, align 8, !dbg !22 // p7 = *x; //-- %main._8 = getelementptr inbounds %struct.foo* %main._7, i32 0, i32 0, //! dbg !22 // p8 = p7 + 0; //-- %main._9 = load i32* %main._8, align 4, !dbg !22 /*C*/ // p9 = *p8; // *(x).a //-- %main._10 = add nsw i32 %main._9, 7, !dbg !22 /*C*/ // p10 = p9 + 7; //-- %main._11 = getelementptr inbounds %struct.foo* %main._6, i32 0, i32 1, //! dbg !22 // p11 = p6 + 4; //-- store i32 %main._10, i32* %main._11, align 4, !dbg !22 /*C*/ // *p11 = p10; // x->b = x->a + 7; // // At this point x->a = 5 and x->b = 12 VariableFactory vfac; MemoryFactory memfac; Variable x(vfac.get("x")); Variable p0(vfac.get("p0")); Variable p1(vfac.get("p1")); Variable p4(vfac.get("p4")); Variable p5(vfac.get("p5")); Variable p6(vfac.get("p6")); Variable p7(vfac.get("p7")); Variable p8(vfac.get("p8")); Variable p11(vfac.get("p11")); MemLocation mx(memfac.get("&x")); MemLocation malloc(memfac.get("malloc")); ConstraintSystem s(64, Unsigned); Interval zero(Int(0, 64, Unsigned)); // declaration of global variable x s.add(Assign::create(x, AddrOperand::create(mx, zero))); // p0 = malloc(8); s.add(Assign::create(p0, AddrOperand::create(malloc, zero))); // p1 = p0; s.add(Assign::create(p1, VarOperand::create(p0, zero))); // *x = p1; s.add(Store::create(x, VarOperand::create(p1, zero))); // p4 = *x; s.add(Load::create(p4, VarOperand::create(x, zero))); // p5 = p4; s.add(Assign::create(p5, VarOperand::create(p4, zero))); // *p5 = 5; // no pointer constraint // p6 = *x; s.add(Load::create(p6, VarOperand::create(x, zero))); // p7 = *x; s.add(Load::create(p7, VarOperand::create(x, zero))); // p8 = p7; s.add(Assign::create(p8, VarOperand::create(p7, zero))); // p9 = *p8; // no pointer constraint // p10 = p9 + 7; // no pointer constraint // p11 = p6 + 4; s.add(Assign::create(p11, VarOperand::create(p6, Interval(Int(4, 64, Unsigned))))); // *p11 = p10; // no pointer constraint s.solve(); BOOST_CHECK(s.get_pointer(p5) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{malloc}, zero)); BOOST_CHECK(s.get_pointer(p8) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{malloc}, zero)); BOOST_CHECK(s.get_pointer(p11) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{malloc}, Interval(Int(4, 64, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_4) { /* l = malloc (sizeof(int) * ncols); for (i=0;i<10;i++) { l[i] = malloc (sizeof(int) * nrows) } */ VariableFactory vfac; MemoryFactory memfac; Variable l(vfac.get("l")); Variable tmp(vfac.get("tmp")); MemLocation ncols(memfac.get("ncols")); MemLocation nrows(memfac.get("nrows")); ConstraintSystem s(64, Unsigned); Interval zero(Int(0, 64, Unsigned)); s.add(Assign::create(l, AddrOperand::create(ncols, zero))); s.add(Assign::create(tmp, VarOperand::create(l, Interval(Int(0, 64, Unsigned), Int(9, 64, Unsigned))))); s.add(Store::create(tmp, AddrOperand::create(nrows, zero))); s.solve(); BOOST_CHECK(s.get_pointer(l) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{ncols}, zero)); BOOST_CHECK( s.get_pointer(tmp) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{ncols}, Interval(Int(0, 64, Unsigned), Int(9, 64, Unsigned)))); BOOST_CHECK(s.get_memory(ncols) == PointerAbsValue(Uninitialized::top(), Nullity::top(), PointsToSet{nrows}, zero)); BOOST_CHECK(s.get_memory(nrows) == PointerAbsValue::bottom(64, Unsigned)); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/uninitialized/000077500000000000000000000000001473507761200236235ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/domain/uninitialized/separate_domain.cpp000066400000000000000000000163211473507761200274650ustar00rootroot00000000000000/******************************************************************************* * * Tests for UninitializedDomain * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_uninitialized_domain #define BOOST_TEST_DYN_LINK #include #include #include #include using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using Uninitialized = ikos::core::Uninitialized; using UninitializedDomain = ikos::core::uninitialized::SeparateDomain< Variable >; BOOST_AUTO_TEST_CASE(is_top_and_bottom) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK(UninitializedDomain::top().is_top()); BOOST_CHECK(!UninitializedDomain::top().is_bottom()); BOOST_CHECK(!UninitializedDomain::bottom().is_top()); BOOST_CHECK(UninitializedDomain::bottom().is_bottom()); auto inv = UninitializedDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.assign_initialized(x); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set(x, Uninitialized::bottom()); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); } BOOST_AUTO_TEST_CASE(set_to_top_and_bottom) { VariableFactory vfac; auto inv = UninitializedDomain::top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); inv.set_to_bottom(); BOOST_CHECK(!inv.is_top()); BOOST_CHECK(inv.is_bottom()); inv.set_to_top(); BOOST_CHECK(inv.is_top()); BOOST_CHECK(!inv.is_bottom()); } BOOST_AUTO_TEST_CASE(leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); BOOST_CHECK(UninitializedDomain::bottom().leq(UninitializedDomain::top())); BOOST_CHECK(UninitializedDomain::bottom().leq(UninitializedDomain::bottom())); BOOST_CHECK(!UninitializedDomain::top().leq(UninitializedDomain::bottom())); BOOST_CHECK(UninitializedDomain::top().leq(UninitializedDomain::top())); auto inv1 = UninitializedDomain::top(); inv1.set(x, Uninitialized::initialized()); BOOST_CHECK(inv1.leq(UninitializedDomain::top())); BOOST_CHECK(!inv1.leq(UninitializedDomain::bottom())); auto inv2 = UninitializedDomain::top(); inv2.set(x, Uninitialized::uninitialized()); BOOST_CHECK(inv2.leq(UninitializedDomain::top())); BOOST_CHECK(!inv2.leq(UninitializedDomain::bottom())); BOOST_CHECK(!inv1.leq(inv2)); BOOST_CHECK(!inv2.leq(inv1)); auto inv3 = UninitializedDomain::top(); inv3.set(x, Uninitialized::initialized()); inv3.set(y, Uninitialized::uninitialized()); BOOST_CHECK(inv3.leq(UninitializedDomain::top())); BOOST_CHECK(!inv3.leq(UninitializedDomain::bottom())); BOOST_CHECK(inv3.leq(inv1)); BOOST_CHECK(!inv1.leq(inv3)); } BOOST_AUTO_TEST_CASE(join) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((UninitializedDomain::bottom().join(UninitializedDomain::top()) == UninitializedDomain::top())); BOOST_CHECK( (UninitializedDomain::bottom().join(UninitializedDomain::bottom()) == UninitializedDomain::bottom())); BOOST_CHECK((UninitializedDomain::top().join(UninitializedDomain::top()) == UninitializedDomain::top())); BOOST_CHECK((UninitializedDomain::top().join(UninitializedDomain::bottom()) == UninitializedDomain::top())); auto inv1 = UninitializedDomain::top(); inv1.set(x, Uninitialized::initialized()); BOOST_CHECK( (inv1.join(UninitializedDomain::top()) == UninitializedDomain::top())); BOOST_CHECK((inv1.join(UninitializedDomain::bottom()) == inv1)); BOOST_CHECK( (UninitializedDomain::top().join(inv1) == UninitializedDomain::top())); BOOST_CHECK((UninitializedDomain::bottom().join(inv1) == inv1)); BOOST_CHECK((inv1.join(inv1) == inv1)); auto inv2 = UninitializedDomain::top(); inv2.set(x, Uninitialized::uninitialized()); BOOST_CHECK((inv1.join(inv2) == UninitializedDomain::top())); BOOST_CHECK((inv2.join(inv1) == UninitializedDomain::top())); } BOOST_AUTO_TEST_CASE(meet) { VariableFactory vfac; Variable x(vfac.get("x")); BOOST_CHECK((UninitializedDomain::bottom().meet(UninitializedDomain::top()) == UninitializedDomain::bottom())); BOOST_CHECK( (UninitializedDomain::bottom().meet(UninitializedDomain::bottom()) == UninitializedDomain::bottom())); BOOST_CHECK((UninitializedDomain::top().meet(UninitializedDomain::top()) == UninitializedDomain::top())); BOOST_CHECK((UninitializedDomain::top().meet(UninitializedDomain::bottom()) == UninitializedDomain::bottom())); auto inv1 = UninitializedDomain::top(); inv1.set(x, Uninitialized::initialized()); BOOST_CHECK((inv1.meet(UninitializedDomain::top()) == inv1)); BOOST_CHECK((inv1.meet(UninitializedDomain::bottom()) == UninitializedDomain::bottom())); BOOST_CHECK((UninitializedDomain::top().meet(inv1) == inv1)); BOOST_CHECK((UninitializedDomain::bottom().meet(inv1) == UninitializedDomain::bottom())); BOOST_CHECK((inv1.meet(inv1) == inv1)); auto inv2 = UninitializedDomain::top(); inv2.set(x, Uninitialized::uninitialized()); BOOST_CHECK((inv1.meet(inv2) == UninitializedDomain::bottom())); BOOST_CHECK((inv2.meet(inv1) == UninitializedDomain::bottom())); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/example/000077500000000000000000000000001473507761200211375ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/example/muzq.cpp000066400000000000000000000524501473507761200226450ustar00rootroot00000000000000/******************************************************************************* * * Tests for muzq * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_muzq #define BOOST_TEST_DYN_LINK #include #include #include #include #include #include using namespace ikos::core; using VariableFactory = example::VariableFactory; using Variable = example::VariableFactory::VariableRef; using ZVarExpr = VariableExpression< ZNumber, Variable >; using QVarExpr = VariableExpression< QNumber, Variable >; using Statement = muzq::Statement< Variable >; using ZLinearExpression = LinearExpression< ZNumber, Variable >; using ZLinearAssignment = muzq::ZLinearAssignment< Variable >; using QLinearAssignment = muzq::QLinearAssignment< Variable >; using ZBinaryOperation = muzq::ZBinaryOperation< Variable >; using QBinaryOperation = muzq::QBinaryOperation< Variable >; using ZLinearAssertion = muzq::ZLinearAssertion< Variable >; using QLinearAssertion = muzq::QLinearAssertion< Variable >; using BinaryOperator = numeric::BinaryOperator; using CheckPoint = muzq::CheckPoint< Variable >; using BasicBlock = muzq::BasicBlock< Variable >; using ControlFlowGraph = muzq::ControlFlowGraph< Variable >; using ZInterval = numeric::Interval< ZNumber >; using ZIntervalDomain = numeric::IntervalDomain< ZNumber, Variable >; using QIntervalDomain = numeric::IntervalDomain< QNumber, Variable >; using ZDBM = numeric::DBM< ZNumber, Variable >; BOOST_AUTO_TEST_CASE(test1) { ControlFlowGraph cfg("entry"); BasicBlock* entry = cfg.get("entry"); BasicBlock* bb1 = cfg.get("bb1"); BasicBlock* bb1_t = cfg.get("bb1_t"); BasicBlock* bb1_f = cfg.get("bb1_f"); BasicBlock* bb2 = cfg.get("bb2"); BasicBlock* ret = cfg.get("ret"); VariableFactory vfac; Variable n1(vfac.get("n1")); Variable i(vfac.get("i")); entry->add_successor(bb1); bb1->add_successor(bb1_t); bb1->add_successor(bb1_f); bb1_t->add_successor(bb2); bb2->add_successor(bb1); bb1_f->add_successor(ret); entry->add(std::make_unique< ZLinearAssignment >(n1, ZLinearExpression(1))); entry->add(std::make_unique< ZLinearAssignment >(i, ZLinearExpression(0))); bb1_t->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) <= 9)); bb1_f->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) >= 10)); bb2->add(std::make_unique< CheckPoint >("loop.in")); bb2->add( std::make_unique< ZLinearAssignment >(i, ZVarExpr(i) + ZVarExpr(n1))); ret->add(std::make_unique< CheckPoint >("loop.end")); // cfg.dump(std::cout); muzq::FixpointIterator< Variable, ZIntervalDomain, QIntervalDomain > fixpoint( cfg); fixpoint.run({ZIntervalDomain::top(), QIntervalDomain::top()}); // fixpoint.dump(std::cout); ZIntervalDomain loop_in = fixpoint.checkpoint("loop.in").first(); BOOST_CHECK(loop_in.to_interval(i) == ZInterval(ZBound(0), ZBound(9))); BOOST_CHECK(loop_in.to_interval(n1) == ZInterval(1)); ZIntervalDomain loop_end = fixpoint.checkpoint("loop.end").first(); BOOST_CHECK(loop_end.to_interval(i) == ZInterval(10)); BOOST_CHECK(loop_end.to_interval(n1) == ZInterval(1)); } BOOST_AUTO_TEST_CASE(test2) { ControlFlowGraph cfg("entry"); BasicBlock* entry = cfg.get("entry"); BasicBlock* bb1 = cfg.get("bb1"); BasicBlock* bb1_t = cfg.get("bb1_t"); BasicBlock* bb1_f = cfg.get("bb1_f"); BasicBlock* bb2 = cfg.get("bb2"); BasicBlock* ret = cfg.get("ret"); VariableFactory vfac; Variable n1(vfac.get("n1")); Variable i(vfac.get("i")); Variable tmp1(vfac.get("tmp1")); Variable tmp2(vfac.get("tmp2")); Variable tmp3(vfac.get("tmp3")); entry->add_successor(bb1); bb1->add_successor(bb1_t); bb1->add_successor(bb1_f); bb1_t->add_successor(bb2); bb2->add_successor(bb1); bb1_f->add_successor(ret); entry->add(std::make_unique< ZLinearAssignment >(n1, ZLinearExpression(1))); entry->add(std::make_unique< ZLinearAssignment >(i, ZLinearExpression(0))); bb1_t->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) <= 9)); bb1_f->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) >= 10)); bb2->add(std::make_unique< CheckPoint >("loop.in")); bb2->add(std::make_unique< ZLinearAssignment >(tmp1, ZLinearExpression(i))); bb2->add(std::make_unique< ZBinaryOperation >(tmp2, BinaryOperator::Add, tmp1, n1)); bb2->add(std::make_unique< ZLinearAssignment >(i, ZLinearExpression(tmp2))); ret->add( std::make_unique< ZBinaryOperation >(tmp3, BinaryOperator::Sub, i, n1)); ret->add(std::make_unique< CheckPoint >("loop.end")); // cfg.dump(std::cout); muzq::FixpointIterator< Variable, ZIntervalDomain, QIntervalDomain > fixpoint( cfg); fixpoint.run({ZIntervalDomain::top(), QIntervalDomain::top()}); // fixpoint.dump(std::cout); ZIntervalDomain loop_in = fixpoint.checkpoint("loop.in").first(); BOOST_CHECK(loop_in.to_interval(i) == ZInterval(ZBound(0), ZBound(9))); BOOST_CHECK(loop_in.to_interval(n1) == ZInterval(1)); ZIntervalDomain loop_end = fixpoint.checkpoint("loop.end").first(); BOOST_CHECK(loop_end.to_interval(i) == ZInterval(10)); BOOST_CHECK(loop_end.to_interval(n1) == ZInterval(1)); BOOST_CHECK(loop_end.to_interval(tmp3) == ZInterval(9)); } BOOST_AUTO_TEST_CASE(test3) { ControlFlowGraph cfg("loop1_entry"); BasicBlock* loop1_entry = cfg.get("loop1_entry"); BasicBlock* loop1_bb1 = cfg.get("loop1_bb1"); BasicBlock* loop1_bb1_t = cfg.get("loop1_bb1_t"); BasicBlock* loop1_bb1_f = cfg.get("loop1_bb1_f"); BasicBlock* loop1_bb2 = cfg.get("loop1_bb2"); BasicBlock* loop2_entry = cfg.get("loop2_entry"); BasicBlock* loop2_bb1 = cfg.get("loop2_bb1"); BasicBlock* loop2_bb1_t = cfg.get("loop2_bb1_t"); BasicBlock* loop2_bb1_f = cfg.get("loop2_bb1_f"); BasicBlock* loop2_bb2 = cfg.get("loop2_bb2"); BasicBlock* ret = cfg.get("ret"); loop1_entry->add_successor(loop1_bb1); loop1_bb1->add_successor(loop1_bb1_t); loop1_bb1->add_successor(loop1_bb1_f); loop1_bb1_t->add_successor(loop1_bb2); loop1_bb2->add_successor(loop1_bb1); loop1_bb1_f->add_successor(loop2_entry); loop2_entry->add_successor(loop2_bb1); loop2_bb1->add_successor(loop2_bb1_t); loop2_bb1->add_successor(loop2_bb1_f); loop2_bb1_t->add_successor(loop2_bb2); loop2_bb2->add_successor(loop2_bb1); loop2_bb1_f->add_successor(ret); VariableFactory vfac; Variable n1(vfac.get("n1")); Variable i(vfac.get("i")); Variable j(vfac.get("j")); Variable s(vfac.get("s")); loop1_entry->add( std::make_unique< ZLinearAssignment >(s, ZLinearExpression(0))); loop1_entry->add( std::make_unique< ZLinearAssignment >(n1, ZLinearExpression(1))); loop1_entry->add( std::make_unique< ZLinearAssignment >(i, ZLinearExpression(0))); loop1_bb1_t->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) <= 9)); loop1_bb1_f->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) >= 10)); loop1_bb2->add(std::make_unique< CheckPoint >("loop1.in")); loop1_bb2->add( std::make_unique< ZBinaryOperation >(i, BinaryOperator::Add, i, n1)); loop1_bb2->add( std::make_unique< ZBinaryOperation >(s, BinaryOperator::Add, s, n1)); loop2_entry->add( std::make_unique< ZLinearAssignment >(j, ZLinearExpression(0))); loop2_bb1_t->add(std::make_unique< ZLinearAssertion >(ZVarExpr(j) <= 9)); loop2_bb1_f->add(std::make_unique< ZLinearAssertion >(ZVarExpr(j) >= 10)); loop2_bb2->add(std::make_unique< CheckPoint >("loop2.in")); loop2_bb2->add( std::make_unique< ZBinaryOperation >(j, BinaryOperator::Add, j, n1)); loop2_bb2->add( std::make_unique< ZBinaryOperation >(s, BinaryOperator::Add, s, n1)); ret->add(std::make_unique< CheckPoint >("end")); // cfg.dump(std::cout); muzq::FixpointIterator< Variable, ZIntervalDomain, QIntervalDomain > fixpoint( cfg); fixpoint.run({ZIntervalDomain::top(), QIntervalDomain::top()}); // fixpoint.dump(std::cout); ZIntervalDomain loop1_in = fixpoint.checkpoint("loop1.in").first(); BOOST_CHECK(loop1_in.to_interval(i) == ZInterval(ZBound(0), ZBound(9))); BOOST_CHECK(loop1_in.to_interval(j) == ZInterval::top()); BOOST_CHECK(loop1_in.to_interval(s) == ZInterval(ZBound(0), ZBound::plus_infinity())); ZIntervalDomain loop2_in = fixpoint.checkpoint("loop2.in").first(); BOOST_CHECK(loop2_in.to_interval(i) == ZInterval(10)); BOOST_CHECK(loop2_in.to_interval(j) == ZInterval(ZBound(0), ZBound(9))); BOOST_CHECK(loop2_in.to_interval(s) == ZInterval(ZBound(0), ZBound::plus_infinity())); ZIntervalDomain end = fixpoint.checkpoint("end").first(); BOOST_CHECK(end.to_interval(i) == ZInterval(10)); BOOST_CHECK(end.to_interval(j) == ZInterval(10)); BOOST_CHECK(end.to_interval(s) == ZInterval(ZBound(0), ZBound::plus_infinity())); } BOOST_AUTO_TEST_CASE(test4) { ControlFlowGraph cfg("entry"); BasicBlock* entry = cfg.get("entry"); BasicBlock* bb1 = cfg.get("bb1"); BasicBlock* bb1_t = cfg.get("bb1_t"); BasicBlock* bb1_f = cfg.get("bb1_f"); BasicBlock* bb2 = cfg.get("bb2"); BasicBlock* ret = cfg.get("ret"); VariableFactory vfac; Variable n1(vfac.get("n1")); Variable i(vfac.get("i")); Variable n(vfac.get("n")); entry->add_successor(bb1); bb1->add_successor(bb1_t); bb1->add_successor(bb1_f); bb1_t->add_successor(bb2); bb2->add_successor(bb1); bb1_f->add_successor(ret); entry->add(std::make_unique< ZLinearAssertion >(ZVarExpr(n) >= 1)); entry->add(std::make_unique< ZLinearAssignment >(n1, ZLinearExpression(1))); entry->add(std::make_unique< ZLinearAssignment >(i, ZLinearExpression(0))); bb1_t->add( std::make_unique< ZLinearAssertion >(ZVarExpr(i) <= ZVarExpr(n) - 1)); bb1_f->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) >= ZVarExpr(n))); bb2->add(std::make_unique< CheckPoint >("loop.in")); bb2->add(std::make_unique< ZBinaryOperation >(i, BinaryOperator::Add, i, n1)); ret->add(std::make_unique< CheckPoint >("loop.end")); // cfg.dump(std::cout); muzq::FixpointIterator< Variable, ZDBM, QIntervalDomain > fixpoint(cfg); fixpoint.run({ZDBM::top(), QIntervalDomain::top()}); // fixpoint.dump(std::cout); ZDBM loop_in = fixpoint.checkpoint("loop.in").first(); BOOST_CHECK(loop_in.to_interval(i) == ZInterval(ZBound(0), ZBound::plus_infinity())); BOOST_CHECK(loop_in.to_interval(n) == ZInterval(ZBound(1), ZBound::plus_infinity())); loop_in.add(ZVarExpr(i) >= ZVarExpr(n)); BOOST_CHECK(loop_in.is_bottom()); ZDBM loop_end = fixpoint.checkpoint("loop.end").first(); BOOST_CHECK(loop_end.to_interval(i) == ZInterval(ZBound(1), ZBound::plus_infinity())); BOOST_CHECK(loop_end.to_interval(n) == ZInterval(ZBound(1), ZBound::plus_infinity())); loop_end.add(ZVarExpr(i) <= ZVarExpr(n) - 1); BOOST_CHECK(loop_end.is_bottom()); } BOOST_AUTO_TEST_CASE(test5) { // This is the program init_rand from Gange et.al paper. ControlFlowGraph cfg("entry"); BasicBlock* entry = cfg.get("entry"); BasicBlock* bb1 = cfg.get("bb1"); BasicBlock* bb1_t = cfg.get("bb1_t"); BasicBlock* bb1_f1 = cfg.get("bb1_f1"); BasicBlock* bb1_f2 = cfg.get("bb1_f2"); BasicBlock* bb1_f = cfg.get("bb1_f"); BasicBlock* bb2_a = cfg.get("bb2_a"); BasicBlock* bb2_b = cfg.get("bb2_b"); BasicBlock* ret = cfg.get("ret"); VariableFactory vfac; Variable n1(vfac.get("n1")); Variable i1(vfac.get("i1")); Variable i2(vfac.get("i2")); Variable n(vfac.get("n")); entry->add_successor(bb1); bb1->add_successor(bb1_t); bb1->add_successor(bb1_f1); bb1->add_successor(bb1_f2); bb1_f1->add_successor(bb1_f); bb1_f2->add_successor(bb1_f); bb1_t->add_successor(bb2_a); bb1_t->add_successor(bb2_b); bb2_a->add_successor(bb1); bb2_b->add_successor(bb1); bb1_f->add_successor(ret); entry->add(std::make_unique< ZLinearAssertion >(ZVarExpr(n) >= 1)); entry->add(std::make_unique< ZLinearAssignment >(n1, ZLinearExpression(1))); entry->add(std::make_unique< ZLinearAssignment >(i1, ZLinearExpression(0))); entry->add(std::make_unique< ZLinearAssignment >(i2, ZLinearExpression(0))); // while (i1 < n && i2 < n){ bb1_t->add( std::make_unique< ZLinearAssertion >(ZVarExpr(i1) <= ZVarExpr(n) - 1)); bb1_t->add( std::make_unique< ZLinearAssertion >(ZVarExpr(i2) <= ZVarExpr(n) - 1)); bb1_t->add(std::make_unique< CheckPoint >("loop.in")); // if (*) bb2_a->add( std::make_unique< ZBinaryOperation >(i1, BinaryOperator::Add, i1, n1)); // else bb2_b->add( std::make_unique< ZBinaryOperation >(i2, BinaryOperator::Add, i2, n1)); // } end while bb1_f1->add( std::make_unique< ZLinearAssertion >(ZVarExpr(i1) >= ZVarExpr(n))); bb1_f2->add( std::make_unique< ZLinearAssertion >(ZVarExpr(i2) >= ZVarExpr(n))); ret->add(std::make_unique< CheckPoint >("loop.end")); // cfg.dump(std::cout); muzq::FixpointIterator< Variable, ZDBM, QIntervalDomain > fixpoint(cfg); fixpoint.run({ZDBM::top(), QIntervalDomain::top()}); // fixpoint.dump(std::cout); ZDBM loop_in_i1 = fixpoint.checkpoint("loop.in").first(); loop_in_i1.add(ZVarExpr(i1) >= ZVarExpr(n)); BOOST_CHECK(loop_in_i1.is_bottom()); ZDBM loop_in_i2 = fixpoint.checkpoint("loop.in").first(); loop_in_i2.add(ZVarExpr(i2) >= ZVarExpr(n)); BOOST_CHECK(loop_in_i2.is_bottom()); } BOOST_AUTO_TEST_CASE(test6) { ControlFlowGraph cfg("entry"); BasicBlock* entry = cfg.get("entry"); BasicBlock* bb7 = cfg.get("bb7"); BasicBlock* pre_bb7_bb = cfg.get("pre_bb7_bb"); BasicBlock* pre_bb7_bb8 = cfg.get("pre_bb7_bb8"); BasicBlock* bb = cfg.get("bb"); BasicBlock* bb8 = cfg.get("bb8"); BasicBlock* bb5 = cfg.get("bb5"); BasicBlock* pre_bb5_bb6 = cfg.get("pre_bb5_bb6"); BasicBlock* pre_bb5_bb1 = cfg.get("pre_bb5_bb1"); BasicBlock* bb6 = cfg.get("bb6"); BasicBlock* bb1 = cfg.get("bb1"); BasicBlock* bb3 = cfg.get("bb3"); BasicBlock* pre_bb3_bb4 = cfg.get("pre_bb3_bb4"); BasicBlock* pre_bb3_bb2 = cfg.get("pre_bb3_bb2"); BasicBlock* bb2 = cfg.get("bb2"); BasicBlock* bb4 = cfg.get("bb4"); BasicBlock* ret = cfg.get("ret"); entry->add_successor(bb7); bb7->add_successor(pre_bb7_bb); bb7->add_successor(pre_bb7_bb8); pre_bb7_bb->add_successor(bb); bb->add_successor(bb5); pre_bb7_bb8->add_successor(bb8); bb8->add_successor(ret); bb5->add_successor(pre_bb5_bb6); bb5->add_successor(pre_bb5_bb1); pre_bb5_bb6->add_successor(bb6); bb6->add_successor(bb7); pre_bb5_bb1->add_successor(bb1); bb1->add_successor(bb3); bb3->add_successor(pre_bb3_bb4); bb3->add_successor(pre_bb3_bb2); pre_bb3_bb4->add_successor(bb4); pre_bb3_bb2->add_successor(bb2); bb4->add_successor(bb5); bb2->add_successor(bb3); VariableFactory vfac; Variable cst_1(vfac.get("#1")); Variable cst_40000(vfac.get("#40000")); Variable cst_4(vfac.get("#4")); Variable cst_400(vfac.get("#400")); Variable i(vfac.get("i")); Variable j(vfac.get("j")); Variable k(vfac.get("k")); Variable x(vfac.get("x")); Variable tmp0(vfac.get("tmp0")); Variable tmp1(vfac.get("tmp1")); Variable tmp2(vfac.get("tmp2")); Variable tmp3(vfac.get("tmp3")); Variable temp1(vfac.get("temp1")); Variable temp2(vfac.get("temp2")); Variable temp3(vfac.get("temp3")); Variable temp4(vfac.get("temp4")); Variable temp5(vfac.get("temp5")); Variable t0(vfac.get("T0")); Variable t1(vfac.get("T1")); entry->add(std::make_unique< ZLinearAssignment >(cst_40000, ZLinearExpression(40000))); entry->add( std::make_unique< ZLinearAssignment >(cst_400, ZLinearExpression(400))); entry->add( std::make_unique< ZLinearAssignment >(cst_1, ZLinearExpression(1))); entry->add( std::make_unique< ZLinearAssignment >(cst_4, ZLinearExpression(4))); entry->add(std::make_unique< ZLinearAssignment >(tmp0, ZLinearExpression(5))); entry->add( std::make_unique< ZLinearAssignment >(temp1, ZLinearExpression(tmp0))); entry->add(std::make_unique< ZLinearAssignment >(i, ZLinearExpression(0))); pre_bb7_bb->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) <= 99)); bb->add( std::make_unique< ZLinearAssignment >(tmp1, ZLinearExpression(temp1))); bb->add( std::make_unique< ZLinearAssignment >(temp2, ZLinearExpression(tmp1))); bb->add(std::make_unique< ZLinearAssignment >(temp3, ZLinearExpression(0))); bb->add(std::make_unique< ZLinearAssignment >(j, ZLinearExpression(0))); pre_bb5_bb6->add(std::make_unique< ZLinearAssertion >(ZVarExpr(j) >= 100)); bb6->add(std::make_unique< ZBinaryOperation >(temp1, BinaryOperator::Add, temp1, cst_40000)); bb6->add( std::make_unique< ZBinaryOperation >(i, BinaryOperator::Add, i, cst_1)); pre_bb5_bb1->add(std::make_unique< ZLinearAssertion >(ZVarExpr(j) <= 99)); bb1->add( std::make_unique< ZLinearAssignment >(tmp2, ZLinearExpression(temp2))); bb1->add( std::make_unique< ZLinearAssignment >(tmp3, ZLinearExpression(temp3))); bb1->add(std::make_unique< ZLinearAssignment >(temp4, ZLinearExpression(0))); bb1->add( std::make_unique< ZLinearAssignment >(temp5, ZLinearExpression(tmp2))); bb1->add(std::make_unique< ZLinearAssignment >(k, ZLinearExpression(0))); pre_bb3_bb2->add(std::make_unique< ZLinearAssertion >(ZVarExpr(k) <= 9999)); bb2->add(std::make_unique< ZLinearAssignment >(t0, ZLinearExpression(temp4))); bb2->add(std::make_unique< ZLinearAssignment >(t1, ZLinearExpression(temp5))); bb2->add( std::make_unique< ZBinaryOperation >(x, BinaryOperator::Add, t0, t1)); bb2->add(std::make_unique< ZBinaryOperation >(temp4, BinaryOperator::Add, temp4, tmp3)); bb2->add(std::make_unique< ZBinaryOperation >(temp5, BinaryOperator::Add, temp5, cst_4)); bb2->add( std::make_unique< ZBinaryOperation >(k, BinaryOperator::Add, k, cst_1)); pre_bb3_bb4->add(std::make_unique< ZLinearAssertion >(ZVarExpr(k) >= 1000)); bb4->add(std::make_unique< ZBinaryOperation >(temp2, BinaryOperator::Add, temp2, cst_400)); bb4->add(std::make_unique< ZBinaryOperation >(temp3, BinaryOperator::Add, temp3, i)); bb4->add( std::make_unique< ZBinaryOperation >(j, BinaryOperator::Add, j, cst_1)); pre_bb7_bb8->add(std::make_unique< ZLinearAssertion >(ZVarExpr(i) >= 100)); ret->add(std::make_unique< CheckPoint >("end")); // cfg.dump(std::cout); muzq::FixpointIterator< Variable, ZIntervalDomain, QIntervalDomain > fixpoint( cfg); fixpoint.run({ZIntervalDomain::top(), QIntervalDomain::top()}); // fixpoint.dump(std::cout); ZIntervalDomain end = fixpoint.checkpoint("end").first(); BOOST_CHECK(end.to_interval(tmp0) == ZInterval(5)); BOOST_CHECK(end.to_interval(i) == ZInterval(100)); BOOST_CHECK(end.to_interval(temp1) == ZInterval(ZBound(5), ZBound::plus_infinity())); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/fixpoint/000077500000000000000000000000001473507761200213445ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/fixpoint/wpo.cpp000066400000000000000000000143531473507761200226630ustar00rootroot00000000000000/******************************************************************************* * * Tests for WPO * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_wpo #define BOOST_TEST_DYN_LINK #include #include #include #include #include using Variable = ikos::core::example::VariableFactory::VariableRef; using BasicBlock = ikos::core::muzq::BasicBlock< Variable >; using ControlFlowGraph = ikos::core::muzq::ControlFlowGraph< Variable >; using Wpo = ikos::core::Wpo< ControlFlowGraph* >; BOOST_AUTO_TEST_CASE(test1) { // Control flow graph from Figure 2 of "Deterministic Parallel Fixpoint // Computation", in POPL 2020. ControlFlowGraph cfg("bb1"); BasicBlock* bb1 = cfg.get("bb1"); BasicBlock* bb2 = cfg.get("bb2"); BasicBlock* bb3 = cfg.get("bb3"); BasicBlock* bb4 = cfg.get("bb4"); BasicBlock* bb5 = cfg.get("bb5"); BasicBlock* bb6 = cfg.get("bb6"); BasicBlock* bb7 = cfg.get("bb7"); BasicBlock* bb8 = cfg.get("bb8"); BasicBlock* bb9 = cfg.get("bb9"); BasicBlock* bb10 = cfg.get("bb10"); bb1->add_successor(bb2); bb2->add_successor(bb3); bb2->add_successor(bb6); bb2->add_successor(bb10); bb3->add_successor(bb4); bb3->add_successor(bb5); bb4->add_successor(bb3); bb5->add_successor(bb2); bb6->add_successor(bb5); bb6->add_successor(bb7); bb6->add_successor(bb9); bb7->add_successor(bb8); bb8->add_successor(bb6); bb9->add_successor(bb8); Wpo wpo(&cfg); // wpo.dump(std::cout); BOOST_CHECK(wpo.size() == 13); BOOST_CHECK(wpo.entry() == 12); BOOST_CHECK(wpo.node(12) == bb1); BOOST_CHECK(wpo.is_plain(12)); BOOST_CHECK(wpo.successors(12) == std::vector< std::size_t >({11})); BOOST_CHECK(wpo.predecessors(12) == std::vector< std::size_t >()); BOOST_CHECK(wpo.node(11) == bb2); BOOST_CHECK(wpo.is_head(11)); BOOST_CHECK(wpo.successors(11) == std::vector< std::size_t >({5, 9})); BOOST_CHECK(wpo.predecessors(11) == std::vector< std::size_t >({12})); BOOST_CHECK(wpo.node(10) == bb2); BOOST_CHECK(wpo.is_exit(10)); BOOST_CHECK(wpo.successors(10) == std::vector< std::size_t >({0})); BOOST_CHECK(wpo.predecessors(10) == std::vector< std::size_t >({6})); BOOST_CHECK(wpo.node(9) == bb3); BOOST_CHECK(wpo.is_head(9)); BOOST_CHECK(wpo.successors(9) == std::vector< std::size_t >({7})); BOOST_CHECK(wpo.predecessors(9) == std::vector< std::size_t >({11})); BOOST_CHECK(wpo.node(8) == bb3); BOOST_CHECK(wpo.is_exit(8)); BOOST_CHECK(wpo.successors(8) == std::vector< std::size_t >({6})); BOOST_CHECK(wpo.predecessors(8) == std::vector< std::size_t >({7})); BOOST_CHECK(wpo.node(7) == bb4); BOOST_CHECK(wpo.is_plain(7)); BOOST_CHECK(wpo.successors(7) == std::vector< std::size_t >({8})); BOOST_CHECK(wpo.predecessors(7) == std::vector< std::size_t >({9})); BOOST_CHECK(wpo.node(6) == bb5); BOOST_CHECK(wpo.is_plain(6)); BOOST_CHECK(wpo.successors(6) == std::vector< std::size_t >({10})); BOOST_CHECK(wpo.predecessors(6) == std::vector< std::size_t >({8, 4})); BOOST_CHECK(wpo.node(5) == bb6); BOOST_CHECK(wpo.is_head(5)); BOOST_CHECK(wpo.successors(5) == std::vector< std::size_t >({1, 3})); BOOST_CHECK(wpo.predecessors(5) == std::vector< std::size_t >({11})); BOOST_CHECK(wpo.node(4) == bb6); BOOST_CHECK(wpo.is_exit(4)); BOOST_CHECK(wpo.successors(4) == std::vector< std::size_t >({6})); BOOST_CHECK(wpo.predecessors(4) == std::vector< std::size_t >({2})); BOOST_CHECK(wpo.node(3) == bb7); BOOST_CHECK(wpo.is_plain(3)); BOOST_CHECK(wpo.successors(3) == std::vector< std::size_t >({2})); BOOST_CHECK(wpo.predecessors(3) == std::vector< std::size_t >({5})); BOOST_CHECK(wpo.node(2) == bb8); BOOST_CHECK(wpo.is_plain(2)); BOOST_CHECK(wpo.successors(2) == std::vector< std::size_t >({4})); BOOST_CHECK(wpo.predecessors(2) == std::vector< std::size_t >({3, 1})); BOOST_CHECK(wpo.node(1) == bb9); BOOST_CHECK(wpo.is_plain(1)); BOOST_CHECK(wpo.successors(1) == std::vector< std::size_t >({2})); BOOST_CHECK(wpo.predecessors(1) == std::vector< std::size_t >({5})); BOOST_CHECK(wpo.node(0) == bb10); BOOST_CHECK(wpo.is_plain(0)); BOOST_CHECK(wpo.successors(0) == std::vector< std::size_t >()); BOOST_CHECK(wpo.predecessors(0) == std::vector< std::size_t >({10})); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/number/000077500000000000000000000000001473507761200207745ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/number/machine_int.cpp000066400000000000000000003273111473507761200237650ustar00rootroot00000000000000/******************************************************************************* * * Tests for MachineInt * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_integer #define BOOST_TEST_DYN_LINK #include #include #include using Int = ikos::core::MachineInt; using ikos::core::Signed; using ikos::core::Unsigned; BOOST_AUTO_TEST_CASE(test_constructor_signed) { BOOST_CHECK(Int(0, 4, Signed) == Int(0, 4, Signed)); BOOST_CHECK(Int(1, 4, Signed) == Int(1, 4, Signed)); BOOST_CHECK(Int(7, 4, Signed) == Int(7, 4, Signed)); BOOST_CHECK(Int(8, 4, Signed) == Int(-8, 4, Signed)); BOOST_CHECK(Int(9, 4, Signed) == Int(-7, 4, Signed)); BOOST_CHECK(Int(15, 4, Signed) == Int(-1, 4, Signed)); BOOST_CHECK(Int(16, 4, Signed) == Int(0, 4, Signed)); BOOST_CHECK(Int(17, 4, Signed) == Int(1, 4, Signed)); BOOST_CHECK(Int(-1, 4, Signed) == Int(-1, 4, Signed)); BOOST_CHECK(Int(-8, 4, Signed) == Int(-8, 4, Signed)); BOOST_CHECK(Int(-9, 4, Signed) == Int(7, 4, Signed)); BOOST_CHECK(Int(-15, 4, Signed) == Int(1, 4, Signed)); BOOST_CHECK(Int(-16, 4, Signed) == Int(0, 4, Signed)); BOOST_CHECK(Int(-17, 4, Signed) == Int(-1, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_constructor_unsigned) { BOOST_CHECK(Int(0, 4, Unsigned) == Int(0, 4, Unsigned)); BOOST_CHECK(Int(1, 4, Unsigned) == Int(1, 4, Unsigned)); BOOST_CHECK(Int(7, 4, Unsigned) == Int(7, 4, Unsigned)); BOOST_CHECK(Int(8, 4, Unsigned) == Int(8, 4, Unsigned)); BOOST_CHECK(Int(9, 4, Unsigned) == Int(9, 4, Unsigned)); BOOST_CHECK(Int(15, 4, Unsigned) == Int(15, 4, Unsigned)); BOOST_CHECK(Int(16, 4, Unsigned) == Int(0, 4, Unsigned)); BOOST_CHECK(Int(17, 4, Unsigned) == Int(1, 4, Unsigned)); BOOST_CHECK(Int(-1, 4, Unsigned) == Int(15, 4, Unsigned)); BOOST_CHECK(Int(-8, 4, Unsigned) == Int(8, 4, Unsigned)); BOOST_CHECK(Int(-9, 4, Unsigned) == Int(7, 4, Unsigned)); BOOST_CHECK(Int(-15, 4, Unsigned) == Int(1, 4, Unsigned)); BOOST_CHECK(Int(-16, 4, Unsigned) == Int(0, 4, Unsigned)); BOOST_CHECK(Int(-17, 4, Unsigned) == Int(15, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_min) { BOOST_CHECK(Int::min(1, Signed) == Int(-1, 1, Signed)); BOOST_CHECK(Int::min(4, Signed) == Int(-8, 4, Signed)); BOOST_CHECK(Int::min(8, Signed) == Int(-128, 8, Signed)); BOOST_CHECK(Int::min(1, Unsigned) == Int(0, 1, Unsigned)); BOOST_CHECK(Int::min(4, Unsigned) == Int(0, 4, Unsigned)); BOOST_CHECK(Int::min(8, Unsigned) == Int(0, 8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_max) { BOOST_CHECK(Int::max(1, Signed) == Int(0, 1, Signed)); BOOST_CHECK(Int::max(4, Signed) == Int(7, 4, Signed)); BOOST_CHECK(Int::max(8, Signed) == Int(127, 8, Signed)); BOOST_CHECK(Int::max(1, Unsigned) == Int(1, 1, Unsigned)); BOOST_CHECK(Int::max(4, Unsigned) == Int(15, 4, Unsigned)); BOOST_CHECK(Int::max(8, Unsigned) == Int(255, 8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_zero) { BOOST_CHECK(Int::zero(1, Signed) == Int(0, 1, Signed)); BOOST_CHECK(Int::zero(4, Signed) == Int(0, 4, Signed)); BOOST_CHECK(Int::zero(8, Signed) == Int(0, 8, Signed)); BOOST_CHECK(Int::zero(1, Unsigned) == Int(0, 1, Unsigned)); BOOST_CHECK(Int::zero(4, Unsigned) == Int(0, 4, Unsigned)); BOOST_CHECK(Int::zero(8, Unsigned) == Int(0, 8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_all_ones_constructor) { BOOST_CHECK(Int::all_ones(1, Signed) == Int(-1, 1, Signed)); BOOST_CHECK(Int::all_ones(4, Signed) == Int(-1, 4, Signed)); BOOST_CHECK(Int::all_ones(8, Signed) == Int(-1, 8, Signed)); BOOST_CHECK(Int::all_ones(1, Unsigned) == Int(1, 1, Unsigned)); BOOST_CHECK(Int::all_ones(4, Unsigned) == Int(15, 4, Unsigned)); BOOST_CHECK(Int::all_ones(8, Unsigned) == Int(255, 8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_assign_add_signed) { BOOST_CHECK((Int(0, 4, Signed) += Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) += Int(1, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) += Int(1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) += Int(1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) += Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) += Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) += Int(-1, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) += Int(-1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) += Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) += Int(7, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) += Int(7, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) += Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) += Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) += Int(-8, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) += Int(-8, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) += Int(-8, 4, Signed)) == Int(0, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_assign_add_unsigned) { BOOST_CHECK((Int(0, 4, Unsigned) += Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) += Int(1, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) += Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(0, 4, Unsigned) += Int(15, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) += Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) += Int(15, 4, Unsigned)) == Int(14, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_assign_sub_signed) { BOOST_CHECK((Int(0, 4, Signed) -= Int(1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) -= Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) -= Int(1, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) -= Int(1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) -= Int(-1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) -= Int(-1, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) -= Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) -= Int(-1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) -= Int(7, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) -= Int(7, 4, Signed)) == Int(-6, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) -= Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) -= Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) -= Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) -= Int(-8, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) -= Int(-8, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) -= Int(-8, 4, Signed)) == Int(0, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_assign_sub_unsigned) { BOOST_CHECK((Int(0, 4, Unsigned) -= Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) -= Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) -= Int(1, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK((Int(0, 4, Unsigned) -= Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) -= Int(15, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) -= Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_assign_mul_signed) { BOOST_CHECK((Int(0, 4, Signed) *= Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) *= Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) *= Int(1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) *= Int(1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) *= Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) *= Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) *= Int(-1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) *= Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) *= Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) *= Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) *= Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) *= Int(7, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) *= Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) *= Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) *= Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) *= Int(-8, 4, Signed)) == Int(0, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_assign_mul_unsigned) { BOOST_CHECK((Int(0, 4, Unsigned) *= Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) *= Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) *= Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((Int(0, 4, Unsigned) *= Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) *= Int(15, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) *= Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(3, 4, Unsigned) *= Int(4, 4, Unsigned)) == Int(12, 4, Unsigned)); BOOST_CHECK((Int(4, 4, Unsigned) *= Int(4, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_assign_div_signed) { BOOST_CHECK((Int(0, 4, Signed) /= Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) /= Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) /= Int(1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) /= Int(1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) /= Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) /= Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) /= Int(-1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) /= Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) /= Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) /= Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) /= Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) /= Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) /= Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) /= Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) /= Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) /= Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(4, 4, Signed) /= Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK((Int(5, 4, Signed) /= Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK((Int(-4, 4, Signed) /= Int(2, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK((Int(-5, 4, Signed) /= Int(2, 4, Signed)) == Int(-2, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_assign_div_unsigned) { BOOST_CHECK((Int(0, 4, Unsigned) /= Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) /= Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) /= Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((Int(0, 4, Unsigned) /= Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) /= Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) /= Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(3, 4, Unsigned) /= Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(4, 4, Unsigned) /= Int(2, 4, Unsigned)) == Int(2, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_assign_rem_signed) { BOOST_CHECK((Int(0, 4, Signed) %= Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) %= Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) %= Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) %= Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) %= Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) %= Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) %= Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) %= Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) %= Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) %= Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) %= Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) %= Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((Int(0, 4, Signed) %= Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(1, 4, Signed) %= Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(7, 4, Signed) %= Int(-8, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((Int(-8, 4, Signed) %= Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(4, 4, Signed) %= Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(5, 4, Signed) %= Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((Int(-4, 4, Signed) %= Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((Int(-5, 4, Signed) %= Int(2, 4, Signed)) == Int(-1, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_assign_rem_unsigned) { BOOST_CHECK((Int(0, 4, Unsigned) %= Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) %= Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) %= Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(0, 4, Unsigned) %= Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(1, 4, Unsigned) %= Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(15, 4, Unsigned) %= Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((Int(3, 4, Unsigned) %= Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((Int(4, 4, Unsigned) %= Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_bit_width) { BOOST_CHECK(Int(0, 4, Signed).bit_width() == 4); BOOST_CHECK(Int(0, 4, Unsigned).bit_width() == 4); BOOST_CHECK(Int(0, 8, Signed).bit_width() == 8); BOOST_CHECK(Int(0, 8, Unsigned).bit_width() == 8); } BOOST_AUTO_TEST_CASE(test_sign) { BOOST_CHECK(Int(0, 4, Signed).sign() == Signed); BOOST_CHECK(Int(0, 4, Unsigned).sign() == Unsigned); BOOST_CHECK(Int(0, 8, Signed).sign() == Signed); BOOST_CHECK(Int(0, 8, Unsigned).sign() == Unsigned); } BOOST_AUTO_TEST_CASE(test_is_min) { BOOST_CHECK(!Int(0, 4, Signed).is_min()); BOOST_CHECK(!Int(7, 4, Signed).is_min()); BOOST_CHECK(Int(-8, 4, Signed).is_min()); BOOST_CHECK(Int(0, 4, Unsigned).is_min()); BOOST_CHECK(!Int(1, 4, Unsigned).is_min()); BOOST_CHECK(!Int(15, 4, Unsigned).is_min()); } BOOST_AUTO_TEST_CASE(test_is_max) { BOOST_CHECK(!Int(0, 4, Signed).is_max()); BOOST_CHECK(Int(7, 4, Signed).is_max()); BOOST_CHECK(!Int(-8, 4, Signed).is_max()); BOOST_CHECK(!Int(0, 4, Unsigned).is_max()); BOOST_CHECK(!Int(1, 4, Unsigned).is_max()); BOOST_CHECK(Int(15, 4, Unsigned).is_max()); } BOOST_AUTO_TEST_CASE(test_is_zero) { BOOST_CHECK(Int(0, 4, Signed).is_zero()); BOOST_CHECK(!Int(7, 4, Signed).is_zero()); BOOST_CHECK(!Int(-8, 4, Signed).is_zero()); BOOST_CHECK(Int(0, 4, Unsigned).is_zero()); BOOST_CHECK(!Int(1, 4, Unsigned).is_zero()); BOOST_CHECK(!Int(15, 4, Unsigned).is_zero()); } BOOST_AUTO_TEST_CASE(test_high_bit) { BOOST_CHECK(!Int(0, 4, Signed).high_bit()); BOOST_CHECK(!Int(7, 4, Signed).high_bit()); BOOST_CHECK(Int(-1, 4, Signed).high_bit()); BOOST_CHECK(Int(-8, 4, Signed).high_bit()); BOOST_CHECK(!Int(0, 4, Unsigned).high_bit()); BOOST_CHECK(!Int(1, 4, Unsigned).high_bit()); BOOST_CHECK(Int(8, 4, Unsigned).high_bit()); BOOST_CHECK(Int(15, 4, Unsigned).high_bit()); } BOOST_AUTO_TEST_CASE(test_is_negative) { BOOST_CHECK(!Int(0, 4, Signed).is_negative()); BOOST_CHECK(!Int(7, 4, Signed).is_negative()); BOOST_CHECK(Int(-1, 4, Signed).is_negative()); BOOST_CHECK(Int(-8, 4, Signed).is_negative()); BOOST_CHECK(!Int(0, 4, Unsigned).is_negative()); BOOST_CHECK(!Int(1, 4, Unsigned).is_negative()); BOOST_CHECK(!Int(15, 4, Unsigned).is_negative()); } BOOST_AUTO_TEST_CASE(test_is_non_negative) { BOOST_CHECK(Int(0, 4, Signed).is_non_negative()); BOOST_CHECK(Int(7, 4, Signed).is_non_negative()); BOOST_CHECK(!Int(-1, 4, Signed).is_non_negative()); BOOST_CHECK(!Int(-8, 4, Signed).is_non_negative()); BOOST_CHECK(Int(0, 4, Unsigned).is_non_negative()); BOOST_CHECK(Int(1, 4, Unsigned).is_non_negative()); BOOST_CHECK(Int(15, 4, Unsigned).is_non_negative()); } BOOST_AUTO_TEST_CASE(test_is_strictly_positive) { BOOST_CHECK(!Int(0, 4, Signed).is_strictly_positive()); BOOST_CHECK(Int(7, 4, Signed).is_strictly_positive()); BOOST_CHECK(!Int(-1, 4, Signed).is_strictly_positive()); BOOST_CHECK(!Int(-8, 4, Signed).is_strictly_positive()); BOOST_CHECK(!Int(0, 4, Unsigned).is_strictly_positive()); BOOST_CHECK(Int(1, 4, Unsigned).is_strictly_positive()); BOOST_CHECK(Int(15, 4, Unsigned).is_strictly_positive()); } BOOST_AUTO_TEST_CASE(test_all_ones_method) { BOOST_CHECK(!Int(0, 4, Signed).all_ones()); BOOST_CHECK(!Int(7, 4, Signed).all_ones()); BOOST_CHECK(Int(-1, 4, Signed).all_ones()); BOOST_CHECK(!Int(-8, 4, Signed).all_ones()); BOOST_CHECK(!Int(0, 4, Unsigned).all_ones()); BOOST_CHECK(!Int(1, 4, Unsigned).all_ones()); BOOST_CHECK(!Int(8, 4, Unsigned).all_ones()); BOOST_CHECK(Int(15, 4, Unsigned).all_ones()); } BOOST_AUTO_TEST_CASE(test_leading_zeros) { BOOST_CHECK(Int(0, 4, Signed).leading_zeros() == 4); BOOST_CHECK(Int(1, 4, Signed).leading_zeros() == 3); BOOST_CHECK(Int(7, 4, Signed).leading_zeros() == 1); BOOST_CHECK(Int(-1, 4, Signed).leading_zeros() == 0); BOOST_CHECK(Int(-2, 4, Signed).leading_zeros() == 0); BOOST_CHECK(Int(-8, 4, Signed).leading_zeros() == 0); BOOST_CHECK(Int(0, 4, Unsigned).leading_zeros() == 4); BOOST_CHECK(Int(1, 4, Unsigned).leading_zeros() == 3); BOOST_CHECK(Int(3, 4, Unsigned).leading_zeros() == 2); BOOST_CHECK(Int(8, 4, Unsigned).leading_zeros() == 0); BOOST_CHECK(Int(15, 4, Unsigned).leading_zeros() == 0); } BOOST_AUTO_TEST_CASE(test_leading_ones) { BOOST_CHECK(Int(0, 4, Signed).leading_ones() == 0); BOOST_CHECK(Int(1, 4, Signed).leading_ones() == 0); BOOST_CHECK(Int(7, 4, Signed).leading_ones() == 0); BOOST_CHECK(Int(-1, 4, Signed).leading_ones() == 4); BOOST_CHECK(Int(-2, 4, Signed).leading_ones() == 3); BOOST_CHECK(Int(-8, 4, Signed).leading_ones() == 1); BOOST_CHECK(Int(0, 4, Unsigned).leading_ones() == 0); BOOST_CHECK(Int(1, 4, Unsigned).leading_ones() == 0); BOOST_CHECK(Int(3, 4, Unsigned).leading_ones() == 0); BOOST_CHECK(Int(8, 4, Unsigned).leading_ones() == 1); BOOST_CHECK(Int(15, 4, Unsigned).leading_ones() == 4); } BOOST_AUTO_TEST_CASE(test_to_z_number) { BOOST_CHECK(Int(0, 4, Signed).to_z_number() == 0); BOOST_CHECK(Int(7, 4, Signed).to_z_number() == 7); BOOST_CHECK(Int(23, 4, Signed).to_z_number() == 7); BOOST_CHECK(Int(-8, 4, Signed).to_z_number() == -8); BOOST_CHECK(Int(-24, 4, Signed).to_z_number() == -8); BOOST_CHECK(Int(8, 4, Signed).to_z_number() == -8); BOOST_CHECK(Int(-9, 4, Signed).to_z_number() == 7); BOOST_CHECK(Int(0, 4, Unsigned).to_z_number() == 0); BOOST_CHECK(Int(15, 4, Unsigned).to_z_number() == 15); BOOST_CHECK(Int(31, 4, Unsigned).to_z_number() == 15); BOOST_CHECK(Int(16, 4, Unsigned).to_z_number() == 0); } BOOST_AUTO_TEST_CASE(test_fits) { BOOST_CHECK(Int(0, 32, Signed).fits< int32_t >()); BOOST_CHECK(Int(1, 32, Signed).fits< int32_t >()); BOOST_CHECK(Int(-1, 32, Signed).fits< int32_t >()); BOOST_CHECK(Int::max(32, Signed).fits< int32_t >()); BOOST_CHECK(Int::min(32, Signed).fits< int32_t >()); BOOST_CHECK(Int(0, 32, Signed).fits< uint32_t >()); BOOST_CHECK(Int(1, 32, Signed).fits< uint32_t >()); BOOST_CHECK(!Int(-1, 32, Signed).fits< uint32_t >()); BOOST_CHECK(Int::max(32, Signed).fits< uint32_t >()); BOOST_CHECK(!Int::min(32, Signed).fits< uint32_t >()); BOOST_CHECK(Int(0, 32, Signed).fits< int64_t >()); BOOST_CHECK(Int(1, 32, Signed).fits< int64_t >()); BOOST_CHECK(Int(-1, 32, Signed).fits< int64_t >()); BOOST_CHECK(Int::max(32, Signed).fits< int64_t >()); BOOST_CHECK(Int::min(32, Signed).fits< int64_t >()); BOOST_CHECK(Int(0, 32, Signed).fits< uint64_t >()); BOOST_CHECK(Int(1, 32, Signed).fits< uint64_t >()); BOOST_CHECK(!Int(-1, 32, Signed).fits< uint64_t >()); BOOST_CHECK(Int::max(32, Signed).fits< uint64_t >()); BOOST_CHECK(!Int::min(32, Signed).fits< uint64_t >()); BOOST_CHECK(Int(0, 64, Signed).fits< int32_t >()); BOOST_CHECK(Int(1, 64, Signed).fits< int32_t >()); BOOST_CHECK(Int(-1, 64, Signed).fits< int32_t >()); BOOST_CHECK(!Int::max(64, Signed).fits< int32_t >()); BOOST_CHECK(!Int::min(64, Signed).fits< int32_t >()); BOOST_CHECK(Int(0, 64, Signed).fits< uint32_t >()); BOOST_CHECK(Int(1, 64, Signed).fits< uint32_t >()); BOOST_CHECK(!Int(-1, 64, Signed).fits< uint32_t >()); BOOST_CHECK(!Int::max(64, Signed).fits< uint32_t >()); BOOST_CHECK(!Int::min(64, Signed).fits< uint32_t >()); BOOST_CHECK(Int(0, 64, Signed).fits< int64_t >()); BOOST_CHECK(Int(1, 64, Signed).fits< int64_t >()); BOOST_CHECK(Int(-1, 64, Signed).fits< int64_t >()); BOOST_CHECK(Int::max(64, Signed).fits< int64_t >()); BOOST_CHECK(Int::min(64, Signed).fits< int64_t >()); BOOST_CHECK(Int(0, 64, Signed).fits< uint64_t >()); BOOST_CHECK(Int(1, 64, Signed).fits< uint64_t >()); BOOST_CHECK(!Int(-1, 64, Signed).fits< uint64_t >()); BOOST_CHECK(Int::max(64, Signed).fits< uint64_t >()); BOOST_CHECK(!Int::min(64, Signed).fits< uint64_t >()); BOOST_CHECK(Int(0, 32, Unsigned).fits< int32_t >()); BOOST_CHECK(Int(1, 32, Unsigned).fits< int32_t >()); BOOST_CHECK(!Int::max(32, Unsigned).fits< int32_t >()); BOOST_CHECK(Int(0, 32, Unsigned).fits< uint32_t >()); BOOST_CHECK(Int(1, 32, Unsigned).fits< uint32_t >()); BOOST_CHECK(Int::max(32, Unsigned).fits< uint32_t >()); BOOST_CHECK(Int(0, 64, Unsigned).fits< int32_t >()); BOOST_CHECK(Int(1, 64, Unsigned).fits< int32_t >()); BOOST_CHECK(!Int::max(64, Unsigned).fits< int32_t >()); BOOST_CHECK(Int(0, 64, Unsigned).fits< uint32_t >()); BOOST_CHECK(Int(1, 64, Unsigned).fits< uint32_t >()); BOOST_CHECK(!Int::max(64, Unsigned).fits< uint32_t >()); BOOST_CHECK(Int(0, 64, Unsigned).fits< int64_t >()); BOOST_CHECK(Int(1, 64, Unsigned).fits< int64_t >()); BOOST_CHECK(!Int::max(64, Unsigned).fits< int64_t >()); BOOST_CHECK(Int(0, 64, Unsigned).fits< uint64_t >()); BOOST_CHECK(Int(1, 64, Unsigned).fits< uint64_t >()); BOOST_CHECK(Int::max(64, Unsigned).fits< uint64_t >()); } BOOST_AUTO_TEST_CASE(test_to) { BOOST_CHECK(Int(0, 32, Signed).to< int32_t >() == int32_t(0)); BOOST_CHECK(Int(1, 32, Signed).to< int32_t >() == int32_t(1)); BOOST_CHECK(Int(-1, 32, Signed).to< int32_t >() == int32_t(-1)); BOOST_CHECK(Int::max(32, Signed).to< int32_t >() == std::numeric_limits< int32_t >::max()); BOOST_CHECK(Int::min(32, Signed).to< int32_t >() == std::numeric_limits< int32_t >::min()); BOOST_CHECK(Int(0, 32, Signed).to< uint32_t >() == uint32_t(0)); BOOST_CHECK(Int(1, 32, Signed).to< uint32_t >() == uint32_t(1)); BOOST_CHECK(Int::max(32, Signed).to< uint32_t >() == uint32_t(std::numeric_limits< int32_t >::max())); BOOST_CHECK(Int(0, 32, Signed).to< int64_t >() == int64_t(0)); BOOST_CHECK(Int(1, 32, Signed).to< int64_t >() == int64_t(1)); BOOST_CHECK(Int(-1, 32, Signed).to< int64_t >() == int64_t(-1)); BOOST_CHECK(Int::max(32, Signed).to< int64_t >() == int64_t(std::numeric_limits< int32_t >::max())); BOOST_CHECK(Int::min(32, Signed).to< int64_t >() == int64_t(std::numeric_limits< int32_t >::min())); BOOST_CHECK(Int(0, 32, Signed).to< uint64_t >() == uint64_t(0)); BOOST_CHECK(Int(1, 32, Signed).to< uint64_t >() == uint64_t(1)); BOOST_CHECK(Int::max(32, Signed).to< uint64_t >() == uint64_t(std::numeric_limits< int32_t >::max())); BOOST_CHECK(Int(0, 64, Signed).to< int32_t >() == int32_t(0)); BOOST_CHECK(Int(1, 64, Signed).to< int32_t >() == int32_t(1)); BOOST_CHECK(Int(-1, 64, Signed).to< int32_t >() == int32_t(-1)); BOOST_CHECK(Int(0, 64, Signed).to< uint32_t >() == uint32_t(0)); BOOST_CHECK(Int(1, 64, Signed).to< uint32_t >() == uint32_t(1)); BOOST_CHECK(Int(0, 64, Signed).to< int64_t >() == int64_t(0)); BOOST_CHECK(Int(1, 64, Signed).to< int64_t >() == int64_t(1)); BOOST_CHECK(Int::max(64, Signed).to< int64_t >() == std::numeric_limits< int64_t >::max()); BOOST_CHECK(Int::min(64, Signed).to< int64_t >() == std::numeric_limits< int64_t >::min()); BOOST_CHECK(Int(0, 64, Signed).to< uint64_t >() == uint64_t(0)); BOOST_CHECK(Int(1, 64, Signed).to< uint64_t >() == uint64_t(1)); BOOST_CHECK(Int::max(64, Signed).to< uint64_t >() == uint64_t(std::numeric_limits< int64_t >::max())); BOOST_CHECK(Int(0, 32, Unsigned).to< int32_t >() == int32_t(0)); BOOST_CHECK(Int(1, 32, Unsigned).to< int32_t >() == int32_t(1)); BOOST_CHECK(Int(0, 32, Unsigned).to< uint32_t >() == uint32_t(0)); BOOST_CHECK(Int(1, 32, Unsigned).to< uint32_t >() == uint32_t(1)); BOOST_CHECK(Int::max(32, Unsigned).to< uint32_t >() == std::numeric_limits< uint32_t >::max()); BOOST_CHECK(Int(0, 64, Unsigned).to< int32_t >() == int32_t(0)); BOOST_CHECK(Int(1, 64, Unsigned).to< int32_t >() == int32_t(1)); BOOST_CHECK(Int(0, 64, Unsigned).to< uint32_t >() == uint32_t(0)); BOOST_CHECK(Int(1, 64, Unsigned).to< uint32_t >() == uint32_t(1)); BOOST_CHECK(Int(0, 64, Unsigned).to< int64_t >() == int64_t(0)); BOOST_CHECK(Int(1, 64, Unsigned).to< int64_t >() == int64_t(1)); BOOST_CHECK(Int(0, 64, Unsigned).to< uint64_t >() == uint64_t(0)); BOOST_CHECK(Int(1, 64, Unsigned).to< uint64_t >() == uint64_t(1)); BOOST_CHECK(Int::max(64, Unsigned).to< uint64_t >() == std::numeric_limits< uint64_t >::max()); } BOOST_AUTO_TEST_CASE(test_set_min) { Int n = Int(1, 4, Signed); n.set_min(); BOOST_CHECK(n.is_min()); n = Int(1, 4, Unsigned); n.set_min(); BOOST_CHECK(n.is_min()); } BOOST_AUTO_TEST_CASE(test_set_max) { Int n = Int(1, 4, Signed); n.set_max(); BOOST_CHECK(n.is_max()); n = Int(1, 4, Unsigned); n.set_max(); BOOST_CHECK(n.is_max()); } BOOST_AUTO_TEST_CASE(test_set_zero) { Int n = Int(1, 4, Signed); n.set_zero(); BOOST_CHECK(n.is_zero()); n = Int(1, 4, Unsigned); n.set_zero(); BOOST_CHECK(n.is_zero()); } BOOST_AUTO_TEST_CASE(test_incr_signed) { BOOST_CHECK((++Int(0, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK((++Int(1, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK((++Int(7, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((++Int(-8, 4, Signed)) == Int(-7, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_incr_unsigned) { BOOST_CHECK((++Int(0, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((++Int(1, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK((++Int(14, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((++Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_decr_signed) { BOOST_CHECK((--Int(0, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((--Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((--Int(7, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK((--Int(-8, 4, Signed)) == Int(7, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_decr_unsigned) { BOOST_CHECK((--Int(0, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((--Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((--Int(14, 4, Unsigned)) == Int(13, 4, Unsigned)); BOOST_CHECK((--Int(15, 4, Unsigned)) == Int(14, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_minus_signed) { BOOST_CHECK((-Int(0, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK((-Int(1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((-Int(7, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK((-Int(-7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK((-Int(-8, 4, Signed)) == Int(-8, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_minus_unsigned) { BOOST_CHECK((-Int(0, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK((-Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((-Int(14, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK((-Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_not_signed) { BOOST_CHECK((~Int(0, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK((~Int(1, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK((~Int(7, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK((~Int(-7, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK((~Int(-8, 4, Signed)) == Int(7, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_not_unsigned) { BOOST_CHECK((~Int(0, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK((~Int(1, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK((~Int(14, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK((~Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_trunc_signed) { BOOST_CHECK(Int(0, 4, Signed).trunc(3) == Int(0, 3, Signed)); BOOST_CHECK(Int(1, 4, Signed).trunc(3) == Int(1, 3, Signed)); BOOST_CHECK(Int(2, 4, Signed).trunc(3) == Int(2, 3, Signed)); BOOST_CHECK(Int(7, 4, Signed).trunc(3) == Int(-1, 3, Signed)); BOOST_CHECK(Int(-8, 4, Signed).trunc(3) == Int(0, 3, Signed)); BOOST_CHECK(Int(0, 4, Signed).trunc(2) == Int(0, 2, Signed)); BOOST_CHECK(Int(1, 4, Signed).trunc(2) == Int(1, 2, Signed)); BOOST_CHECK(Int(2, 4, Signed).trunc(2) == Int(-2, 2, Signed)); BOOST_CHECK(Int(7, 4, Signed).trunc(2) == Int(-1, 2, Signed)); BOOST_CHECK(Int(-8, 4, Signed).trunc(2) == Int(0, 2, Signed)); BOOST_CHECK(Int(0, 4, Signed).trunc(1) == Int(0, 1, Signed)); BOOST_CHECK(Int(1, 4, Signed).trunc(1) == Int(-1, 1, Signed)); BOOST_CHECK(Int(2, 4, Signed).trunc(1) == Int(0, 1, Signed)); BOOST_CHECK(Int(7, 4, Signed).trunc(1) == Int(-1, 1, Signed)); BOOST_CHECK(Int(-8, 4, Signed).trunc(1) == Int(0, 1, Signed)); } BOOST_AUTO_TEST_CASE(test_trunc_unsigned) { BOOST_CHECK(Int(0, 4, Unsigned).trunc(3) == Int(0, 3, Unsigned)); BOOST_CHECK(Int(1, 4, Unsigned).trunc(3) == Int(1, 3, Unsigned)); BOOST_CHECK(Int(2, 4, Unsigned).trunc(3) == Int(2, 3, Unsigned)); BOOST_CHECK(Int(14, 4, Unsigned).trunc(3) == Int(6, 3, Unsigned)); BOOST_CHECK(Int(15, 4, Unsigned).trunc(3) == Int(7, 3, Unsigned)); BOOST_CHECK(Int(0, 4, Unsigned).trunc(2) == Int(0, 2, Unsigned)); BOOST_CHECK(Int(1, 4, Unsigned).trunc(2) == Int(1, 2, Unsigned)); BOOST_CHECK(Int(2, 4, Unsigned).trunc(2) == Int(2, 2, Unsigned)); BOOST_CHECK(Int(14, 4, Unsigned).trunc(2) == Int(2, 2, Unsigned)); BOOST_CHECK(Int(15, 4, Unsigned).trunc(2) == Int(3, 2, Unsigned)); BOOST_CHECK(Int(0, 4, Unsigned).trunc(1) == Int(0, 1, Unsigned)); BOOST_CHECK(Int(1, 4, Unsigned).trunc(1) == Int(1, 1, Unsigned)); BOOST_CHECK(Int(2, 4, Unsigned).trunc(1) == Int(0, 1, Unsigned)); BOOST_CHECK(Int(14, 4, Unsigned).trunc(1) == Int(0, 1, Unsigned)); BOOST_CHECK(Int(15, 4, Unsigned).trunc(1) == Int(1, 1, Unsigned)); } BOOST_AUTO_TEST_CASE(test_ext_signed) { BOOST_CHECK(Int(0, 4, Signed).ext(5) == Int(0, 5, Signed)); BOOST_CHECK(Int(1, 4, Signed).ext(5) == Int(1, 5, Signed)); BOOST_CHECK(Int(2, 4, Signed).ext(5) == Int(2, 5, Signed)); BOOST_CHECK(Int(7, 4, Signed).ext(5) == Int(7, 5, Signed)); BOOST_CHECK(Int(-8, 4, Signed).ext(5) == Int(-8, 5, Signed)); BOOST_CHECK(Int(0, 4, Signed).ext(6) == Int(0, 6, Signed)); BOOST_CHECK(Int(1, 4, Signed).ext(6) == Int(1, 6, Signed)); BOOST_CHECK(Int(2, 4, Signed).ext(6) == Int(2, 6, Signed)); BOOST_CHECK(Int(7, 4, Signed).ext(6) == Int(7, 6, Signed)); BOOST_CHECK(Int(-8, 4, Signed).ext(6) == Int(-8, 6, Signed)); } BOOST_AUTO_TEST_CASE(test_ext_unsigned) { BOOST_CHECK(Int(0, 4, Unsigned).ext(5) == Int(0, 5, Unsigned)); BOOST_CHECK(Int(1, 4, Unsigned).ext(5) == Int(1, 5, Unsigned)); BOOST_CHECK(Int(2, 4, Unsigned).ext(5) == Int(2, 5, Unsigned)); BOOST_CHECK(Int(14, 4, Unsigned).ext(5) == Int(14, 5, Unsigned)); BOOST_CHECK(Int(15, 4, Unsigned).ext(5) == Int(15, 5, Unsigned)); BOOST_CHECK(Int(0, 4, Unsigned).ext(6) == Int(0, 6, Unsigned)); BOOST_CHECK(Int(1, 4, Unsigned).ext(6) == Int(1, 6, Unsigned)); BOOST_CHECK(Int(2, 4, Unsigned).ext(6) == Int(2, 6, Unsigned)); BOOST_CHECK(Int(14, 4, Unsigned).ext(6) == Int(14, 6, Unsigned)); BOOST_CHECK(Int(15, 4, Unsigned).ext(6) == Int(15, 6, Unsigned)); } BOOST_AUTO_TEST_CASE(test_sign_cast_signed) { BOOST_CHECK(Int(0, 4, Signed).sign_cast(Unsigned) == Int(0, 4, Unsigned)); BOOST_CHECK(Int(1, 4, Signed).sign_cast(Unsigned) == Int(1, 4, Unsigned)); BOOST_CHECK(Int(2, 4, Signed).sign_cast(Unsigned) == Int(2, 4, Unsigned)); BOOST_CHECK(Int(7, 4, Signed).sign_cast(Unsigned) == Int(7, 4, Unsigned)); BOOST_CHECK(Int(-7, 4, Signed).sign_cast(Unsigned) == Int(9, 4, Unsigned)); BOOST_CHECK(Int(-8, 4, Signed).sign_cast(Unsigned) == Int(8, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_sign_cast_unsigned) { BOOST_CHECK(Int(0, 4, Unsigned).sign_cast(Signed) == Int(0, 4, Signed)); BOOST_CHECK(Int(1, 4, Unsigned).sign_cast(Signed) == Int(1, 4, Signed)); BOOST_CHECK(Int(2, 4, Unsigned).sign_cast(Signed) == Int(2, 4, Signed)); BOOST_CHECK(Int(14, 4, Unsigned).sign_cast(Signed) == Int(-2, 4, Signed)); BOOST_CHECK(Int(15, 4, Unsigned).sign_cast(Signed) == Int(-1, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_cast) { BOOST_CHECK(Int(0, 4, Signed).cast(8, Unsigned) == Int(0, 8, Unsigned)); BOOST_CHECK(Int(1, 4, Signed).cast(8, Unsigned) == Int(1, 8, Unsigned)); BOOST_CHECK(Int(2, 4, Signed).cast(8, Unsigned) == Int(2, 8, Unsigned)); BOOST_CHECK(Int(7, 4, Signed).cast(8, Unsigned) == Int(7, 8, Unsigned)); BOOST_CHECK(Int(-7, 4, Signed).cast(8, Unsigned) == Int(249, 8, Unsigned)); BOOST_CHECK(Int(-8, 4, Signed).cast(8, Unsigned) == Int(248, 8, Unsigned)); BOOST_CHECK(Int(-1, 4, Signed).cast(8, Unsigned) == Int(255, 8, Unsigned)); BOOST_CHECK(Int(0, 4, Unsigned).cast(8, Signed) == Int(0, 8, Signed)); BOOST_CHECK(Int(1, 4, Unsigned).cast(8, Signed) == Int(1, 8, Signed)); BOOST_CHECK(Int(2, 4, Unsigned).cast(8, Signed) == Int(2, 8, Signed)); BOOST_CHECK(Int(14, 4, Unsigned).cast(8, Signed) == Int(14, 8, Signed)); BOOST_CHECK(Int(15, 4, Unsigned).cast(8, Signed) == Int(15, 8, Signed)); BOOST_CHECK(Int(0, 4, Signed).cast(3, Unsigned) == Int(0, 3, Unsigned)); BOOST_CHECK(Int(1, 4, Signed).cast(3, Unsigned) == Int(1, 3, Unsigned)); BOOST_CHECK(Int(2, 4, Signed).cast(3, Unsigned) == Int(2, 3, Unsigned)); BOOST_CHECK(Int(7, 4, Signed).cast(3, Unsigned) == Int(7, 3, Unsigned)); BOOST_CHECK(Int(-8, 4, Signed).cast(3, Unsigned) == Int(0, 3, Unsigned)); BOOST_CHECK(Int(0, 4, Signed).cast(2, Unsigned) == Int(0, 2, Unsigned)); BOOST_CHECK(Int(1, 4, Signed).cast(2, Unsigned) == Int(1, 2, Unsigned)); BOOST_CHECK(Int(2, 4, Signed).cast(2, Unsigned) == Int(2, 2, Unsigned)); BOOST_CHECK(Int(7, 4, Signed).cast(2, Unsigned) == Int(3, 2, Unsigned)); BOOST_CHECK(Int(-8, 4, Signed).cast(2, Unsigned) == Int(0, 2, Unsigned)); BOOST_CHECK(Int(0, 4, Signed).cast(1, Unsigned) == Int(0, 1, Unsigned)); BOOST_CHECK(Int(1, 4, Signed).cast(1, Unsigned) == Int(1, 1, Unsigned)); BOOST_CHECK(Int(2, 4, Signed).cast(1, Unsigned) == Int(0, 1, Unsigned)); BOOST_CHECK(Int(7, 4, Signed).cast(1, Unsigned) == Int(1, 1, Unsigned)); BOOST_CHECK(Int(-8, 4, Signed).cast(1, Unsigned) == Int(0, 1, Unsigned)); BOOST_CHECK(Int(0, 4, Unsigned).cast(3, Signed) == Int(0, 3, Signed)); BOOST_CHECK(Int(1, 4, Unsigned).cast(3, Signed) == Int(1, 3, Signed)); BOOST_CHECK(Int(2, 4, Unsigned).cast(3, Signed) == Int(2, 3, Signed)); BOOST_CHECK(Int(14, 4, Unsigned).cast(3, Signed) == Int(-2, 3, Signed)); BOOST_CHECK(Int(15, 4, Unsigned).cast(3, Signed) == Int(-1, 3, Signed)); BOOST_CHECK(Int(0, 4, Unsigned).cast(2, Signed) == Int(0, 2, Signed)); BOOST_CHECK(Int(1, 4, Unsigned).cast(2, Signed) == Int(1, 2, Signed)); BOOST_CHECK(Int(2, 4, Unsigned).cast(2, Signed) == Int(2, 2, Signed)); BOOST_CHECK(Int(14, 4, Unsigned).cast(2, Signed) == Int(-2, 2, Signed)); BOOST_CHECK(Int(15, 4, Unsigned).cast(2, Signed) == Int(-1, 2, Signed)); BOOST_CHECK(Int(0, 4, Unsigned).cast(1, Signed) == Int(0, 1, Signed)); BOOST_CHECK(Int(1, 4, Unsigned).cast(1, Signed) == Int(-1, 1, Signed)); BOOST_CHECK(Int(2, 4, Unsigned).cast(1, Signed) == Int(0, 1, Signed)); BOOST_CHECK(Int(14, 4, Unsigned).cast(1, Signed) == Int(0, 1, Signed)); BOOST_CHECK(Int(15, 4, Unsigned).cast(1, Signed) == Int(-1, 1, Signed)); } BOOST_AUTO_TEST_CASE(test_add_signed) { BOOST_CHECK(add(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(add(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(add(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(add(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(add(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(add(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(add(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK(add(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(add(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(add(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(add(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(add(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(add(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(add(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(add(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(add(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_add_with_overflow_signed) { bool overflow = false; BOOST_CHECK((add(Int(0, 4, Signed), Int(1, 4, Signed), overflow) == Int(1, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(1, 4, Signed), Int(1, 4, Signed), overflow) == Int(2, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(7, 4, Signed), Int(1, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((add(Int(-8, 4, Signed), Int(1, 4, Signed), overflow) == Int(-7, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(0, 4, Signed), Int(-1, 4, Signed), overflow) == Int(-1, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(1, 4, Signed), Int(-1, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(7, 4, Signed), Int(-1, 4, Signed), overflow) == Int(6, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(-8, 4, Signed), Int(-1, 4, Signed), overflow) == Int(7, 4, Signed) && overflow)); BOOST_CHECK((add(Int(0, 4, Signed), Int(7, 4, Signed), overflow) == Int(7, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(1, 4, Signed), Int(7, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((add(Int(7, 4, Signed), Int(7, 4, Signed), overflow) == Int(-2, 4, Signed) && overflow)); BOOST_CHECK((add(Int(-8, 4, Signed), Int(7, 4, Signed), overflow) == Int(-1, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(0, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-8, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(1, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-7, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(7, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-1, 4, Signed) && !overflow)); BOOST_CHECK((add(Int(-8, 4, Signed), Int(-8, 4, Signed), overflow) == Int(0, 4, Signed) && overflow)); } BOOST_AUTO_TEST_CASE(test_add_unsigned) { BOOST_CHECK(add(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(add(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK(add(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(add(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(add(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(add(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(14, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_add_with_overflow_unsigned) { bool overflow = false; BOOST_CHECK((add(Int(0, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(1, 4, Unsigned) && !overflow)); BOOST_CHECK((add(Int(1, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(2, 4, Unsigned) && !overflow)); BOOST_CHECK((add(Int(15, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && overflow)); BOOST_CHECK((add(Int(0, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(15, 4, Unsigned) && !overflow)); BOOST_CHECK((add(Int(1, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && overflow)); BOOST_CHECK((add(Int(15, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(14, 4, Unsigned) && overflow)); BOOST_CHECK((add(Int(7, 4, Unsigned), Int(8, 4, Unsigned), overflow) == Int(15, 4, Unsigned) && !overflow)); BOOST_CHECK((add(Int(7, 4, Unsigned), Int(9, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && overflow)); } BOOST_AUTO_TEST_CASE(test_sub_signed) { BOOST_CHECK(sub(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(sub(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(sub(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK(sub(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(sub(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(sub(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(sub(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(sub(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(sub(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(sub(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(-6, 4, Signed)); BOOST_CHECK(sub(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(sub(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(sub(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(sub(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(sub(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(sub(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_sub_with_overflow_signed) { bool overflow = false; BOOST_CHECK((sub(Int(0, 4, Signed), Int(1, 4, Signed), overflow) == Int(-1, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(1, 4, Signed), Int(1, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(7, 4, Signed), Int(1, 4, Signed), overflow) == Int(6, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(-8, 4, Signed), Int(1, 4, Signed), overflow) == Int(7, 4, Signed) && overflow)); BOOST_CHECK((sub(Int(0, 4, Signed), Int(-1, 4, Signed), overflow) == Int(1, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(1, 4, Signed), Int(-1, 4, Signed), overflow) == Int(2, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(7, 4, Signed), Int(-1, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((sub(Int(-8, 4, Signed), Int(-1, 4, Signed), overflow) == Int(-7, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(0, 4, Signed), Int(7, 4, Signed), overflow) == Int(-7, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(1, 4, Signed), Int(7, 4, Signed), overflow) == Int(-6, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(7, 4, Signed), Int(7, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((sub(Int(-8, 4, Signed), Int(7, 4, Signed), overflow) == Int(1, 4, Signed) && overflow)); BOOST_CHECK((sub(Int(0, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((sub(Int(1, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-7, 4, Signed) && overflow)); BOOST_CHECK((sub(Int(7, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-1, 4, Signed) && overflow)); BOOST_CHECK((sub(Int(-8, 4, Signed), Int(-8, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); } BOOST_AUTO_TEST_CASE(test_sub_unsigned) { BOOST_CHECK(sub(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(sub(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(sub(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(sub(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(sub(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK(sub(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_sub_with_overflow_unsigned) { bool overflow = false; BOOST_CHECK((sub(Int(0, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(15, 4, Unsigned) && overflow)); BOOST_CHECK((sub(Int(1, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((sub(Int(15, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(14, 4, Unsigned) && !overflow)); BOOST_CHECK((sub(Int(0, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(1, 4, Unsigned) && overflow)); BOOST_CHECK((sub(Int(1, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(2, 4, Unsigned) && overflow)); BOOST_CHECK((sub(Int(15, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((sub(Int(3, 4, Unsigned), Int(2, 4, Unsigned), overflow) == Int(1, 4, Unsigned) && !overflow)); BOOST_CHECK((sub(Int(3, 4, Unsigned), Int(4, 4, Unsigned), overflow) == Int(15, 4, Unsigned) && overflow)); } BOOST_AUTO_TEST_CASE(test_mul_signed) { BOOST_CHECK(mul(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mul(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(mul(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(mul(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(mul(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mul(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(mul(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(mul(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(mul(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mul(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(mul(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(mul(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(mul(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mul(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(mul(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(mul(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_mul_with_overflow_signed) { bool overflow = false; BOOST_CHECK((mul(Int(0, 4, Signed), Int(1, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(1, 4, Signed), Int(1, 4, Signed), overflow) == Int(1, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(7, 4, Signed), Int(1, 4, Signed), overflow) == Int(7, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(-8, 4, Signed), Int(1, 4, Signed), overflow) == Int(-8, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(0, 4, Signed), Int(-1, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(1, 4, Signed), Int(-1, 4, Signed), overflow) == Int(-1, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(7, 4, Signed), Int(-1, 4, Signed), overflow) == Int(-7, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(-8, 4, Signed), Int(-1, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((mul(Int(0, 4, Signed), Int(7, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(1, 4, Signed), Int(7, 4, Signed), overflow) == Int(7, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(7, 4, Signed), Int(7, 4, Signed), overflow) == Int(1, 4, Signed) && overflow)); BOOST_CHECK((mul(Int(-8, 4, Signed), Int(7, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((mul(Int(0, 4, Signed), Int(-8, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(1, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-8, 4, Signed) && !overflow)); BOOST_CHECK((mul(Int(7, 4, Signed), Int(-8, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((mul(Int(-8, 4, Signed), Int(-8, 4, Signed), overflow) == Int(0, 4, Signed) && overflow)); BOOST_CHECK((mul(Int(-1, 1, Signed), Int(-1, 1, Signed), overflow) == Int(-1, 1, Signed) && overflow)); } BOOST_AUTO_TEST_CASE(test_mul_unsigned) { BOOST_CHECK(mul(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(mul(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(mul(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(mul(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(mul(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(mul(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(mul(Int(3, 4, Unsigned), Int(4, 4, Unsigned)) == Int(12, 4, Unsigned)); BOOST_CHECK(mul(Int(4, 4, Unsigned), Int(4, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_mul_with_overflow_unsigned) { bool overflow = false; BOOST_CHECK((mul(Int(0, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((mul(Int(1, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(1, 4, Unsigned) && !overflow)); BOOST_CHECK((mul(Int(15, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(15, 4, Unsigned) && !overflow)); BOOST_CHECK((mul(Int(0, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((mul(Int(1, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(15, 4, Unsigned) && !overflow)); BOOST_CHECK((mul(Int(15, 4, Unsigned), Int(15, 4, Unsigned), overflow) == Int(1, 4, Unsigned) && overflow)); BOOST_CHECK((mul(Int(3, 4, Unsigned), Int(4, 4, Unsigned), overflow) == Int(12, 4, Unsigned) && !overflow)); BOOST_CHECK((mul(Int(4, 4, Unsigned), Int(4, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && overflow)); } BOOST_AUTO_TEST_CASE(test_div_signed) { BOOST_CHECK(div(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(div(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(div(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(div(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(div(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(div(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(div(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(div(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(div(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(div(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(div(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(div(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(div(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(div(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(div(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(div(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(div(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(div(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(div(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(div(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(-2, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_div_with_overflow_and_exact_signed) { bool overflow = false; bool exact = false; BOOST_CHECK((div(Int(0, 4, Signed), Int(1, 4, Signed), overflow, exact) == Int(0, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(1, 4, Signed), Int(1, 4, Signed), overflow, exact) == Int(1, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(7, 4, Signed), Int(1, 4, Signed), overflow, exact) == Int(7, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(-8, 4, Signed), Int(1, 4, Signed), overflow, exact) == Int(-8, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(0, 4, Signed), Int(-1, 4, Signed), overflow, exact) == Int(0, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(1, 4, Signed), Int(-1, 4, Signed), overflow, exact) == Int(-1, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(7, 4, Signed), Int(-1, 4, Signed), overflow, exact) == Int(-7, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(-8, 4, Signed), Int(-1, 4, Signed), overflow, exact) == Int(-8, 4, Signed) && overflow && exact)); BOOST_CHECK((div(Int(0, 4, Signed), Int(7, 4, Signed), overflow, exact) == Int(0, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(1, 4, Signed), Int(7, 4, Signed), overflow, exact) == Int(0, 4, Signed) && !overflow && !exact)); BOOST_CHECK((div(Int(7, 4, Signed), Int(7, 4, Signed), overflow, exact) == Int(1, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(-8, 4, Signed), Int(7, 4, Signed), overflow, exact) == Int(-1, 4, Signed) && !overflow && !exact)); BOOST_CHECK((div(Int(0, 4, Signed), Int(-8, 4, Signed), overflow, exact) == Int(0, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(1, 4, Signed), Int(-8, 4, Signed), overflow, exact) == Int(0, 4, Signed) && !overflow && !exact)); BOOST_CHECK((div(Int(7, 4, Signed), Int(-8, 4, Signed), overflow, exact) == Int(0, 4, Signed) && !overflow && !exact)); BOOST_CHECK((div(Int(-8, 4, Signed), Int(-8, 4, Signed), overflow, exact) == Int(1, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(4, 4, Signed), Int(2, 4, Signed), overflow, exact) == Int(2, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(5, 4, Signed), Int(2, 4, Signed), overflow, exact) == Int(2, 4, Signed) && !overflow && !exact)); BOOST_CHECK((div(Int(-4, 4, Signed), Int(2, 4, Signed), overflow, exact) == Int(-2, 4, Signed) && !overflow && exact)); BOOST_CHECK((div(Int(-5, 4, Signed), Int(2, 4, Signed), overflow, exact) == Int(-2, 4, Signed) && !overflow && !exact)); } BOOST_AUTO_TEST_CASE(test_div_unsigned) { BOOST_CHECK(div(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(div(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(div(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(div(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(div(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(div(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(div(Int(3, 4, Unsigned), Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(div(Int(4, 4, Unsigned), Int(2, 4, Unsigned)) == Int(2, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_div_with_overflow_and_exact_unsigned) { bool overflow = false; bool exact = false; BOOST_CHECK((div(Int(0, 4, Unsigned), Int(1, 4, Unsigned), overflow, exact) == Int(0, 4, Unsigned) && !overflow && exact)); BOOST_CHECK((div(Int(1, 4, Unsigned), Int(1, 4, Unsigned), overflow, exact) == Int(1, 4, Unsigned) && !overflow && exact)); BOOST_CHECK( (div(Int(15, 4, Unsigned), Int(1, 4, Unsigned), overflow, exact) == Int(15, 4, Unsigned) && !overflow && exact)); BOOST_CHECK( (div(Int(0, 4, Unsigned), Int(15, 4, Unsigned), overflow, exact) == Int(0, 4, Unsigned) && !overflow && exact)); BOOST_CHECK( (div(Int(1, 4, Unsigned), Int(15, 4, Unsigned), overflow, exact) == Int(0, 4, Unsigned) && !overflow && !exact)); BOOST_CHECK( (div(Int(15, 4, Unsigned), Int(15, 4, Unsigned), overflow, exact) == Int(1, 4, Unsigned) && !overflow && exact)); BOOST_CHECK((div(Int(3, 4, Unsigned), Int(2, 4, Unsigned), overflow, exact) == Int(1, 4, Unsigned) && !overflow && !exact)); BOOST_CHECK((div(Int(4, 4, Unsigned), Int(2, 4, Unsigned), overflow, exact) == Int(2, 4, Unsigned) && !overflow && exact)); } BOOST_AUTO_TEST_CASE(test_rem_signed) { BOOST_CHECK(rem(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(rem(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(rem(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(rem(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(rem(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(rem(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(rem(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(-1, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_rem_unsigned) { BOOST_CHECK(rem(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(rem(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(rem(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(rem(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(rem(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(rem(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(rem(Int(3, 4, Unsigned), Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(rem(Int(4, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_mod_signed) { BOOST_CHECK(mod(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(mod(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK(mod(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(mod(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(mod(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(mod(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(mod(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_mod_unsigned) { BOOST_CHECK(mod(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(mod(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(mod(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(mod(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(mod(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(mod(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(mod(Int(3, 4, Unsigned), Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(mod(Int(4, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_shl_signed) { BOOST_CHECK(shl(Int(0, 4, Signed), Int(0, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(1, 4, Signed), Int(0, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(shl(Int(7, 4, Signed), Int(0, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(shl(Int(-8, 4, Signed), Int(0, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(shl(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(shl(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(shl(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(0, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(1, 4, Signed), Int(2, 4, Signed)) == Int(4, 4, Signed)); BOOST_CHECK(shl(Int(7, 4, Signed), Int(2, 4, Signed)) == Int(-4, 4, Signed)); BOOST_CHECK(shl(Int(-8, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(4, 4, Signed)); BOOST_CHECK(shl(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(-4, 4, Signed)); BOOST_CHECK(shl(Int(0, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(shl(Int(1, 4, Signed), Int(3, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(shl(Int(7, 4, Signed), Int(3, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(shl(Int(-8, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_shl_with_overflow_signed) { bool overflow = false; BOOST_CHECK((shl(Int(0, 4, Signed), Int(0, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Signed), Int(0, 4, Signed), overflow) == Int(1, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(7, 4, Signed), Int(0, 4, Signed), overflow) == Int(7, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(-8, 4, Signed), Int(0, 4, Signed), overflow) == Int(-8, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(0, 4, Signed), Int(1, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Signed), Int(1, 4, Signed), overflow) == Int(2, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(7, 4, Signed), Int(1, 4, Signed), overflow) == Int(-2, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(-8, 4, Signed), Int(1, 4, Signed), overflow) == Int(0, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(0, 4, Signed), Int(2, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Signed), Int(2, 4, Signed), overflow) == Int(4, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(7, 4, Signed), Int(2, 4, Signed), overflow) == Int(-4, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(-8, 4, Signed), Int(2, 4, Signed), overflow) == Int(0, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(4, 4, Signed), Int(2, 4, Signed), overflow) == Int(0, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(5, 4, Signed), Int(2, 4, Signed), overflow) == Int(4, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(-4, 4, Signed), Int(2, 4, Signed), overflow) == Int(0, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(-5, 4, Signed), Int(2, 4, Signed), overflow) == Int(-4, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(0, 4, Signed), Int(3, 4, Signed), overflow) == Int(0, 4, Signed) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Signed), Int(3, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(7, 4, Signed), Int(3, 4, Signed), overflow) == Int(-8, 4, Signed) && overflow)); BOOST_CHECK((shl(Int(-8, 4, Signed), Int(3, 4, Signed), overflow) == Int(0, 4, Signed) && overflow)); } BOOST_AUTO_TEST_CASE(test_shl_unsigned) { BOOST_CHECK(shl(Int(0, 4, Unsigned), Int(0, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(shl(Int(1, 4, Unsigned), Int(0, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(shl(Int(14, 4, Unsigned), Int(0, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(shl(Int(15, 4, Unsigned), Int(0, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(shl(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(shl(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK(shl(Int(14, 4, Unsigned), Int(1, 4, Unsigned)) == Int(12, 4, Unsigned)); BOOST_CHECK(shl(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(shl(Int(0, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(shl(Int(1, 4, Unsigned), Int(2, 4, Unsigned)) == Int(4, 4, Unsigned)); BOOST_CHECK(shl(Int(14, 4, Unsigned), Int(2, 4, Unsigned)) == Int(8, 4, Unsigned)); BOOST_CHECK(shl(Int(15, 4, Unsigned), Int(2, 4, Unsigned)) == Int(12, 4, Unsigned)); BOOST_CHECK(shl(Int(0, 4, Unsigned), Int(3, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(shl(Int(1, 4, Unsigned), Int(3, 4, Unsigned)) == Int(8, 4, Unsigned)); BOOST_CHECK(shl(Int(14, 4, Unsigned), Int(3, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(shl(Int(15, 4, Unsigned), Int(3, 4, Unsigned)) == Int(8, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_shl_with_overflow_unsigned) { bool overflow = false; BOOST_CHECK((shl(Int(0, 4, Unsigned), Int(0, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Unsigned), Int(0, 4, Unsigned), overflow) == Int(1, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(14, 4, Unsigned), Int(0, 4, Unsigned), overflow) == Int(14, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(15, 4, Unsigned), Int(0, 4, Unsigned), overflow) == Int(15, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(0, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(2, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(14, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(12, 4, Unsigned) && overflow)); BOOST_CHECK((shl(Int(15, 4, Unsigned), Int(1, 4, Unsigned), overflow) == Int(14, 4, Unsigned) && overflow)); BOOST_CHECK((shl(Int(0, 4, Unsigned), Int(2, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Unsigned), Int(2, 4, Unsigned), overflow) == Int(4, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(14, 4, Unsigned), Int(2, 4, Unsigned), overflow) == Int(8, 4, Unsigned) && overflow)); BOOST_CHECK((shl(Int(15, 4, Unsigned), Int(2, 4, Unsigned), overflow) == Int(12, 4, Unsigned) && overflow)); BOOST_CHECK((shl(Int(0, 4, Unsigned), Int(3, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(1, 4, Unsigned), Int(3, 4, Unsigned), overflow) == Int(8, 4, Unsigned) && !overflow)); BOOST_CHECK((shl(Int(14, 4, Unsigned), Int(3, 4, Unsigned), overflow) == Int(0, 4, Unsigned) && overflow)); BOOST_CHECK((shl(Int(15, 4, Unsigned), Int(3, 4, Unsigned), overflow) == Int(8, 4, Unsigned) && overflow)); } BOOST_AUTO_TEST_CASE(test_lshr_signed) { BOOST_CHECK(lshr(Int(0, 4, Signed), Int(0, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(1, 4, Signed), Int(0, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(lshr(Int(7, 4, Signed), Int(0, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(lshr(Int(-8, 4, Signed), Int(0, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(lshr(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(3, 4, Signed)); BOOST_CHECK(lshr(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(4, 4, Signed)); BOOST_CHECK(lshr(Int(0, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(1, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(7, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(lshr(Int(-8, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(lshr(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(lshr(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(lshr(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(3, 4, Signed)); BOOST_CHECK(lshr(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(lshr(Int(0, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(1, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(7, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(lshr(Int(-8, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_lshr_with_exact_signed) { bool exact = true; BOOST_CHECK( (lshr(Int(0, 4, Signed), Int(0, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(1, 4, Signed), Int(0, 4, Signed), exact) == Int(1, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(7, 4, Signed), Int(0, 4, Signed), exact) == Int(7, 4, Signed) && exact)); BOOST_CHECK((lshr(Int(-8, 4, Signed), Int(0, 4, Signed), exact) == Int(-8, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(0, 4, Signed), Int(1, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(1, 4, Signed), Int(1, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK( (lshr(Int(7, 4, Signed), Int(1, 4, Signed), exact) == Int(3, 4, Signed) && !exact)); BOOST_CHECK((lshr(Int(-8, 4, Signed), Int(1, 4, Signed), exact) == Int(4, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(0, 4, Signed), Int(2, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(1, 4, Signed), Int(2, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK( (lshr(Int(7, 4, Signed), Int(2, 4, Signed), exact) == Int(1, 4, Signed) && !exact)); BOOST_CHECK((lshr(Int(-8, 4, Signed), Int(2, 4, Signed), exact) == Int(2, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(4, 4, Signed), Int(2, 4, Signed), exact) == Int(1, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(5, 4, Signed), Int(2, 4, Signed), exact) == Int(1, 4, Signed) && !exact)); BOOST_CHECK((lshr(Int(-4, 4, Signed), Int(2, 4, Signed), exact) == Int(3, 4, Signed) && exact)); BOOST_CHECK((lshr(Int(-5, 4, Signed), Int(2, 4, Signed), exact) == Int(2, 4, Signed) && !exact)); BOOST_CHECK( (lshr(Int(0, 4, Signed), Int(3, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (lshr(Int(1, 4, Signed), Int(3, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK( (lshr(Int(7, 4, Signed), Int(3, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK((lshr(Int(-8, 4, Signed), Int(3, 4, Signed), exact) == Int(1, 4, Signed) && exact)); } BOOST_AUTO_TEST_CASE(test_lshr_unsigned) { BOOST_CHECK(lshr(Int(0, 4, Unsigned), Int(0, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(lshr(Int(1, 4, Unsigned), Int(0, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(lshr(Int(14, 4, Unsigned), Int(0, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(lshr(Int(15, 4, Unsigned), Int(0, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(lshr(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(lshr(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(lshr(Int(14, 4, Unsigned), Int(1, 4, Unsigned)) == Int(7, 4, Unsigned)); BOOST_CHECK(lshr(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(7, 4, Unsigned)); BOOST_CHECK(lshr(Int(0, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(lshr(Int(1, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(lshr(Int(14, 4, Unsigned), Int(2, 4, Unsigned)) == Int(3, 4, Unsigned)); BOOST_CHECK(lshr(Int(15, 4, Unsigned), Int(2, 4, Unsigned)) == Int(3, 4, Unsigned)); BOOST_CHECK(lshr(Int(0, 4, Unsigned), Int(3, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(lshr(Int(1, 4, Unsigned), Int(3, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(lshr(Int(14, 4, Unsigned), Int(3, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(lshr(Int(15, 4, Unsigned), Int(3, 4, Unsigned)) == Int(1, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_lshr_with_exact_unsigned) { bool exact = true; BOOST_CHECK((lshr(Int(0, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(1, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(1, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(14, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(14, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(15, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(15, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(0, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(1, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(0, 4, Unsigned) && !exact)); BOOST_CHECK((lshr(Int(14, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(7, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(15, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(7, 4, Unsigned) && !exact)); BOOST_CHECK((lshr(Int(0, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(1, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(0, 4, Unsigned) && !exact)); BOOST_CHECK((lshr(Int(14, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(3, 4, Unsigned) && !exact)); BOOST_CHECK((lshr(Int(15, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(3, 4, Unsigned) && !exact)); BOOST_CHECK((lshr(Int(0, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((lshr(Int(1, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(0, 4, Unsigned) && !exact)); BOOST_CHECK((lshr(Int(14, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(1, 4, Unsigned) && !exact)); BOOST_CHECK((lshr(Int(15, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(1, 4, Unsigned) && !exact)); } BOOST_AUTO_TEST_CASE(test_ashr_signed) { BOOST_CHECK(ashr(Int(0, 4, Signed), Int(0, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(1, 4, Signed), Int(0, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(ashr(Int(7, 4, Signed), Int(0, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(ashr(Int(-8, 4, Signed), Int(0, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(ashr(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(3, 4, Signed)); BOOST_CHECK(ashr(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(-4, 4, Signed)); BOOST_CHECK(ashr(Int(0, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(1, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(7, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(ashr(Int(-8, 4, Signed), Int(2, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(ashr(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(ashr(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(ashr(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(ashr(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(ashr(Int(0, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(1, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(7, 4, Signed), Int(3, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(ashr(Int(-8, 4, Signed), Int(3, 4, Signed)) == Int(-1, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_ashr_with_exact_signed) { bool exact = true; BOOST_CHECK( (ashr(Int(0, 4, Signed), Int(0, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(1, 4, Signed), Int(0, 4, Signed), exact) == Int(1, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(7, 4, Signed), Int(0, 4, Signed), exact) == Int(7, 4, Signed) && exact)); BOOST_CHECK((ashr(Int(-8, 4, Signed), Int(0, 4, Signed), exact) == Int(-8, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(0, 4, Signed), Int(1, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(1, 4, Signed), Int(1, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK( (ashr(Int(7, 4, Signed), Int(1, 4, Signed), exact) == Int(3, 4, Signed) && !exact)); BOOST_CHECK((ashr(Int(-8, 4, Signed), Int(1, 4, Signed), exact) == Int(-4, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(0, 4, Signed), Int(2, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(1, 4, Signed), Int(2, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK( (ashr(Int(7, 4, Signed), Int(2, 4, Signed), exact) == Int(1, 4, Signed) && !exact)); BOOST_CHECK((ashr(Int(-8, 4, Signed), Int(2, 4, Signed), exact) == Int(-2, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(4, 4, Signed), Int(2, 4, Signed), exact) == Int(1, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(5, 4, Signed), Int(2, 4, Signed), exact) == Int(1, 4, Signed) && !exact)); BOOST_CHECK((ashr(Int(-4, 4, Signed), Int(2, 4, Signed), exact) == Int(-1, 4, Signed) && exact)); BOOST_CHECK((ashr(Int(-5, 4, Signed), Int(2, 4, Signed), exact) == Int(-2, 4, Signed) && !exact)); BOOST_CHECK( (ashr(Int(0, 4, Signed), Int(3, 4, Signed), exact) == Int(0, 4, Signed) && exact)); BOOST_CHECK( (ashr(Int(1, 4, Signed), Int(3, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK( (ashr(Int(7, 4, Signed), Int(3, 4, Signed), exact) == Int(0, 4, Signed) && !exact)); BOOST_CHECK((ashr(Int(-8, 4, Signed), Int(3, 4, Signed), exact) == Int(-1, 4, Signed) && exact)); } BOOST_AUTO_TEST_CASE(test_ashr_unsigned) { BOOST_CHECK(ashr(Int(0, 4, Unsigned), Int(0, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(ashr(Int(1, 4, Unsigned), Int(0, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(ashr(Int(14, 4, Unsigned), Int(0, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(ashr(Int(15, 4, Unsigned), Int(0, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(ashr(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(ashr(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(ashr(Int(14, 4, Unsigned), Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(ashr(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(ashr(Int(0, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(ashr(Int(1, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(ashr(Int(14, 4, Unsigned), Int(2, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(ashr(Int(15, 4, Unsigned), Int(2, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(ashr(Int(0, 4, Unsigned), Int(3, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(ashr(Int(1, 4, Unsigned), Int(3, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(ashr(Int(14, 4, Unsigned), Int(3, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(ashr(Int(15, 4, Unsigned), Int(3, 4, Unsigned)) == Int(15, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_ashr_with_exact_unsigned) { bool exact = true; BOOST_CHECK((ashr(Int(0, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(1, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(1, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(14, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(14, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(15, 4, Unsigned), Int(0, 4, Unsigned), exact) == Int(15, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(0, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(1, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(0, 4, Unsigned) && !exact)); BOOST_CHECK((ashr(Int(14, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(15, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(15, 4, Unsigned), Int(1, 4, Unsigned), exact) == Int(15, 4, Unsigned) && !exact)); BOOST_CHECK((ashr(Int(0, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(1, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(0, 4, Unsigned) && !exact)); BOOST_CHECK((ashr(Int(14, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(15, 4, Unsigned) && !exact)); BOOST_CHECK((ashr(Int(15, 4, Unsigned), Int(2, 4, Unsigned), exact) == Int(15, 4, Unsigned) && !exact)); BOOST_CHECK((ashr(Int(0, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(0, 4, Unsigned) && exact)); BOOST_CHECK((ashr(Int(1, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(0, 4, Unsigned) && !exact)); BOOST_CHECK((ashr(Int(14, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(15, 4, Unsigned) && !exact)); BOOST_CHECK((ashr(Int(15, 4, Unsigned), Int(3, 4, Unsigned), exact) == Int(15, 4, Unsigned) && !exact)); } BOOST_AUTO_TEST_CASE(test_and_signed) { BOOST_CHECK(and_(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(and_(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(and_(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(and_(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(and_(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(and_(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(and_(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(and_(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(and_(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(and_(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(and_(Int(-7, 4, Signed), Int(-3, 4, Signed)) == Int(-7, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_and_unsigned) { BOOST_CHECK(and_(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(and_(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(and_(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(and_(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(and_(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(and_(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(and_(Int(3, 4, Unsigned), Int(2, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK(and_(Int(4, 4, Unsigned), Int(2, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(and_(Int(10, 4, Unsigned), Int(5, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(and_(Int(10, 4, Unsigned), Int(8, 4, Unsigned)) == Int(8, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_or_signed) { BOOST_CHECK(or_(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(or_(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(or_(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(or_(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(or_(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(or_(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(or_(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(or_(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(or_(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(or_(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(or_(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(or_(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(or_(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(or_(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(or_(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(or_(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(or_(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK(or_(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(or_(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(or_(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(-5, 4, Signed)); BOOST_CHECK(or_(Int(-7, 4, Signed), Int(-3, 4, Signed)) == Int(-3, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_xor_signed) { BOOST_CHECK(xor_(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(xor_(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(xor_(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK(xor_(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(xor_(Int(0, 4, Signed), Int(-1, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(xor_(Int(1, 4, Signed), Int(-1, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(xor_(Int(7, 4, Signed), Int(-1, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(xor_(Int(-8, 4, Signed), Int(-1, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(xor_(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(xor_(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK(xor_(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(xor_(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(xor_(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(xor_(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(xor_(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(-1, 4, Signed)); BOOST_CHECK(xor_(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(xor_(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(6, 4, Signed)); BOOST_CHECK(xor_(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(xor_(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(-2, 4, Signed)); BOOST_CHECK(xor_(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(-7, 4, Signed)); BOOST_CHECK(xor_(Int(-7, 4, Signed), Int(-3, 4, Signed)) == Int(4, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_xor_unsigned) { BOOST_CHECK(xor_(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(xor_(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(xor_(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(xor_(Int(0, 4, Unsigned), Int(15, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(xor_(Int(1, 4, Unsigned), Int(15, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(xor_(Int(15, 4, Unsigned), Int(15, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(xor_(Int(3, 4, Unsigned), Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(xor_(Int(4, 4, Unsigned), Int(2, 4, Unsigned)) == Int(6, 4, Unsigned)); BOOST_CHECK(xor_(Int(10, 4, Unsigned), Int(5, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(xor_(Int(10, 4, Unsigned), Int(8, 4, Unsigned)) == Int(2, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_gcd_signed) { BOOST_CHECK(gcd(Int(0, 4, Signed), Int(0, 4, Signed)) == Int(0, 4, Signed)); BOOST_CHECK(gcd(Int(1, 4, Signed), Int(0, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(7, 4, Signed), Int(0, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(gcd(Int(-8, 4, Signed), Int(0, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(gcd(Int(0, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(1, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(7, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-8, 4, Signed), Int(1, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(0, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(gcd(Int(1, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(7, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-8, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(gcd(Int(4, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(gcd(Int(5, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-4, 4, Signed), Int(2, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(gcd(Int(-5, 4, Signed), Int(2, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(0, 4, Signed), Int(3, 4, Signed)) == Int(3, 4, Signed)); BOOST_CHECK(gcd(Int(1, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(7, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-8, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(4, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(5, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(6, 4, Signed), Int(3, 4, Signed)) == Int(3, 4, Signed)); BOOST_CHECK(gcd(Int(-4, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-5, 4, Signed), Int(3, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-6, 4, Signed), Int(3, 4, Signed)) == Int(3, 4, Signed)); BOOST_CHECK(gcd(Int(0, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(gcd(Int(1, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(7, 4, Signed), Int(7, 4, Signed)) == Int(7, 4, Signed)); BOOST_CHECK(gcd(Int(-8, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(4, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(5, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(6, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-4, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-5, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-6, 4, Signed), Int(7, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(0, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(gcd(Int(1, 4, Signed), Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(7, 4, Signed), Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-8, 4, Signed), Int(-8, 4, Signed)) == Int(-8, 4, Signed)); BOOST_CHECK(gcd(Int(4, 4, Signed), Int(-8, 4, Signed)) == Int(4, 4, Signed)); BOOST_CHECK(gcd(Int(5, 4, Signed), Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(6, 4, Signed), Int(-8, 4, Signed)) == Int(2, 4, Signed)); BOOST_CHECK(gcd(Int(-4, 4, Signed), Int(-8, 4, Signed)) == Int(4, 4, Signed)); BOOST_CHECK(gcd(Int(-5, 4, Signed), Int(-8, 4, Signed)) == Int(1, 4, Signed)); BOOST_CHECK(gcd(Int(-6, 4, Signed), Int(-8, 4, Signed)) == Int(2, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_gcd_unsigned) { BOOST_CHECK(gcd(Int(0, 4, Unsigned), Int(0, 4, Unsigned)) == Int(0, 4, Unsigned)); BOOST_CHECK(gcd(Int(1, 4, Unsigned), Int(0, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(14, 4, Unsigned), Int(0, 4, Unsigned)) == Int(14, 4, Unsigned)); BOOST_CHECK(gcd(Int(15, 4, Unsigned), Int(0, 4, Unsigned)) == Int(15, 4, Unsigned)); BOOST_CHECK(gcd(Int(0, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(1, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(14, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(15, 4, Unsigned), Int(1, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(0, 4, Unsigned), Int(2, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK(gcd(Int(1, 4, Unsigned), Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(3, 4, Unsigned), Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(4, 4, Unsigned), Int(2, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK(gcd(Int(14, 4, Unsigned), Int(2, 4, Unsigned)) == Int(2, 4, Unsigned)); BOOST_CHECK(gcd(Int(15, 4, Unsigned), Int(2, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(0, 4, Unsigned), Int(3, 4, Unsigned)) == Int(3, 4, Unsigned)); BOOST_CHECK(gcd(Int(1, 4, Unsigned), Int(3, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(3, 4, Unsigned), Int(3, 4, Unsigned)) == Int(3, 4, Unsigned)); BOOST_CHECK(gcd(Int(4, 4, Unsigned), Int(3, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(14, 4, Unsigned), Int(3, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(15, 4, Unsigned), Int(3, 4, Unsigned)) == Int(3, 4, Unsigned)); BOOST_CHECK(gcd(Int(0, 4, Unsigned), Int(5, 4, Unsigned)) == Int(5, 4, Unsigned)); BOOST_CHECK(gcd(Int(1, 4, Unsigned), Int(5, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(3, 4, Unsigned), Int(5, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(4, 4, Unsigned), Int(5, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(1, 4, Unsigned), Int(5, 4, Unsigned)) == Int(1, 4, Unsigned)); BOOST_CHECK(gcd(Int(15, 4, Unsigned), Int(5, 4, Unsigned)) == Int(5, 4, Unsigned)); } BOOST_AUTO_TEST_CASE(test_lt_signed) { BOOST_CHECK(Int(-8, 4, Signed) < Int(0, 4, Signed)); BOOST_CHECK(Int(-1, 4, Signed) < Int(0, 4, Signed)); BOOST_CHECK(!(Int(0, 4, Signed) < Int(0, 4, Signed))); BOOST_CHECK(!(Int(7, 4, Signed) < Int(0, 4, Signed))); BOOST_CHECK(Int(-8, 4, Signed) < Int(-7, 4, Signed)); BOOST_CHECK(!(Int(-1, 4, Signed) < Int(-7, 4, Signed))); BOOST_CHECK(!(Int(0, 4, Signed) < Int(-7, 4, Signed))); BOOST_CHECK(!(Int(7, 4, Signed) < Int(-7, 4, Signed))); BOOST_CHECK(!(Int(-8, 4, Signed) < Int(-8, 4, Signed))); BOOST_CHECK(!(Int(-1, 4, Signed) < Int(-8, 4, Signed))); BOOST_CHECK(!(Int(0, 4, Signed) < Int(-8, 4, Signed))); BOOST_CHECK(!(Int(7, 4, Signed) < Int(-8, 4, Signed))); BOOST_CHECK(Int(-8, 4, Signed) < Int(7, 4, Signed)); BOOST_CHECK(Int(-1, 4, Signed) < Int(7, 4, Signed)); BOOST_CHECK(Int(0, 4, Signed) < Int(7, 4, Signed)); BOOST_CHECK(!(Int(7, 4, Signed) < Int(7, 4, Signed))); } BOOST_AUTO_TEST_CASE(test_lt_unsigned) { BOOST_CHECK(!(Int(0, 4, Unsigned) < Int(0, 4, Unsigned))); BOOST_CHECK(!(Int(13, 4, Unsigned) < Int(0, 4, Unsigned))); BOOST_CHECK(!(Int(15, 4, Unsigned) < Int(0, 4, Unsigned))); BOOST_CHECK(Int(0, 4, Unsigned) < Int(1, 4, Unsigned)); BOOST_CHECK(!(Int(13, 4, Unsigned) < Int(1, 4, Unsigned))); BOOST_CHECK(!(Int(15, 4, Unsigned) < Int(1, 4, Unsigned))); BOOST_CHECK(Int(0, 4, Unsigned) < Int(15, 4, Unsigned)); BOOST_CHECK(Int(13, 4, Unsigned) < Int(15, 4, Unsigned)); BOOST_CHECK(!(Int(15, 4, Unsigned) < Int(15, 4, Unsigned))); } BOOST_AUTO_TEST_CASE(test_le_signed) { BOOST_CHECK(Int(-8, 4, Signed) <= Int(0, 4, Signed)); BOOST_CHECK(Int(-1, 4, Signed) <= Int(0, 4, Signed)); BOOST_CHECK(Int(0, 4, Signed) <= Int(0, 4, Signed)); BOOST_CHECK(!(Int(7, 4, Signed) <= Int(0, 4, Signed))); BOOST_CHECK(Int(-8, 4, Signed) <= Int(-7, 4, Signed)); BOOST_CHECK(!(Int(-1, 4, Signed) <= Int(-7, 4, Signed))); BOOST_CHECK(!(Int(0, 4, Signed) <= Int(-7, 4, Signed))); BOOST_CHECK(!(Int(7, 4, Signed) <= Int(-7, 4, Signed))); BOOST_CHECK(Int(-8, 4, Signed) <= Int(-8, 4, Signed)); BOOST_CHECK(!(Int(-1, 4, Signed) <= Int(-8, 4, Signed))); BOOST_CHECK(!(Int(0, 4, Signed) <= Int(-8, 4, Signed))); BOOST_CHECK(!(Int(7, 4, Signed) <= Int(-8, 4, Signed))); BOOST_CHECK(Int(-8, 4, Signed) <= Int(7, 4, Signed)); BOOST_CHECK(Int(-1, 4, Signed) <= Int(7, 4, Signed)); BOOST_CHECK(Int(0, 4, Signed) <= Int(7, 4, Signed)); BOOST_CHECK(Int(7, 4, Signed) <= Int(7, 4, Signed)); } BOOST_AUTO_TEST_CASE(test_le_unsigned) { BOOST_CHECK(Int(0, 4, Unsigned) <= Int(0, 4, Unsigned)); BOOST_CHECK(!(Int(13, 4, Unsigned) <= Int(0, 4, Unsigned))); BOOST_CHECK(!(Int(15, 4, Unsigned) <= Int(0, 4, Unsigned))); BOOST_CHECK(Int(0, 4, Unsigned) <= Int(1, 4, Unsigned)); BOOST_CHECK(!(Int(13, 4, Unsigned) <= Int(1, 4, Unsigned))); BOOST_CHECK(!(Int(15, 4, Unsigned) <= Int(1, 4, Unsigned))); BOOST_CHECK(Int(0, 4, Unsigned) <= Int(15, 4, Unsigned)); BOOST_CHECK(Int(13, 4, Unsigned) <= Int(15, 4, Unsigned)); BOOST_CHECK(Int(15, 4, Unsigned) <= Int(15, 4, Unsigned)); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/number/q_number.cpp000066400000000000000000000313431473507761200233140ustar00rootroot00000000000000/******************************************************************************* * * Tests for QNumber * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_q_number #define BOOST_TEST_DYN_LINK #include #include #include #if BOOST_VERSION >= 107100 #include #else #include #endif #include BOOST_AUTO_TEST_CASE(test_q_number) { using Z = ikos::core::ZNumber; using Q = ikos::core::QNumber; using NumberError = ikos::core::NumberError; // constructors BOOST_CHECK((Q() == Q(0))); BOOST_CHECK((Q(1) == Q(static_cast< int >(1)))); BOOST_CHECK((Q(-1) == Q(static_cast< int >(-1)))); BOOST_CHECK((Q(1) == Q(static_cast< unsigned int >(1)))); BOOST_CHECK((Q(1) == Q(static_cast< long >(1)))); BOOST_CHECK((Q(-1) == Q(static_cast< long >(-1)))); BOOST_CHECK((Q(1) == Q(static_cast< unsigned long >(1)))); BOOST_CHECK((Q(1) == Q(static_cast< long long >(1)))); BOOST_CHECK((Q(-1) == Q(static_cast< long long >(-1)))); BOOST_CHECK((Q(1) == Q(static_cast< unsigned long long >(1)))); BOOST_CHECK((Q(1, 2) == Q(static_cast< int >(2), 4))); BOOST_CHECK((Q(-1, 2) == Q(static_cast< int >(-2), 4))); BOOST_CHECK((Q(1, 2) == Q(static_cast< unsigned int >(2), 4))); BOOST_CHECK((Q(1, 2) == Q(static_cast< long >(2), 4))); BOOST_CHECK((Q(-1, 2) == Q(static_cast< long >(-2), 4))); BOOST_CHECK((Q(1, 2) == Q(static_cast< unsigned long >(2), 4))); BOOST_CHECK((Q(1, 2) == Q(static_cast< long long >(2), 4))); BOOST_CHECK((Q(-1, 2) == Q(static_cast< long long >(-2), 4))); BOOST_CHECK((Q(1, 2) == Q(static_cast< unsigned long long >(2), 4))); BOOST_CHECK((Q(1, 2) == Q(2, static_cast< int >(4)))); BOOST_CHECK((Q(-1, 2) == Q(2, static_cast< int >(-4)))); BOOST_CHECK((Q(1, 2) == Q(2, static_cast< unsigned int >(4)))); BOOST_CHECK((Q(1, 2) == Q(2, static_cast< long >(4)))); BOOST_CHECK((Q(-1, 2) == Q(2, static_cast< long >(-4)))); BOOST_CHECK((Q(1, 2) == Q(2, static_cast< unsigned long >(4)))); BOOST_CHECK((Q(1, 2) == Q(2, static_cast< long long >(4)))); BOOST_CHECK((Q(-1, 2) == Q(2, static_cast< long long >(-4)))); BOOST_CHECK((Q(1, 2) == Q(2, static_cast< unsigned long long >(4)))); BOOST_CHECK((Q(1) == Q(Z(1)))); BOOST_CHECK((Q(1, 2) == Q(Z(2), Z(4)))); // operator= Q n; BOOST_CHECK((Q(1) == (n = static_cast< int >(1)))); BOOST_CHECK((Q(-1) == (n = static_cast< int >(-1)))); BOOST_CHECK((Q(1) == (n = static_cast< unsigned int >(1)))); BOOST_CHECK((Q(1) == (n = static_cast< long >(1)))); BOOST_CHECK((Q(-1) == (n = static_cast< long >(-1)))); BOOST_CHECK((Q(1) == (n = static_cast< unsigned long >(1)))); BOOST_CHECK((Q(1) == (n = static_cast< long long >(1)))); BOOST_CHECK((Q(-1) == (n = static_cast< long long >(-1)))); BOOST_CHECK((Q(1) == (n = static_cast< unsigned long long >(1)))); BOOST_CHECK((Q(1) == (n = Z(1)))); // from_string BOOST_CHECK((Q(1) == Q::from_string("1"))); BOOST_CHECK((Q(-1) == Q::from_string("-1"))); BOOST_CHECK((Q(1) == Q::from_string("01"))); BOOST_CHECK((Q(1) == Q::from_string(" 1"))); BOOST_CHECK((Q(1) == Q::from_string("1\n"))); BOOST_CHECK((Q(101) == Q::from_string("1 0 1"))); BOOST_CHECK((Q(1, 2) == Q::from_string("1/2"))); BOOST_CHECK((Q(1, 2) == Q::from_string("2 / 4"))); BOOST_CHECK((Q(1, 2) == Q::from_string("2 /\n4"))); BOOST_CHECK((Q(1) == Q::from_string("1", 10))); BOOST_CHECK((Q(2) == Q::from_string("10", 2))); BOOST_CHECK((Q(3) == Q::from_string("11", 2))); BOOST_CHECK((Q(1, 2) == Q::from_string("10/100", 2))); BOOST_CHECK((Q(10) == Q::from_string("A", 16))); BOOST_CHECK((Q(10) == Q::from_string("a", 16))); BOOST_CHECK((Q(0xFF) == Q::from_string("FF", 16))); BOOST_CHECK((Q(1, 17) == Q::from_string("A/AA", 16))); BOOST_CHECK_THROW((Q::from_string("a")), NumberError); BOOST_CHECK_THROW((Q::from_string("12a")), NumberError); BOOST_CHECK_THROW((Q::from_string("a12")), NumberError); BOOST_CHECK_THROW((Q::from_string("0.12")), NumberError); BOOST_CHECK_THROW((Q::from_string("12\na")), NumberError); BOOST_CHECK_THROW((Q::from_string("1a/2")), NumberError); BOOST_CHECK_THROW((Q::from_string("1 / 2a")), NumberError); // BOOST_CHECK_THROW((Q::from_string("1/0")), NumberError); BOOST_CHECK_THROW((Q::from_string("NaN")), NumberError); // operator+ BOOST_CHECK((Q(1) + Q(2) == Q(3))); BOOST_CHECK((Q(1) + 2 == Q(3))); BOOST_CHECK((1 + Q(2) == Q(3))); n = 1; BOOST_CHECK((Q(3) == (n += Q(2)))); n = 1; BOOST_CHECK((Q(3) == (n += 2))); BOOST_CHECK((Q(1) + Q(-2) == Q(-1))); BOOST_CHECK((Q(-1) + Q(2) == Q(1))); BOOST_CHECK((Q(-1) + Q(-2) == Q(-3))); BOOST_CHECK((Q(1, 2) + Q(1, 3) == Q(5, 6))); BOOST_CHECK((Q(-1, 2) + Q(1, 3) == Q(-1, 6))); BOOST_CHECK((Q(1, 2) + Q(-1, 3) == Q(1, 6))); BOOST_CHECK((Q(-1, 2) + Q(-1, 3) == Q(-5, 6))); BOOST_CHECK((Q::from_string("deadbeefbada550ff1ce", 16) + Q::from_string("deadbeefbadf00d", 16) == Q::from_string("deadccda96c950bde1db", 16))); // operator- BOOST_CHECK((Q(3) - Q(2) == Q(1))); BOOST_CHECK((Q(3) - 2 == Q(1))); BOOST_CHECK((3 - Q(2) == Q(1))); n = 3; BOOST_CHECK((Q(1) == (n -= Q(2)))); n = 3; BOOST_CHECK((Q(1) == (n -= 2))); BOOST_CHECK((Q(-3) - Q(1) == Q(-4))); BOOST_CHECK((Q(3) - Q(-1) == Q(4))); BOOST_CHECK((Q(-2) - Q(-3) == Q(1))); BOOST_CHECK((Q(1, 2) - Q(1, 3) == Q(1, 6))); BOOST_CHECK((Q(-1, 2) - Q(1, 3) == Q(-5, 6))); BOOST_CHECK((Q(1, 2) - Q(-1, 3) == Q(5, 6))); BOOST_CHECK((Q(-1, 2) - Q(-1, 3) == Q(-1, 6))); BOOST_CHECK((Q::from_string("deadbeefbada550ff1ce", 16) - Q::from_string("deadbeefbadf00d", 16) == Q::from_string("deadb104deeb596201c1", 16))); // operator* BOOST_CHECK((Q(3) * Q(2) == Q(6))); BOOST_CHECK((Q(3) * 2 == Q(6))); BOOST_CHECK((3 * Q(2) == Q(6))); n = 3; BOOST_CHECK((Q(6) == (n *= Q(2)))); n = 3; BOOST_CHECK((Q(6) == (n *= 2))); BOOST_CHECK((Q(3) * Q(-2) == Q(-6))); BOOST_CHECK((Q(-3) * Q(2) == Q(-6))); BOOST_CHECK((Q(-3) * Q(-2) == Q(6))); BOOST_CHECK((Q(1, 2) * Q(1, 3) == Q(1, 6))); BOOST_CHECK((Q(-1, 2) * Q(1, 3) == Q(-1, 6))); BOOST_CHECK((Q(1, 2) * Q(-1, 3) == Q(-1, 6))); BOOST_CHECK((Q(-1, 2) * Q(-1, 3) == Q(1, 6))); BOOST_CHECK((Q::from_string("deadbeefbada550ff1ce", 16) * Q::from_string("deadbeefbadf00d", 16) == Q::from_string("c1b1cd13668200953a2fd455234a6b66776", 16))); // operator/ BOOST_CHECK((Q(3) / Q(2) == Q(3, 2))); BOOST_CHECK((Q(3) / 2 == Q(3, 2))); BOOST_CHECK((3 / Q(2) == Q(3, 2))); n = 3; BOOST_CHECK((Q(3, 2) == (n /= Q(2)))); n = 3; BOOST_CHECK((Q(3, 2) == (n /= 2))); BOOST_CHECK((Q(11) / Q(3) == Q(11, 3))); BOOST_CHECK((Q(11) / Q(-3) == Q(-11, 3))); BOOST_CHECK((Q(-11) / Q(3) == Q(-11, 3))); BOOST_CHECK((Q(-11) / Q(-3) == Q(11, 3))); BOOST_CHECK((Q(12) / Q(3) == Q(12, 3))); BOOST_CHECK((Q(12) / Q(-3) == Q(-12, 3))); BOOST_CHECK((Q(-12) / Q(3) == Q(-12, 3))); BOOST_CHECK((Q(-12) / Q(-3) == Q(12, 3))); // operator++ n = 0; BOOST_CHECK((n++ == Q(0))); n = 0; BOOST_CHECK((++n == Q(1))); // operator-- n = 10; BOOST_CHECK((n-- == Q(10))); n = 10; BOOST_CHECK((--n == Q(9))); // operator== BOOST_CHECK((Q(1) == Q(1))); BOOST_CHECK((Q(1) == 1)); BOOST_CHECK((1 == Q(1))); BOOST_CHECK((Q(1, 2) == Q(2, 4))); BOOST_CHECK((!(Q(1, 2) == Q(2, 1)))); // operator!= BOOST_CHECK((Q(1) != Q(2))); BOOST_CHECK((Q(1) != 2)); BOOST_CHECK((1 != Q(2))); BOOST_CHECK((Q(1, 2) != Q(2, 1))); BOOST_CHECK((!(Q(1, 2) != Q(2, 4)))); // operator< BOOST_CHECK((Q(1) < Q(2))); BOOST_CHECK((Q(1) < 2)); BOOST_CHECK((1 < Q(2))); BOOST_CHECK((Q(1, 3) < Q(1, 2))); BOOST_CHECK((!(Q(1, 2) < Q(1, 3)))); BOOST_CHECK((!(Q(1, 2) < Q(1, 2)))); BOOST_CHECK((Q::from_string("deadbeefbadf00d", 16) < Q::from_string("deadbeefbada550ff1ce", 16))); // operator<= BOOST_CHECK((Q(1) <= Q(2))); BOOST_CHECK((Q(1) <= 2)); BOOST_CHECK((1 <= Q(2))); BOOST_CHECK((Q(1, 3) <= Q(1, 2))); BOOST_CHECK((!(Q(1, 2) <= Q(1, 3)))); BOOST_CHECK((Q(1, 2) <= Q(1, 2))); BOOST_CHECK((Q::from_string("deadbeefbadf00d", 16) <= Q::from_string("deadbeefbada550ff1ce", 16))); // operator> BOOST_CHECK((Q(2) > Q(1))); BOOST_CHECK((Q(2) > 1)); BOOST_CHECK((2 > Q(1))); BOOST_CHECK((Q(1, 2) > Q(1, 3))); BOOST_CHECK((!(Q(1, 3) > Q(1, 2)))); BOOST_CHECK((!(Q(1, 2) > Q(1, 2)))); BOOST_CHECK((Q::from_string("deadbeefbada550ff1ce", 16) > Q::from_string("deadbeefbadf00d", 16))); // operator>= BOOST_CHECK((Q(2) >= Q(1))); BOOST_CHECK((Q(2) >= 1)); BOOST_CHECK((2 >= Q(1))); BOOST_CHECK((Q(1, 2) >= Q(1, 3))); BOOST_CHECK((!(Q(1, 3) >= Q(1, 2)))); BOOST_CHECK((Q(1, 2) >= Q(1, 2))); BOOST_CHECK((Q::from_string("deadbeefbada550ff1ce", 16) >= Q::from_string("deadbeefbadf00d", 16))); // numerator BOOST_CHECK((Q(1, 2).numerator() == Z(1))); BOOST_CHECK((Q(1, -2).numerator() == Z(-1))); BOOST_CHECK((Q(-1, 2).numerator() == Z(-1))); BOOST_CHECK((Q(-1, -2).numerator() == Z(1))); BOOST_CHECK((Q(2, 4).numerator() == Z(1))); BOOST_CHECK((Q(7, 11).numerator() == Z(7))); // denominator BOOST_CHECK((Q(1, 2).denominator() == Z(2))); BOOST_CHECK((Q(1, -2).denominator() == Z(2))); BOOST_CHECK((Q(-1, 2).denominator() == Z(2))); BOOST_CHECK((Q(-1, -2).denominator() == Z(2))); BOOST_CHECK((Q(2, 4).denominator() == Z(2))); BOOST_CHECK((Q(7, 11).denominator() == Z(11))); // round_to_upper BOOST_CHECK((Q(1, 3).round_to_upper() == Z(1))); BOOST_CHECK((Q(4, 3).round_to_upper() == Z(2))); BOOST_CHECK((Q(1).round_to_upper() == Z(1))); BOOST_CHECK((Q(-1, 3).round_to_upper() == Z(0))); BOOST_CHECK((Q(-4, 3).round_to_upper() == Z(-1))); // round_to_lower BOOST_CHECK((Q(1, 3).round_to_lower() == Z(0))); BOOST_CHECK((Q(4, 3).round_to_lower() == Z(1))); BOOST_CHECK((Q(1).round_to_lower() == Z(1))); BOOST_CHECK((Q(-1, 3).round_to_lower() == Z(-1))); BOOST_CHECK((Q(-4, 3).round_to_lower() == Z(-2))); // min BOOST_CHECK((min(Q(1), Q(2)) == Q(1))); BOOST_CHECK((min(Q(2), Q(1)) == Q(1))); BOOST_CHECK((min(Q(2), Q(1), Q(3)) == Q(1))); BOOST_CHECK((min(Q(2), Q(1), Q(3), Q(-1)) == Q(-1))); // max BOOST_CHECK((max(Q(1), Q(2)) == Q(2))); BOOST_CHECK((max(Q(2), Q(1)) == Q(2))); BOOST_CHECK((max(Q(2), Q(1), Q(3)) == Q(3))); BOOST_CHECK((max(Q(2), Q(1), Q(3), Q(-1)) == Q(3))); // abs BOOST_CHECK((abs(Q(0)) == Q(0))); BOOST_CHECK((abs(Q(2)) == Q(2))); BOOST_CHECK((abs(Q(-2)) == Q(2))); BOOST_CHECK((abs(Q(1, 2)) == Q(1, 2))); BOOST_CHECK((abs(Q(-1, 2)) == Q(1, 2))); BOOST_CHECK((abs(Q(1, -2)) == Q(1, 2))); BOOST_CHECK((abs(Q(-1, -2)) == Q(1, 2))); // operator<< boost::test_tools::output_test_stream output; output << Q(1, 2); BOOST_CHECK(output.is_equal("1/2")); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/number/z_number.cpp000066400000000000000000000567471473507761200233440ustar00rootroot00000000000000/******************************************************************************* * * Tests for ZNumber * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #define BOOST_TEST_MODULE test_z_number #define BOOST_TEST_DYN_LINK #include #include #include #if BOOST_VERSION >= 107100 #include #else #include #endif #include BOOST_AUTO_TEST_CASE(test_z_number) { using Z = ikos::core::ZNumber; using NumberError = ikos::core::NumberError; // Assume (unsigned) long long is 8 bytes // NOLINTNEXTLINE(google-runtime-int) static_assert(sizeof(long long) == 8, "unexpected size"); // NOLINTNEXTLINE(google-runtime-int) static_assert(sizeof(unsigned long long) == 8, "unexpected size"); // constructors BOOST_CHECK((Z() == Z(0))); BOOST_CHECK((Z(1) == Z(static_cast< int >(1)))); BOOST_CHECK((Z(-1) == Z(static_cast< int >(-1)))); BOOST_CHECK((Z(1) == Z(static_cast< unsigned int >(1)))); BOOST_CHECK((Z(1) == Z(static_cast< long >(1)))); BOOST_CHECK((Z(-1) == Z(static_cast< long >(-1)))); BOOST_CHECK((Z(1) == Z(static_cast< unsigned long >(1)))); BOOST_CHECK((Z(1) == Z(static_cast< long long >(1)))); BOOST_CHECK((Z(-1) == Z(static_cast< long long >(-1)))); BOOST_CHECK((-(Z(1) << 63) == Z(std::numeric_limits< long long >::min()))); BOOST_CHECK((Z(1) << 63) - 1 == Z(std::numeric_limits< long long >::max())); BOOST_CHECK((Z(0x12345678) << 32) + Z(0x01234567) == Z(0x1234567801234567LL)); BOOST_CHECK((Z(1) == Z(static_cast< unsigned long long >(1)))); BOOST_CHECK((Z(1) << 64) - 1 == Z(std::numeric_limits< unsigned long long >::max())); BOOST_CHECK((Z(0x12345678) << 32) + Z(0x01234567) == Z(0x1234567801234567ULL)); // operator= Z n; BOOST_CHECK((Z(1) == (n = static_cast< int >(1)))); BOOST_CHECK((Z(-1) == (n = static_cast< int >(-1)))); BOOST_CHECK((Z(1) == (n = static_cast< unsigned int >(1)))); BOOST_CHECK((Z(1) == (n = static_cast< long >(1)))); BOOST_CHECK((Z(-1) == (n = static_cast< long >(-1)))); BOOST_CHECK((Z(1) == (n = static_cast< unsigned long >(1)))); BOOST_CHECK((Z(1) == (n = static_cast< long long >(1)))); BOOST_CHECK((Z(-1) == (n = static_cast< long long >(-1)))); BOOST_CHECK((Z(1) == (n = static_cast< unsigned long long >(1)))); // from_string BOOST_CHECK((Z(1) == Z::from_string("1"))); BOOST_CHECK((Z(-1) == Z::from_string("-1"))); BOOST_CHECK((Z(1) == Z::from_string("01"))); BOOST_CHECK((Z(1) == Z::from_string(" 1"))); BOOST_CHECK((Z(1) == Z::from_string("1\n"))); BOOST_CHECK((Z(101) == Z::from_string("1 0 1"))); BOOST_CHECK((Z(1) == Z::from_string("1", 10))); BOOST_CHECK((Z(2) == Z::from_string("10", 2))); BOOST_CHECK((Z(3) == Z::from_string("11", 2))); BOOST_CHECK((Z(10) == Z::from_string("A", 16))); BOOST_CHECK((Z(10) == Z::from_string("a", 16))); BOOST_CHECK((Z(0xFF) == Z::from_string("FF", 16))); BOOST_CHECK_THROW((Z::from_string("a")), NumberError); BOOST_CHECK_THROW((Z::from_string("12a")), NumberError); BOOST_CHECK_THROW((Z::from_string("a12")), NumberError); BOOST_CHECK_THROW((Z::from_string("0.12")), NumberError); BOOST_CHECK_THROW((Z::from_string("12\na")), NumberError); // operator+ BOOST_CHECK((Z(1) + Z(2) == Z(3))); BOOST_CHECK((Z(1) + 2 == Z(3))); BOOST_CHECK((1 + Z(2) == Z(3))); n = 1; BOOST_CHECK((Z(3) == (n += Z(2)))); n = 1; BOOST_CHECK((Z(3) == (n += 2))); BOOST_CHECK((Z(1) + Z(-2) == Z(-1))); BOOST_CHECK((Z(-1) + Z(2) == Z(1))); BOOST_CHECK((Z(-1) + Z(-2) == Z(-3))); BOOST_CHECK((Z::from_string("deadbeefbada550ff1ce", 16) + Z::from_string("deadbeefbadf00d", 16) == Z::from_string("deadccda96c950bde1db", 16))); // operator- BOOST_CHECK((Z(3) - Z(2) == Z(1))); BOOST_CHECK((Z(3) - 2 == Z(1))); BOOST_CHECK((3 - Z(2) == Z(1))); n = 3; BOOST_CHECK((Z(1) == (n -= Z(2)))); n = 3; BOOST_CHECK((Z(1) == (n -= 2))); BOOST_CHECK((Z(-3) - Z(1) == Z(-4))); BOOST_CHECK((Z(3) - Z(-1) == Z(4))); BOOST_CHECK((Z(-2) - Z(-3) == Z(1))); BOOST_CHECK((Z::from_string("deadbeefbada550ff1ce", 16) - Z::from_string("deadbeefbadf00d", 16) == Z::from_string("deadb104deeb596201c1", 16))); // operator* BOOST_CHECK((Z(3) * Z(2) == Z(6))); BOOST_CHECK((Z(3) * 2 == Z(6))); BOOST_CHECK((3 * Z(2) == Z(6))); n = 3; BOOST_CHECK((Z(6) == (n *= Z(2)))); n = 3; BOOST_CHECK((Z(6) == (n *= 2))); BOOST_CHECK((Z(3) * Z(-2) == Z(-6))); BOOST_CHECK((Z(-3) * Z(2) == Z(-6))); BOOST_CHECK((Z(-3) * Z(-2) == Z(6))); BOOST_CHECK((Z::from_string("deadbeefbada550ff1ce", 16) * Z::from_string("deadbeefbadf00d", 16) == Z::from_string("c1b1cd13668200953a2fd455234a6b66776", 16))); // operator/ BOOST_CHECK((Z(3) / Z(2) == Z(1))); BOOST_CHECK((Z(3) / 2 == Z(1))); BOOST_CHECK((3 / Z(2) == Z(1))); n = 3; BOOST_CHECK((Z(1) == (n /= Z(2)))); n = 3; BOOST_CHECK((Z(1) == (n /= 2))); BOOST_CHECK((Z(11) / Z(3) == Z(3))); BOOST_CHECK((Z(11) / Z(-3) == Z(-3))); BOOST_CHECK((Z(-11) / Z(3) == Z(-3))); BOOST_CHECK((Z(-11) / Z(-3) == Z(3))); BOOST_CHECK((Z(12) / Z(3) == Z(4))); BOOST_CHECK((Z(12) / Z(-3) == Z(-4))); BOOST_CHECK((Z(-12) / Z(3) == Z(-4))); BOOST_CHECK((Z(-12) / Z(-3) == Z(4))); BOOST_CHECK((Z::from_string("deadbeefbada550ff1ce", 16) / Z::from_string("deadbeefbadf00d", 16) == Z(0xfffff))); // operator% BOOST_CHECK((Z(3) % Z(2) == Z(1))); BOOST_CHECK((Z(3) % 2 == Z(1))); BOOST_CHECK((3 % Z(2) == Z(1))); n = 3; BOOST_CHECK((Z(1) == (n %= Z(2)))); n = 3; BOOST_CHECK((Z(1) == (n %= 2))); BOOST_CHECK((Z(11) % Z(3) == Z(2))); BOOST_CHECK((Z(11) % Z(-3) == Z(2))); BOOST_CHECK((Z(-11) % Z(3) == Z(-2))); BOOST_CHECK((Z(-11) % Z(-3) == Z(-2))); BOOST_CHECK((Z(12) % Z(3) == Z(0))); BOOST_CHECK((Z(12) % Z(-3) == Z(0))); BOOST_CHECK((Z(-12) % Z(3) == Z(0))); BOOST_CHECK((Z(-12) % Z(-3) == Z(0))); BOOST_CHECK((Z::from_string("deadbeefbada550ff1ce", 16) % Z::from_string("deadbeefbadf00d", 16) == Z::from_string("deadbea4fede1db", 16))); // operator& BOOST_CHECK(((Z(12) & Z(10)) == Z(8))); BOOST_CHECK(((Z(12) & 10) == Z(8))); BOOST_CHECK(((12 & Z(10)) == Z(8))); n = 12; BOOST_CHECK((Z(8) == (n &= Z(10)))); n = 12; BOOST_CHECK((Z(8) == (n &= 10))); BOOST_CHECK(((Z(12) & Z(10)) == Z(8))); BOOST_CHECK(((Z(12) & Z(-10)) == Z(4))); BOOST_CHECK(((Z(-12) & Z(10)) == Z(0))); BOOST_CHECK(((Z(-12) & Z(-10)) == Z(-12))); BOOST_CHECK(((Z::from_string("deadbeefbada550ff1ce", 16) & Z::from_string("deadbeefbadf00d", 16)) == Z::from_string("cea9aca510df00c", 16))); // operator| BOOST_CHECK(((Z(12) | Z(10)) == Z(14))); BOOST_CHECK(((Z(12) | 10) == Z(14))); BOOST_CHECK(((12 | Z(10)) == Z(14))); n = 14; BOOST_CHECK((Z(14) == (n |= Z(10)))); n = 12; BOOST_CHECK((Z(14) == (n |= 10))); BOOST_CHECK(((Z(12) | Z(10)) == Z(14))); BOOST_CHECK(((Z(12) | Z(-10)) == Z(-2))); BOOST_CHECK(((Z(-12) | Z(10)) == Z(-2))); BOOST_CHECK(((Z(-12) | Z(-10)) == Z(-10))); BOOST_CHECK(((Z::from_string("deadbeefbada550ff1ce", 16) | Z::from_string("deadbeefbadf00d", 16)) == Z::from_string("deadbfeffbfeffaff1cf", 16))); // operator^ BOOST_CHECK(((Z(12) ^ Z(10)) == Z(6))); BOOST_CHECK(((Z(12) ^ 10) == Z(6))); BOOST_CHECK(((12 ^ Z(10)) == Z(6))); n = 12; BOOST_CHECK((Z(6) == (n ^= Z(10)))); n = 12; BOOST_CHECK((Z(6) == (n ^= 10))); BOOST_CHECK(((Z(12) ^ Z(10)) == Z(6))); BOOST_CHECK(((Z(12) ^ Z(-10)) == Z(-6))); BOOST_CHECK(((Z(-12) ^ Z(10)) == Z(-2))); BOOST_CHECK(((Z(-12) ^ Z(-10)) == Z(2))); BOOST_CHECK(((Z::from_string("deadbeefbada550ff1ce", 16) ^ Z::from_string("deadbeefbadf00d", 16)) == Z::from_string("deadb3056134aea201c3", 16))); // operator<< BOOST_CHECK(((Z(10) << Z(2)) == Z(40))); BOOST_CHECK(((Z(10) << 2) == Z(40))); n = 10; BOOST_CHECK((Z(40) == (n <<= Z(2)))); n = 10; BOOST_CHECK((Z(40) == (n <<= 2))); BOOST_CHECK(((Z(10) << Z(2)) == Z(40))); BOOST_CHECK(((Z(-10) << Z(2)) == Z(-40))); BOOST_CHECK(((Z::from_string("deadbeefbada550ff1ce", 16) << 42) == Z::from_string("37ab6fbbeeb69543fc7380000000000", 16))); // operator>> BOOST_CHECK(((Z(10) >> Z(2)) == Z(2))); BOOST_CHECK(((Z(10) >> 2) == Z(2))); n = 10; BOOST_CHECK((Z(2) == (n >>= Z(2)))); n = 10; BOOST_CHECK((Z(2) == (n >>= 2))); BOOST_CHECK(((Z(10) >> Z(2)) == Z(2))); BOOST_CHECK(((Z(-10) >> Z(2)) == Z(-3))); BOOST_CHECK(((Z::from_string("deadbeefbada550ff1ce", 16) >> 42) == Z::from_string("37ab6fbbee", 16))); // operator++ n = 0; BOOST_CHECK((n++ == Z(0))); n = 0; BOOST_CHECK((++n == Z(1))); // operator-- n = 10; BOOST_CHECK((n-- == Z(10))); n = 10; BOOST_CHECK((--n == Z(9))); // operator== BOOST_CHECK((Z(1) == Z(1))); BOOST_CHECK((Z(1) == 1)); BOOST_CHECK((1 == Z(1))); BOOST_CHECK((Z(1) == Z(1))); BOOST_CHECK((!(Z(1) == Z(2)))); // operator!= BOOST_CHECK((Z(1) != Z(2))); BOOST_CHECK((Z(1) != 2)); BOOST_CHECK((1 != Z(2))); BOOST_CHECK((Z(1) != Z(2))); BOOST_CHECK((!(Z(1) != Z(1)))); // operator< BOOST_CHECK((Z(1) < Z(2))); BOOST_CHECK((Z(1) < 2)); BOOST_CHECK((1 < Z(2))); BOOST_CHECK((Z(1) < Z(2))); BOOST_CHECK((!(Z(2) < Z(1)))); BOOST_CHECK((!(Z(1) < Z(1)))); BOOST_CHECK((Z::from_string("deadbeefbadf00d", 16) < Z::from_string("deadbeefbada550ff1ce", 16))); // operator<= BOOST_CHECK((Z(1) <= Z(2))); BOOST_CHECK((Z(1) <= 2)); BOOST_CHECK((1 <= Z(2))); BOOST_CHECK((Z(1) <= Z(2))); BOOST_CHECK((!(Z(2) <= Z(1)))); BOOST_CHECK((Z(1) <= Z(1))); BOOST_CHECK((Z::from_string("deadbeefbadf00d", 16) <= Z::from_string("deadbeefbada550ff1ce", 16))); // operator> BOOST_CHECK((Z(2) > Z(1))); BOOST_CHECK((Z(2) > 1)); BOOST_CHECK((2 > Z(1))); BOOST_CHECK((Z(2) > Z(1))); BOOST_CHECK((!(Z(1) > Z(2)))); BOOST_CHECK((!(Z(1) > Z(1)))); BOOST_CHECK((Z::from_string("deadbeefbada550ff1ce", 16) > Z::from_string("deadbeefbadf00d", 16))); // operator>= BOOST_CHECK((Z(2) >= Z(1))); BOOST_CHECK((Z(2) >= 1)); BOOST_CHECK((2 >= Z(1))); BOOST_CHECK((Z(2) >= Z(1))); BOOST_CHECK((!(Z(1) >= Z(2)))); BOOST_CHECK((Z(1) >= Z(1))); BOOST_CHECK((Z::from_string("deadbeefbada550ff1ce", 16) >= Z::from_string("deadbeefbadf00d", 16))); // trailing_zeros BOOST_CHECK(Z(1).trailing_zeros() == 0); BOOST_CHECK(Z(2).trailing_zeros() == 1); BOOST_CHECK(Z(3).trailing_zeros() == 0); BOOST_CHECK(Z(4).trailing_zeros() == 2); BOOST_CHECK(Z(5).trailing_zeros() == 0); BOOST_CHECK(Z(-1).trailing_zeros() == 0); BOOST_CHECK(Z(-2).trailing_zeros() == 1); BOOST_CHECK(Z(-3).trailing_zeros() == 0); // trailing_ones BOOST_CHECK(Z(0).trailing_ones() == 0); BOOST_CHECK(Z(1).trailing_ones() == 1); BOOST_CHECK(Z(2).trailing_ones() == 0); BOOST_CHECK(Z(3).trailing_ones() == 2); BOOST_CHECK(Z(4).trailing_ones() == 0); BOOST_CHECK(Z(5).trailing_ones() == 1); BOOST_CHECK(Z(-2).trailing_ones() == 0); BOOST_CHECK(Z(-3).trailing_ones() == 1); // size_in_bits BOOST_CHECK(Z(0).size_in_bits() == 1); BOOST_CHECK(Z(1).size_in_bits() == 1); BOOST_CHECK(Z(2).size_in_bits() == 2); BOOST_CHECK(Z(3).size_in_bits() == 2); BOOST_CHECK(Z(4).size_in_bits() == 3); BOOST_CHECK(Z(5).size_in_bits() == 3); BOOST_CHECK(Z(6).size_in_bits() == 3); BOOST_CHECK(Z(7).size_in_bits() == 3); BOOST_CHECK(Z(8).size_in_bits() == 4); BOOST_CHECK(Z(9).size_in_bits() == 4); BOOST_CHECK(Z(-2).size_in_bits() == 2); BOOST_CHECK(Z(-3).size_in_bits() == 2); // next_power_of_2 BOOST_CHECK(Z(0).next_power_of_2() == 1); BOOST_CHECK(Z(1).next_power_of_2() == 1); BOOST_CHECK(Z(2).next_power_of_2() == 2); BOOST_CHECK(Z(3).next_power_of_2() == 4); BOOST_CHECK(Z(4).next_power_of_2() == 4); BOOST_CHECK(Z(5).next_power_of_2() == 8); BOOST_CHECK(Z(6).next_power_of_2() == 8); BOOST_CHECK(Z(7).next_power_of_2() == 8); BOOST_CHECK(Z(8).next_power_of_2() == 8); BOOST_CHECK(Z(9).next_power_of_2() == 16); BOOST_CHECK(Z(10).next_power_of_2() == 16); BOOST_CHECK(Z(15).next_power_of_2() == 16); BOOST_CHECK(Z(16).next_power_of_2() == 16); BOOST_CHECK(Z(17).next_power_of_2() == 32); // min BOOST_CHECK((min(Z(1), Z(2)) == Z(1))); BOOST_CHECK((min(Z(2), Z(1)) == Z(1))); BOOST_CHECK((min(Z(2), Z(1), Z(3)) == Z(1))); BOOST_CHECK((min(Z(2), Z(1), Z(3), Z(-1)) == Z(-1))); // max BOOST_CHECK((max(Z(1), Z(2)) == Z(2))); BOOST_CHECK((max(Z(2), Z(1)) == Z(2))); BOOST_CHECK((max(Z(2), Z(1), Z(3)) == Z(3))); BOOST_CHECK((max(Z(2), Z(1), Z(3), Z(-1)) == Z(3))); // mod BOOST_CHECK((mod(Z(11), Z(3)) == Z(2))); BOOST_CHECK((mod(Z(11), Z(-3)) == Z(2))); BOOST_CHECK((mod(Z(-11), Z(3)) == Z(1))); BOOST_CHECK((mod(Z(-11), Z(-3)) == Z(1))); BOOST_CHECK((mod(Z(12), Z(3)) == Z(0))); BOOST_CHECK((mod(Z(12), Z(-3)) == Z(0))); BOOST_CHECK((mod(Z(-12), Z(3)) == Z(0))); BOOST_CHECK((mod(Z(-12), Z(-3)) == Z(0))); // abs BOOST_CHECK((abs(Z(0)) == Z(0))); BOOST_CHECK((abs(Z(2)) == Z(2))); BOOST_CHECK((abs(Z(-2)) == Z(2))); // gcd BOOST_CHECK((gcd(Z(0), Z(0)) == Z(0))); BOOST_CHECK((gcd(Z(0), Z(2)) == Z(2))); BOOST_CHECK((gcd(Z(2), Z(4)) == Z(2))); BOOST_CHECK((gcd(Z(-2), Z(4)) == Z(2))); BOOST_CHECK((gcd(Z(2), Z(-4)) == Z(2))); BOOST_CHECK((gcd(Z(-2), Z(-4)) == Z(2))); BOOST_CHECK((gcd(Z(3), Z(7)) == Z(1))); BOOST_CHECK((gcd(Z(21), Z(35)) == Z(7))); // lcm BOOST_CHECK((lcm(Z(0), Z(0)) == Z(0))); BOOST_CHECK((lcm(Z(0), Z(2)) == Z(0))); BOOST_CHECK((lcm(Z(2), Z(4)) == Z(4))); BOOST_CHECK((lcm(Z(-2), Z(4)) == Z(4))); BOOST_CHECK((lcm(Z(2), Z(-4)) == Z(4))); BOOST_CHECK((lcm(Z(-2), Z(-4)) == Z(4))); BOOST_CHECK((lcm(Z(3), Z(7)) == Z(21))); BOOST_CHECK((lcm(Z(21), Z(35)) == Z(105))); // gcd_extended Z g; Z a; Z b; Z u; Z v; gcd_extended(a = Z(0), b = Z(0), g, u, v); BOOST_CHECK((g == Z(0) && g == a * u + b * v)); gcd_extended(a = Z(0), b = Z(2), g, u, v); BOOST_CHECK((g == Z(2) && g == a * u + b * v)); gcd_extended(a = Z(2), b = Z(4), g, u, v); BOOST_CHECK((g == Z(2) && g == a * u + b * v)); gcd_extended(a = Z(-2), b = Z(4), g, u, v); BOOST_CHECK((g == Z(2) && g == a * u + b * v)); gcd_extended(a = Z(2), b = Z(-4), g, u, v); BOOST_CHECK((g == Z(2) && g == a * u + b * v)); gcd_extended(a = Z(-2), b = Z(-4), g, u, v); BOOST_CHECK((g == Z(2) && g == a * u + b * v)); gcd_extended(a = Z(3), b = Z(7), g, u, v); BOOST_CHECK((g == Z(1) && g == a * u + b * v)); gcd_extended(a = Z(21), b = Z(35), g, u, v); BOOST_CHECK((g == Z(7) && g == a * u + b * v)); gcd_extended(a = Z(3), b = Z(4), g, u, v); BOOST_CHECK((g == Z(1) && g == a * u + b * v)); gcd_extended(a = Z(270), b = Z(192), g, u, v); BOOST_CHECK((g == Z(6) && g == a * u + b * v)); // fits< T > BOOST_CHECK(Z(1).fits< int >()); BOOST_CHECK(Z(-1).fits< int >()); BOOST_CHECK(Z(std::numeric_limits< int >::max()).fits< int >()); BOOST_CHECK(Z(std::numeric_limits< int >::min()).fits< int >()); BOOST_CHECK(!(Z(std::numeric_limits< int >::max()) + 1).fits< int >()); BOOST_CHECK(!(Z(std::numeric_limits< int >::min()) - 1).fits< int >()); BOOST_CHECK(Z(0).fits< unsigned int >()); BOOST_CHECK(Z(1).fits< unsigned int >()); BOOST_CHECK( Z(std::numeric_limits< unsigned int >::max()).fits< unsigned int >()); BOOST_CHECK(!Z(-1).fits< unsigned int >()); BOOST_CHECK(!(Z(std::numeric_limits< unsigned int >::max()) + 1) .fits< unsigned int >()); BOOST_CHECK(Z(1).fits< long >()); BOOST_CHECK(Z(-1).fits< long >()); BOOST_CHECK(Z(std::numeric_limits< long >::max()).fits< long >()); BOOST_CHECK(Z(std::numeric_limits< long >::min()).fits< long >()); BOOST_CHECK(!(Z(std::numeric_limits< long >::max()) + 1).fits< long >()); BOOST_CHECK(!(Z(std::numeric_limits< long >::min()) - 1).fits< long >()); BOOST_CHECK(Z(0).fits< unsigned long >()); BOOST_CHECK(Z(1).fits< unsigned long >()); BOOST_CHECK( Z(std::numeric_limits< unsigned long >::max()).fits< unsigned long >()); BOOST_CHECK(!Z(-1).fits< unsigned long >()); BOOST_CHECK(!(Z(std::numeric_limits< unsigned long >::max()) + 1) .fits< unsigned long >()); BOOST_CHECK(Z(1).fits< long long >()); BOOST_CHECK(Z(-1).fits< long long >()); BOOST_CHECK(Z(std::numeric_limits< long long >::max()).fits< long long >()); BOOST_CHECK(Z(std::numeric_limits< long long >::min()).fits< long long >()); BOOST_CHECK( !(Z(std::numeric_limits< long long >::max()) + 1).fits< long long >()); BOOST_CHECK( !(Z(std::numeric_limits< long long >::min()) - 1).fits< long long >()); BOOST_CHECK(((Z(0x12345678) << 32) + Z(0x01234567)).fits< long long >()); BOOST_CHECK(!((Z(0x82345678) << 32) + Z(0x01234567)).fits< long long >()); BOOST_CHECK(!(-((Z(0x82345678) << 32) + Z(0x01234567))).fits< long long >()); BOOST_CHECK(Z(0).fits< unsigned long long >()); BOOST_CHECK(Z(1).fits< unsigned long long >()); BOOST_CHECK(!Z(-1).fits< unsigned long long >()); BOOST_CHECK(Z(std::numeric_limits< unsigned long long >::max()) .fits< unsigned long long >()); BOOST_CHECK(!(Z(std::numeric_limits< unsigned long long >::max()) + 1) .fits< unsigned long long >()); BOOST_CHECK( ((Z(0x12345678) << 32) + Z(0x01234567)).fits< unsigned long long >()); BOOST_CHECK( ((Z(0x82345678) << 32) + Z(0x01234567)).fits< unsigned long long >()); BOOST_CHECK( !(-((Z(0x82345678) << 32) + Z(0x01234567))).fits< unsigned long long >()); // to< T > BOOST_CHECK(Z(1).to< int >() == static_cast< int >(1)); BOOST_CHECK(Z(-1).to< int >() == static_cast< int >(-1)); BOOST_CHECK(Z(std::numeric_limits< int >::max()).to< int >() == std::numeric_limits< int >::max()); BOOST_CHECK(Z(std::numeric_limits< int >::min()).to< int >() == std::numeric_limits< int >::min()); BOOST_CHECK(Z(0).to< unsigned int >() == static_cast< unsigned int >(0)); BOOST_CHECK(Z(1).to< unsigned int >() == static_cast< unsigned int >(1)); BOOST_CHECK( Z(std::numeric_limits< unsigned int >::max()).to< unsigned int >() == std::numeric_limits< unsigned int >::max()); BOOST_CHECK(Z(1).to< long >() == static_cast< long >(1)); BOOST_CHECK(Z(-1).to< long >() == static_cast< long >(-1)); BOOST_CHECK(Z(std::numeric_limits< long >::max()).to< long >() == std::numeric_limits< long >::max()); BOOST_CHECK(Z(std::numeric_limits< long >::min()).to< long >() == std::numeric_limits< long >::min()); BOOST_CHECK(Z(0).to< unsigned long >() == static_cast< unsigned long >(0)); BOOST_CHECK(Z(1).to< unsigned long >() == static_cast< unsigned long >(1)); BOOST_CHECK( Z(std::numeric_limits< unsigned long >::max()).to< unsigned long >() == std::numeric_limits< unsigned long >::max()); BOOST_CHECK(Z(1).to< long long >() == static_cast< long long >(1)); BOOST_CHECK(Z(-1).to< long long >() == static_cast< long long >(-1)); BOOST_CHECK(Z(std::numeric_limits< long long >::max()).to< long long >() == std::numeric_limits< long long >::max()); BOOST_CHECK(Z(std::numeric_limits< long long >::min()).to< long long >() == std::numeric_limits< long long >::min()); BOOST_CHECK(((Z(0x12345678) << 32) + Z(0x01234567)).to< long long >() == 0x1234567801234567LL); BOOST_CHECK(Z(0).to< unsigned long long >() == static_cast< unsigned long long >(0)); BOOST_CHECK(Z(1).to< unsigned long long >() == static_cast< unsigned long long >(1)); BOOST_CHECK(Z(std::numeric_limits< unsigned long long >::max()) .to< unsigned long long >() == std::numeric_limits< unsigned long long >::max()); BOOST_CHECK( ((Z(0x12345678) << 32) + Z(0x01234567)).to< unsigned long long >() == 0x1234567801234567ULL); BOOST_CHECK( ((Z(0x82345678) << 32) + Z(0x01234567)).to< unsigned long long >() == 0x8234567801234567ULL); // operator<< boost::test_tools::output_test_stream output; output << Z(42); BOOST_CHECK(output.is_equal("42")); // ZNumber single_mask(const ZNumber& size); BOOST_CHECK(single_mask(Z(0)) == Z(0)); BOOST_CHECK(single_mask((Z(1) << 32) - 1) == single_mask((Z(1) << 32) - 1)); // On some platforms bigger values will work, but don't count on it. // BOOST_CHECK(single_mask(Z(1) << 34) == single_mask(Z(1) << 34)); BOOST_CHECK(single_mask(Z(5)).str(2) == "11111"); // ZNumber double_mask(const ZNumber& low, const ZNumber& high); BOOST_CHECK(double_mask(Z(2), Z(5)).str(2) == "11100"); BOOST_CHECK(double_mask(Z(0), Z(5)).str(2) == "11111"); // ZNumber make_clipped_mask( // const ZNumber& low, const ZNumber& size, // const ZNumber& lower_clip, const ZNumber& size_clip); BOOST_CHECK(make_clipped_mask(Z(2), Z(5), Z(2), Z(5)).str(2) == "11111"); BOOST_CHECK(make_clipped_mask(Z(0), Z(10), Z(2), Z(5)).str(2) == "11111"); BOOST_CHECK(make_clipped_mask(Z(0), Z(7), Z(2), Z(5)).str(2) == "11111"); BOOST_CHECK(make_clipped_mask(Z(0), Z(5), Z(2), Z(5)).str(2) == "111"); BOOST_CHECK(make_clipped_mask(Z(0), Z(2), Z(2), Z(5)).str(2) == "0"); BOOST_CHECK(make_clipped_mask(Z(0), Z(1), Z(2), Z(5)).str(2) == "0"); BOOST_CHECK(make_clipped_mask(Z(3), Z(2), Z(2), Z(5)).str(2) == "110"); BOOST_CHECK(make_clipped_mask(Z(2), Z(4), Z(2), Z(5)).str(2) == "1111"); BOOST_CHECK(make_clipped_mask(Z(2), Z(5), Z(2), Z(5)).str(2) == "11111"); BOOST_CHECK(make_clipped_mask(Z(6), Z(2), Z(2), Z(5)).str(2) == "10000"); BOOST_CHECK(make_clipped_mask(Z(7), Z(5), Z(2), Z(5)).str(2) == "0"); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/000077500000000000000000000000001473507761200206205ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/machine_int/000077500000000000000000000000001473507761200230765ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/machine_int/congruence.cpp000066400000000000000000007006271473507761200257460ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::Congruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_integer_congruence #define BOOST_TEST_DYN_LINK #include #include #include #include using Z = ikos::core::ZNumber; using Int = ikos::core::MachineInt; using Congruence = ikos::core::machine_int::Congruence; using ikos::core::Signed; using ikos::core::Unsigned; BOOST_AUTO_TEST_CASE(test_constructors) { // Congruence(Int) BOOST_CHECK(Congruence(Int(0, 8, Signed)) == Congruence(Int(0, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(1, 8, Signed)) == Congruence(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(-128, 8, Signed)) == Congruence(Int(0, 8, Signed), Int(-128, 8, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed)) == Congruence(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)) == Congruence(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(1, 8, Unsigned)) == Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned)) == Congruence(Int(0, 8, Unsigned), Int(255, 8, Unsigned))); // Congruence(Int a, Int b) BOOST_CHECK(Congruence(Int(0, 8, Signed), Int(0, 8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Signed), Int(1, 8, Signed)) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(1, 8, Signed), Int(0, 8, Signed)) == Congruence(Int(1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(1, 8, Signed), Int(1, 8, Signed)) == Congruence(Int(1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(1, 8, Signed), Int(-1, 8, Signed)) == Congruence(Int(1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(2, 8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(-2, 8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)) == Congruence(Int(2, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed), Int(1, 8, Signed)) == Congruence(Int(127, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed), Int(-1, 8, Signed)) == Congruence(Int(127, 8, Signed), Int(126, 8, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned), Int(0, 8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned)) == Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(1, 8, Unsigned), Int(1, 8, Unsigned)) == Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(1, 8, Unsigned), Int(255, 8, Unsigned)) == Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(2, 8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(4, 8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned), Int(1, 8, Unsigned)) == Congruence(Int(255, 8, Unsigned), Int(1, 8, Unsigned))); // tricky cases BOOST_CHECK(Congruence(Int(254, 8, Unsigned), Int(2, 8, Unsigned)) == Congruence(Int(0, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(250, 8, Unsigned), Int(6, 8, Unsigned)) == Congruence(Int(0, 8, Unsigned), Int(6, 8, Unsigned))); // Congruence(Z a, Z b) BOOST_CHECK(Congruence(Z(128), Z(-1), 8, Signed) == Congruence(Z(128), Z(127), 8, Signed)); BOOST_CHECK(Congruence(Z(254), Z(2), 8, Signed) == Congruence(Z(0), Z(2), 8, Signed)); BOOST_CHECK(Congruence(Z(254), Z(128), 8, Signed) == Congruence(Z(0), Z(-126), 8, Signed)); BOOST_CHECK(Congruence(Z(254), Z(2), 8, Unsigned) == Congruence(Z(0), Z(2), 8, Unsigned)); BOOST_CHECK(Congruence(Z(250), Z(6), 8, Unsigned) == Congruence(Z(0), Z(6), 8, Unsigned)); // Congruence::top()/bottom() BOOST_CHECK(Congruence::top(1, Signed) == Congruence(Z(1), Z(0), 1, Signed)); BOOST_CHECK(Congruence::top(8, Signed) == Congruence(Z(1), Z(0), 8, Signed)); BOOST_CHECK(Congruence::top(1, Unsigned) == Congruence(Z(1), Z(0), 1, Unsigned)); BOOST_CHECK(Congruence::top(8, Unsigned) == Congruence(Z(1), Z(0), 8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_bit_width) { BOOST_CHECK(Congruence(Int(0, 4, Signed)).bit_width() == 4); BOOST_CHECK(Congruence(Int(0, 4, Unsigned)).bit_width() == 4); BOOST_CHECK(Congruence(Int(0, 8, Signed)).bit_width() == 8); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)).bit_width() == 8); } BOOST_AUTO_TEST_CASE(test_sign) { BOOST_CHECK(Congruence(Int(0, 4, Signed)).sign() == Signed); BOOST_CHECK(Congruence(Int(0, 4, Unsigned)).sign() == Unsigned); BOOST_CHECK(Congruence(Int(0, 8, Signed)).sign() == Signed); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)).sign() == Unsigned); } BOOST_AUTO_TEST_CASE(test_modulus_and_residue) { BOOST_CHECK(Congruence(Int(0, 8, Signed), Int(1, 8, Signed)).modulus() == Z(0)); BOOST_CHECK(Congruence(Int(0, 8, Signed), Int(1, 8, Signed)).residue() == Z(1)); BOOST_CHECK(Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).modulus() == Z(0)); BOOST_CHECK(Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).residue() == Z(1)); } BOOST_AUTO_TEST_CASE(test_bottom) { BOOST_CHECK(Congruence::bottom(8, Signed).is_bottom()); BOOST_CHECK(!Congruence::top(8, Signed).is_bottom()); BOOST_CHECK(!Congruence(Int(0, 8, Signed), Int(1, 8, Signed)).is_bottom()); BOOST_CHECK(!Congruence(Int(1, 8, Signed), Int(0, 8, Signed)).is_bottom()); BOOST_CHECK(Congruence::bottom(8, Unsigned).is_bottom()); BOOST_CHECK(!Congruence::top(8, Unsigned).is_bottom()); BOOST_CHECK( !Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).is_bottom()); BOOST_CHECK( !Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned)).is_bottom()); BOOST_CHECK( !Congruence(Int(0, 8, Unsigned), Int(255, 8, Unsigned)).is_bottom()); } BOOST_AUTO_TEST_CASE(test_top) { BOOST_CHECK(!Congruence::bottom(8, Signed).is_top()); BOOST_CHECK(Congruence::top(8, Signed).is_top()); BOOST_CHECK(!Congruence(Int(0, 8, Signed), Int(1, 8, Signed)).is_top()); BOOST_CHECK(Congruence(Int(1, 8, Signed), Int(0, 8, Signed)).is_top()); BOOST_CHECK(!Congruence::bottom(8, Unsigned).is_top()); BOOST_CHECK(Congruence::top(8, Unsigned).is_top()); BOOST_CHECK(!Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).is_top()); BOOST_CHECK(Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned)).is_top()); BOOST_CHECK(!Congruence(Int(0, 8, Unsigned), Int(255, 8, Unsigned)).is_top()); } BOOST_AUTO_TEST_CASE(test_set_to_bottom) { Congruence i(Int(0, 8, Signed)); i.set_to_bottom(); BOOST_CHECK(i.is_bottom()); BOOST_CHECK(!i.is_top()); } BOOST_AUTO_TEST_CASE(test_set_to_top) { Congruence i(Int(0, 8, Signed)); i.set_to_top(); BOOST_CHECK(!i.is_bottom()); BOOST_CHECK(i.is_top()); } BOOST_AUTO_TEST_CASE(test_leq) { BOOST_CHECK(Congruence::bottom(8, Signed).leq(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence::bottom(8, Signed).leq(Congruence::top(8, Signed))); BOOST_CHECK(!Congruence::top(8, Signed).leq(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence::top(8, Signed).leq(Congruence::top(8, Signed))); // Signed BOOST_CHECK( !Congruence(Int(0, 8, Signed)).leq(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Signed)).leq(Congruence::top(8, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(0, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( !Congruence(Int(127, 8, Signed)).leq(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed)).leq(Congruence::top(8, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .leq(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .leq(Congruence::top(8, Signed))); BOOST_CHECK(!Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .leq(Congruence(Int(4, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .leq(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)))); BOOST_CHECK(!Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .leq(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .leq(Congruence::top(8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .leq(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .leq(Congruence::top(8, Signed))); BOOST_CHECK(!Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .leq(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( !Congruence(Z(128), Z(7), 8, Signed).leq(Congruence::bottom(8, Signed))); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed).leq(Congruence::top(8, Signed))); BOOST_CHECK(!Congruence(Z(128), Z(7), 8, Signed) .leq(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .leq(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); // Unsigned BOOST_CHECK( !Congruence(Int(0, 8, Unsigned)).leq(Congruence::bottom(8, Unsigned))); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).leq(Congruence::top(8, Unsigned))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(0, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(255, 8, Unsigned)).leq(Congruence::bottom(8, Unsigned))); BOOST_CHECK( Congruence(Int(255, 8, Unsigned)).leq(Congruence::top(8, Unsigned))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(255, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .leq(Congruence::bottom(8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .leq(Congruence::top(8, Unsigned))); BOOST_CHECK(!Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .leq(Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .leq(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .leq(Congruence::bottom(8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .leq(Congruence::top(8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .leq(Congruence::bottom(8, Unsigned))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .leq(Congruence::top(8, Unsigned))); BOOST_CHECK(!Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .leq(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_equals) { BOOST_CHECK( Congruence::bottom(8, Signed).equals(Congruence::bottom(8, Signed))); BOOST_CHECK( !Congruence::bottom(8, Signed).equals(Congruence::top(8, Signed))); BOOST_CHECK( !Congruence::top(8, Signed).equals(Congruence::bottom(8, Signed))); BOOST_CHECK(Congruence::top(8, Signed).equals(Congruence::top(8, Signed))); // Signed BOOST_CHECK( !Congruence(Int(0, 8, Signed)).equals(Congruence::bottom(8, Signed))); BOOST_CHECK( !Congruence(Int(0, 8, Signed)).equals(Congruence::top(8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).equals(Congruence(Int(0, 8, Signed)))); BOOST_CHECK( !Congruence(Int(0, 8, Signed)).equals(Congruence(Int(1, 8, Signed)))); BOOST_CHECK(!Congruence(Int(0, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(0, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( !Congruence(Int(127, 8, Signed)).equals(Congruence::bottom(8, Signed))); BOOST_CHECK( !Congruence(Int(127, 8, Signed)).equals(Congruence::top(8, Signed))); BOOST_CHECK( Congruence(Int(127, 8, Signed)).equals(Congruence(Int(127, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .equals(Congruence::bottom(8, Signed))); BOOST_CHECK(!Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .equals(Congruence::top(8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(2, 8, Signed)))); BOOST_CHECK(!Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .equals(Congruence::bottom(8, Signed))); BOOST_CHECK(!Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .equals(Congruence::top(8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .equals(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)))); BOOST_CHECK(!Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .equals(Congruence(Int(4, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .equals(Congruence::bottom(8, Signed))); BOOST_CHECK(!Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .equals(Congruence::top(8, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .equals(Congruence(Int(127, 8, Signed), Int(7, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Int(127, 8, Signed), Int(7, 8, Signed)) .equals(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(!Congruence(Z(128), Z(7), 8, Signed) .equals(Congruence::bottom(8, Signed))); BOOST_CHECK( !Congruence(Z(128), Z(7), 8, Signed).equals(Congruence::top(8, Signed))); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .equals(Congruence(Z(128), Z(7), 8, Signed))); BOOST_CHECK(!Congruence(Z(128), Z(7), 8, Signed) .equals(Congruence(Z(128), Z(6), 8, Signed))); BOOST_CHECK(!Congruence(Z(128), Z(7), 8, Signed) .equals(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Congruence(Z(128), Z(7), 8, Signed) .equals(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)))); // Unsigned BOOST_CHECK( !Congruence(Int(0, 8, Unsigned)).equals(Congruence::bottom(8, Unsigned))); BOOST_CHECK( !Congruence(Int(0, 8, Unsigned)).equals(Congruence::top(8, Unsigned))); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).equals(Congruence(Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(0, 8, Unsigned)).equals(Congruence(Int(1, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(0, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(0, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(255, 8, Unsigned)) .equals(Congruence::bottom(8, Unsigned))); BOOST_CHECK( !Congruence(Int(255, 8, Unsigned)).equals(Congruence::top(8, Unsigned))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned)) .equals(Congruence(Int(255, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(255, 8, Unsigned)) .equals(Congruence(Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(255, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(255, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .equals(Congruence::bottom(8, Unsigned))); BOOST_CHECK(!Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .equals(Congruence::top(8, Unsigned))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(2, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .equals(Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .equals(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .equals(Congruence::bottom(8, Unsigned))); BOOST_CHECK(!Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .equals(Congruence::top(8, Unsigned))); BOOST_CHECK( Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .equals(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .equals(Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK(!Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence::bottom(8, Unsigned))); BOOST_CHECK(!Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence::top(8, Unsigned))); BOOST_CHECK( Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK( !Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)))); // tricky cases BOOST_CHECK(Congruence(Z(254), Z(2), 8, Signed) .equals(Congruence(Z(0), Z(2), 8, Signed))); BOOST_CHECK(Congruence(Z(254), Z(128), 8, Signed) .equals(Congruence(Z(0), Z(-126), 8, Signed))); BOOST_CHECK(Congruence(Z(254), Z(2), 8, Unsigned) .equals(Congruence(Z(0), Z(2), 8, Unsigned))); BOOST_CHECK(Congruence(Z(250), Z(6), 8, Unsigned) .equals(Congruence(Z(0), Z(6), 8, Unsigned))); BOOST_CHECK( Congruence(Int(255, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence(Int(0, 8, Unsigned), Int(7, 8, Unsigned)))); BOOST_CHECK( Congruence(Int(254, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence(Int(0, 8, Unsigned), Int(7, 8, Unsigned)))); BOOST_CHECK( Congruence(Int(253, 8, Unsigned), Int(7, 8, Unsigned)) .equals(Congruence(Int(0, 8, Unsigned), Int(7, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_join) { BOOST_CHECK(Congruence::top(8, Signed).join(Congruence::bottom(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence::top(8, Signed).join(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence::bottom(8, Signed).join(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence::bottom(8, Signed).join(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); // Signed BOOST_CHECK( Congruence(Int(0, 8, Signed)).join(Congruence::bottom(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Signed)).join(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence(Int(0, 8, Signed)).join(Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).join(Congruence(Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence(Int(0, 8, Signed)).join(Congruence(Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(-128, 8, Signed)).join(Congruence(Int(127, 8, Signed))) == Congruence(Z(255), Z(127), 8, Signed)); BOOST_CHECK( Congruence(Int(-127, 8, Signed)).join(Congruence(Int(127, 8, Signed))) == Congruence(Z(254), Z(127), 8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .join(Congruence::bottom(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .join(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .join(Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .join(Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .join(Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .join(Congruence::bottom(8, Signed)) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .join(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .join(Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .join(Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .join(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed).join(Congruence::bottom(8, Signed)) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed).join(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed).join(Congruence(Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .join(Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .join(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); // Unsigned BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).join(Congruence::bottom(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).join(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).join(Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( Congruence(Int(2, 8, Unsigned)).join(Congruence(Int(4, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(255, 8, Unsigned)).join(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .join(Congruence::bottom(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .join(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .join(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .join(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .join(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .join(Congruence::bottom(8, Unsigned)) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .join(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .join(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .join(Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .join(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .join(Congruence::bottom(8, Unsigned)) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .join(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .join(Congruence(Int(0, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .join(Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .join(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_widening) { BOOST_CHECK(Congruence::top(8, Signed).widening( Congruence::bottom(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence::top(8, Signed).widening(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence::bottom(8, Signed).widening(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence::bottom(8, Signed).widening( Congruence::top(8, Signed)) == Congruence::top(8, Signed)); // Signed BOOST_CHECK( Congruence(Int(0, 8, Signed)).widening(Congruence::bottom(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).widening(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence(Int(0, 8, Signed)).widening(Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).widening(Congruence(Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence(Int(0, 8, Signed)).widening(Congruence(Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(-128, 8, Signed)) .widening(Congruence(Int(127, 8, Signed))) == Congruence(Z(255), Z(127), 8, Signed)); BOOST_CHECK(Congruence(Int(-127, 8, Signed)) .widening(Congruence(Int(127, 8, Signed))) == Congruence(Z(254), Z(127), 8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .widening(Congruence::bottom(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .widening(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .widening(Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .widening(Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .widening(Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .widening(Congruence::bottom(8, Signed)) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .widening(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .widening(Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .widening(Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .widening(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .widening(Congruence::bottom(8, Signed)) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .widening(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .widening(Congruence(Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .widening(Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .widening(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); // Unsigned BOOST_CHECK(Congruence(Int(0, 8, Unsigned)) .widening(Congruence::bottom(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).widening(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)) .widening(Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned)) .widening(Congruence(Int(4, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned)) .widening(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .widening(Congruence::bottom(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .widening(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .widening(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .widening(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .widening(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .widening(Congruence::bottom(8, Unsigned)) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .widening(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .widening(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .widening(Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .widening(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .widening(Congruence::bottom(8, Unsigned)) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .widening(Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .widening(Congruence(Int(0, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Unsigned) .widening(Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Unsigned) .widening(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_meet) { BOOST_CHECK(Congruence::top(8, Signed).meet(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence::top(8, Signed).meet(Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence::bottom(8, Signed).meet(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence::bottom(8, Signed).meet(Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( Congruence(Int(0, 8, Signed)).meet(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(0, 8, Signed)).meet(Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).meet(Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).meet(Congruence(Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Int(0, 8, Signed)).meet(Congruence(Int(2, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Int(-128, 8, Signed)).meet(Congruence(Int(127, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Int(-127, 8, Signed)).meet(Congruence(Int(127, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .meet(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .meet(Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .meet(Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .meet(Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .meet(Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .meet(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .meet(Congruence::top(8, Signed)) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .meet(Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .meet(Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .meet(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed).meet(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed).meet(Congruence::top(8, Signed)) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed).meet(Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .meet(Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .meet(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); // Unsigned BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).meet(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).meet(Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).meet(Congruence(Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( Congruence(Int(2, 8, Unsigned)).meet(Congruence(Int(4, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( Congruence(Int(255, 8, Unsigned)).meet(Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .meet(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .meet(Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .meet(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .meet(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .meet(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .meet(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .meet(Congruence::top(8, Unsigned)) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .meet(Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .meet(Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .meet(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .meet(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .meet(Congruence::top(8, Unsigned)) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .meet(Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .meet(Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .meet(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_narrowing) { BOOST_CHECK( Congruence::top(8, Signed).narrowing(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence::top(8, Signed).narrowing( Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( Congruence::bottom(8, Signed).narrowing(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence::bottom(8, Signed).narrowing( Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( Congruence(Int(0, 8, Signed)).narrowing(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Int(0, 8, Signed)).narrowing(Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).narrowing(Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(0, 8, Signed)).narrowing(Congruence(Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Int(0, 8, Signed)).narrowing(Congruence(Int(2, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(-128, 8, Signed)) .narrowing(Congruence(Int(127, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(-127, 8, Signed)) .narrowing(Congruence(Int(127, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .narrowing(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .narrowing(Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .narrowing(Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .narrowing(Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK( Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .narrowing(Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .narrowing(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .narrowing(Congruence::top(8, Signed)) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .narrowing(Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .narrowing(Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK( Congruence(Int(4, 8, Signed), Int(2, 8, Signed)) .narrowing(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .narrowing(Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .narrowing(Congruence::top(8, Signed)) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Signed) .narrowing(Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed) .narrowing(Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Signed) .narrowing(Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); // Unsigned BOOST_CHECK(Congruence(Int(0, 8, Unsigned)) .narrowing(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( Congruence(Int(0, 8, Unsigned)).narrowing(Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)) .narrowing(Congruence(Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned)) .narrowing(Congruence(Int(4, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(255, 8, Unsigned)) .narrowing(Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .narrowing(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .narrowing(Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .narrowing(Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .narrowing(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .narrowing(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .narrowing(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .narrowing(Congruence::top(8, Unsigned)) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .narrowing(Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .narrowing(Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)) .narrowing(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .narrowing(Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .narrowing(Congruence::top(8, Unsigned)) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(Congruence(Z(128), Z(7), 8, Unsigned) .narrowing(Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Unsigned) .narrowing(Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK( Congruence(Z(128), Z(7), 8, Unsigned) .narrowing(Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_singleton) { BOOST_CHECK((Congruence::bottom(8, Signed).singleton() == boost::none)); BOOST_CHECK((Congruence::top(8, Signed).singleton() == boost::none)); BOOST_CHECK((Congruence(Int(2, 8, Signed), Int(1, 8, Signed)).singleton() == boost::none)); BOOST_CHECK((Congruence(Int(0, 8, Signed)).singleton() == boost::optional< Int >(Int(0, 8, Signed)))); BOOST_CHECK((Congruence::bottom(8, Unsigned).singleton() == boost::none)); BOOST_CHECK((Congruence::top(8, Unsigned).singleton() == boost::none)); BOOST_CHECK( (Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)).singleton() == boost::none)); BOOST_CHECK((Congruence(Int(0, 8, Unsigned)).singleton() == boost::optional< Int >(Int(0, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_contains) { BOOST_CHECK(!Congruence::bottom(8, Signed).contains(Int(0, 8, Signed))); BOOST_CHECK(Congruence::top(8, Signed).contains(Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Signed)).contains(Int(0, 8, Signed))); BOOST_CHECK(!Congruence(Int(0, 8, Signed)).contains(Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)) .contains(Int(0, 8, Signed))); BOOST_CHECK(!Congruence(Int(2, 8, Signed), Int(1, 8, Signed)) .contains(Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)) .contains(Int(-1, 8, Signed))); BOOST_CHECK(!Congruence::bottom(8, Unsigned).contains(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence::top(8, Unsigned).contains(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)).contains(Int(0, 8, Unsigned))); BOOST_CHECK(!Congruence(Int(0, 8, Unsigned)).contains(Int(1, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)) .contains(Int(0, 8, Unsigned))); BOOST_CHECK(!Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)) .contains(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)) .contains(Int(3, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_trunc) { BOOST_CHECK(Congruence(Int(0, 8, Signed)).trunc(6) == Congruence(Int(0, 6, Signed))); BOOST_CHECK(Congruence(Int(1, 8, Signed)).trunc(6) == Congruence(Int(1, 6, Signed))); BOOST_CHECK(Congruence(Int(-128, 8, Signed)).trunc(6) == Congruence(Int(0, 6, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed)).trunc(6) == Congruence(Int(-1, 6, Signed))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)).trunc(6) == Congruence(Int(0, 6, Unsigned))); BOOST_CHECK(Congruence(Int(1, 8, Unsigned)).trunc(6) == Congruence(Int(1, 6, Unsigned))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned)).trunc(6) == Congruence(Int(63, 6, Unsigned))); BOOST_CHECK(Congruence(Int(1, 8, Signed), Int(0, 8, Signed)).trunc(6) == Congruence(Int(1, 6, Signed), Int(0, 6, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)).trunc(6) == Congruence(Int(2, 6, Signed), Int(0, 6, Signed))); BOOST_CHECK(Congruence(Int(2, 8, Signed), Int(1, 8, Signed)).trunc(6) == Congruence(Int(2, 6, Signed), Int(1, 6, Signed))); BOOST_CHECK(Congruence(Int(8, 8, Signed), Int(3, 8, Signed)).trunc(6) == Congruence(Int(8, 6, Signed), Int(3, 6, Signed))); BOOST_CHECK(Congruence(Int(127, 8, Signed), Int(1, 8, Signed)).trunc(6) == Congruence::top(6, Signed)); BOOST_CHECK(Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned)).trunc(6) == Congruence(Int(1, 6, Unsigned), Int(0, 6, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)).trunc(6) == Congruence(Int(2, 6, Unsigned), Int(0, 6, Unsigned))); BOOST_CHECK(Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)).trunc(6) == Congruence(Int(2, 6, Unsigned), Int(1, 6, Unsigned))); BOOST_CHECK(Congruence(Int(8, 8, Unsigned), Int(3, 8, Unsigned)).trunc(6) == Congruence(Int(8, 6, Unsigned), Int(3, 6, Unsigned))); BOOST_CHECK(Congruence(Int(254, 8, Unsigned), Int(1, 8, Unsigned)).trunc(6) == Congruence(Int(2, 6, Unsigned), Int(1, 6, Unsigned))); } BOOST_AUTO_TEST_CASE(test_ext) { BOOST_CHECK(Congruence(Int(0, 6, Signed)).ext(8) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(1, 6, Signed)).ext(8) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(-32, 6, Signed)).ext(8) == Congruence(Int(-32, 8, Signed))); BOOST_CHECK(Congruence(Int(31, 6, Signed)).ext(8) == Congruence(Int(31, 8, Signed))); BOOST_CHECK(Congruence(Int(0, 6, Unsigned)).ext(8) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(1, 6, Unsigned)).ext(8) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(Congruence(Int(63, 6, Unsigned)).ext(8) == Congruence(Int(63, 8, Unsigned))); BOOST_CHECK(Congruence(Int(1, 6, Signed), Int(0, 6, Signed)).ext(8) == Congruence(Int(1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 6, Signed), Int(0, 6, Signed)).ext(8) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(2, 6, Signed), Int(1, 6, Signed)).ext(8) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(8, 6, Signed), Int(3, 6, Signed)).ext(8) == Congruence(Int(8, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(Congruence(Int(31, 6, Signed), Int(1, 6, Signed)).ext(8) == Congruence(Int(31, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(1, 6, Unsigned), Int(0, 6, Unsigned)).ext(8) == Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 6, Unsigned), Int(0, 6, Unsigned)).ext(8) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(2, 6, Unsigned), Int(1, 6, Unsigned)).ext(8) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Congruence(Int(8, 6, Unsigned), Int(3, 6, Unsigned)).ext(8) == Congruence(Int(8, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(Congruence(Int(62, 6, Unsigned), Int(1, 6, Unsigned)).ext(8) == Congruence(Int(62, 8, Unsigned), Int(1, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_sign_cast) { BOOST_CHECK(Congruence(Int(0, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(Congruence(Int(1, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(Congruence(Int(-128, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(128, 8, Unsigned))); BOOST_CHECK(Congruence(Int(127, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(127, 8, Unsigned))); BOOST_CHECK(Congruence(Int(0, 8, Unsigned)).sign_cast(Signed) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(Congruence(Int(1, 8, Unsigned)).sign_cast(Signed) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(Congruence(Int(255, 8, Unsigned)).sign_cast(Signed) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( Congruence(Int(1, 8, Signed), Int(0, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(2, 8, Signed), Int(0, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( Congruence(Int(2, 8, Signed), Int(1, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( Congruence(Int(8, 8, Signed), Int(3, 8, Signed)).sign_cast(Unsigned) == Congruence(Int(8, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK( Congruence(Int(127, 8, Signed), Int(1, 8, Signed)).sign_cast(Unsigned) == Congruence::top(8, Unsigned)); BOOST_CHECK( Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned)).sign_cast(Signed) == Congruence(Int(1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)).sign_cast(Signed) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned)).sign_cast(Signed) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( Congruence(Int(8, 8, Unsigned), Int(3, 8, Unsigned)).sign_cast(Signed) == Congruence(Int(8, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(Congruence(Int(254, 8, Unsigned), Int(1, 8, Unsigned)) .sign_cast(Signed) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); } BOOST_AUTO_TEST_CASE(test_add) { BOOST_CHECK(add(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( add(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( add(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( add(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( add(Congruence(Int(0, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( add(Congruence(Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed))); BOOST_CHECK( add(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( add(Congruence(Int(-127, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( add(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(127, 8, Signed))); BOOST_CHECK( add(Congruence(Int(127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(-128, 8, Signed))); BOOST_CHECK(add(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(add(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(add(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(add(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(add(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(add(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(add(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(add(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(add(Congruence(Int(3, 8, Signed), Int(1, 8, Signed)), Congruence(Int(3, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(add(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( add(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( add(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(6, 8, Signed))); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); // Unsigned BOOST_CHECK( add(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( add(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK( add(Congruence(Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK( add(Congruence(Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned))); BOOST_CHECK( add(Congruence(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK( add(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(add(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(add(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(add(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(add(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(add(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(add(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(add(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(add(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(add(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(add(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(0, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(6, 8, Unsigned))); BOOST_CHECK(add(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_add_no_wrap) { BOOST_CHECK( add_no_wrap(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK(add_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(-127, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Int(127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(3, 8, Signed), Int(1, 8, Signed)), Congruence(Int(3, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(3, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(6, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(6, 8, Signed))); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); // Unsigned BOOST_CHECK(add_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Congruence(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(3, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(add_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(0, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK( add_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(6, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_sub) { BOOST_CHECK(sub(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( sub(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( sub(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( sub(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( sub(Congruence(Int(0, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( sub(Congruence(Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(-2, 8, Signed))); BOOST_CHECK( sub(Congruence(Int(-128, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( sub(Congruence(Int(-127, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( sub(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(127, 8, Signed))); BOOST_CHECK( sub(Congruence(Int(127, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(-128, 8, Signed))); BOOST_CHECK(sub(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(sub(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(sub(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(sub(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(sub(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(sub(Congruence(Int(3, 8, Signed), Int(1, 8, Signed)), Congruence(Int(3, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(sub(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( sub(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( sub(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(6, 8, Signed))); // Unsigned BOOST_CHECK( sub(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( sub(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK( sub(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK( sub(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned))); BOOST_CHECK( sub(Congruence(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK( sub(Congruence(Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(0, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(sub(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(6, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_sub_no_wrap) { BOOST_CHECK( sub_no_wrap(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( sub_no_wrap(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( sub_no_wrap(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK(sub_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( sub_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(-2, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(-128, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(-127, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Int(127, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(3, 8, Signed), Int(1, 8, Signed)), Congruence(Int(3, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(3, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(6, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(6, 8, Signed))); // Unsigned BOOST_CHECK(sub_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Congruence(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(3, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(0, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK( sub_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(6, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_mul) { BOOST_CHECK(mul(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( mul(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( mul(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( mul(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( mul(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( mul(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed))); BOOST_CHECK( mul(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-128, 8, Signed))); BOOST_CHECK( mul(Congruence(Int(-127, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( mul(Congruence(Int(127, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(-127, 8, Signed))); BOOST_CHECK( mul(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(-128, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(4, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(mul(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(mul(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( mul(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( mul(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence(Int(16, 8, Signed), Int(8, 8, Signed))); BOOST_CHECK(mul(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(6, 8, Signed))); // Unsigned BOOST_CHECK( mul(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( mul(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( mul(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned))); BOOST_CHECK( mul(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(40, 8, Unsigned))); BOOST_CHECK( mul(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK( mul(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(254, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(4, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(mul(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(mul(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(mul(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(mul(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(3, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_mul_no_wrap) { BOOST_CHECK( mul_no_wrap(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( mul_no_wrap(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( mul_no_wrap(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK(mul_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( mul_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence(Int(-127, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence(Int(127, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(-127, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(4, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence(Int(9, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(6, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence(Int(16, 8, Signed), Int(8, 8, Signed))); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(6, 8, Signed))); // Unsigned BOOST_CHECK(mul_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(40, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( mul_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( mul_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( mul_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(4, 8, Unsigned))); BOOST_CHECK( mul_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( mul_no_wrap(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( mul_no_wrap(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(mul_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK( mul_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( mul_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(3, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_div) { BOOST_CHECK(div(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( div(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( div(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( div(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( div(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( div(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( div(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(3, 8, Signed))); BOOST_CHECK( div(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( div(Congruence(Int(-127, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( div(Congruence(Int(127, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(-127, 8, Signed))); BOOST_CHECK( div(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(div(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK( div(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( div(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(div(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(div(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); // Unsigned BOOST_CHECK( div(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( div(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( div(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned))); BOOST_CHECK( div(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned))); BOOST_CHECK( div(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK( div(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(127, 8, Unsigned))); BOOST_CHECK(div(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(div(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(div(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(div(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(div(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(div(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_rem) { BOOST_CHECK(rem(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( rem(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( rem(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( rem(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(-7, 8, Signed)), Congruence(Int(5, 8, Signed))) == Congruence(Int(-2, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(-127, 8, Signed)), Congruence(Int(-127, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(127, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( rem(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(rem(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(rem(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(rem(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(rem(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(rem(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(rem(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(rem(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(rem(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(rem(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence(Int(3, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(rem(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK( rem(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( rem(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(rem(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(rem(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); // Unsigned BOOST_CHECK( rem(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( rem(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned))); BOOST_CHECK( rem(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(rem(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(rem(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(rem(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(rem(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(rem(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(rem(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(rem(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(rem(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_shl) { BOOST_CHECK(shl(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( shl(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( shl(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(28, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(-7, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(-56, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(-127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(1, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( shl(Congruence(Int(1, 8, Signed)), Congruence(Int(7, 8, Signed))) == Congruence(Int(-128, 8, Signed))); BOOST_CHECK( shl(Congruence(Int(1, 8, Signed)), Congruence(Int(8, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(4, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(shl(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( shl(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( shl(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(shl(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence(Int(32, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); // Unsigned BOOST_CHECK( shl(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( shl(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned))); BOOST_CHECK( shl(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(160, 8, Unsigned))); BOOST_CHECK( shl(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(254, 8, Unsigned))); BOOST_CHECK( shl(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(252, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(4, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(shl(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(14, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(128, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_shl_no_wrap) { BOOST_CHECK( shl_no_wrap(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK(shl_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(28, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(-7, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(-56, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Int(-127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Int(1, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Int(1, 8, Signed)), Congruence(Int(7, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Int(1, 8, Signed)), Congruence(Int(8, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(4, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence(Int(3, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(6, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence(Int(32, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); // Unsigned BOOST_CHECK(shl_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(160, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(4, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(6, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(14, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(128, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK( shl_no_wrap(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_lshr) { BOOST_CHECK(lshr(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( lshr(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( lshr(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(-7, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(31, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(64, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(-127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(64, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(1, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( lshr(Congruence(Int(1, 8, Signed)), Congruence(Int(7, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( lshr(Congruence(Int(1, 8, Signed)), Congruence(Int(8, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(lshr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(lshr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(lshr(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); // Unsigned BOOST_CHECK( lshr(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( lshr(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK( lshr(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(lshr(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(127, 8, Unsigned))); BOOST_CHECK(lshr(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(63, 8, Unsigned))); BOOST_CHECK(lshr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(lshr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(lshr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_lshr_exact) { BOOST_CHECK( lshr_exact(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK(lshr_exact(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(-7, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(31, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(64, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(-127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(64, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(7, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(8, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); // Unsigned BOOST_CHECK(lshr_exact(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(127, 8, Unsigned))); BOOST_CHECK(lshr_exact(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(63, 8, Unsigned))); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(lshr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(lshr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( lshr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_ashr) { BOOST_CHECK(ashr(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( ashr(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( ashr(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(-7, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(-64, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(-127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(-64, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(1, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK( ashr(Congruence(Int(1, 8, Signed)), Congruence(Int(7, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( ashr(Congruence(Int(1, 8, Signed)), Congruence(Int(8, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(ashr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(ashr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(ashr(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); // Unsigned BOOST_CHECK( ashr(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( ashr(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK( ashr(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(ashr(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(ashr(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(ashr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(ashr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(ashr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_ashr_exact) { BOOST_CHECK( ashr_exact(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK(ashr_exact(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(7, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(-7, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(-128, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(-64, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(-127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(-64, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(7, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(1, 8, Signed)), Congruence(Int(8, 8, Signed))) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(3, 8, Signed), Int(0, 8, Signed)), Congruence(Int(3, 8, Signed), Int(0, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(8, 8, Signed), Int(4, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(6), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); // Unsigned BOOST_CHECK(ashr_exact(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(ashr_exact(Congruence(Int(10, 8, Unsigned)), Congruence(Int(4, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Congruence(Int(255, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(ashr_exact(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(ashr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(ashr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK( ashr_exact(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_and) { BOOST_CHECK(and_(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(and_(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( and_(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(and_(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( and_(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(and_(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( and_(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( and_(Congruence(Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( and_(Congruence(Int(1, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( and_(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( and_(Congruence(Int(-127, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK( and_(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(128, 8, Signed))); BOOST_CHECK( and_(Congruence(Int(127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(1, 8, Signed))); BOOST_CHECK(and_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(and_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(and_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(and_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(and_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(and_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(and_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(and_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(and_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(and_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(and_(Congruence(Int(3, 8, Signed), Int(1, 8, Signed)), Congruence(Int(3, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(and_(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(1, 8, Signed))); // Unsigned BOOST_CHECK( and_(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( and_(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( and_(Congruence(Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK( and_(Congruence(Int(2, 8, Unsigned)), Congruence(Int(3, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(and_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(and_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(and_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(and_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(and_(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(0, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(and_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_or) { BOOST_CHECK(or_(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(or_(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( or_(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(or_(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( or_(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(or_(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( or_(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( or_(Congruence(Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(3, 8, Signed))); BOOST_CHECK( or_(Congruence(Int(1, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(3, 8, Signed))); BOOST_CHECK( or_(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( or_(Congruence(Int(-127, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( or_(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( or_(Congruence(Int(127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(127, 8, Signed))); BOOST_CHECK(or_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(or_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(or_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(or_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(or_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(or_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(or_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(or_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(or_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(or_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(or_(Congruence(Int(3, 8, Signed), Int(1, 8, Signed)), Congruence(Int(3, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(or_(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( or_(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( or_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(3, 8, Signed))); // Unsigned BOOST_CHECK( or_(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( or_(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK( or_(Congruence(Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK( or_(Congruence(Int(2, 8, Unsigned)), Congruence(Int(3, 8, Unsigned))) == Congruence(Int(3, 8, Unsigned))); BOOST_CHECK( or_(Congruence(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK( or_(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(or_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(or_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(or_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(or_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(or_(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(0, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(or_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(3, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_xor) { BOOST_CHECK(xor_(Congruence::top(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(xor_(Congruence::top(8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( xor_(Congruence::bottom(8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(xor_(Congruence::bottom(8, Signed), Congruence::top(8, Signed)) == Congruence::bottom(8, Signed)); // Signed BOOST_CHECK( xor_(Congruence(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(xor_(Congruence(Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK( xor_(Congruence(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(0, 8, Signed))); BOOST_CHECK( xor_(Congruence(Int(2, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(3, 8, Signed))); BOOST_CHECK( xor_(Congruence(Int(1, 8, Signed)), Congruence(Int(3, 8, Signed))) == Congruence(Int(2, 8, Signed))); BOOST_CHECK( xor_(Congruence(Int(-128, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-1, 8, Signed))); BOOST_CHECK( xor_(Congruence(Int(-127, 8, Signed)), Congruence(Int(127, 8, Signed))) == Congruence(Int(-2, 8, Signed))); BOOST_CHECK( xor_(Congruence(Int(-128, 8, Signed)), Congruence(Int(-1, 8, Signed))) == Congruence(Int(127, 8, Signed))); BOOST_CHECK( xor_(Congruence(Int(127, 8, Signed)), Congruence(Int(1, 8, Signed))) == Congruence(Int(126, 8, Signed))); BOOST_CHECK(xor_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(xor_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(xor_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(xor_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(4, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(xor_(Congruence(Int(2, 8, Signed), Int(0, 8, Signed)), Congruence(Int(2, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(xor_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(xor_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(xor_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(0, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(xor_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(2, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(xor_(Congruence(Int(4, 8, Signed), Int(2, 8, Signed)), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(xor_(Congruence(Int(3, 8, Signed), Int(1, 8, Signed)), Congruence(Int(3, 8, Signed), Int(1, 8, Signed))) == Congruence::top(8, Signed)); BOOST_CHECK(xor_(Congruence(Int(6, 8, Signed), Int(1, 8, Signed)), Congruence(Int(6, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Signed), Congruence::bottom(8, Signed)) == Congruence::bottom(8, Signed)); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Signed), Congruence::top(8, Signed)) == Congruence::top(8, Signed)); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(0, 8, Signed))) == Congruence(Z(128), Z(7), 8, Signed)); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(8, 8, Signed), Int(7, 8, Signed))) == Congruence(Int(8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Signed), Congruence(Int(4, 8, Signed), Int(1, 8, Signed))) == Congruence(Int(4, 8, Signed), Int(2, 8, Signed))); // Unsigned BOOST_CHECK( xor_(Congruence(Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK( xor_(Congruence(Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK( xor_(Congruence(Int(0, 8, Unsigned)), Congruence(Int(1, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK( xor_(Congruence(Int(2, 8, Unsigned)), Congruence(Int(3, 8, Unsigned))) == Congruence(Int(1, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(255, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(255, 8, Unsigned)), Congruence(Int(2, 8, Unsigned))) == Congruence(Int(253, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(xor_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(xor_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)), Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(xor_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(xor_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(0, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(8, 8, Unsigned), Int(2, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(3, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence::top(8, Unsigned)); BOOST_CHECK(xor_(Congruence(Int(6, 8, Unsigned), Int(1, 8, Unsigned)), Congruence(Int(12, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::bottom(8, Unsigned)) == Congruence::bottom(8, Unsigned)); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence::top(8, Unsigned)) == Congruence::top(8, Unsigned)); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(0, 8, Unsigned))) == Congruence(Z(128), Z(7), 8, Unsigned)); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(8, 8, Unsigned), Int(7, 8, Unsigned))) == Congruence(Int(8, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(xor_(Congruence(Z(128), Z(7), 8, Unsigned), Congruence(Int(4, 8, Unsigned), Int(1, 8, Unsigned))) == Congruence(Int(4, 8, Unsigned), Int(2, 8, Unsigned))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/machine_int/constant.cpp000066400000000000000000002455121473507761200254440ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::Constant * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_integer_constant #define BOOST_TEST_DYN_LINK #include #include #include #include using Int = ikos::core::MachineInt; using Constant = ikos::core::machine_int::Constant; using ikos::core::Signed; using ikos::core::Unsigned; BOOST_AUTO_TEST_CASE(test_bit_width) { BOOST_CHECK(Constant(Int(0, 4, Signed)).bit_width() == 4); BOOST_CHECK(Constant(Int(0, 4, Unsigned)).bit_width() == 4); BOOST_CHECK(Constant(Int(0, 8, Signed)).bit_width() == 8); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).bit_width() == 8); } BOOST_AUTO_TEST_CASE(test_sign) { BOOST_CHECK(Constant(Int(0, 4, Signed)).sign() == Signed); BOOST_CHECK(Constant(Int(0, 4, Unsigned)).sign() == Unsigned); BOOST_CHECK(Constant(Int(0, 8, Signed)).sign() == Signed); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).sign() == Unsigned); } BOOST_AUTO_TEST_CASE(test_bottom) { BOOST_CHECK(Constant::bottom(8, Signed).is_bottom()); BOOST_CHECK(!Constant::top(8, Signed).is_bottom()); BOOST_CHECK(!Constant(Int(0, 8, Signed)).is_bottom()); BOOST_CHECK(Constant::bottom(8, Unsigned).is_bottom()); BOOST_CHECK(!Constant::top(8, Unsigned).is_bottom()); BOOST_CHECK(!Constant(Int(0, 8, Unsigned)).is_bottom()); } BOOST_AUTO_TEST_CASE(test_top) { BOOST_CHECK(!Constant::bottom(8, Signed).is_top()); BOOST_CHECK(Constant::top(8, Signed).is_top()); BOOST_CHECK(!Constant(Int(0, 8, Signed)).is_top()); BOOST_CHECK(!Constant::bottom(8, Unsigned).is_top()); BOOST_CHECK(Constant::top(8, Unsigned).is_top()); BOOST_CHECK(!Constant(Int(0, 8, Unsigned)).is_top()); } BOOST_AUTO_TEST_CASE(test_set_to_bottom) { Constant i(Int(0, 8, Signed)); i.set_to_bottom(); BOOST_CHECK(i.is_bottom()); BOOST_CHECK(!i.is_top()); } BOOST_AUTO_TEST_CASE(test_set_to_top) { Constant i(Int(0, 8, Signed)); i.set_to_top(); BOOST_CHECK(!i.is_bottom()); BOOST_CHECK(i.is_top()); } BOOST_AUTO_TEST_CASE(test_leq) { BOOST_CHECK(Constant::bottom(1, Signed).leq(Constant::bottom(1, Signed))); BOOST_CHECK(Constant::bottom(1, Signed).leq(Constant::top(1, Signed))); BOOST_CHECK(Constant::bottom(1, Signed).leq(Constant(Int(0, 1, Signed)))); BOOST_CHECK(!Constant::top(1, Signed).leq(Constant::bottom(1, Signed))); BOOST_CHECK(Constant::top(1, Signed).leq(Constant::top(1, Signed))); BOOST_CHECK(!Constant::top(1, Signed).leq(Constant(Int(0, 1, Signed)))); BOOST_CHECK(!Constant(Int(0, 8, Signed)).leq(Constant::bottom(8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).leq(Constant::top(8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).leq(Constant(Int(0, 8, Signed)))); BOOST_CHECK(!Constant(Int(0, 8, Signed)).leq(Constant(Int(1, 8, Signed)))); BOOST_CHECK( !Constant(Int(0, 8, Unsigned)).leq(Constant::bottom(8, Unsigned))); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).leq(Constant::top(8, Unsigned))); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).leq(Constant(Int(0, 8, Unsigned)))); BOOST_CHECK( !Constant(Int(0, 8, Unsigned)).leq(Constant(Int(1, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_equals) { BOOST_CHECK(Constant::bottom(1, Signed).equals(Constant::bottom(1, Signed))); BOOST_CHECK(!Constant::bottom(1, Signed).equals(Constant::top(1, Signed))); BOOST_CHECK(!Constant::bottom(1, Signed).equals(Constant(Int(0, 1, Signed)))); BOOST_CHECK(!Constant::top(1, Signed).equals(Constant::bottom(1, Signed))); BOOST_CHECK(Constant::top(1, Signed).equals(Constant::top(1, Signed))); BOOST_CHECK(!Constant::top(1, Signed).equals(Constant(Int(0, 1, Signed)))); BOOST_CHECK(!Constant(Int(0, 8, Signed)).equals(Constant::bottom(8, Signed))); BOOST_CHECK(!Constant(Int(0, 8, Signed)).equals(Constant::top(8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).equals(Constant(Int(0, 8, Signed)))); BOOST_CHECK(!Constant(Int(0, 8, Signed)).equals(Constant(Int(1, 8, Signed)))); BOOST_CHECK( !Constant(Int(0, 8, Unsigned)).equals(Constant::bottom(8, Unsigned))); BOOST_CHECK( !Constant(Int(0, 8, Unsigned)).equals(Constant::top(8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).equals(Constant(Int(0, 8, Unsigned)))); BOOST_CHECK( !Constant(Int(0, 8, Unsigned)).equals(Constant(Int(1, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_join) { BOOST_CHECK(Constant::top(1, Signed).join(Constant::bottom(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).join(Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).join(Constant(Int(0, 1, Signed))) == Constant::top(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).join(Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).join(Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).join(Constant(Int(0, 1, Signed))) == Constant(Int(0, 1, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).join(Constant::bottom(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).join(Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(Constant(Int(0, 8, Signed)).join(Constant(Int(0, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).join(Constant(Int(1, 8, Signed))) == Constant::top(8, Signed)); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).join(Constant::bottom(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).join(Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).join(Constant(Int(0, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).join(Constant(Int(1, 8, Unsigned))) == Constant::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_widening) { BOOST_CHECK(Constant::top(1, Signed).widening(Constant::bottom(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).widening(Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).widening(Constant(Int(0, 1, Signed))) == Constant::top(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).widening( Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).widening(Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).widening( Constant(Int(0, 1, Signed))) == Constant(Int(0, 1, Signed))); BOOST_CHECK( Constant(Int(0, 8, Signed)).widening(Constant::bottom(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).widening(Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( Constant(Int(0, 8, Signed)).widening(Constant(Int(0, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( Constant(Int(0, 8, Signed)).widening(Constant(Int(1, 8, Signed))) == Constant::top(8, Signed)); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).widening(Constant::bottom(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).widening(Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).widening(Constant(Int(0, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).widening(Constant(Int(1, 8, Unsigned))) == Constant::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_meet) { BOOST_CHECK(Constant::top(1, Signed).meet(Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).meet(Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).meet(Constant(Int(0, 1, Signed))) == Constant(Int(0, 1, Signed))); BOOST_CHECK(Constant::bottom(1, Signed).meet(Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).meet(Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).meet(Constant(Int(0, 1, Signed))) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant(Int(0, 8, Signed)).meet(Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(Constant(Int(0, 8, Signed)).meet(Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).meet(Constant(Int(0, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).meet(Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).meet(Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).meet(Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).meet(Constant(Int(0, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).meet(Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_narrowing) { BOOST_CHECK(Constant::top(1, Signed).narrowing(Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).narrowing(Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(Constant::top(1, Signed).narrowing(Constant(Int(0, 1, Signed))) == Constant(Int(0, 1, Signed))); BOOST_CHECK(Constant::bottom(1, Signed).narrowing( Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).narrowing(Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(Constant::bottom(1, Signed).narrowing( Constant(Int(0, 1, Signed))) == Constant::bottom(1, Signed)); BOOST_CHECK( Constant(Int(0, 8, Signed)).narrowing(Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(Constant(Int(0, 8, Signed)).narrowing(Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK( Constant(Int(0, 8, Signed)).narrowing(Constant(Int(0, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( Constant(Int(0, 8, Signed)).narrowing(Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).narrowing(Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).narrowing(Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).narrowing(Constant(Int(0, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( Constant(Int(0, 8, Unsigned)).narrowing(Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_trunc) { BOOST_CHECK(Constant::bottom(8, Signed).trunc(6) == Constant::bottom(6, Signed)); BOOST_CHECK(Constant::top(8, Signed).trunc(6) == Constant::top(6, Signed)); BOOST_CHECK(Constant(Int(0, 8, Signed)).trunc(6) == Constant(Int(0, 6, Signed))); BOOST_CHECK(Constant(Int(1, 8, Signed)).trunc(6) == Constant(Int(1, 6, Signed))); BOOST_CHECK(Constant(Int(65, 8, Signed)).trunc(6) == Constant(Int(1, 6, Signed))); BOOST_CHECK(Constant(Int(-1, 8, Signed)).trunc(6) == Constant(Int(-1, 6, Signed))); BOOST_CHECK(Constant::bottom(8, Unsigned).trunc(6) == Constant::bottom(6, Unsigned)); BOOST_CHECK(Constant::top(8, Unsigned).trunc(6) == Constant::top(6, Unsigned)); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).trunc(6) == Constant(Int(0, 6, Unsigned))); BOOST_CHECK(Constant(Int(1, 8, Unsigned)).trunc(6) == Constant(Int(1, 6, Unsigned))); BOOST_CHECK(Constant(Int(65, 8, Unsigned)).trunc(6) == Constant(Int(1, 6, Unsigned))); BOOST_CHECK(Constant(Int(255, 8, Unsigned)).trunc(6) == Constant(Int(63, 6, Unsigned))); } BOOST_AUTO_TEST_CASE(test_ext) { BOOST_CHECK(Constant::bottom(6, Signed).ext(8) == Constant::bottom(8, Signed)); BOOST_CHECK(Constant::top(6, Signed).ext(8) == Constant::top(8, Signed)); BOOST_CHECK(Constant(Int(0, 6, Signed)).ext(8) == Constant(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(1, 6, Signed)).ext(8) == Constant(Int(1, 8, Signed))); BOOST_CHECK(Constant(Int(-1, 6, Signed)).ext(8) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(Constant::bottom(6, Unsigned).ext(8) == Constant::bottom(8, Unsigned)); BOOST_CHECK(Constant::top(6, Unsigned).ext(8) == Constant::top(8, Unsigned)); BOOST_CHECK(Constant(Int(0, 6, Unsigned)).ext(8) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(Constant(Int(1, 6, Unsigned)).ext(8) == Constant(Int(1, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_sign_cast) { BOOST_CHECK(Constant::bottom(8, Signed).sign_cast(Unsigned) == Constant::bottom(8, Unsigned)); BOOST_CHECK(Constant::top(8, Signed).sign_cast(Unsigned) == Constant::top(8, Unsigned)); BOOST_CHECK(Constant(Int(0, 8, Signed)).sign_cast(Unsigned) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(Constant(Int(32, 8, Signed)).sign_cast(Unsigned) == Constant(Int(32, 8, Unsigned))); BOOST_CHECK(Constant(Int(96, 8, Signed)).sign_cast(Unsigned) == Constant(Int(96, 8, Unsigned))); BOOST_CHECK(Constant(Int(-1, 8, Signed)).sign_cast(Unsigned) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK(Constant(Int(-2, 8, Signed)).sign_cast(Unsigned) == Constant(Int(254, 8, Unsigned))); BOOST_CHECK(Constant::bottom(8, Unsigned).sign_cast(Signed) == Constant::bottom(8, Signed)); BOOST_CHECK(Constant::top(8, Unsigned).sign_cast(Signed) == Constant::top(8, Signed)); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).sign_cast(Signed) == Constant(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(255, 8, Unsigned)).sign_cast(Signed) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(Constant(Int(32, 8, Unsigned)).sign_cast(Signed) == Constant(Int(32, 8, Signed))); BOOST_CHECK(Constant(Int(150, 8, Unsigned)).sign_cast(Signed) == Constant(Int(-106, 8, Signed))); BOOST_CHECK(Constant(Int(254, 8, Unsigned)).sign_cast(Signed) == Constant(Int(-2, 8, Signed))); } BOOST_AUTO_TEST_CASE(test_cast) { BOOST_CHECK(Constant::bottom(8, Signed).cast(4, Unsigned) == Constant::bottom(4, Unsigned)); BOOST_CHECK(Constant::top(8, Signed).cast(4, Unsigned) == Constant::top(4, Unsigned)); BOOST_CHECK(Constant(Int(0, 8, Signed)).cast(4, Unsigned) == Constant(Int(0, 4, Unsigned))); BOOST_CHECK(Constant(Int(32, 8, Signed)).cast(4, Unsigned) == Constant(Int(0, 4, Unsigned))); BOOST_CHECK(Constant(Int(96, 8, Signed)).cast(4, Unsigned) == Constant(Int(0, 4, Unsigned))); BOOST_CHECK(Constant(Int(-1, 8, Signed)).cast(4, Unsigned) == Constant(Int(15, 4, Unsigned))); BOOST_CHECK(Constant(Int(-2, 8, Signed)).cast(4, Unsigned) == Constant(Int(14, 4, Unsigned))); BOOST_CHECK(Constant::bottom(8, Unsigned).cast(4, Signed) == Constant::bottom(4, Signed)); BOOST_CHECK(Constant::top(8, Unsigned).cast(4, Signed) == Constant::top(4, Signed)); BOOST_CHECK(Constant(Int(0, 8, Unsigned)).cast(4, Signed) == Constant(Int(0, 4, Signed))); BOOST_CHECK(Constant(Int(255, 8, Unsigned)).cast(4, Signed) == Constant(Int(-1, 4, Signed))); BOOST_CHECK(Constant(Int(32, 8, Unsigned)).cast(4, Signed) == Constant(Int(0, 4, Signed))); BOOST_CHECK(Constant(Int(150, 8, Unsigned)).cast(4, Signed) == Constant(Int(6, 4, Signed))); BOOST_CHECK(Constant(Int(254, 8, Unsigned)).cast(4, Signed) == Constant(Int(-2, 4, Signed))); } BOOST_AUTO_TEST_CASE(test_singleton) { BOOST_CHECK((Constant::bottom(8, Signed).singleton() == boost::none)); BOOST_CHECK((Constant::top(8, Signed).singleton() == boost::none)); BOOST_CHECK((Constant(Int(0, 8, Signed)).singleton() == boost::optional< Int >(Int(0, 8, Signed)))); BOOST_CHECK((Constant::bottom(8, Unsigned).singleton() == boost::none)); BOOST_CHECK((Constant::top(8, Unsigned).singleton() == boost::none)); BOOST_CHECK((Constant(Int(0, 8, Unsigned)).singleton() == boost::optional< Int >(Int(0, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_contains) { BOOST_CHECK(!Constant::bottom(8, Signed).contains(Int(0, 8, Signed))); BOOST_CHECK(Constant::top(8, Signed).contains(Int(0, 8, Signed))); BOOST_CHECK(Constant(Int(0, 8, Signed)).contains(Int(0, 8, Signed))); BOOST_CHECK(!Constant(Int(0, 8, Signed)).contains(Int(2, 8, Signed))); BOOST_CHECK(!Constant::bottom(8, Unsigned).contains(Int(0, 8, Unsigned))); BOOST_CHECK(Constant::top(8, Unsigned).contains(Int(0, 8, Unsigned))); BOOST_CHECK(Constant(Int(1, 8, Unsigned)).contains(Int(1, 8, Unsigned))); BOOST_CHECK(!Constant(Int(1, 8, Unsigned)).contains(Int(3, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_add) { BOOST_CHECK(add(Constant::top(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(add(Constant::top(1, Signed), Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(add(Constant::bottom(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(add(Constant::bottom(1, Signed), Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(add(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(add(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(add(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(add(Constant(Int(-1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(add(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-128, 8, Signed))); BOOST_CHECK( add(Constant(Int(-128, 8, Signed)), Constant(Int(-129, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK( add(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(add(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( add(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( add(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(3, 8, Unsigned))); BOOST_CHECK( add(Constant(Int(255, 8, Unsigned)), Constant(Int(256, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_add_no_wrap) { BOOST_CHECK( add_no_wrap(Constant::top(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(add_no_wrap(Constant::top(1, Signed), Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK( add_no_wrap(Constant::bottom(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK( add_no_wrap(Constant::bottom(1, Signed), Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK( add_no_wrap(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( add_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( add_no_wrap(Constant(Int(-1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( add_no_wrap(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(-129, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(add_no_wrap(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( add_no_wrap(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK(add_no_wrap(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(3, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Constant(Int(255, 8, Unsigned)), Constant(Int(256, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Constant(Int(255, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_sub) { BOOST_CHECK(sub(Constant::top(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(sub(Constant::top(1, Signed), Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(sub(Constant::bottom(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(sub(Constant::bottom(1, Signed), Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(sub(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(sub(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(sub(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(sub(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( sub(Constant(Int(-128, 8, Signed)), Constant(Int(-129, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( sub(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(127, 8, Signed))); BOOST_CHECK( sub(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(sub(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( sub(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(-1, 8, Unsigned))); BOOST_CHECK( sub(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( sub(Constant(Int(255, 8, Unsigned)), Constant(Int(256, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_sub_no_wrap) { BOOST_CHECK( sub_no_wrap(Constant::top(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(sub_no_wrap(Constant::top(1, Signed), Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK( sub_no_wrap(Constant::bottom(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK( sub_no_wrap(Constant::bottom(1, Signed), Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK( sub_no_wrap(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( sub_no_wrap(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( sub_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK( sub_no_wrap(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(-129, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( sub_no_wrap(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Constant(Int(255, 8, Unsigned)), Constant(Int(256, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_div) { BOOST_CHECK(div(Constant::top(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(div(Constant::top(1, Signed), Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(div(Constant::bottom(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(div(Constant::bottom(1, Signed), Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(div(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(div(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(div(Constant(Int(0, 8, Signed)), Constant(Int(0, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(div(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(div(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(div(Constant(Int(9, 8, Signed)), Constant(Int(3, 8, Signed))) == Constant(Int(3, 8, Signed))); BOOST_CHECK(div(Constant(Int(-9, 8, Signed)), Constant(Int(3, 8, Signed))) == Constant(Int(-3, 8, Signed))); BOOST_CHECK( div(Constant(Int(-128, 8, Signed)), Constant(Int(127, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK( div(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-128, 8, Signed))); BOOST_CHECK(div(Constant(Int(-128, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( div(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(div(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( div(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( div(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( div(Constant(Int(254, 8, Unsigned)), Constant(Int(255, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_div_exact) { BOOST_CHECK( div_exact(Constant::top(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(div_exact(Constant::top(1, Signed), Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK( div_exact(Constant::bottom(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK( div_exact(Constant::bottom(1, Signed), Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK( div_exact(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( div_exact(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK( div_exact(Constant(Int(0, 8, Signed)), Constant(Int(0, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( div_exact(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( div_exact(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( div_exact(Constant(Int(9, 8, Signed)), Constant(Int(3, 8, Signed))) == Constant(Int(3, 8, Signed))); BOOST_CHECK( div_exact(Constant(Int(10, 8, Signed)), Constant(Int(3, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( div_exact(Constant(Int(-9, 8, Signed)), Constant(Int(3, 8, Signed))) == Constant(Int(-3, 8, Signed))); BOOST_CHECK(div_exact(Constant(Int(-128, 8, Signed)), Constant(Int(127, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( div_exact(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-128, 8, Signed))); BOOST_CHECK( div_exact(Constant(Int(-128, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( div_exact(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( div_exact(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( div_exact(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( div_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK(div_exact(Constant(Int(254, 8, Unsigned)), Constant(Int(255, 8, Unsigned))) == Constant::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_rem) { BOOST_CHECK(rem(Constant::top(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(rem(Constant::top(1, Signed), Constant::top(1, Signed)) == Constant::top(1, Signed)); BOOST_CHECK(rem(Constant::bottom(1, Signed), Constant::bottom(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(rem(Constant::bottom(1, Signed), Constant::top(1, Signed)) == Constant::bottom(1, Signed)); BOOST_CHECK(rem(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(rem(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(rem(Constant(Int(0, 8, Signed)), Constant(Int(0, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(rem(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(rem(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(rem(Constant(Int(10, 8, Signed)), Constant(Int(3, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(rem(Constant(Int(-10, 8, Signed)), Constant(Int(3, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK( rem(Constant(Int(-128, 8, Signed)), Constant(Int(127, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(rem(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(rem(Constant(Int(-128, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( rem(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(rem(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Constant(Int(254, 8, Unsigned)), Constant(Int(255, 8, Unsigned))) == Constant(Int(254, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_shl) { BOOST_CHECK(shl(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(shl(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(0, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(1, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(1, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(shl(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(2, 8, Signed))); BOOST_CHECK(shl(Constant(Int(1, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(4, 8, Signed))); BOOST_CHECK(shl(Constant(Int(1, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(64, 8, Signed))); BOOST_CHECK(shl(Constant(Int(1, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(-128, 8, Signed))); BOOST_CHECK(shl(Constant(Int(1, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(127, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(127, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(shl(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-2, 8, Signed))); BOOST_CHECK(shl(Constant(Int(127, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(-4, 8, Signed))); BOOST_CHECK(shl(Constant(Int(127, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(-64, 8, Signed))); BOOST_CHECK(shl(Constant(Int(127, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(-128, 8, Signed))); BOOST_CHECK(shl(Constant(Int(-128, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl(Constant(Int(-128, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(shl(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(-128, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(-128, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(-128, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(shl(Constant(Int(-128, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(0, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(0, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(0, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK( shl(Constant(Int(1, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( shl(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(2, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(4, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(1, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(64, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(1, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(128, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(1, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK( shl(Constant(Int(127, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl(Constant(Int(127, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( shl(Constant(Int(127, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(254, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(127, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(252, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(127, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(192, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(127, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(128, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(128, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl(Constant(Int(128, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( shl(Constant(Int(128, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(128, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(128, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Constant(Int(128, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_shl_no_wrap) { BOOST_CHECK( shl_no_wrap(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(1, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(1, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(2, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(1, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(4, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(1, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(64, 8, Signed))); BOOST_CHECK( shl_no_wrap(Constant(Int(1, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(1, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(127, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(127, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(127, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(127, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(127, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant(Int(-128, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Constant(Int(-128, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant(Int(-128, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( shl_no_wrap(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(0, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(0, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(0, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(1, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(2, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(4, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(1, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(64, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(1, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(128, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(1, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(127, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(127, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(127, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(254, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Constant(Int(127, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(127, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(127, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(128, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(128, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(128, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(128, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(128, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Constant(Int(128, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_lshr) { BOOST_CHECK(lshr(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(lshr(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(0, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(0, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant(Int(0, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant(Int(1, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant(Int(1, 8, Signed)), Constant(Int(0, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(1, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(1, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(1, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(1, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant(Int(127, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(63, 8, Signed))); BOOST_CHECK( lshr(Constant(Int(127, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(31, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(127, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(127, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(-128, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr(Constant(Int(-128, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( lshr(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(64, 8, Signed))); BOOST_CHECK( lshr(Constant(Int(-128, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(32, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(-128, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(2, 8, Signed))); BOOST_CHECK(lshr(Constant(Int(-128, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( lshr(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(255, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(1, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( lshr(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(1, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(1, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(1, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK( lshr(Constant(Int(127, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( lshr(Constant(Int(127, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(63, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(127, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(31, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(127, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(127, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(128, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( lshr(Constant(Int(128, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(64, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(128, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(32, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(128, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(2, 8, Unsigned))); BOOST_CHECK( lshr(Constant(Int(128, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_lshr_exact) { BOOST_CHECK( lshr_exact(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( lshr_exact(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Constant(Int(0, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Constant(Int(0, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(0, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(1, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(1, 8, Signed)), Constant(Int(0, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( lshr_exact(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(1, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(1, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(1, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(1, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(127, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(127, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(127, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(127, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(-128, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Constant(Int(-128, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( lshr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(64, 8, Signed))); BOOST_CHECK( lshr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(32, 8, Signed))); BOOST_CHECK( lshr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(2, 8, Signed))); BOOST_CHECK( lshr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(lshr_exact(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( lshr_exact(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(255, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK(lshr_exact(Constant(Int(1, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(127, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(128, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(64, 8, Unsigned))); BOOST_CHECK(lshr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(32, 8, Unsigned))); BOOST_CHECK(lshr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(2, 8, Unsigned))); BOOST_CHECK(lshr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_ashr) { BOOST_CHECK(ashr(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(ashr(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(0, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(0, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant(Int(0, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant(Int(1, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant(Int(1, 8, Signed)), Constant(Int(0, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(1, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(1, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(1, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(1, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant(Int(127, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(63, 8, Signed))); BOOST_CHECK( ashr(Constant(Int(127, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(31, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(127, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(127, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(ashr(Constant(Int(-128, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr(Constant(Int(-128, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( ashr(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-64, 8, Signed))); BOOST_CHECK( ashr(Constant(Int(-128, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(-32, 8, Signed))); BOOST_CHECK( ashr(Constant(Int(-128, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(-2, 8, Signed))); BOOST_CHECK( ashr(Constant(Int(-128, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK( ashr(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(255, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(1, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( ashr(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(1, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(1, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(1, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK( ashr(Constant(Int(127, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( ashr(Constant(Int(127, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(63, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(127, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(31, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(127, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(127, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(128, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( ashr(Constant(Int(128, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(192, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(128, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(224, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(128, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(254, 8, Unsigned))); BOOST_CHECK( ashr(Constant(Int(128, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_ashr_exact) { BOOST_CHECK( ashr_exact(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( ashr_exact(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Constant(Int(0, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Constant(Int(0, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(0, 8, Signed)), Constant(Int(-1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(1, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(1, 8, Signed)), Constant(Int(0, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( ashr_exact(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(1, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(1, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(1, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(1, 8, Signed)), Constant(Int(8, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(127, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(127, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(127, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(127, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(127, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(-128, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Constant(Int(-128, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK( ashr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(-64, 8, Signed))); BOOST_CHECK( ashr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(2, 8, Signed))) == Constant(Int(-32, 8, Signed))); BOOST_CHECK( ashr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(6, 8, Signed))) == Constant(Int(-2, 8, Signed))); BOOST_CHECK( ashr_exact(Constant(Int(-128, 8, Signed)), Constant(Int(7, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(ashr_exact(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK( ashr_exact(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(255, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK(ashr_exact(Constant(Int(1, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(1, 8, Unsigned)), Constant(Int(8, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(127, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(127, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(128, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(192, 8, Unsigned))); BOOST_CHECK(ashr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(2, 8, Unsigned))) == Constant(Int(224, 8, Unsigned))); BOOST_CHECK(ashr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(6, 8, Unsigned))) == Constant(Int(254, 8, Unsigned))); BOOST_CHECK(ashr_exact(Constant(Int(128, 8, Unsigned)), Constant(Int(7, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_and) { BOOST_CHECK(and_(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(and_(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(and_(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(and_(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(and_(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(and_(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant(Int(0, 8, Signed))); BOOST_CHECK(and_(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(and_(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( and_(Constant(Int(-128, 8, Signed)), Constant(Int(127, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(and_(Constant(Int(5, 8, Signed)), Constant(Int(10, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK(and_(Constant(Int(5, 8, Signed)), Constant(Int(11, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( and_(Constant(Int(-1, 8, Signed)), Constant(Int(-2, 8, Signed))) == Constant(Int(-2, 8, Signed))); BOOST_CHECK( and_(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(and_(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( and_(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( and_(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( and_(Constant(Int(255, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( and_(Constant(Int(5, 8, Unsigned)), Constant(Int(10, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_or) { BOOST_CHECK(or_(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(or_(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(or_(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(or_(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(or_(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(or_(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(or_(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(or_(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( or_(Constant(Int(-128, 8, Signed)), Constant(Int(127, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(or_(Constant(Int(5, 8, Signed)), Constant(Int(10, 8, Signed))) == Constant(Int(15, 8, Signed))); BOOST_CHECK(or_(Constant(Int(5, 8, Signed)), Constant(Int(11, 8, Signed))) == Constant(Int(15, 8, Signed))); BOOST_CHECK(or_(Constant(Int(-1, 8, Signed)), Constant(Int(-2, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK( or_(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(or_(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( or_(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( or_(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( or_(Constant(Int(255, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK( or_(Constant(Int(5, 8, Unsigned)), Constant(Int(10, 8, Unsigned))) == Constant(Int(15, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_xor) { BOOST_CHECK(xor_(Constant::top(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(xor_(Constant::top(8, Signed), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(xor_(Constant::bottom(8, Signed), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(xor_(Constant::bottom(8, Signed), Constant::top(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(xor_(Constant(Int(0, 8, Signed)), Constant::bottom(8, Signed)) == Constant::bottom(8, Signed)); BOOST_CHECK(xor_(Constant(Int(0, 8, Signed)), Constant::top(8, Signed)) == Constant::top(8, Signed)); BOOST_CHECK(xor_(Constant(Int(0, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK(xor_(Constant(Int(1, 8, Signed)), Constant(Int(1, 8, Signed))) == Constant(Int(0, 8, Signed))); BOOST_CHECK( xor_(Constant(Int(-128, 8, Signed)), Constant(Int(127, 8, Signed))) == Constant(Int(-1, 8, Signed))); BOOST_CHECK(xor_(Constant(Int(5, 8, Signed)), Constant(Int(10, 8, Signed))) == Constant(Int(15, 8, Signed))); BOOST_CHECK(xor_(Constant(Int(5, 8, Signed)), Constant(Int(11, 8, Signed))) == Constant(Int(14, 8, Signed))); BOOST_CHECK( xor_(Constant(Int(-1, 8, Signed)), Constant(Int(-2, 8, Signed))) == Constant(Int(1, 8, Signed))); BOOST_CHECK( xor_(Constant(Int(0, 8, Unsigned)), Constant::bottom(8, Unsigned)) == Constant::bottom(8, Unsigned)); BOOST_CHECK(xor_(Constant(Int(0, 8, Unsigned)), Constant::top(8, Unsigned)) == Constant::top(8, Unsigned)); BOOST_CHECK( xor_(Constant(Int(0, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(1, 8, Unsigned))); BOOST_CHECK( xor_(Constant(Int(1, 8, Unsigned)), Constant(Int(1, 8, Unsigned))) == Constant(Int(0, 8, Unsigned))); BOOST_CHECK( xor_(Constant(Int(255, 8, Unsigned)), Constant(Int(0, 8, Unsigned))) == Constant(Int(255, 8, Unsigned))); BOOST_CHECK( xor_(Constant(Int(5, 8, Unsigned)), Constant(Int(10, 8, Unsigned))) == Constant(Int(15, 8, Unsigned))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/machine_int/interval.cpp000066400000000000000000006123011473507761200254310ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::Interval * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_integer_interval #define BOOST_TEST_DYN_LINK #include #include #include #include using Int = ikos::core::MachineInt; using Interval = ikos::core::machine_int::Interval; using ikos::core::Signed; using ikos::core::Unsigned; using ZBound = ikos::core::Bound< ikos::core::ZNumber >; using ZInterval = ikos::core::numeric::ZInterval; BOOST_AUTO_TEST_CASE(test_constructors) { BOOST_CHECK(Interval(Int(0, 8, Signed)) == Interval(Int(0, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(1, 8, Unsigned)) == Interval(Int(1, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval(Int(1, 8, Signed), Int(2, 8, Signed)) == Interval(Int(1, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)) == Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(Interval::top(1, Signed) == Interval(Int(-1, 1, Signed), Int(0, 1, Signed))); BOOST_CHECK(Interval::top(8, Signed) == Interval(Int(-128, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::top(1, Unsigned) == Interval(Int(0, 1, Unsigned), Int(1, 1, Unsigned))); BOOST_CHECK(Interval::top(8, Unsigned) == Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_bit_width) { BOOST_CHECK(Interval(Int(0, 4, Signed)).bit_width() == 4); BOOST_CHECK(Interval(Int(0, 4, Unsigned)).bit_width() == 4); BOOST_CHECK(Interval(Int(0, 8, Signed)).bit_width() == 8); BOOST_CHECK(Interval(Int(0, 8, Unsigned)).bit_width() == 8); } BOOST_AUTO_TEST_CASE(test_sign) { BOOST_CHECK(Interval(Int(0, 4, Signed)).sign() == Signed); BOOST_CHECK(Interval(Int(0, 4, Unsigned)).sign() == Unsigned); BOOST_CHECK(Interval(Int(0, 8, Signed)).sign() == Signed); BOOST_CHECK(Interval(Int(0, 8, Unsigned)).sign() == Unsigned); } BOOST_AUTO_TEST_CASE(test_lb_and_ub) { BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)).lb() == Int(0, 8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)).ub() == Int(1, 8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).lb() == Int(0, 8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).ub() == Int(1, 8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_bottom) { BOOST_CHECK(Interval::bottom(8, Signed).is_bottom()); BOOST_CHECK(!Interval::top(8, Signed).is_bottom()); BOOST_CHECK(!Interval(Int(0, 8, Signed), Int(1, 8, Signed)).is_bottom()); BOOST_CHECK(!Interval(Int(-128, 8, Signed), Int(127, 8, Signed)).is_bottom()); BOOST_CHECK(Interval(Int(1, 8, Signed), Int(0, 8, Signed)).is_bottom()); BOOST_CHECK(Interval::bottom(8, Unsigned).is_bottom()); BOOST_CHECK(!Interval::top(8, Unsigned).is_bottom()); BOOST_CHECK(!Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).is_bottom()); BOOST_CHECK(Interval(Int(1, 8, Unsigned), Int(0, 8, Unsigned)).is_bottom()); BOOST_CHECK( !Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)).is_bottom()); } BOOST_AUTO_TEST_CASE(test_top) { BOOST_CHECK(!Interval::bottom(8, Signed).is_top()); BOOST_CHECK(Interval::top(8, Signed).is_top()); BOOST_CHECK(!Interval(Int(0, 8, Signed), Int(1, 8, Signed)).is_top()); BOOST_CHECK(!Interval(Int(1, 8, Signed), Int(0, 8, Signed)).is_top()); BOOST_CHECK(Interval(Int(-128, 8, Signed), Int(127, 8, Signed)).is_top()); BOOST_CHECK(!Interval::bottom(8, Unsigned).is_top()); BOOST_CHECK(Interval::top(8, Unsigned).is_top()); BOOST_CHECK(!Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).is_top()); BOOST_CHECK(!Interval(Int(1, 8, Unsigned), Int(0, 8, Unsigned)).is_top()); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)).is_top()); } BOOST_AUTO_TEST_CASE(test_set_to_bottom) { Interval i(Int(0, 8, Signed)); i.set_to_bottom(); BOOST_CHECK(i.is_bottom()); BOOST_CHECK(!i.is_top()); } BOOST_AUTO_TEST_CASE(test_set_to_top) { Interval i(Int(0, 8, Signed)); i.set_to_top(); BOOST_CHECK(!i.is_bottom()); BOOST_CHECK(i.is_top()); } BOOST_AUTO_TEST_CASE(test_leq) { BOOST_CHECK(Interval::bottom(8, Signed).leq(Interval::bottom(8, Signed))); BOOST_CHECK(Interval::bottom(8, Signed).leq(Interval::top(8, Signed))); BOOST_CHECK(!Interval::top(8, Signed).leq(Interval::bottom(8, Signed))); BOOST_CHECK(Interval::top(8, Signed).leq(Interval::top(8, Signed))); BOOST_CHECK(!Interval(Int(0, 8, Signed)).leq(Interval::bottom(8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed)).leq(Interval::top(8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed)) .leq(Interval(Int(-1, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(!Interval(Int(0, 8, Signed)) .leq(Interval(Int(1, 8, Signed), Int(2, 8, Signed)))); BOOST_CHECK( !Interval(Int(0, 8, Unsigned)).leq(Interval::bottom(8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned)).leq(Interval::top(8, Unsigned))); BOOST_CHECK(Interval(Int(1, 8, Unsigned)) .leq(Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned)))); BOOST_CHECK(!Interval(Int(1, 8, Unsigned)) .leq(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .leq(Interval::bottom(8, Signed))); BOOST_CHECK(Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .leq(Interval::top(8, Signed))); BOOST_CHECK(Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .leq(Interval(Int(-5, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .leq(Interval(Int(-3, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .leq(Interval(Int(-5, 8, Signed), Int(-3, 8, Signed)))); BOOST_CHECK(!Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .leq(Interval::bottom(8, Unsigned))); BOOST_CHECK(Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .leq(Interval::top(8, Unsigned))); BOOST_CHECK(Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .leq(Interval(Int(99, 8, Unsigned), Int(201, 8, Unsigned)))); BOOST_CHECK( !Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .leq(Interval(Int(151, 8, Unsigned), Int(255, 8, Unsigned)))); BOOST_CHECK(!Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .leq(Interval(Int(42, 8, Unsigned), Int(101, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_equals) { BOOST_CHECK(Interval::bottom(8, Signed).equals(Interval::bottom(8, Signed))); BOOST_CHECK(!Interval::bottom(8, Signed).equals(Interval::top(8, Signed))); BOOST_CHECK(!Interval::top(8, Signed).equals(Interval::bottom(8, Signed))); BOOST_CHECK(Interval::top(8, Signed).equals(Interval::top(8, Signed))); BOOST_CHECK(!Interval(Int(0, 8, Signed)).equals(Interval::bottom(8, Signed))); BOOST_CHECK(!Interval(Int(0, 8, Signed)).equals(Interval::top(8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed)).equals(Interval(Int(0, 8, Signed)))); BOOST_CHECK(!Interval(Int(0, 8, Signed)) .equals(Interval(Int(-1, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK(!Interval(Int(0, 8, Signed)) .equals(Interval(Int(1, 8, Signed), Int(2, 8, Signed)))); BOOST_CHECK( !Interval(Int(0, 8, Unsigned)).equals(Interval::bottom(8, Unsigned))); BOOST_CHECK( !Interval(Int(0, 8, Unsigned)).equals(Interval::top(8, Unsigned))); BOOST_CHECK(!Interval(Int(1, 8, Unsigned)) .equals(Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned)))); BOOST_CHECK(!Interval(Int(1, 8, Unsigned)) .equals(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .equals(Interval::bottom(8, Signed))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .equals(Interval::top(8, Signed))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .equals(Interval(Int(-5, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .equals(Interval(Int(-3, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK(!Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .equals(Interval(Int(-5, 8, Signed), Int(-3, 8, Signed)))); BOOST_CHECK(Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)) .equals(Interval(Int(-4, 8, Signed), Int(-2, 8, Signed)))); BOOST_CHECK(!Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .equals(Interval::bottom(8, Unsigned))); BOOST_CHECK(!Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .equals(Interval::top(8, Unsigned))); BOOST_CHECK( !Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .equals(Interval(Int(99, 8, Unsigned), Int(201, 8, Unsigned)))); BOOST_CHECK( !Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .equals(Interval(Int(151, 8, Unsigned), Int(255, 8, Unsigned)))); BOOST_CHECK( !Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .equals(Interval(Int(42, 8, Unsigned), Int(101, 8, Unsigned)))); BOOST_CHECK( Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)) .equals(Interval(Int(100, 8, Unsigned), Int(200, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_join) { BOOST_CHECK(Interval::top(8, Signed).join(Interval::bottom(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval::top(8, Signed).join(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).join(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).join(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed)).join(Interval::bottom(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed)).join(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed)).join(Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(-1, 8, Signed)).join(Interval(Int(1, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( Interval(Int(-128, 8, Signed)).join(Interval(Int(-129, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .join(Interval::bottom(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .join(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .join(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .join(Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .join(Interval::bottom(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .join(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .join(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .join(Interval(Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).join(Interval::bottom(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned)).join(Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).join(Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( Interval(Int(1, 8, Unsigned)).join(Interval(Int(2, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK( Interval(Int(255, 8, Unsigned)).join(Interval(Int(256, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .join(Interval::bottom(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .join(Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .join(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .join(Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(2, 8, Unsigned), Int(4, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .join(Interval::bottom(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .join(Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .join(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_widening) { BOOST_CHECK(Interval::top(8, Signed).widening(Interval::bottom(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval::top(8, Signed).widening(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).widening( Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).widening(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( Interval(Int(0, 8, Signed)).widening(Interval::bottom(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed)).widening(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( Interval(Int(0, 8, Signed)).widening(Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( Interval(Int(-1, 8, Signed)).widening(Interval(Int(-2, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .widening(Interval::bottom(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .widening(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .widening(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .widening(Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .widening(Interval::bottom(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .widening(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .widening(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .widening(Interval(Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( Interval(Int(1, 8, Unsigned)).widening(Interval::bottom(8, Unsigned)) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).widening(Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval(Int(1, 8, Unsigned)).widening(Interval(Int(2, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(Interval(Int(255, 8, Unsigned)) .widening(Interval(Int(256, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .widening(Interval::bottom(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .widening(Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .widening(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK( Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .widening(Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(2, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .widening(Interval::bottom(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .widening(Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .widening(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_meet) { BOOST_CHECK(Interval::top(8, Signed).meet(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::top(8, Signed).meet(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).meet(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).meet(Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed)).meet(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed)).meet(Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed)).meet(Interval(Int(1, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(-1, 8, Signed)).meet(Interval(Int(1, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .meet(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .meet(Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .meet(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .meet(Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .meet(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .meet(Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .meet(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .meet(Interval(Int(-128, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).meet(Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned)).meet(Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).meet(Interval(Int(1, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK( Interval(Int(1, 8, Unsigned)).meet(Interval(Int(2, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .meet(Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .meet(Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .meet(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(2, 8, Unsigned))); BOOST_CHECK(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .meet(Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(3, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .meet(Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .meet(Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .meet(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_narrowing) { BOOST_CHECK(Interval::top(8, Signed).narrowing(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::top(8, Signed).narrowing(Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).narrowing( Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::bottom(8, Signed).narrowing(Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( Interval(Int(0, 8, Signed)).narrowing(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed)).narrowing(Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK( Interval(Int(0, 8, Signed)).narrowing(Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( Interval(Int(-1, 8, Signed)).narrowing(Interval(Int(1, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .narrowing(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .narrowing(Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .narrowing(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .narrowing(Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .narrowing(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .narrowing(Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .narrowing(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .narrowing(Interval(Int(-128, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)) .narrowing(Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)) .narrowing(Interval::top(8, Signed)) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)) .narrowing(Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).narrowing(Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).narrowing(Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Unsigned)).narrowing(Interval(Int(1, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK( Interval(Int(1, 8, Unsigned)).narrowing(Interval(Int(2, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .narrowing(Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)) .narrowing(Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .narrowing(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK( Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)) .narrowing(Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .narrowing(Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .narrowing(Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)) .narrowing(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(10, 8, Unsigned), Int(255, 8, Unsigned)) .narrowing(Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval(Int(10, 8, Unsigned), Int(255, 8, Unsigned)) .narrowing(Interval::top(8, Unsigned)) == Interval(Int(10, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK( Interval(Int(10, 8, Unsigned), Int(255, 8, Unsigned)) .narrowing(Interval(Int(10, 8, Unsigned), Int(11, 8, Unsigned))) == Interval(Int(10, 8, Unsigned), Int(11, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_trunc) { BOOST_CHECK(Interval::bottom(8, Signed).trunc(6) == Interval::bottom(6, Signed)); BOOST_CHECK(Interval::top(8, Signed).trunc(6) == Interval::top(6, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)).trunc(6) == Interval(Int(0, 6, Signed), Int(1, 6, Signed))); BOOST_CHECK(Interval(Int(-128, 8, Signed), Int(127, 8, Signed)).trunc(6) == Interval::top(6, Signed)); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(32, 8, Signed)).trunc(6) == Interval::top(6, Signed)); BOOST_CHECK(Interval(Int(96, 8, Signed), Int(97, 8, Signed)).trunc(6) == Interval(Int(32, 6, Signed), Int(33, 6, Signed))); BOOST_CHECK(Interval(Int(-1, 8, Signed), Int(0, 8, Signed)).trunc(6) == Interval::top(6, Signed)); BOOST_CHECK(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)).trunc(6) == Interval(Int(-2, 6, Signed), Int(-1, 6, Signed))); BOOST_CHECK(Interval(Int(0, 32, Signed), Int(255, 32, Signed)).trunc(8) == Interval::top(8, Signed)); BOOST_CHECK(Interval::bottom(8, Unsigned).trunc(6) == Interval::bottom(6, Unsigned)); BOOST_CHECK(Interval::top(8, Unsigned).trunc(6) == Interval::top(6, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).trunc(6) == Interval(Int(0, 6, Unsigned), Int(1, 6, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)).trunc(6) == Interval::top(6, Unsigned)); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(32, 8, Unsigned)).trunc(6) == Interval(Int(0, 6, Unsigned), Int(32, 6, Unsigned))); BOOST_CHECK(Interval(Int(96, 8, Unsigned), Int(97, 8, Unsigned)).trunc(6) == Interval(Int(32, 6, Unsigned), Int(33, 6, Unsigned))); BOOST_CHECK(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)).trunc(6) == Interval(Int(62, 6, Unsigned), Int(63, 6, Unsigned))); } BOOST_AUTO_TEST_CASE(test_ext) { BOOST_CHECK(Interval::bottom(6, Signed).ext(8) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::top(6, Signed).ext(8) == Interval(Int(-32, 8, Signed), Int(31, 8, Signed))); BOOST_CHECK(Interval(Int(0, 6, Signed), Int(1, 6, Signed)).ext(8) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval(Int(-32, 6, Signed), Int(31, 6, Signed)).ext(8) == Interval(Int(-32, 8, Signed), Int(31, 8, Signed))); BOOST_CHECK(Interval(Int(0, 6, Signed), Int(31, 6, Signed)).ext(8) == Interval(Int(0, 8, Signed), Int(31, 8, Signed))); BOOST_CHECK(Interval(Int(-1, 6, Signed), Int(0, 6, Signed)).ext(8) == Interval(Int(-1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(-2, 6, Signed), Int(-1, 6, Signed)).ext(8) == Interval(Int(-2, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(Interval::bottom(6, Unsigned).ext(8) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval::top(6, Unsigned).ext(8) == Interval(Int(0, 8, Unsigned), Int(63, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 6, Unsigned), Int(1, 6, Unsigned)).ext(8) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 6, Unsigned), Int(32, 6, Unsigned)).ext(8) == Interval(Int(0, 8, Unsigned), Int(32, 8, Unsigned))); BOOST_CHECK(Interval(Int(32, 6, Unsigned), Int(33, 6, Unsigned)).ext(8) == Interval(Int(32, 8, Unsigned), Int(33, 8, Unsigned))); BOOST_CHECK(Interval(Int(62, 6, Unsigned), Int(63, 6, Unsigned)).ext(8) == Interval(Int(62, 8, Unsigned), Int(63, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_sign_cast) { BOOST_CHECK(Interval::bottom(8, Signed).sign_cast(Unsigned) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval::top(8, Signed).sign_cast(Unsigned) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(1, 8, Signed)).sign_cast(Unsigned) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(32, 8, Signed)).sign_cast(Unsigned) == Interval(Int(0, 8, Unsigned), Int(32, 8, Unsigned))); BOOST_CHECK( Interval(Int(96, 8, Signed), Int(97, 8, Signed)).sign_cast(Unsigned) == Interval(Int(96, 8, Unsigned), Int(97, 8, Unsigned))); BOOST_CHECK( Interval(Int(-1, 8, Signed), Int(0, 8, Signed)).sign_cast(Unsigned) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)).sign_cast(Unsigned) == Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(Interval(Int(-128, 8, Signed), Int(-127, 8, Signed)) .sign_cast(Unsigned) == Interval(Int(128, 8, Unsigned), Int(129, 8, Unsigned))); BOOST_CHECK(Interval::bottom(8, Unsigned).sign_cast(Signed) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::top(8, Unsigned).sign_cast(Signed) == Interval::top(8, Signed)); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).sign_cast(Signed) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)).sign_cast(Signed) == Interval::top(8, Signed)); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(32, 8, Unsigned)).sign_cast(Signed) == Interval(Int(0, 8, Signed), Int(32, 8, Signed))); BOOST_CHECK(Interval(Int(150, 8, Unsigned), Int(151, 8, Unsigned)) .sign_cast(Signed) == Interval(Int(-106, 8, Signed), Int(-105, 8, Signed))); BOOST_CHECK(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)) .sign_cast(Signed) == Interval(Int(-2, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK( Interval(Int(1, 8, Unsigned), Int(150, 8, Unsigned)).sign_cast(Signed) == Interval::top(8, Signed)); } BOOST_AUTO_TEST_CASE(test_cast) { BOOST_CHECK(Interval::bottom(8, Signed).cast(4, Unsigned) == Interval::bottom(4, Unsigned)); BOOST_CHECK(Interval::top(8, Signed).cast(4, Unsigned) == Interval::top(4, Unsigned)); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(1, 8, Signed)).cast(4, Unsigned) == Interval(Int(0, 4, Unsigned), Int(1, 4, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(32, 8, Signed)).cast(4, Unsigned) == Interval(Int(0, 4, Unsigned), Int(15, 4, Unsigned))); BOOST_CHECK( Interval(Int(96, 8, Signed), Int(97, 8, Signed)).cast(4, Unsigned) == Interval(Int(0, 4, Unsigned), Int(1, 4, Unsigned))); BOOST_CHECK( Interval(Int(-1, 8, Signed), Int(0, 8, Signed)).cast(4, Unsigned) == Interval::top(4, Unsigned)); BOOST_CHECK( Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)).cast(4, Unsigned) == Interval(Int(14, 4, Unsigned), Int(15, 4, Unsigned))); BOOST_CHECK( Interval(Int(-128, 8, Signed), Int(-127, 8, Signed)).cast(4, Unsigned) == Interval(Int(0, 4, Unsigned), Int(1, 4, Unsigned))); BOOST_CHECK(Interval::bottom(8, Unsigned).cast(4, Signed) == Interval::bottom(4, Signed)); BOOST_CHECK(Interval::top(8, Unsigned).cast(4, Signed) == Interval::top(4, Signed)); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).cast(4, Signed) == Interval(Int(0, 4, Signed), Int(1, 4, Signed))); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)).cast(4, Signed) == Interval::top(4, Signed)); BOOST_CHECK( Interval(Int(0, 8, Unsigned), Int(32, 8, Unsigned)).cast(4, Signed) == Interval::top(4, Signed)); BOOST_CHECK( Interval(Int(150, 8, Unsigned), Int(151, 8, Unsigned)).cast(4, Signed) == Interval(Int(6, 4, Signed), Int(7, 4, Signed))); BOOST_CHECK( Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)).cast(4, Signed) == Interval(Int(-2, 4, Signed), Int(-1, 4, Signed))); BOOST_CHECK( Interval(Int(1, 8, Unsigned), Int(150, 8, Unsigned)).cast(4, Signed) == Interval::top(4, Signed)); } BOOST_AUTO_TEST_CASE(test_singleton) { BOOST_CHECK((Interval::bottom(8, Signed).singleton() == boost::none)); BOOST_CHECK((Interval::top(8, Signed).singleton() == boost::none)); BOOST_CHECK((Interval(Int(0, 8, Signed), Int(1, 8, Signed)).singleton() == boost::none)); BOOST_CHECK((Interval(Int(0, 8, Signed)).singleton() == boost::optional< Int >(Int(0, 8, Signed)))); BOOST_CHECK((Interval::bottom(8, Unsigned).singleton() == boost::none)); BOOST_CHECK((Interval::top(8, Unsigned).singleton() == boost::none)); BOOST_CHECK((Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)).singleton() == boost::none)); BOOST_CHECK((Interval(Int(0, 8, Unsigned)).singleton() == boost::optional< Int >(Int(0, 8, Unsigned)))); } BOOST_AUTO_TEST_CASE(test_contains) { BOOST_CHECK(!Interval::bottom(8, Signed).contains(Int(0, 8, Signed))); BOOST_CHECK(Interval::top(8, Signed).contains(Int(0, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .contains(Int(0, 8, Signed))); BOOST_CHECK(!Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .contains(Int(2, 8, Signed))); BOOST_CHECK(!Interval(Int(0, 8, Signed), Int(1, 8, Signed)) .contains(Int(-1, 8, Signed))); BOOST_CHECK(!Interval::bottom(8, Unsigned).contains(Int(0, 8, Unsigned))); BOOST_CHECK(Interval::top(8, Unsigned).contains(Int(0, 8, Unsigned))); BOOST_CHECK(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)) .contains(Int(1, 8, Unsigned))); BOOST_CHECK(!Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)) .contains(Int(3, 8, Unsigned))); BOOST_CHECK(!Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)) .contains(Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_add) { BOOST_CHECK(add(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(add(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(add(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(add(Interval(Int(-1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( add(Interval(Int(-128, 8, Signed)), Interval(Int(-129, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(1, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(add(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-127, 8, Signed))); BOOST_CHECK(add(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-3, 8, Signed))); BOOST_CHECK(add(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(add(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval(Int(126, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(add(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( add(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(add(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( add(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( add(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(3, 8, Unsigned))); BOOST_CHECK( add(Interval(Int(255, 8, Unsigned)), Interval(Int(256, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(add(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(add(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(add(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(3, 8, Unsigned), Int(5, 8, Unsigned))); BOOST_CHECK(add(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(5, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(add(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(add(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(add(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(add(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(add(Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned))); BOOST_CHECK(add(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(add(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(128, 8, Unsigned), Int(128, 8, Unsigned))) == Interval(Int(126, 8, Unsigned), Int(127, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_add_no_wrap) { BOOST_CHECK( add_no_wrap(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( add_no_wrap(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( add_no_wrap(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK( add_no_wrap(Interval(Int(-1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(add_no_wrap(Interval(Int(-128, 8, Signed)), Interval(Int(127, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(1, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(add_no_wrap(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(127, 8, Signed))); BOOST_CHECK( add_no_wrap(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK( add_no_wrap(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval(Int(-128, 8, Signed))); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( add_no_wrap(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(3, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Interval(Int(255, 8, Unsigned)), Interval(Int(256, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(add_no_wrap(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(3, 8, Unsigned), Int(5, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(5, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(add_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( add_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK( add_no_wrap(Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK( add_no_wrap(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK( add_no_wrap(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(128, 8, Unsigned), Int(128, 8, Unsigned))) == Interval::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_sub) { BOOST_CHECK(sub(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(sub(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(sub(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(sub(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( sub(Interval(Int(-128, 8, Signed)), Interval(Int(-129, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(-2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(sub(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-126, 8, Signed), Int(-125, 8, Signed))); BOOST_CHECK(sub(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-126, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(sub(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-127, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(sub(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval(Int(126, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(sub(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( sub(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( sub(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(-1, 8, Unsigned))); BOOST_CHECK( sub(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( sub(Interval(Int(255, 8, Unsigned)), Interval(Int(256, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(sub(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(sub(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(129, 8, Unsigned))); BOOST_CHECK(sub(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(sub(Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(sub(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(128, 8, Unsigned), Int(128, 8, Unsigned))) == Interval(Int(126, 8, Unsigned), Int(127, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_sub_no_wrap) { BOOST_CHECK( sub_no_wrap(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( sub_no_wrap(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( sub_no_wrap(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( sub_no_wrap(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( sub_no_wrap(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(-127, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( sub_no_wrap(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK( sub_no_wrap(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(-128, 8, Signed)), Interval(Int(-129, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(-127, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(-2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(-127, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(sub_no_wrap(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-126, 8, Signed), Int(-125, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-126, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-127, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK( sub_no_wrap(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval(Int(126, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( sub_no_wrap(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval(Int(126, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( sub_no_wrap(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Interval(Int(255, 8, Unsigned)), Interval(Int(256, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(sub_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK( sub_no_wrap(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK( sub_no_wrap(Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( sub_no_wrap(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(128, 8, Unsigned), Int(128, 8, Unsigned))) == Interval(Int(126, 8, Unsigned), Int(127, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_rem) { BOOST_CHECK(rem(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(rem(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval(Int(-127, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(rem(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(rem(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(rem(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(rem(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(rem(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( rem(Interval(Int(-128, 8, Signed)), Interval(Int(127, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(rem(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(rem(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(126, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(126, 8, Signed))); BOOST_CHECK(rem(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval(Int(-2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(rem(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval(Int(-2, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(rem(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(rem(Interval::top(8, Signed), Interval(Int(42, 8, Signed))) == Interval(Int(-41, 8, Signed), Int(41, 8, Signed))); BOOST_CHECK(rem(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(41, 8, Signed))); BOOST_CHECK(rem(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(51, 8, Signed))); BOOST_CHECK(rem(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval(Int(-51, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(rem(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(rem(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval(Int(-127, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(rem(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval(Int(-127, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( rem(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(rem(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( rem(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(rem(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(rem(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(rem(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned))); BOOST_CHECK(rem(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(128, 8, Unsigned), Int(128, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_shl) { BOOST_CHECK(shl(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(0, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval(Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(1, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(2, 8, Signed))); BOOST_CHECK(shl(Interval(Int(1, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(4, 8, Signed))); BOOST_CHECK(shl(Interval(Int(1, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(64, 8, Signed))); BOOST_CHECK(shl(Interval(Int(1, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed))); BOOST_CHECK(shl(Interval(Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval(Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(127, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(127, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(-2, 8, Signed))); BOOST_CHECK(shl(Interval(Int(127, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(-4, 8, Signed))); BOOST_CHECK(shl(Interval(Int(127, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(-64, 8, Signed))); BOOST_CHECK(shl(Interval(Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed))); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(4, 8, Signed))); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval::top(8, Signed), Interval(Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( shl(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(2, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(shl(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(4, 8, Unsigned), Int(12, 8, Unsigned))); BOOST_CHECK(shl(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(16, 8, Unsigned), Int(48, 8, Unsigned))); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(4, 8, Unsigned), Int(4, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK( shl(Interval(Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(shl(Interval(Int(1, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(2, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(4, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(1, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(64, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(1, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(128, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(127, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK( shl(Interval(Int(127, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(254, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(127, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(252, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(127, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(192, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(127, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(128, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(128, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(128, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(128, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK( shl(Interval(Int(128, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(128, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(128, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( shl(Interval(Int(128, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(shl(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(4, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_shl_no_wrap) { BOOST_CHECK( shl_no_wrap(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval(Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(1, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(1, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(2, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval(Int(1, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(4, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval(Int(1, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(64, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval(Int(1, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(127, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval(Int(127, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(127, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(127, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval(Int(-128, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(-128, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(4, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval::bottom(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( shl_no_wrap(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( shl_no_wrap(Interval::top(8, Signed), Interval(Int(4, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed))) == Interval(Int(16, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( shl_no_wrap(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(2, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(4, 8, Unsigned), Int(12, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(16, 8, Unsigned), Int(48, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(4, 8, Unsigned), Int(4, 8, Unsigned))) == Interval::top(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(2, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(4, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(64, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(1, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(128, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(127, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(127, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(254, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(127, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(128, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(128, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(128, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(128, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(128, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(128, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(128, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(128, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(128, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(shl_no_wrap(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(4, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_lshr) { BOOST_CHECK(lshr(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(lshr(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval(Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(127, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( lshr(Interval(Int(127, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(63, 8, Signed))); BOOST_CHECK( lshr(Interval(Int(127, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(31, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(127, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( lshr(Interval(Int(-128, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(64, 8, Signed))); BOOST_CHECK( lshr(Interval(Int(-128, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(32, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(2, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(63, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(lshr(Interval::top(8, Signed), Interval(Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK(lshr(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK( lshr(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(4, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr(Interval(Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(1, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(1, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(1, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( lshr(Interval(Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(127, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(127, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(63, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(127, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(31, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(127, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(127, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(128, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( lshr(Interval(Int(128, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(128, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(128, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(64, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(128, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(32, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(128, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(2, 8, Unsigned))); BOOST_CHECK( lshr(Interval(Int(128, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_lshr_exact) { BOOST_CHECK( lshr_exact(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( lshr_exact(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Interval(Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(1, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(1, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(1, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( lshr_exact(Interval(Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(127, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(127, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(63, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(127, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(31, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(127, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(-128, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Interval(Int(-128, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(lshr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( lshr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(64, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(32, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(2, 8, Signed))); BOOST_CHECK( lshr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(63, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( lshr_exact(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( lshr_exact(Interval::top(8, Signed), Interval(Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(15, 8, Signed))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( lshr_exact(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(4, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( lshr_exact(Interval(Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( lshr_exact(Interval(Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(63, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(31, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(128, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( lshr_exact(Interval(Int(128, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(128, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(64, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(32, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(2, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(lshr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_ashr) { BOOST_CHECK(ashr(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(ashr(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval(Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(127, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( ashr(Interval(Int(127, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(63, 8, Signed))); BOOST_CHECK( ashr(Interval(Int(127, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(31, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(127, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(-128, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval(Int(-128, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(-128, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK( ashr(Interval(Int(-128, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(-64, 8, Signed))); BOOST_CHECK( ashr(Interval(Int(-128, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(-32, 8, Signed))); BOOST_CHECK( ashr(Interval(Int(-128, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(-2, 8, Signed))); BOOST_CHECK( ashr(Interval(Int(-128, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(63, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(ashr(Interval::top(8, Signed), Interval(Int(4, 8, Signed))) == Interval(Int(-8, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(-8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(ashr(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(-8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( ashr(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(4, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr(Interval(Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(1, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(1, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(1, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( ashr(Interval(Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(127, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(127, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(63, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(127, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(31, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(127, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(127, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(128, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( ashr(Interval(Int(128, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(128, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(128, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(128, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(128, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(192, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(128, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(224, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(128, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(254, 8, Unsigned))); BOOST_CHECK( ashr(Interval(Int(128, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_ashr_exact) { BOOST_CHECK( ashr_exact(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK( ashr_exact(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Interval(Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(1, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(1, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(1, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Interval(Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(127, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(127, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(63, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(127, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(31, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(127, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(-128, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK( ashr_exact(Interval(Int(-128, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(0, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-128, 8, Signed), Int(-1, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(-64, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(2, 8, Signed))) == Interval(Int(-32, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(6, 8, Signed))) == Interval(Int(-2, 8, Signed))); BOOST_CHECK( ashr_exact(Interval(Int(-128, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(63, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(7, 8, Signed), Int(7, 8, Signed))) == Interval(Int(-1, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( ashr_exact(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( ashr_exact(Interval::top(8, Signed), Interval(Int(4, 8, Signed))) == Interval(Int(-8, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(-8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(0, 8, Signed), Int(7, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(4, 8, Signed), Int(4, 8, Signed))) == Interval(Int(-8, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( ashr_exact(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(4, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( ashr_exact(Interval(Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(1, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( ashr_exact(Interval(Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(63, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(31, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(127, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(128, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK( ashr_exact(Interval(Int(128, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(128, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))) == Interval(Int(128, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(192, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(2, 8, Unsigned))) == Interval(Int(224, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(6, 8, Unsigned))) == Interval(Int(254, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(128, 8, Unsigned)), Interval(Int(7, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(ashr_exact(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(0, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_and) { BOOST_CHECK(and_(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(and_(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(and_(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(and_(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(and_(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(and_(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(and_(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK( and_(Interval(Int(-128, 8, Signed)), Interval(Int(127, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(and_(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(2, 8, Signed))); BOOST_CHECK(and_(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(126, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(126, 8, Signed))); BOOST_CHECK(and_(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(and_(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(and_(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK(and_(Interval::top(8, Signed), Interval(Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(42, 8, Signed))); BOOST_CHECK(and_(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(42, 8, Signed))); BOOST_CHECK(and_(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(and_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(and_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(and_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(and_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( and_(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(and_(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( and_(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( and_(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( and_(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(and_(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(and_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(1, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(255, 8, Unsigned), Int(255, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(and_(Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned)), Interval(Int(128, 8, Unsigned), Int(128, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(128, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_or) { BOOST_CHECK(or_(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(or_(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(or_(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(or_(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK( or_(Interval(Int(-128, 8, Signed)), Interval(Int(127, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(or_(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(or_(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval::top(8, Signed), Interval(Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(or_(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(or_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( or_(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(or_(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( or_(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( or_(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( or_(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(or_(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(or_(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(or_(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(or_(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(or_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(or_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(or_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_xor) { BOOST_CHECK(xor_(Interval::top(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(xor_(Interval::top(8, Signed), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval::bottom(8, Signed), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(xor_(Interval::bottom(8, Signed), Interval::top(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(1, 8, Signed))); BOOST_CHECK(xor_(Interval(Int(1, 8, Signed)), Interval(Int(1, 8, Signed))) == Interval(Int(0, 8, Signed))); BOOST_CHECK( xor_(Interval(Int(-128, 8, Signed)), Interval(Int(127, 8, Signed))) == Interval(Int(-1, 8, Signed))); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(1, 8, Signed)), Interval(Int(1, 8, Signed), Int(2, 8, Signed))) == Interval(Int(0, 8, Signed), Int(3, 8, Signed))); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::bottom(8, Signed)) == Interval::bottom(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval::top(8, Signed)) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-1, 8, Signed), Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(1, 8, Signed), Int(2, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(xor_(Interval(Int(1, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(126, 8, Signed)), Interval(Int(127, 8, Signed), Int(127, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(xor_(Interval(Int(-2, 8, Signed), Int(-1, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(-2, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(-128, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval::top(8, Signed), Interval(Int(0, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval::top(8, Signed), Interval(Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(42, 8, Signed))) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(xor_(Interval(Int(1, 8, Signed), Int(127, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-52, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(0, 8, Signed), Int(127, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(42, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK(xor_(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)), Interval(Int(-128, 8, Signed), Int(127, 8, Signed))) == Interval::top(8, Signed)); BOOST_CHECK( xor_(Interval(Int(0, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(xor_(Interval(Int(0, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK( xor_(Interval(Int(0, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(1, 8, Unsigned))); BOOST_CHECK( xor_(Interval(Int(1, 8, Unsigned)), Interval(Int(1, 8, Unsigned))) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( xor_(Interval(Int(255, 8, Unsigned)), Interval(Int(0, 8, Unsigned))) == Interval(Int(255, 8, Unsigned))); BOOST_CHECK(xor_(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(xor_(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(xor_(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(3, 8, Unsigned))); BOOST_CHECK(xor_(Interval(Int(2, 8, Unsigned), Int(3, 8, Unsigned)), Interval(Int(3, 8, Unsigned), Int(4, 8, Unsigned))) == Interval(Int(0, 8, Unsigned), Int(7, 8, Unsigned))); BOOST_CHECK(xor_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::bottom(8, Unsigned)) == Interval::bottom(8, Unsigned)); BOOST_CHECK(xor_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval::top(8, Unsigned)) == Interval::top(8, Unsigned)); BOOST_CHECK(xor_(Interval(Int(0, 8, Unsigned), Int(127, 8, Unsigned)), Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))) == Interval::top(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_to_z_interval) { BOOST_CHECK(Interval::bottom(8, Signed).to_z_interval() == ZInterval::bottom()); BOOST_CHECK(Interval::top(8, Signed).to_z_interval() == ZInterval(ZBound(-128), ZBound(127))); BOOST_CHECK(Interval(Int(0, 8, Signed), Int(1, 8, Signed)).to_z_interval() == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(Interval(Int(-1, 8, Signed), Int(1, 8, Signed)).to_z_interval() == ZInterval(ZBound(-1), ZBound(1))); BOOST_CHECK(Interval::bottom(8, Unsigned).to_z_interval() == ZInterval::bottom()); BOOST_CHECK(Interval::top(8, Unsigned).to_z_interval() == ZInterval(ZBound(0), ZBound(255))); BOOST_CHECK( Interval(Int(1, 8, Unsigned), Int(2, 8, Unsigned)).to_z_interval() == ZInterval(ZBound(1), ZBound(2))); BOOST_CHECK( Interval(Int(1, 8, Unsigned), Int(254, 8, Unsigned)).to_z_interval() == ZInterval(ZBound(1), ZBound(254))); } BOOST_AUTO_TEST_CASE(test_from_z_interval_wrap) { using WrapTag = Interval::WrapTag; BOOST_CHECK( Interval::from_z_interval(ZInterval::bottom(), 8, Signed, WrapTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK( Interval::from_z_interval(ZInterval::top(), 8, Signed, WrapTag{}) == Interval::top(8, Signed)); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound::minus_infinity(), ZBound(0)), 8, Signed, WrapTag{}) == Interval::top(8, Signed)); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound(0), ZBound::plus_infinity()), 8, Signed, WrapTag{}) == Interval::top(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(1)), 8, Signed, WrapTag{}) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(127)), 8, Signed, WrapTag{}) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(128)), 8, Signed, WrapTag{}) == Interval::top(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(128), ZBound(129)), 8, Signed, WrapTag{}) == Interval(Int(-128, 8, Signed), Int(-127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(128), ZBound(256)), 8, Signed, WrapTag{}) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(128), ZBound(383)), 8, Signed, WrapTag{}) == Interval(Int(-128, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-128), ZBound(-127)), 8, Signed, WrapTag{}) == Interval(Int(-128, 8, Signed), Int(-127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-129), ZBound(-127)), 8, Signed, WrapTag{}) == Interval::top(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-130), ZBound(-129)), 8, Signed, WrapTag{}) == Interval(Int(126, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-383), ZBound(-129)), 8, Signed, WrapTag{}) == Interval(Int(-127, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-385), ZBound(-129)), 8, Signed, WrapTag{}) == Interval::top(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-385), ZBound(-383)), 8, Signed, WrapTag{}) == Interval::top(8, Signed)); BOOST_CHECK( Interval::from_z_interval(ZInterval::bottom(), 8, Unsigned, WrapTag{}) == Interval::bottom(8, Unsigned)); BOOST_CHECK( Interval::from_z_interval(ZInterval::top(), 8, Unsigned, WrapTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound::minus_infinity(), ZBound(0)), 8, Unsigned, WrapTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound(0), ZBound::plus_infinity()), 8, Unsigned, WrapTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(1)), 8, Unsigned, WrapTag{}) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(254)), 8, Unsigned, WrapTag{}) == Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(255)), 8, Unsigned, WrapTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(256), ZBound(257)), 8, Unsigned, WrapTag{}) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(256), ZBound(510)), 8, Unsigned, WrapTag{}) == Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-2), ZBound(-1)), 8, Unsigned, WrapTag{}) == Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-256), ZBound(-1)), 8, Unsigned, WrapTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-257), ZBound(-256)), 8, Unsigned, WrapTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-258), ZBound(-257)), 8, Unsigned, WrapTag{}) == Interval(Int(254, 8, Unsigned), Int(255, 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_from_z_interval_trunc) { using TruncTag = Interval::TruncTag; BOOST_CHECK( Interval::from_z_interval(ZInterval::bottom(), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK( Interval::from_z_interval(ZInterval::top(), 8, Signed, TruncTag{}) == Interval::top(8, Signed)); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound::minus_infinity(), ZBound(0)), 8, Signed, TruncTag{}) == Interval(Int(-128, 8, Signed), Int(0, 8, Signed))); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound(0), ZBound::plus_infinity()), 8, Signed, TruncTag{}) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(1)), 8, Signed, TruncTag{}) == Interval(Int(0, 8, Signed), Int(1, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(127)), 8, Signed, TruncTag{}) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(128)), 8, Signed, TruncTag{}) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(128), ZBound(129)), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(128), ZBound(256)), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(128), ZBound(383)), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-128), ZBound(-127)), 8, Signed, TruncTag{}) == Interval(Int(-128, 8, Signed), Int(-127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-129), ZBound(-127)), 8, Signed, TruncTag{}) == Interval(Int(-128, 8, Signed), Int(-127, 8, Signed))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-130), ZBound(-129)), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-383), ZBound(-129)), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-385), ZBound(-129)), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-385), ZBound(-383)), 8, Signed, TruncTag{}) == Interval::bottom(8, Signed)); BOOST_CHECK( Interval::from_z_interval(ZInterval::bottom(), 8, Unsigned, TruncTag{}) == Interval::bottom(8, Unsigned)); BOOST_CHECK( Interval::from_z_interval(ZInterval::top(), 8, Unsigned, TruncTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound::minus_infinity(), ZBound(0)), 8, Unsigned, TruncTag{}) == Interval(Int(0, 8, Unsigned))); BOOST_CHECK( Interval::from_z_interval(ZInterval(ZBound(0), ZBound::plus_infinity()), 8, Unsigned, TruncTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(1)), 8, Unsigned, TruncTag{}) == Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(254)), 8, Unsigned, TruncTag{}) == Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned))); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(0), ZBound(255)), 8, Unsigned, TruncTag{}) == Interval::top(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(256), ZBound(257)), 8, Unsigned, TruncTag{}) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(256), ZBound(510)), 8, Unsigned, TruncTag{}) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-2), ZBound(-1)), 8, Unsigned, TruncTag{}) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-256), ZBound(-1)), 8, Unsigned, TruncTag{}) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-257), ZBound(-256)), 8, Unsigned, TruncTag{}) == Interval::bottom(8, Unsigned)); BOOST_CHECK(Interval::from_z_interval(ZInterval(ZBound(-258), ZBound(-257)), 8, Unsigned, TruncTag{}) == Interval::bottom(8, Unsigned)); } BOOST_AUTO_TEST_CASE(test_widening_threshold) { BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(128, 8, Unsigned)) .widening_threshold(Interval(Int(0, 8, Unsigned), Int(140, 8, Unsigned)), Int(142, 8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(142, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(10, 8, Signed)) .widening_threshold(Interval(Int(0, 8, Signed), Int(20, 8, Signed)), Int(18, 8, Signed)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); BOOST_CHECK(Interval(Int(3, 8, Unsigned), Int(254, 8, Unsigned)) .widening_threshold(Interval(Int(1, 8, Unsigned), Int(254, 8, Unsigned)), Int(0, 8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned))); BOOST_CHECK( Interval(Int(42, 8, Signed), Int(43, 8, Signed)) .widening_threshold(Interval(Int(41, 8, Signed), Int(42, 8, Signed)), Int(42, 8, Signed)) == Interval(Int(-128, 8, Signed), Int(43, 8, Signed))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(42, 8, Unsigned)) .widening_threshold(Interval(Int(0, 8, Unsigned), Int(73, 8, Unsigned)), Int(73, 8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(73, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(47, 8, Signed)) .widening_threshold(Interval(Int(0, 8, Signed), Int(48, 8, Signed)), Int(49, 32, Unsigned)) == Interval(Int(0, 8, Signed), Int(49, 8, Signed))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(47, 8, Signed)) .widening_threshold(Interval(Int(0, 8, Signed), Int(48, 8, Signed)), Int(257, 32, Unsigned)) == Interval(Int(0, 8, Signed), Int(127, 8, Signed))); } BOOST_AUTO_TEST_CASE(test_narrowing_threshold) { BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(255, 8, Unsigned)) .narrowing_threshold(Interval(Int(0, 8, Unsigned), Int(200, 8, Unsigned)), Int(100, 8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(200, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(100, 8, Unsigned)) .narrowing_threshold(Interval(Int(0, 8, Unsigned), Int(80, 8, Unsigned)), Int(100, 8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(80, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(150, 8, Unsigned)) .narrowing_threshold(Interval(Int(0, 8, Unsigned), Int(80, 8, Unsigned)), Int(100, 8, Unsigned)) == Interval(Int(0, 8, Unsigned), Int(150, 8, Unsigned))); BOOST_CHECK(Interval(Int(0, 8, Unsigned), Int(100, 8, Unsigned)) .narrowing_threshold(Interval(Int(5, 8, Unsigned), Int(100, 8, Unsigned)), Int(10, 8, Unsigned)) == Interval(Int(5, 8, Unsigned), Int(100, 8, Unsigned))); BOOST_CHECK(Interval(Int(10, 8, Unsigned), Int(100, 8, Unsigned)) .narrowing_threshold(Interval(Int(20, 8, Unsigned), Int(100, 8, Unsigned)), Int(10, 8, Unsigned)) == Interval(Int(20, 8, Unsigned), Int(100, 8, Unsigned))); BOOST_CHECK(Interval(Int(20, 8, Unsigned), Int(100, 8, Unsigned)) .narrowing_threshold(Interval(Int(30, 8, Unsigned), Int(100, 8, Unsigned)), Int(10, 8, Unsigned)) == Interval(Int(20, 8, Unsigned), Int(100, 8, Unsigned))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(127, 8, Signed)) .narrowing_threshold(Interval(Int(0, 8, Signed), Int(120, 8, Signed)), Int(100, 8, Signed)) == Interval(Int(0, 8, Signed), Int(120, 8, Signed))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(100, 8, Signed)) .narrowing_threshold(Interval(Int(0, 8, Signed), Int(80, 8, Signed)), Int(100, 8, Signed)) == Interval(Int(0, 8, Signed), Int(80, 8, Signed))); BOOST_CHECK( Interval(Int(0, 8, Signed), Int(100, 8, Signed)) .narrowing_threshold(Interval(Int(0, 8, Signed), Int(80, 8, Signed)), Int(90, 8, Signed)) == Interval(Int(0, 8, Signed), Int(100, 8, Signed))); BOOST_CHECK(Interval(Int(-128, 8, Signed), Int(100, 8, Signed)) .narrowing_threshold(Interval(Int(-120, 8, Signed), Int(100, 8, Signed)), Int(-100, 8, Signed)) == Interval(Int(-120, 8, Signed), Int(100, 8, Signed))); BOOST_CHECK(Interval(Int(-100, 8, Signed), Int(100, 8, Signed)) .narrowing_threshold(Interval(Int(-80, 8, Signed), Int(100, 8, Signed)), Int(-100, 8, Signed)) == Interval(Int(-80, 8, Signed), Int(100, 8, Signed))); BOOST_CHECK(Interval(Int(-90, 8, Signed), Int(100, 8, Signed)) .narrowing_threshold(Interval(Int(-80, 8, Signed), Int(100, 8, Signed)), Int(-100, 8, Signed)) == Interval(Int(-90, 8, Signed), Int(100, 8, Signed))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/machine_int/interval_congruence.cpp000066400000000000000000001005651473507761200276450ustar00rootroot00000000000000/******************************************************************************* * * Tests for machine_int::IntervalCongruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_machine_integer_interval_congruence #define BOOST_TEST_DYN_LINK #include #include #include #include using ikos::core::Signed; using ikos::core::Unsigned; using Z = ikos::core::ZNumber; using Int = ikos::core::MachineInt; using ZBound = ikos::core::ZBound; using ZInterval = ikos::core::numeric::ZInterval; using ZCongruence = ikos::core::numeric::ZCongruence; using ZIntervalCongruence = ikos::core::numeric::IntervalCongruence< Z >; using Interval = ikos::core::machine_int::Interval; using Congruence = ikos::core::machine_int::Congruence; using IntervalCongruence = ikos::core::machine_int::IntervalCongruence; BOOST_AUTO_TEST_CASE(test_constructors) { // IntervalCongruence(Int) BOOST_CHECK( IntervalCongruence(Int(0, 8, Signed)) == IntervalCongruence(Interval(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Int(1, 8, Signed)) == IntervalCongruence(Interval(Int(1, 8, Signed)), Congruence(Int(0, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Int(-128, 8, Signed)) == IntervalCongruence(Interval(Int(-128, 8, Signed)), Congruence(Int(0, 8, Signed), Int(-128, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Int(127, 8, Signed)) == IntervalCongruence(Interval(Int(127, 8, Signed)), Congruence(Int(0, 8, Signed), Int(127, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Int(0, 8, Unsigned)) == IntervalCongruence(Interval(Int(0, 8, Unsigned)), Congruence(Int(0, 8, Unsigned), Int(0, 8, Unsigned)))); BOOST_CHECK( IntervalCongruence(Int(1, 8, Unsigned)) == IntervalCongruence(Interval(Int(1, 8, Unsigned)), Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK(IntervalCongruence(Int(255, 8, Unsigned)) == IntervalCongruence(Interval(Int(255, 8, Unsigned)), Congruence(Int(0, 8, Unsigned), Int(255, 8, Unsigned)))); // IntervalCongruence(Interval) BOOST_CHECK( IntervalCongruence(Interval(Int(1, 8, Signed))) == IntervalCongruence(Interval(Int(1, 8, Signed)), Congruence(Int(0, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Interval(Int(0, 8, Signed), Int(2, 8, Signed))) == IntervalCongruence(Interval(Int(0, 8, Signed), Int(2, 8, Signed)), Congruence(Int(1, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Interval(Int(1, 8, Unsigned))) == IntervalCongruence(Interval(Int(1, 8, Unsigned)), Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK( IntervalCongruence(Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned))) == IntervalCongruence(Interval(Int(0, 8, Unsigned), Int(2, 8, Unsigned)), Congruence(Int(1, 8, Unsigned), Int(0, 8, Unsigned)))); // IntervalCongruence(Congruence) BOOST_CHECK( IntervalCongruence(Congruence(Int(1, 8, Signed))) == IntervalCongruence(Interval(Int(1, 8, Signed)), Congruence(Int(0, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Congruence(Int(2, 8, Signed), Int(0, 8, Signed))) == IntervalCongruence(Interval::top(8, Signed), Congruence(Int(2, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Congruence(Int(1, 8, Unsigned))) == IntervalCongruence(Interval(Int(1, 8, Unsigned)), Congruence(Int(0, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK( IntervalCongruence( Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned))) == IntervalCongruence(Interval::top(8, Unsigned), Congruence(Int(2, 8, Unsigned), Int(0, 8, Unsigned)))); // IntervalCongruence(Interval a, Congruence b) BOOST_CHECK( IntervalCongruence(Interval::bottom(8, Signed), Congruence(Int(0, 8, Signed), Int(1, 8, Signed))) .is_bottom()); BOOST_CHECK(IntervalCongruence(Interval(Int(0, 8, Signed)), Congruence::bottom(8, Signed)) .is_bottom()); BOOST_CHECK( IntervalCongruence(Interval(Int(2, 8, Signed)), Congruence(Int(1, 8, Signed), Int(0, 8, Signed))) == IntervalCongruence(Interval(Int(2, 8, Signed)), Congruence(Int(0, 8, Signed), Int(2, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Interval(Int(0, 8, Signed)), Congruence(Int(0, 8, Signed), Int(1, 8, Signed))) .is_bottom()); BOOST_CHECK( IntervalCongruence(Interval(Int(0, 8, Signed), Int(4, 8, Signed)), Congruence(Int(0, 8, Signed), Int(-1, 8, Signed))) .is_bottom()); BOOST_CHECK( IntervalCongruence(Interval::top(8, Signed), Congruence(Int(0, 8, Signed), Int(1, 8, Signed))) == IntervalCongruence(Interval(Int(1, 8, Signed)), Congruence(Int(0, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Interval(Int(0, 8, Signed), Int(12, 8, Signed)), Congruence(Int(8, 8, Signed), Int(1, 8, Signed))) == IntervalCongruence(Interval(Int(1, 8, Signed), Int(9, 8, Signed)), Congruence(Int(8, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Interval(Int(0, 8, Signed), Int(2, 8, Signed)), Congruence(Int(8, 8, Signed), Int(1, 8, Signed))) == IntervalCongruence(Interval(Int(1, 8, Signed)), Congruence(Int(8, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence(Interval(Int(2, 8, Signed), Int(8, 8, Signed)), Congruence(Int(8, 8, Signed), Int(1, 8, Signed))) .is_bottom()); BOOST_CHECK( IntervalCongruence::top(1, Signed) == IntervalCongruence(Interval::top(1, Signed), Congruence::top(1, Signed))); BOOST_CHECK( IntervalCongruence::top(8, Signed) == IntervalCongruence(Interval::top(8, Signed), Congruence::top(8, Signed))); BOOST_CHECK(IntervalCongruence::top(1, Unsigned) == IntervalCongruence(Interval::top(1, Unsigned), Congruence::top(1, Unsigned))); BOOST_CHECK(IntervalCongruence::top(8, Unsigned) == IntervalCongruence(Interval::top(8, Unsigned), Congruence::top(8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_from_z_interval_congruence_wrap) { using WrapTag = IntervalCongruence::WrapTag; BOOST_CHECK(IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence::bottom(), 8, Signed, WrapTag{}) == IntervalCongruence::bottom(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence::top(), 8, Signed, WrapTag{}) == IntervalCongruence::top(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound(1))), 8, Signed, WrapTag{}) == IntervalCongruence(Interval(Int(0, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound::minus_infinity(), ZBound(0))), 8, Signed, WrapTag{}) == IntervalCongruence::top(8, Signed)); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound::plus_infinity())), 8, Signed, WrapTag{}) == IntervalCongruence::top(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound( 127))), 8, Signed, WrapTag{}) == IntervalCongruence(Interval(Int(0, 8, Signed), Int(127, 8, Signed)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound( 128))), 8, Signed, WrapTag{}) == IntervalCongruence::top(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(-128), ZBound( -127))), 8, Signed, WrapTag{}) == IntervalCongruence(Interval(Int(-128, 8, Signed), Int(-127, 8, Signed)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(-129), ZBound( -127))), 8, Signed, WrapTag{}) == IntervalCongruence::top(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(128)), 8, Signed, WrapTag{}) == IntervalCongruence(Int(-128, 8, Signed))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(128), Z(1))), 8, Signed, WrapTag{}) == IntervalCongruence(Congruence(Z(128), Z(1), 8, Signed))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(3), Z(1))), 8, Signed, WrapTag{}) == IntervalCongruence::top(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(6), Z(1))), 8, Signed, WrapTag{}) == IntervalCongruence(Congruence(Z(2), Z(1), 8, Signed))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence(ZInterval(ZBound(1), ZBound(121)), ZCongruence(Z(6), Z(1))), 8, Signed, WrapTag{}) == IntervalCongruence(Interval(Int(1, 8, Signed), Int(121, 8, Signed)), Congruence(Z(2), Z(1), 8, Signed))); BOOST_CHECK(IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence::bottom(), 8, Unsigned, WrapTag{}) == IntervalCongruence::bottom(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence::top(), 8, Unsigned, WrapTag{}) == IntervalCongruence::top(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound(1))), 8, Unsigned, WrapTag{}) == IntervalCongruence(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound::minus_infinity(), ZBound(0))), 8, Unsigned, WrapTag{}) == IntervalCongruence::top(8, Unsigned)); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound::plus_infinity())), 8, Unsigned, WrapTag{}) == IntervalCongruence::top(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound( 254))), 8, Unsigned, WrapTag{}) == IntervalCongruence(Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(257)), 8, Unsigned, WrapTag{}) == IntervalCongruence(Int(1, 8, Unsigned))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(128), Z(1))), 8, Unsigned, WrapTag{}) == IntervalCongruence(Congruence(Z(128), Z(1), 8, Unsigned))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(3), Z(1))), 8, Unsigned, WrapTag{}) == IntervalCongruence::top(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(6), Z(1))), 8, Unsigned, WrapTag{}) == IntervalCongruence(Congruence(Z(2), Z(1), 8, Unsigned))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence(ZInterval(ZBound(1), ZBound(121)), ZCongruence(Z(6), Z(1))), 8, Unsigned, WrapTag{}) == IntervalCongruence(Interval(Int(1, 8, Unsigned), Int(121, 8, Unsigned)), Congruence(Z(2), Z(1), 8, Unsigned))); } BOOST_AUTO_TEST_CASE(test_from_z_interval_congruence_trunc) { using TruncTag = IntervalCongruence::TruncTag; BOOST_CHECK(IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence::bottom(), 8, Signed, TruncTag{}) == IntervalCongruence::bottom(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence::top(), 8, Signed, TruncTag{}) == IntervalCongruence::top(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound(1))), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(0, 8, Signed), Int(1, 8, Signed)))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound::minus_infinity(), ZBound(0))), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(-128, 8, Signed), Int(0, 8, Signed)))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound::plus_infinity())), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(0, 8, Signed), Int(127, 8, Signed)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound( 127))), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(0, 8, Signed), Int(127, 8, Signed)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound( 128))), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(0, 8, Signed), Int(127, 8, Signed)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(-128), ZBound( -127))), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(-128, 8, Signed), Int(-127, 8, Signed)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(-129), ZBound( -127))), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(-128, 8, Signed), Int(-127, 8, Signed)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(128)), 8, Signed, TruncTag{}) == IntervalCongruence::bottom(8, Signed)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(128), Z(1))), 8, Signed, TruncTag{}) == IntervalCongruence(Congruence(Z(128), Z(1), 8, Signed))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(3), Z(1))), 8, Signed, TruncTag{}) == IntervalCongruence(Congruence(Z(3), Z(1), 8, Signed))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(6), Z(1))), 8, Signed, TruncTag{}) == IntervalCongruence(Congruence(Z(6), Z(1), 8, Signed))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence(ZInterval(ZBound(1), ZBound(121)), ZCongruence(Z(6), Z(1))), 8, Signed, TruncTag{}) == IntervalCongruence(Interval(Int(1, 8, Signed), Int(121, 8, Signed)), Congruence(Z(6), Z(1), 8, Signed))); BOOST_CHECK(IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence::bottom(), 8, Unsigned, TruncTag{}) == IntervalCongruence::bottom(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence::top(), 8, Unsigned, TruncTag{}) == IntervalCongruence::top(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound(1))), 8, Unsigned, TruncTag{}) == IntervalCongruence(Interval(Int(0, 8, Unsigned), Int(1, 8, Unsigned)))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound::minus_infinity(), ZBound(0))), 8, Unsigned, TruncTag{}) == IntervalCongruence(Int(0, 8, Unsigned))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound::plus_infinity())), 8, Unsigned, TruncTag{}) == IntervalCongruence::top(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZInterval(ZBound(0), ZBound( 254))), 8, Unsigned, TruncTag{}) == IntervalCongruence(Interval(Int(0, 8, Unsigned), Int(254, 8, Unsigned)))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(257)), 8, Unsigned, TruncTag{}) == IntervalCongruence::bottom(8, Unsigned)); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(128), Z(1))), 8, Unsigned, TruncTag{}) == IntervalCongruence(Congruence(Z(128), Z(1), 8, Unsigned))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(3), Z(1))), 8, Unsigned, TruncTag{}) == IntervalCongruence(Congruence(Z(3), Z(1), 8, Unsigned))); BOOST_CHECK( IntervalCongruence::from_z_interval_congruence(ZIntervalCongruence( ZCongruence(Z(6), Z(1))), 8, Unsigned, TruncTag{}) == IntervalCongruence(Congruence(Z(6), Z(1), 8, Unsigned))); BOOST_CHECK( IntervalCongruence:: from_z_interval_congruence(ZIntervalCongruence(ZInterval(ZBound(1), ZBound(121)), ZCongruence(Z(6), Z(1))), 8, Unsigned, TruncTag{}) == IntervalCongruence(Interval(Int(1, 8, Unsigned), Int(121, 8, Unsigned)), Congruence(Z(6), Z(1), 8, Unsigned))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/numeric/000077500000000000000000000000001473507761200222625ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/numeric/congruence.cpp000066400000000000000000001003021473507761200251120ustar00rootroot00000000000000/******************************************************************************* * * Tests for Congruence * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_congruence #define BOOST_TEST_DYN_LINK #include #include #include using namespace ikos::core; using namespace ikos::core::numeric; BOOST_AUTO_TEST_CASE(test_join) { BOOST_CHECK(ZCongruence(2).join(ZCongruence(4)) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(ZCongruence(1).join(ZCongruence(3)) == ZCongruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) .join(ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); } BOOST_AUTO_TEST_CASE(test_meet) { BOOST_CHECK(ZCongruence(2).meet(ZCongruence(4)) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)).meet(ZCongruence(1)) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(1)).meet(ZCongruence(1)) == ZCongruence(1)); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) .meet(ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::bottom()); } BOOST_AUTO_TEST_CASE(test_addition) { BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) + ZCongruence(4) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(ZCongruence::top() + ZCongruence(4) == ZCongruence::top()); } BOOST_AUTO_TEST_CASE(test_substract) { BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) - ZCongruence(4) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(ZCongruence::top() - ZCongruence(4) == ZCongruence::top()); } BOOST_AUTO_TEST_CASE(test_multiply) { BOOST_CHECK(ZCongruence::bottom() * ZCongruence(4) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(2) * ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(2) * ZCongruence(4) == ZCongruence(8)); BOOST_CHECK(ZCongruence(2) * ZCongruence(-4) == ZCongruence(-8)); BOOST_CHECK(ZCongruence(7) * ZCongruence(3) == ZCongruence(21)); BOOST_CHECK(ZCongruence(7) * ZCongruence(0) == ZCongruence(0)); BOOST_CHECK(ZCongruence(4) * ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(ZNumber(8), ZNumber(0))); BOOST_CHECK(ZCongruence(4) * ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence(ZNumber(8), ZNumber(4))); BOOST_CHECK(ZCongruence(0) * ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(0)); BOOST_CHECK(ZCongruence(4) * ZCongruence::top() == ZCongruence(ZNumber(4), ZNumber(0))); BOOST_CHECK(ZCongruence(0) * ZCongruence::top() == ZCongruence(0)); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence(0) == ZCongruence(0)); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence(4) == ZCongruence(ZNumber(20), ZNumber(4))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence(-4) == ZCongruence(ZNumber(20), ZNumber(16))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence(ZNumber(10), ZNumber(0)) == ZCongruence(ZNumber(10), ZNumber(0))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) * ZCongruence(ZNumber(10), ZNumber(2)) == ZCongruence(ZNumber(10), ZNumber(2))); } BOOST_AUTO_TEST_CASE(test_divide) { BOOST_CHECK(ZCongruence::bottom() / ZCongruence(4) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence::top() / ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(2) / ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(3) / ZCongruence(2) == ZCongruence(1)); BOOST_CHECK(ZCongruence(-3) / ZCongruence(2) == ZCongruence(-1)); BOOST_CHECK(ZCongruence(7) / ZCongruence(3) == ZCongruence(2)); BOOST_CHECK(ZCongruence(7) / ZCongruence(0) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(4) / ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) / ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(0) / ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(0)); BOOST_CHECK(ZCongruence(-4) / ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) / ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(2) / ZCongruence(ZNumber(3), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(7) / ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(12) / ZCongruence(ZNumber(3), ZNumber(2)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(6) / ZCongruence(ZNumber(6), ZNumber(3)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(5) / ZCongruence(ZNumber(5), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) / ZCongruence::top() == ZCongruence::top()); BOOST_CHECK(ZCongruence(0) / ZCongruence::top() == ZCongruence(0)); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence(0) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(4), ZNumber(1)) / ZCongruence(2) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence(-4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(1)) / ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(4)) / ZCongruence(4) == ZCongruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(12), ZNumber(7)) / ZCongruence(3) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence(ZNumber(10), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) / ZCongruence(ZNumber(10), ZNumber(2)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) / ZCongruence(4) == ZCongruence::top()); } BOOST_AUTO_TEST_CASE(test_mod) { BOOST_CHECK(mod(ZCongruence::bottom(), ZCongruence(4)) == ZCongruence::bottom()); BOOST_CHECK(mod(ZCongruence::top(), ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(2), ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK(mod(ZCongruence(3), ZCongruence(2)) == ZCongruence(1)); BOOST_CHECK(mod(ZCongruence(-3), ZCongruence(2)) == ZCongruence(1)); BOOST_CHECK(mod(ZCongruence(7), ZCongruence(3)) == ZCongruence(1)); BOOST_CHECK(mod(ZCongruence(7), ZCongruence(0)) == ZCongruence::bottom()); BOOST_CHECK(mod(ZCongruence(4), ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(mod(ZCongruence(4), ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(0), ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence(0)); BOOST_CHECK(mod(ZCongruence(-4), ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(4), ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(2), ZCongruence(ZNumber(3), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(7), ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(12), ZCongruence(ZNumber(3), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(6), ZCongruence(ZNumber(6), ZNumber(3))) == ZCongruence(ZNumber(3), ZNumber(0))); BOOST_CHECK(mod(ZCongruence(5), ZCongruence(ZNumber(5), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(4), ZCongruence::top()) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(0), ZCongruence::top()) == ZCongruence(0)); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence(0)) == ZCongruence::bottom()); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(ZNumber(4), ZNumber(1)), ZCongruence(2)) == ZCongruence(1)); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence(-4)) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(ZNumber(8), ZNumber(1)), ZCongruence(4)) == ZCongruence(1)); BOOST_CHECK(mod(ZCongruence(ZNumber(8), ZNumber(4)), ZCongruence(4)) == ZCongruence(0)); BOOST_CHECK(mod(ZCongruence(ZNumber(12), ZNumber(7)), ZCongruence(3)) == ZCongruence(1)); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence(ZNumber(10), ZNumber(0))) == ZCongruence(ZNumber(5), ZNumber(1))); BOOST_CHECK(mod(ZCongruence(ZNumber(5), ZNumber(1)), ZCongruence(ZNumber(10), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK(mod(ZCongruence(ZNumber(2), ZNumber(0)), ZCongruence(4)) == ZCongruence(ZNumber(2), ZNumber(0))); } BOOST_AUTO_TEST_CASE(test_rem) { BOOST_CHECK(ZCongruence::bottom() % ZCongruence(4) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence::top() % ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(2) % ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(3) % ZCongruence(2) == ZCongruence(1)); BOOST_CHECK(ZCongruence(-3) % ZCongruence(2) == ZCongruence(-1)); BOOST_CHECK(ZCongruence(7) % ZCongruence(3) == ZCongruence(1)); BOOST_CHECK(ZCongruence(7) % ZCongruence(0) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(4) % ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(ZCongruence(4) % ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(0) % ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(0)); BOOST_CHECK(ZCongruence(-4) % ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) % ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(2) % ZCongruence(ZNumber(3), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(7) % ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(12) % ZCongruence(ZNumber(3), ZNumber(2)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(6) % ZCongruence(ZNumber(6), ZNumber(3)) == ZCongruence(ZNumber(3), ZNumber(0))); BOOST_CHECK(ZCongruence(5) % ZCongruence(ZNumber(5), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) % ZCongruence::top() == ZCongruence::top()); BOOST_CHECK(ZCongruence(0) % ZCongruence::top() == ZCongruence(0)); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence(0) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(4), ZNumber(1)) % ZCongruence(2) == ZCongruence(ZNumber(2), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence(-4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(1)) % ZCongruence(4) == ZCongruence(ZNumber(4), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(4)) % ZCongruence(4) == ZCongruence(0)); BOOST_CHECK(ZCongruence(ZNumber(12), ZNumber(7)) % ZCongruence(3) == ZCongruence(ZNumber(3), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence(ZNumber(10), ZNumber(0)) == ZCongruence(ZNumber(5), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) % ZCongruence(ZNumber(10), ZNumber(2)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) % ZCongruence(4) == ZCongruence(ZNumber(2), ZNumber(0))); } BOOST_AUTO_TEST_CASE(test_shl) { BOOST_CHECK(ZCongruence::bottom() << ZCongruence(4) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(4) << ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(3) << ZCongruence(2) == ZCongruence(12)); BOOST_CHECK(ZCongruence(-3) << ZCongruence(2) == ZCongruence(-12)); BOOST_CHECK(ZCongruence(7) << ZCongruence(3) == ZCongruence(56)); BOOST_CHECK(ZCongruence(7) << ZCongruence(-1) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(4) << ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(ZNumber(12), ZNumber(4))); BOOST_CHECK(ZCongruence(4) << ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence(ZNumber(24), ZNumber(8))); BOOST_CHECK(ZCongruence(0) << ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(0)); BOOST_CHECK(ZCongruence(-4) << ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence(ZNumber(120), ZNumber(112))); BOOST_CHECK(ZCongruence(4) << ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence(ZNumber(120), ZNumber(8))); BOOST_CHECK(ZCongruence(2) << ZCongruence(ZNumber(3), ZNumber(1)) == ZCongruence(ZNumber(28), ZNumber(4))); BOOST_CHECK(ZCongruence(7) << ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence(ZNumber(210), ZNumber(14))); BOOST_CHECK(ZCongruence(12) << ZCongruence(ZNumber(3), ZNumber(2)) == ZCongruence(ZNumber(336), ZNumber(48))); BOOST_CHECK(ZCongruence(6) << ZCongruence(ZNumber(6), ZNumber(3)) == ZCongruence(ZNumber(3024), ZNumber(48))); BOOST_CHECK(ZCongruence(5) << ZCongruence(ZNumber(5), ZNumber(1)) == ZCongruence(ZNumber(310), ZNumber(10))); BOOST_CHECK(ZCongruence(4) << ZCongruence::top() == ZCongruence(ZNumber(4), ZNumber(0))); BOOST_CHECK(ZCongruence(0) << ZCongruence::top() == ZCongruence(0)); BOOST_CHECK(ZCongruence::top() << ZCongruence(4) == ZCongruence(ZNumber(16), ZNumber(0))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence(0) == ZCongruence(ZNumber(5), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence(4) == ZCongruence(ZNumber(80), ZNumber(16))); BOOST_CHECK(ZCongruence(ZNumber(4), ZNumber(1)) << ZCongruence(2) == ZCongruence(ZNumber(16), ZNumber(4))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence(-4) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(1)) << ZCongruence(4) == ZCongruence(ZNumber(128), ZNumber(16))); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(4)) << ZCongruence(4) == ZCongruence(ZNumber(128), ZNumber(64))); BOOST_CHECK(ZCongruence(ZNumber(12), ZNumber(7)) << ZCongruence(3) == ZCongruence(ZNumber(96), ZNumber(56))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence(ZNumber(10), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) << ZCongruence(ZNumber(10), ZNumber(2)) == ZCongruence(ZNumber(4), ZNumber(0))); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) << ZCongruence(4) == ZCongruence(ZNumber(32), ZNumber(0))); } BOOST_AUTO_TEST_CASE(test_shr) { BOOST_CHECK(ZCongruence::bottom() >> ZCongruence(4) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(4) >> ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(12) >> ZCongruence(2) == ZCongruence(3)); BOOST_CHECK(ZCongruence(-12) >> ZCongruence(2) == ZCongruence(-3)); BOOST_CHECK(ZCongruence(17) >> ZCongruence(3) == ZCongruence(2)); BOOST_CHECK(ZCongruence(7) >> ZCongruence(-1) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(4) >> ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) >> ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(0) >> ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence(0)); BOOST_CHECK(ZCongruence(-4) >> ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) >> ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(2) >> ZCongruence(ZNumber(3), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(7) >> ZCongruence(ZNumber(4), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(12) >> ZCongruence(ZNumber(3), ZNumber(2)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(6) >> ZCongruence(ZNumber(6), ZNumber(3)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(5) >> ZCongruence(ZNumber(5), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(4) >> ZCongruence::top() == ZCongruence::top()); BOOST_CHECK(ZCongruence(0) >> ZCongruence::top() == ZCongruence(0)); BOOST_CHECK(ZCongruence::top() >> ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence::bottom() == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence(0) == ZCongruence(ZNumber(5), ZNumber(1))); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(4), ZNumber(1)) >> ZCongruence(2) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence(-4) == ZCongruence::bottom()); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(1)) >> ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(8), ZNumber(4)) >> ZCongruence(4) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(12), ZNumber(7)) >> ZCongruence(3) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence(ZNumber(2), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence(ZNumber(2), ZNumber(1)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence(ZNumber(10), ZNumber(0)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(5), ZNumber(1)) >> ZCongruence(ZNumber(10), ZNumber(2)) == ZCongruence::top()); BOOST_CHECK(ZCongruence(ZNumber(2), ZNumber(0)) >> ZCongruence(4) == ZCongruence::top()); } BOOST_AUTO_TEST_CASE(test_and) { BOOST_CHECK((ZCongruence::bottom() & ZCongruence(4)) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(4) & ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(12) & ZCongruence(6)) == ZCongruence(4)); BOOST_CHECK((ZCongruence(-12) & ZCongruence(6)) == ZCongruence(4)); BOOST_CHECK((ZCongruence(17) & ZCongruence(3)) == ZCongruence(1)); BOOST_CHECK((ZCongruence(7) & ZCongruence(-1)) == ZCongruence(7)); BOOST_CHECK((ZCongruence(4) & ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(4) & ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(0) & ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence(0)); BOOST_CHECK((ZCongruence(-1) & ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence(ZNumber(4), ZNumber(1))); BOOST_CHECK((ZCongruence(4) & ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(2) & ZCongruence(ZNumber(3), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(7) & ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(12) & ZCongruence(ZNumber(3), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(6) & ZCongruence(ZNumber(6), ZNumber(3))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(5) & ZCongruence(ZNumber(5), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(4) & ZCongruence::top()) == ZCongruence::top()); BOOST_CHECK((ZCongruence(0) & ZCongruence::top()) == ZCongruence(0)); BOOST_CHECK((ZCongruence::top() & ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence(0)) == ZCongruence(0)); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(4), ZNumber(1)) & ZCongruence(2)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence(-4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(8), ZNumber(1)) & ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(8), ZNumber(4)) & ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(12), ZNumber(7)) & ZCongruence(3)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence(ZNumber(10), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) & ZCongruence(ZNumber(10), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(2), ZNumber(0)) & ZCongruence(4)) == ZCongruence::top()); } BOOST_AUTO_TEST_CASE(test_or) { BOOST_CHECK((ZCongruence::bottom() | ZCongruence(4)) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(4) | ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(12) | ZCongruence(6)) == ZCongruence(14)); BOOST_CHECK((ZCongruence(-12) | ZCongruence(6)) == ZCongruence(-10)); BOOST_CHECK((ZCongruence(17) | ZCongruence(3)) == ZCongruence(19)); BOOST_CHECK((ZCongruence(7) | ZCongruence(-1)) == ZCongruence(-1)); BOOST_CHECK((ZCongruence(4) | ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(4) | ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(0) | ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK((ZCongruence(-1) | ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence(-1)); BOOST_CHECK((ZCongruence(4) | ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(2) | ZCongruence(ZNumber(3), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(7) | ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(12) | ZCongruence(ZNumber(3), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(6) | ZCongruence(ZNumber(6), ZNumber(3))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(5) | ZCongruence(ZNumber(5), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(4) | ZCongruence::top()) == ZCongruence::top()); BOOST_CHECK((ZCongruence(0) | ZCongruence::top()) == ZCongruence::top()); BOOST_CHECK((ZCongruence::top() | ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence(0)) == ZCongruence(ZNumber(5), ZNumber(1))); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(4), ZNumber(1)) | ZCongruence(2)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence(-4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(8), ZNumber(1)) | ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(8), ZNumber(4)) | ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(12), ZNumber(7)) | ZCongruence(3)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence(ZNumber(10), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) | ZCongruence(ZNumber(10), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(2), ZNumber(0)) | ZCongruence(4)) == ZCongruence::top()); } BOOST_AUTO_TEST_CASE(test_xor) { BOOST_CHECK((ZCongruence::bottom() ^ ZCongruence(4)) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(4) ^ ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(12) ^ ZCongruence(6)) == ZCongruence(10)); BOOST_CHECK((ZCongruence(-12) ^ ZCongruence(6)) == ZCongruence(-14)); BOOST_CHECK((ZCongruence(17) ^ ZCongruence(3)) == ZCongruence(18)); BOOST_CHECK((ZCongruence(7) ^ ZCongruence(-1)) == ZCongruence(-8)); BOOST_CHECK((ZCongruence(4) ^ ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(4) ^ ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(0) ^ ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence(ZNumber(2), ZNumber(0))); BOOST_CHECK((ZCongruence(-1) ^ ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(4) ^ ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(2) ^ ZCongruence(ZNumber(3), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(7) ^ ZCongruence(ZNumber(4), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(12) ^ ZCongruence(ZNumber(3), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(6) ^ ZCongruence(ZNumber(6), ZNumber(3))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(5) ^ ZCongruence(ZNumber(5), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(4) ^ ZCongruence::top()) == ZCongruence::top()); BOOST_CHECK((ZCongruence(0) ^ ZCongruence::top()) == ZCongruence::top()); BOOST_CHECK((ZCongruence::top() ^ ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence::bottom()) == ZCongruence::bottom()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence(0)) == ZCongruence(ZNumber(5), ZNumber(1))); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(4), ZNumber(1)) ^ ZCongruence(2)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence(-4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(8), ZNumber(1)) ^ ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(8), ZNumber(4)) ^ ZCongruence(4)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(12), ZNumber(7)) ^ ZCongruence(3)) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence(ZNumber(2), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence(ZNumber(2), ZNumber(1))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence(ZNumber(10), ZNumber(0))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(5), ZNumber(1)) ^ ZCongruence(ZNumber(10), ZNumber(2))) == ZCongruence::top()); BOOST_CHECK((ZCongruence(ZNumber(2), ZNumber(0)) ^ ZCongruence(4)) == ZCongruence::top()); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/numeric/constant.cpp000066400000000000000000000170601473507761200246230ustar00rootroot00000000000000/******************************************************************************* * * Tests for Constant * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_constant #define BOOST_TEST_DYN_LINK #include #include #include using namespace ikos::core; using namespace ikos::core::numeric; BOOST_AUTO_TEST_CASE(join) { BOOST_CHECK(ZConstant(2).join(ZConstant(4)) == ZConstant::top()); BOOST_CHECK(ZConstant(3).join(ZConstant(3)) == ZConstant(3)); } BOOST_AUTO_TEST_CASE(meet) { BOOST_CHECK(ZConstant(2).meet(ZConstant(4)) == ZConstant::bottom()); BOOST_CHECK(ZConstant(3).meet(ZConstant(3)) == ZConstant(3)); } BOOST_AUTO_TEST_CASE(addition) { BOOST_CHECK(ZConstant(10) + ZConstant(5) == ZConstant(15)); } BOOST_AUTO_TEST_CASE(substract) { BOOST_CHECK(ZConstant(10) - ZConstant(5) == ZConstant(5)); } BOOST_AUTO_TEST_CASE(multiply) { BOOST_CHECK(ZConstant(10) * ZConstant(5) == ZConstant(50)); BOOST_CHECK(ZConstant(10) * ZConstant(0) == ZConstant(0)); BOOST_CHECK(ZConstant(0) * ZConstant(10) == ZConstant(0)); } BOOST_AUTO_TEST_CASE(divide) { BOOST_CHECK(ZConstant(10) / ZConstant(5) == ZConstant(2)); BOOST_CHECK(ZConstant(10) / ZConstant(0) == ZConstant::bottom()); BOOST_CHECK(ZConstant(0) / ZConstant::top() == ZConstant(0)); } BOOST_AUTO_TEST_CASE(test_remainder) { BOOST_CHECK(ZConstant::bottom() % ZConstant(5) == ZConstant::bottom()); BOOST_CHECK(ZConstant(10) % ZConstant::bottom() == ZConstant::bottom()); BOOST_CHECK(ZConstant(10) % ZConstant(0) == ZConstant::bottom()); BOOST_CHECK(ZConstant(0) % ZConstant::top() == ZConstant(0)); BOOST_CHECK(ZConstant(10) % ZConstant::top() == ZConstant::top()); BOOST_CHECK(ZConstant::top() % ZConstant(5) == ZConstant::top()); BOOST_CHECK(ZConstant(11) % ZConstant(5) == ZConstant(1)); BOOST_CHECK(ZConstant(-11) % ZConstant(5) == ZConstant(-1)); } BOOST_AUTO_TEST_CASE(test_mod) { BOOST_CHECK(mod(ZConstant::bottom(), ZConstant(5)) == ZConstant::bottom()); BOOST_CHECK(mod(ZConstant(10), ZConstant::bottom()) == ZConstant::bottom()); BOOST_CHECK(mod(ZConstant(10), ZConstant(0)) == ZConstant::bottom()); BOOST_CHECK(mod(ZConstant(0), ZConstant::top()) == ZConstant(0)); BOOST_CHECK(mod(ZConstant(10), ZConstant::top()) == ZConstant::top()); BOOST_CHECK(mod(ZConstant::top(), ZConstant(5)) == ZConstant::top()); BOOST_CHECK(mod(ZConstant(11), ZConstant(5)) == ZConstant(1)); BOOST_CHECK(mod(ZConstant(-11), ZConstant(5)) == ZConstant(4)); } BOOST_AUTO_TEST_CASE(test_shl) { BOOST_CHECK(ZConstant::bottom() << ZConstant(5) == ZConstant::bottom()); BOOST_CHECK(ZConstant(10) << ZConstant::bottom() == ZConstant::bottom()); BOOST_CHECK(ZConstant(10) << ZConstant(-1) == ZConstant::bottom()); BOOST_CHECK(ZConstant(0) << ZConstant::top() == ZConstant(0)); BOOST_CHECK(ZConstant(10) << ZConstant::top() == ZConstant::top()); BOOST_CHECK(ZConstant::top() << ZConstant(2) == ZConstant::top()); BOOST_CHECK(ZConstant(11) << ZConstant(2) == ZConstant(44)); BOOST_CHECK(ZConstant(-11) << ZConstant(2) == ZConstant(-44)); } BOOST_AUTO_TEST_CASE(test_shr) { BOOST_CHECK(ZConstant::bottom() >> ZConstant(5) == ZConstant::bottom()); BOOST_CHECK(ZConstant(10) >> ZConstant::bottom() == ZConstant::bottom()); BOOST_CHECK(ZConstant(10) >> ZConstant(-1) == ZConstant::bottom()); BOOST_CHECK(ZConstant(0) >> ZConstant::top() == ZConstant(0)); BOOST_CHECK(ZConstant(10) >> ZConstant::top() == ZConstant::top()); BOOST_CHECK(ZConstant::top() >> ZConstant(2) == ZConstant::top()); BOOST_CHECK(ZConstant(11) >> ZConstant(2) == ZConstant(2)); BOOST_CHECK(ZConstant(-11) >> ZConstant(2) == ZConstant(-3)); } BOOST_AUTO_TEST_CASE(test_and) { BOOST_CHECK((ZConstant::bottom() & ZConstant(5)) == ZConstant::bottom()); BOOST_CHECK((ZConstant(10) & ZConstant::bottom()) == ZConstant::bottom()); BOOST_CHECK((ZConstant(0) & ZConstant::top()) == ZConstant(0)); BOOST_CHECK((ZConstant::top() & ZConstant(0)) == ZConstant(0)); BOOST_CHECK((ZConstant(10) & ZConstant::top()) == ZConstant::top()); BOOST_CHECK((ZConstant::top() & ZConstant(2)) == ZConstant::top()); BOOST_CHECK((ZConstant(1) & ZConstant(2)) == ZConstant(0)); BOOST_CHECK((ZConstant(3) & ZConstant(2)) == ZConstant(2)); BOOST_CHECK((ZConstant(-1) & ZConstant(2)) == ZConstant(2)); BOOST_CHECK((ZConstant(-1) & ZConstant(-2)) == ZConstant(-2)); } BOOST_AUTO_TEST_CASE(test_or) { BOOST_CHECK((ZConstant::bottom() | ZConstant(5)) == ZConstant::bottom()); BOOST_CHECK((ZConstant(10) | ZConstant::bottom()) == ZConstant::bottom()); BOOST_CHECK((ZConstant(-1) | ZConstant::top()) == ZConstant(-1)); BOOST_CHECK((ZConstant::top() | ZConstant(-1)) == ZConstant(-1)); BOOST_CHECK((ZConstant(10) | ZConstant::top()) == ZConstant::top()); BOOST_CHECK((ZConstant::top() | ZConstant(2)) == ZConstant::top()); BOOST_CHECK((ZConstant(1) | ZConstant(2)) == ZConstant(3)); BOOST_CHECK((ZConstant(3) | ZConstant(2)) == ZConstant(3)); BOOST_CHECK((ZConstant(-1) | ZConstant(2)) == ZConstant(-1)); BOOST_CHECK((ZConstant(-1) | ZConstant(-2)) == ZConstant(-1)); } BOOST_AUTO_TEST_CASE(test_xor) { BOOST_CHECK((ZConstant::bottom() ^ ZConstant(5)) == ZConstant::bottom()); BOOST_CHECK((ZConstant(10) ^ ZConstant::bottom()) == ZConstant::bottom()); BOOST_CHECK((ZConstant(10) ^ ZConstant::top()) == ZConstant::top()); BOOST_CHECK((ZConstant::top() ^ ZConstant(2)) == ZConstant::top()); BOOST_CHECK((ZConstant(1) ^ ZConstant(2)) == ZConstant(3)); BOOST_CHECK((ZConstant(3) ^ ZConstant(2)) == ZConstant(1)); BOOST_CHECK((ZConstant(-1) ^ ZConstant(2)) == ZConstant(-3)); BOOST_CHECK((ZConstant(-1) ^ ZConstant(-2)) == ZConstant(1)); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/numeric/gauge.cpp000066400000000000000000003406201473507761200240630ustar00rootroot00000000000000/******************************************************************************* * * Tests for Gauge * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_gauge #define BOOST_TEST_DYN_LINK #include #include #include #include #include #include using ZNumber = ikos::core::ZNumber; using ZBound = ikos::core::ZBound; using VariableFactory = ikos::core::example::VariableFactory; using Variable = ikos::core::example::VariableFactory::VariableRef; using ZConstant = ikos::core::numeric::ZConstant; using ZInterval = ikos::core::numeric::ZInterval; using GaugeBound = ikos::core::numeric::GaugeBound< ZNumber, Variable >; using Gauge = ikos::core::numeric::Gauge< ZNumber, Variable >; #define test_gauge_bound(g, \ is_infinite_v, \ is_plus_infinity_v, \ is_minus_infinity_v, \ num_coeffs_v, \ is_constant_v, \ constant_v) \ do { \ BOOST_CHECK((g).is_infinite() == (is_infinite_v)); \ BOOST_CHECK((g).is_plus_infinity() == (is_plus_infinity_v)); \ BOOST_CHECK((g).is_minus_infinity() == (is_minus_infinity_v)); \ BOOST_CHECK((g).is_constant() == (is_constant_v)); \ if ((g).is_finite()) { \ BOOST_CHECK((g).num_coeffs() == (num_coeffs_v)); \ } \ if ((g).is_constant()) { \ BOOST_CHECK((g).constant() == (constant_v)); \ } \ } while (0) BOOST_AUTO_TEST_CASE(gauge_bound_constructors) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_bound(GaugeBound::plus_infinity(), true, true, false, 0, false, 0); test_gauge_bound(GaugeBound::minus_infinity(), true, false, true, 0, false, 0); test_gauge_bound(GaugeBound(0), false, false, false, 0, true, 0); test_gauge_bound(GaugeBound(1), false, false, false, 0, true, 1); test_gauge_bound(GaugeBound(x), false, false, false, 1, false, 0); test_gauge_bound(GaugeBound(2, x), false, false, false, 1, false, 0); GaugeBound g(1); g = g + GaugeBound(2, x); g = g + GaugeBound(3, y); test_gauge_bound(g, false, false, false, 2, false, 0); } #define test_gauge_bound_coeff(g, v, c) BOOST_CHECK((g).coeff(v) == (c)) BOOST_AUTO_TEST_CASE(gauge_bound_coeff) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_bound_coeff(GaugeBound(0), x, 0); test_gauge_bound_coeff(GaugeBound(1), x, 0); test_gauge_bound_coeff(GaugeBound(0) + GaugeBound(x), x, 1); test_gauge_bound_coeff(GaugeBound(0) + GaugeBound(-1, x), x, -1); test_gauge_bound_coeff(GaugeBound(0) + GaugeBound(y), x, 0); test_gauge_bound_coeff(GaugeBound(0) + GaugeBound(-1, y), x, 0); test_gauge_bound_coeff(GaugeBound(0) + GaugeBound(x) + GaugeBound(y), x, 1); test_gauge_bound_coeff(GaugeBound(0) + GaugeBound(-1, x) + GaugeBound(y), x, -1); } #define test_gauge_bound_to_zbound(g, b) BOOST_CHECK((g).to_bound() == (b)) BOOST_AUTO_TEST_CASE(gauge_bound_to_bound) { VariableFactory vfac; Variable x(vfac.get("x")); test_gauge_bound_to_zbound(GaugeBound::minus_infinity(), boost::optional< ZBound >( ZBound::minus_infinity())); test_gauge_bound_to_zbound(GaugeBound::plus_infinity(), boost::optional< ZBound >( ZBound::plus_infinity())); test_gauge_bound_to_zbound(GaugeBound(1), boost::optional< ZBound >(ZBound(1))); test_gauge_bound_to_zbound(GaugeBound(42), boost::optional< ZBound >(ZBound(42))); test_gauge_bound_to_zbound(GaugeBound(x), boost::none); test_gauge_bound_to_zbound(GaugeBound(3) + GaugeBound(2, x), boost::none); } #define test_gauge_bound_add(x, y, z) BOOST_CHECK((x) + (y) == (z)) BOOST_AUTO_TEST_CASE(gauge_bound_add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); test_gauge_bound_add(GaugeBound::plus_infinity(), GaugeBound::plus_infinity(), GaugeBound::plus_infinity()); test_gauge_bound_add(GaugeBound::plus_infinity(), GaugeBound(1), GaugeBound::plus_infinity()); test_gauge_bound_add(GaugeBound::plus_infinity(), GaugeBound(2, x), GaugeBound::plus_infinity()); test_gauge_bound_add(GaugeBound::minus_infinity(), GaugeBound::minus_infinity(), GaugeBound::minus_infinity()); test_gauge_bound_add(GaugeBound::minus_infinity(), GaugeBound(1), GaugeBound::minus_infinity()); test_gauge_bound_add(GaugeBound::minus_infinity(), GaugeBound(2, x), GaugeBound::minus_infinity()); test_gauge_bound_add(GaugeBound(1), GaugeBound::plus_infinity(), GaugeBound::plus_infinity()); test_gauge_bound_add(GaugeBound(1), GaugeBound(2), GaugeBound(3)); test_gauge_bound_add(GaugeBound(1), GaugeBound(2, x), GaugeBound(1) + GaugeBound(2, x)); test_gauge_bound_add(GaugeBound(x), GaugeBound(2, x), GaugeBound(3, x)); test_gauge_bound_add(GaugeBound(x), GaugeBound(2, y), GaugeBound(x) + GaugeBound(2, y)); test_gauge_bound_add(GaugeBound(x) + GaugeBound(2, y), GaugeBound(3, y) + GaugeBound(4, z), GaugeBound(x) + GaugeBound(5, y) + GaugeBound(4, z)); } #define test_gauge_bound_sub(x, y, z) BOOST_CHECK((x) - (y) == (z)) BOOST_AUTO_TEST_CASE(gauge_bound_sub) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); test_gauge_bound_sub(GaugeBound::plus_infinity(), GaugeBound::minus_infinity(), GaugeBound::plus_infinity()); test_gauge_bound_sub(GaugeBound::plus_infinity(), GaugeBound(1), GaugeBound::plus_infinity()); test_gauge_bound_sub(GaugeBound::plus_infinity(), GaugeBound(2, x), GaugeBound::plus_infinity()); test_gauge_bound_sub(GaugeBound::minus_infinity(), GaugeBound::plus_infinity(), GaugeBound::minus_infinity()); test_gauge_bound_sub(GaugeBound::minus_infinity(), GaugeBound(1), GaugeBound::minus_infinity()); test_gauge_bound_sub(GaugeBound::minus_infinity(), GaugeBound(2, x), GaugeBound::minus_infinity()); test_gauge_bound_sub(GaugeBound(1), GaugeBound::plus_infinity(), GaugeBound::minus_infinity()); test_gauge_bound_sub(GaugeBound(1), GaugeBound(2), GaugeBound(-1)); test_gauge_bound_sub(GaugeBound(1), GaugeBound(2, x), GaugeBound(1) + GaugeBound(-2, x)); test_gauge_bound_sub(GaugeBound(x), GaugeBound(2, x), GaugeBound(-1, x)); test_gauge_bound_sub(GaugeBound(x), GaugeBound(2, y), GaugeBound(x) + GaugeBound(-2, y)); test_gauge_bound_sub(GaugeBound(x) + GaugeBound(2, y), GaugeBound(3, y) + GaugeBound(4, z), GaugeBound(x) + GaugeBound(-1, y) + GaugeBound(-4, z)); } #define test_gauge_bound_neg(x, y) BOOST_CHECK(-(x) == (y)) BOOST_AUTO_TEST_CASE(gauge_bound_neg) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_bound_neg(GaugeBound::plus_infinity(), GaugeBound::minus_infinity()); test_gauge_bound_neg(GaugeBound::minus_infinity(), GaugeBound::plus_infinity()); test_gauge_bound_neg(GaugeBound(1), GaugeBound(-1)); test_gauge_bound_neg(GaugeBound(-2), GaugeBound(2)); test_gauge_bound_neg(GaugeBound(2, x), GaugeBound(-2, x)); test_gauge_bound_neg(GaugeBound(2) + GaugeBound(x) + GaugeBound(3, y), GaugeBound(-2) + GaugeBound(-1, x) + GaugeBound(-3, y)); } #define test_gauge_bound_mul(x, y, z) BOOST_CHECK((x)*ZNumber(y) == (z)) BOOST_AUTO_TEST_CASE(gauge_bound_mul) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_bound_mul(GaugeBound::plus_infinity(), 2, GaugeBound::plus_infinity()); test_gauge_bound_mul(GaugeBound::plus_infinity(), -2, GaugeBound::minus_infinity()); test_gauge_bound_mul(GaugeBound::plus_infinity(), 0, GaugeBound(0)); test_gauge_bound_mul(GaugeBound::minus_infinity(), 2, GaugeBound::minus_infinity()); test_gauge_bound_mul(GaugeBound::minus_infinity(), -2, GaugeBound::plus_infinity()); test_gauge_bound_mul(GaugeBound::minus_infinity(), 0, GaugeBound(0)); test_gauge_bound_mul(GaugeBound(1), 2, GaugeBound(2)); test_gauge_bound_mul(GaugeBound(1), -2, GaugeBound(-2)); test_gauge_bound_mul(GaugeBound(1), 0, GaugeBound(0)); test_gauge_bound_mul(GaugeBound(2, x), 2, GaugeBound(4, x)); test_gauge_bound_mul(GaugeBound(2, x), -2, GaugeBound(-4, x)); test_gauge_bound_mul(GaugeBound(2, x), 0, GaugeBound(0)); test_gauge_bound_mul(GaugeBound(2) + GaugeBound(x) + GaugeBound(-3, y), 2, GaugeBound(4) + GaugeBound(2, x) + GaugeBound(-6, y)); test_gauge_bound_mul(GaugeBound(2) + GaugeBound(x) + GaugeBound(-3, y), -2, GaugeBound(-4) + GaugeBound(-2, x) + GaugeBound(6, y)); test_gauge_bound_mul(GaugeBound(2) + GaugeBound(x) + GaugeBound(-3, y), 0, GaugeBound(0)); } #define test_gauge_bound_le(x, y, r) BOOST_CHECK(((x) <= (y)) == (r)) BOOST_AUTO_TEST_CASE(gauge_bound_le) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); test_gauge_bound_le(GaugeBound::plus_infinity(), GaugeBound::plus_infinity(), true); test_gauge_bound_le(GaugeBound::plus_infinity(), GaugeBound::minus_infinity(), false); test_gauge_bound_le(GaugeBound::plus_infinity(), GaugeBound(1), false); test_gauge_bound_le(GaugeBound::plus_infinity(), GaugeBound(2, x), false); test_gauge_bound_le(GaugeBound::minus_infinity(), GaugeBound::plus_infinity(), true); test_gauge_bound_le(GaugeBound::minus_infinity(), GaugeBound::minus_infinity(), true); test_gauge_bound_le(GaugeBound::minus_infinity(), GaugeBound(1), true); test_gauge_bound_le(GaugeBound::minus_infinity(), GaugeBound(2, x), true); test_gauge_bound_le(GaugeBound(1), GaugeBound::plus_infinity(), true); test_gauge_bound_le(GaugeBound(1), GaugeBound(2), true); test_gauge_bound_le(GaugeBound(1), GaugeBound(0), false); test_gauge_bound_le(GaugeBound(1), GaugeBound(2, x), false); test_gauge_bound_le(GaugeBound(1), GaugeBound(2) + GaugeBound(2, x), true); test_gauge_bound_le(GaugeBound(x), GaugeBound(2, x), true); test_gauge_bound_le(GaugeBound(x), GaugeBound(2, y), false); test_gauge_bound_le(GaugeBound(x) + GaugeBound(2, y), GaugeBound(3, y) + GaugeBound(4, z), false); } #define test_gauge_bound_ge(x, y, r) BOOST_CHECK(((x) >= (y)) == (r)) BOOST_AUTO_TEST_CASE(gauge_bound_ge) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); test_gauge_bound_ge(GaugeBound::plus_infinity(), GaugeBound::plus_infinity(), true); test_gauge_bound_ge(GaugeBound::plus_infinity(), GaugeBound::minus_infinity(), true); test_gauge_bound_ge(GaugeBound::plus_infinity(), GaugeBound(1), true); test_gauge_bound_ge(GaugeBound::plus_infinity(), GaugeBound(2, x), true); test_gauge_bound_ge(GaugeBound::minus_infinity(), GaugeBound::plus_infinity(), false); test_gauge_bound_ge(GaugeBound::minus_infinity(), GaugeBound::minus_infinity(), true); test_gauge_bound_ge(GaugeBound::minus_infinity(), GaugeBound(1), false); test_gauge_bound_ge(GaugeBound::minus_infinity(), GaugeBound(2, x), false); test_gauge_bound_ge(GaugeBound(1), GaugeBound::plus_infinity(), false); test_gauge_bound_ge(GaugeBound(1), GaugeBound(2), false); test_gauge_bound_ge(GaugeBound(1), GaugeBound(0), true); test_gauge_bound_ge(GaugeBound(1), GaugeBound(2, x), false); test_gauge_bound_ge(GaugeBound(2) + GaugeBound(2, x), GaugeBound(1), true); test_gauge_bound_ge(GaugeBound(3, x), GaugeBound(2, x), true); test_gauge_bound_ge(GaugeBound(x), GaugeBound(2, y), false); test_gauge_bound_ge(GaugeBound(x) + GaugeBound(2, y), GaugeBound(3, y) + GaugeBound(4, z), false); } #define test_gauge_bound_min(x, y, z) BOOST_CHECK(min((x), (y)) == (z)) BOOST_AUTO_TEST_CASE(gauge_bound_min) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); test_gauge_bound_min(GaugeBound::plus_infinity(), GaugeBound::minus_infinity(), GaugeBound::minus_infinity()); test_gauge_bound_min(GaugeBound::plus_infinity(), GaugeBound(1), GaugeBound(1)); test_gauge_bound_min(GaugeBound::plus_infinity(), GaugeBound(2, x), GaugeBound(2, x)); test_gauge_bound_min(GaugeBound::minus_infinity(), GaugeBound::plus_infinity(), GaugeBound::minus_infinity()); test_gauge_bound_min(GaugeBound::minus_infinity(), GaugeBound(1), GaugeBound::minus_infinity()); test_gauge_bound_min(GaugeBound::minus_infinity(), GaugeBound(2, x), GaugeBound::minus_infinity()); test_gauge_bound_min(GaugeBound(1), GaugeBound::plus_infinity(), GaugeBound(1)); test_gauge_bound_min(GaugeBound(1), GaugeBound(2), GaugeBound(1)); test_gauge_bound_min(GaugeBound(1), GaugeBound(2, x), GaugeBound(0)); test_gauge_bound_min(GaugeBound(x), GaugeBound(2, x), GaugeBound(x)); test_gauge_bound_min(GaugeBound(x), GaugeBound(2, y), GaugeBound(0)); test_gauge_bound_min(GaugeBound(x) + GaugeBound(2, y), GaugeBound(3, y) + GaugeBound(4, z), GaugeBound(2, y)); test_gauge_bound_min(GaugeBound(4) + GaugeBound(x) + GaugeBound(4, y), GaugeBound(2) + GaugeBound(3, y) + GaugeBound(-4, z), GaugeBound(2) + GaugeBound(3, y) + GaugeBound(-4, z)); } #define test_gauge_bound_max(x, y, z) BOOST_CHECK(max((x), (y)) == (z)) BOOST_AUTO_TEST_CASE(gauge_bound_max) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); Variable z(vfac.get("z")); test_gauge_bound_max(GaugeBound::plus_infinity(), GaugeBound::minus_infinity(), GaugeBound::plus_infinity()); test_gauge_bound_max(GaugeBound::plus_infinity(), GaugeBound(1), GaugeBound::plus_infinity()); test_gauge_bound_max(GaugeBound::plus_infinity(), GaugeBound(2, x), GaugeBound::plus_infinity()); test_gauge_bound_max(GaugeBound::minus_infinity(), GaugeBound::plus_infinity(), GaugeBound::plus_infinity()); test_gauge_bound_max(GaugeBound::minus_infinity(), GaugeBound(1), GaugeBound(1)); test_gauge_bound_max(GaugeBound::minus_infinity(), GaugeBound(2, x), GaugeBound(2, x)); test_gauge_bound_max(GaugeBound(1), GaugeBound::plus_infinity(), GaugeBound::plus_infinity()); test_gauge_bound_max(GaugeBound(1), GaugeBound(2), GaugeBound(2)); test_gauge_bound_max(GaugeBound(1), GaugeBound(2, x), GaugeBound(1) + GaugeBound(2, x)); test_gauge_bound_max(GaugeBound(x), GaugeBound(2, x), GaugeBound(2, x)); test_gauge_bound_max(GaugeBound(x), GaugeBound(2, y), GaugeBound(x) + GaugeBound(2, y)); test_gauge_bound_max(GaugeBound(x) + GaugeBound(2, y), GaugeBound(3, y) + GaugeBound(4, z), GaugeBound(x) + GaugeBound(3, y) + GaugeBound(4, z)); test_gauge_bound_max(GaugeBound(2) + GaugeBound(x) + GaugeBound(4, y), GaugeBound(4) + GaugeBound(3, y) + GaugeBound(-4, z), GaugeBound(4) + GaugeBound(x) + GaugeBound(4, y)); } #define test_gauge(g, is_bottom_v, is_top_v, is_singleton_v, singleton_v) \ do { \ BOOST_CHECK((g).is_bottom() == (is_bottom_v)); \ BOOST_CHECK((g).is_top() == (is_top_v)); \ BOOST_CHECK(!!((g).singleton()) == (is_singleton_v)); \ if ((g).singleton()) { \ BOOST_CHECK(*(g).singleton() == GaugeBound(singleton_v)); \ } \ } while (0) BOOST_AUTO_TEST_CASE(gauge_constructors) { VariableFactory vfac; Variable x(vfac.get("x")); test_gauge(Gauge::top(), false, true, false, 0); test_gauge(Gauge::bottom(), true, false, false, 0); test_gauge(Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), false, false, false, 0); test_gauge(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), false, false, false, 0); test_gauge(Gauge(GaugeBound::minus_infinity(), GaugeBound::plus_infinity()), false, true, false, 0); test_gauge(Gauge(0), false, false, true, 0); test_gauge(Gauge(GaugeBound(x)), false, false, true, x); test_gauge(Gauge(GaugeBound(0), GaugeBound(x)), false, false, false, 0); } #define test_gauge_interval(g, i) BOOST_CHECK((g).interval() == (i)) BOOST_AUTO_TEST_CASE(gauge_interval) { VariableFactory vfac; Variable x(vfac.get("x")); test_gauge_interval(Gauge::top(), boost::optional< ZInterval >(ZInterval::top())); test_gauge_interval(Gauge::bottom(), boost::optional< ZInterval >(ZInterval::bottom())); test_gauge_interval(Gauge(GaugeBound(1), GaugeBound(2)), boost::optional< ZInterval >( ZInterval(ZBound(1), ZBound(2)))); test_gauge_interval(Gauge(GaugeBound::minus_infinity(), GaugeBound(2)), boost::optional< ZInterval >( ZInterval(ZBound::minus_infinity(), ZBound(2)))); test_gauge_interval(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), boost::optional< ZInterval >( ZInterval(ZBound(1), ZBound::plus_infinity()))); test_gauge_interval(Gauge(GaugeBound(0), GaugeBound(2, x)), boost::none); test_gauge_interval(Gauge(GaugeBound(-2, x), GaugeBound(2, x)), boost::none); } #define test_gauge_le(x, y, r) BOOST_CHECK((x).leq(y) == (r)) BOOST_AUTO_TEST_CASE(gauge_leq) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_le(Gauge::top(), Gauge::bottom(), false); test_gauge_le(Gauge::top(), Gauge::top(), true); test_gauge_le(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), false); test_gauge_le(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, x)), false); test_gauge_le(Gauge::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), false); test_gauge_le(Gauge::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), false); test_gauge_le(Gauge::bottom(), Gauge::bottom(), true); test_gauge_le(Gauge::bottom(), Gauge::top(), true); test_gauge_le(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), true); test_gauge_le(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, x)), true); test_gauge_le(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), true); test_gauge_le(Gauge::bottom(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), true); test_gauge_le(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom(), false); test_gauge_le(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top(), true); test_gauge_le(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound(1)), false); test_gauge_le(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), true); test_gauge_le(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), false); test_gauge_le(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(2, x)), false); test_gauge_le(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), true); test_gauge_le(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2) + GaugeBound(2, x)), true); test_gauge_le(Gauge(GaugeBound(-2), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), false); test_gauge_le(Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(-1), GaugeBound(2)), false); test_gauge_le(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-1), GaugeBound(4) + GaugeBound(4, x) + GaugeBound(y)), true); } #define test_gauge_eq(x, y, r) BOOST_CHECK((x).equals(y) == (r)) BOOST_AUTO_TEST_CASE(gauge_equals) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_eq(Gauge::top(), Gauge::bottom(), false); test_gauge_eq(Gauge::top(), Gauge::top(), true); test_gauge_eq(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), false); test_gauge_eq(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, x)), false); test_gauge_eq(Gauge::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), false); test_gauge_eq(Gauge::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), false); test_gauge_eq(Gauge::bottom(), Gauge::bottom(), true); test_gauge_eq(Gauge::bottom(), Gauge::top(), false); test_gauge_eq(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), false); test_gauge_eq(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, x)), false); test_gauge_eq(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), false); test_gauge_eq(Gauge::bottom(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom(), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top(), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound(1)), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), true); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(2, x)), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2) + GaugeBound(2, x)), false); test_gauge_eq(Gauge(GaugeBound(-2), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), false); test_gauge_eq(Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(-1), GaugeBound(2)), false); test_gauge_eq(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-1), GaugeBound(4) + GaugeBound(4, x) + GaugeBound(y)), false); } #define test_gauge_join(x, y, z) BOOST_CHECK((x).join(y) == (z)) BOOST_AUTO_TEST_CASE(gauge_join) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_join(Gauge::top(), Gauge::bottom(), Gauge::top()); test_gauge_join(Gauge::top(), Gauge::top(), Gauge::top()); test_gauge_join(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge::top()); test_gauge_join(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge::top()); test_gauge_join(Gauge::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top()); test_gauge_join(Gauge::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::top()); test_gauge_join(Gauge::bottom(), Gauge::bottom(), Gauge::bottom()); test_gauge_join(Gauge::bottom(), Gauge::top(), Gauge::top()); test_gauge_join(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_join(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge(GaugeBound(0), GaugeBound(2, x))); test_gauge_join(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_join(Gauge::bottom(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(GaugeBound::minus_infinity(), GaugeBound(0))); test_gauge_join(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_join(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top(), Gauge::top()); test_gauge_join(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_join(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_join(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::top()); test_gauge_join(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(2, x)), Gauge::top()); test_gauge_join(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-1), GaugeBound(2))); test_gauge_join(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2) + GaugeBound(2, x)), Gauge(GaugeBound(-1), GaugeBound(2) + GaugeBound(2, x))); test_gauge_join(Gauge(GaugeBound(-2), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-2), GaugeBound(2))); test_gauge_join(Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-1), GaugeBound(3))); test_gauge_join(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-1), GaugeBound(4) + GaugeBound(4, x) + GaugeBound(y)), Gauge(GaugeBound(-1), GaugeBound(4) + GaugeBound(4, x) + GaugeBound(y))); } #define test_gauge_meet(x, y, z) BOOST_CHECK((x).meet(y) == (z)) BOOST_AUTO_TEST_CASE(gauge_meet) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_meet(Gauge::top(), Gauge::bottom(), Gauge::bottom()); test_gauge_meet(Gauge::top(), Gauge::top(), Gauge::top()); test_gauge_meet(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_meet(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge(GaugeBound(0), GaugeBound(2, x))); test_gauge_meet(Gauge::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_meet(Gauge::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(GaugeBound::minus_infinity(), GaugeBound(0))); test_gauge_meet(Gauge::bottom(), Gauge::bottom(), Gauge::bottom()); test_gauge_meet(Gauge::bottom(), Gauge::top(), Gauge::bottom()); test_gauge_meet(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge::bottom()); test_gauge_meet(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge::bottom()); test_gauge_meet(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom()); test_gauge_meet(Gauge::bottom(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::bottom()); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom(), Gauge::bottom()); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(GaugeBound(0), GaugeBound(0))); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(2, x)), Gauge(GaugeBound(0), GaugeBound(2, x))); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2) + GaugeBound(2, x)), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_meet(Gauge(GaugeBound(-2), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-1), GaugeBound(1))); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(0), GaugeBound(2))); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(4), GaugeBound(5)), Gauge::bottom()); test_gauge_meet(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-1), GaugeBound(4) + GaugeBound(4, x) + GaugeBound(y)), Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x))); test_gauge_meet(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-1) + GaugeBound(3, y), GaugeBound(3) + GaugeBound(4, y)), Gauge(GaugeBound(-1) + GaugeBound(3, y), GaugeBound(3) + GaugeBound(3, x) + GaugeBound(3, y))); test_gauge_meet(Gauge(GaugeBound(0), GaugeBound(y)), Gauge(GaugeBound(x), GaugeBound::plus_infinity()), Gauge(GaugeBound(x), GaugeBound(x) + GaugeBound(y))); test_gauge_meet(Gauge(GaugeBound(x), GaugeBound(1) + GaugeBound(x)), Gauge(GaugeBound(x) + GaugeBound(y) + GaugeBound(1), GaugeBound::plus_infinity()), Gauge(GaugeBound(x) + GaugeBound(y) + GaugeBound(1))); } #define test_gauge_neg(x, y) BOOST_CHECK(-(x) == (y)) BOOST_AUTO_TEST_CASE(gauge_neg) { VariableFactory vfac; Variable x(vfac.get("x")); test_gauge_neg(Gauge::top(), Gauge::top()); test_gauge_neg(Gauge::bottom(), Gauge::bottom()); test_gauge_neg(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(0))); test_gauge_neg(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(0))); test_gauge_neg(Gauge(GaugeBound(-2), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2))); test_gauge_neg(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-3) + GaugeBound(-3, x), GaugeBound(1) + GaugeBound(-2, x))); } #define test_gauge_add(x, y, z) BOOST_CHECK((x) + (y) == (z)) BOOST_AUTO_TEST_CASE(gauge_add) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_add(Gauge::top(), Gauge::bottom(), Gauge::bottom()); test_gauge_add(Gauge::top(), Gauge::top(), Gauge::top()); test_gauge_add(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge::top()); test_gauge_add(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge::top()); test_gauge_add(Gauge::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top()); test_gauge_add(Gauge::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::top()); test_gauge_add(Gauge::bottom(), Gauge::bottom(), Gauge::bottom()); test_gauge_add(Gauge::bottom(), Gauge::top(), Gauge::bottom()); test_gauge_add(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge::bottom()); test_gauge_add(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge::bottom()); test_gauge_add(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom()); test_gauge_add(Gauge::bottom(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::bottom()); test_gauge_add(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom(), Gauge::bottom()); test_gauge_add(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top(), Gauge::top()); test_gauge_add(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_add(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_add(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::top()); test_gauge_add(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(2, x)), Gauge::top()); test_gauge_add(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-1), GaugeBound(3))); test_gauge_add(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2) + GaugeBound(2, x)), Gauge(GaugeBound(-1), GaugeBound(3) + GaugeBound(2, x))); test_gauge_add(Gauge(GaugeBound(-2), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-3), GaugeBound(3))); test_gauge_add(Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-1), GaugeBound(5))); test_gauge_add(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-1), GaugeBound(4) + GaugeBound(4, x) + GaugeBound(y)), Gauge(GaugeBound(-2) + GaugeBound(2, x), GaugeBound(7) + GaugeBound(7, x) + GaugeBound(y))); } #define test_gauge_sub(x, y, z) BOOST_CHECK((x) - (y) == (z)) BOOST_AUTO_TEST_CASE(gauge_sub) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_sub(Gauge::top(), Gauge::bottom(), Gauge::bottom()); test_gauge_sub(Gauge::top(), Gauge::top(), Gauge::top()); test_gauge_sub(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge::top()); test_gauge_sub(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge::top()); test_gauge_sub(Gauge::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top()); test_gauge_sub(Gauge::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::top()); test_gauge_sub(Gauge::bottom(), Gauge::bottom(), Gauge::bottom()); test_gauge_sub(Gauge::bottom(), Gauge::top(), Gauge::bottom()); test_gauge_sub(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge::bottom()); test_gauge_sub(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, x)), Gauge::bottom()); test_gauge_sub(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom()); test_gauge_sub(Gauge::bottom(), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge::bottom()); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::bottom(), Gauge::bottom()); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top(), Gauge::top()); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound::plus_infinity())); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge::top()); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(2, x)), Gauge(GaugeBound(-2, x), GaugeBound::plus_infinity())); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-2), GaugeBound(2))); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2) + GaugeBound(2, x)), Gauge(GaugeBound(-2) + GaugeBound(-2, x), GaugeBound(2))); test_gauge_sub(Gauge(GaugeBound(-2), GaugeBound(1)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-4), GaugeBound(2))); test_gauge_sub(Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(-1), GaugeBound(2)), Gauge(GaugeBound(-2), GaugeBound(4))); test_gauge_sub(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), Gauge(GaugeBound(-1), GaugeBound(4) + GaugeBound(4, x) + GaugeBound(y)), Gauge(GaugeBound(-5) + GaugeBound(-2, x) + GaugeBound(-1, y), GaugeBound(4) + GaugeBound(3, x))); } #define test_gauge_mul_cst(x, y, z) BOOST_CHECK((x)*ZNumber(y) == (z)) BOOST_AUTO_TEST_CASE(gauge_mul_cst) { VariableFactory vfac; Variable x(vfac.get("x")); test_gauge_mul_cst(Gauge::top(), 0, Gauge(0)); test_gauge_mul_cst(Gauge::top(), 1, Gauge::top()); test_gauge_mul_cst(Gauge::top(), -1, Gauge::top()); test_gauge_mul_cst(Gauge::bottom(), 0, Gauge::bottom()); test_gauge_mul_cst(Gauge::bottom(), 1, Gauge::bottom()); test_gauge_mul_cst(Gauge::bottom(), -1, Gauge::bottom()); test_gauge_mul_cst(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), 0, Gauge(0)); test_gauge_mul_cst(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), 2, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_mul_cst(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), -2, Gauge(GaugeBound::minus_infinity(), GaugeBound(0))); test_gauge_mul_cst(Gauge(GaugeBound(0), GaugeBound(1)), 0, Gauge(0)); test_gauge_mul_cst(Gauge(GaugeBound(0), GaugeBound(1)), 2, Gauge(GaugeBound(0), GaugeBound(2))); test_gauge_mul_cst(Gauge(GaugeBound(0), GaugeBound(1)), -2, Gauge(GaugeBound(-2), GaugeBound(0))); test_gauge_mul_cst(Gauge(GaugeBound(-2), GaugeBound(1)), 0, Gauge(0)); test_gauge_mul_cst(Gauge(GaugeBound(-2), GaugeBound(1)), 2, Gauge(GaugeBound(-4), GaugeBound(2))); test_gauge_mul_cst(Gauge(GaugeBound(-2), GaugeBound(1)), -2, Gauge(GaugeBound(-2), GaugeBound(4))); test_gauge_mul_cst(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), 0, Gauge(0)); test_gauge_mul_cst(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), 2, Gauge(GaugeBound(-2) + GaugeBound(4, x), GaugeBound(6) + GaugeBound(6, x))); test_gauge_mul_cst(Gauge(GaugeBound(-1) + GaugeBound(2, x), GaugeBound(3) + GaugeBound(3, x)), -2, Gauge(GaugeBound(-6) + GaugeBound(-6, x), GaugeBound(2) + GaugeBound(-4, x))); } #define test_gauge_mul_intv(x, y, z) BOOST_CHECK((x) * (y) == (z)) BOOST_AUTO_TEST_CASE(gauge_mul_intv) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_mul_intv(Gauge::top(), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge::top(), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge::top(), ZInterval(ZBound(0), ZBound(1)), Gauge::top()); test_gauge_mul_intv(Gauge::top(), ZInterval(ZBound::minus_infinity(), ZBound(1)), Gauge::top()); test_gauge_mul_intv(Gauge::top(), ZInterval(ZBound(0), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge::bottom(), ZInterval::top(), Gauge::bottom()); test_gauge_mul_intv(Gauge::bottom(), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge::bottom(), ZInterval(ZBound(0), ZBound(1)), Gauge::bottom()); test_gauge_mul_intv(Gauge::bottom(), ZInterval(ZBound::minus_infinity(), ZBound(1)), Gauge::bottom()); test_gauge_mul_intv(Gauge::bottom(), ZInterval(ZBound(0), ZBound::plus_infinity()), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(6))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(-3))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge(GaugeBound(-4), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(2), GaugeBound(6))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(-6), GaugeBound(-2))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(2)), ZInterval(ZBound(-2), ZBound(3)), Gauge(GaugeBound(-4), GaugeBound(6))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(3) + GaugeBound(3, x))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(-3))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge(GaugeBound(-2) + GaugeBound(-2, x), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(2), GaugeBound(3) + GaugeBound(3, x))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(-3) + GaugeBound(-3, x), GaugeBound(-2))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(-2), ZBound(3)), Gauge(GaugeBound(-2) + GaugeBound(-2, x), GaugeBound(3) + GaugeBound(3, x))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(-3))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(2), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound::minus_infinity(), GaugeBound(-2))); test_gauge_mul_intv(Gauge(GaugeBound(1), GaugeBound::plus_infinity()), ZInterval(ZBound(-2), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(-3), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound::minus_infinity(), GaugeBound(3))); test_gauge_mul_intv(Gauge(GaugeBound(-1), GaugeBound::plus_infinity()), ZInterval(ZBound(-2), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(-3) + GaugeBound(-6, x))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(2) + GaugeBound(4, x), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound::minus_infinity(), GaugeBound(-2) + GaugeBound(-4, x))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(2, x), GaugeBound::plus_infinity()), ZInterval(ZBound(-2), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge(GaugeBound(3), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(-1))); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(-2))); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(2), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(-1)), ZInterval(ZBound(-2), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(3))); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(-3), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), ZInterval(ZBound(-2), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound::minus_infinity(), GaugeBound(3) + GaugeBound(9, x))); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(-3) + GaugeBound(-9, x), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(3, x)), ZInterval(ZBound(-2), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge(GaugeBound(-3) + GaugeBound(-6, x), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge(GaugeBound(3), GaugeBound::plus_infinity())); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(-1))); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge(GaugeBound::minus_infinity(), GaugeBound(2) + GaugeBound(4, x))); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(-3) + GaugeBound(-6, x), GaugeBound(-2))); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(2), GaugeBound(3) + GaugeBound(6, x))); test_gauge_mul_intv(Gauge(GaugeBound(-1) + GaugeBound(-2, x), GaugeBound(-1)), ZInterval(ZBound(-2), ZBound(3)), Gauge(GaugeBound(-3) + GaugeBound(-6, x), GaugeBound(2) + GaugeBound(4, x))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(2) + GaugeBound(-3, x), GaugeBound(3) + GaugeBound(3, x))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(-3) + GaugeBound(-3, x), GaugeBound(-2) + GaugeBound(3, x))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x)), ZInterval(ZBound(-2), ZBound(3)), Gauge(GaugeBound(-2) + GaugeBound(-3, x), GaugeBound(3) + GaugeBound(3, x))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval::top(), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval::bottom(), Gauge::bottom()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval(ZBound::minus_infinity(), ZBound(3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval(ZBound::minus_infinity(), ZBound(-3)), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval(ZBound(1), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval(ZBound(-2), ZBound::plus_infinity()), Gauge::top()); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval(ZBound(2), ZBound(3)), Gauge(GaugeBound(2) + GaugeBound(-3, x), GaugeBound(3) + GaugeBound(3, x) + GaugeBound(6, y))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval(ZBound(-3), ZBound(-2)), Gauge(GaugeBound(-3) + GaugeBound(-3, x) + GaugeBound(-6, y), GaugeBound(-2) + GaugeBound(3, x))); test_gauge_mul_intv(Gauge(GaugeBound(1) + GaugeBound(-1, x), GaugeBound(1) + GaugeBound(x) + GaugeBound(2, y)), ZInterval(ZBound(-2), ZBound(3)), Gauge(GaugeBound(-2) + GaugeBound(-3, x) + GaugeBound(-4, y), GaugeBound(3) + GaugeBound(3, x) + GaugeBound(6, y))); } #define test_gauge_forget(x, v, y) BOOST_CHECK((x).forget(v) == (y)) BOOST_AUTO_TEST_CASE(gauge_forget) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_forget(Gauge::top(), x, Gauge::top()); test_gauge_forget(Gauge::bottom(), x, Gauge::bottom()); test_gauge_forget(Gauge(GaugeBound(0), GaugeBound(1)), x, Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_forget(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), x, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_forget(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), x, Gauge(GaugeBound::minus_infinity(), GaugeBound(1))); test_gauge_forget(Gauge(GaugeBound(0), GaugeBound(2, x)), x, Gauge::top()); test_gauge_forget(Gauge(GaugeBound(-1, x), GaugeBound(2)), x, Gauge::top()); test_gauge_forget(Gauge(GaugeBound(0), GaugeBound(2, y)), x, Gauge(GaugeBound(0), GaugeBound(2, y))); } #define test_gauge_coalesce(x, v, l, u, y) \ BOOST_CHECK((x).coalesce(v, ZNumber(l), u) == (y)) BOOST_AUTO_TEST_CASE(gauge_coalesce) { VariableFactory vfac; Variable x(vfac.get("x")); Variable y(vfac.get("y")); test_gauge_coalesce(Gauge::top(), x, 0, ZBound::plus_infinity(), Gauge::top()); test_gauge_coalesce(Gauge::bottom(), x, 0, ZBound::plus_infinity(), Gauge::bottom()); test_gauge_coalesce(Gauge(GaugeBound(0), GaugeBound(1)), x, 0, ZBound::plus_infinity(), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_coalesce(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), x, 0, ZBound::plus_infinity(), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_coalesce(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), x, 0, ZBound::plus_infinity(), Gauge(GaugeBound::minus_infinity(), GaugeBound(1))); test_gauge_coalesce(Gauge(GaugeBound(0), GaugeBound(2, x)), x, 0, ZBound::plus_infinity(), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_coalesce(Gauge(GaugeBound(-1, x), GaugeBound(2)), x, 0, ZBound::plus_infinity(), Gauge(GaugeBound::minus_infinity(), GaugeBound(2))); test_gauge_coalesce(Gauge(GaugeBound(0), GaugeBound(2, y)), x, 0, ZBound::plus_infinity(), Gauge(GaugeBound(0), GaugeBound(2, y))); test_gauge_coalesce(Gauge(GaugeBound(x), GaugeBound(1) + GaugeBound(x)), x, 1, ZBound(2), Gauge(GaugeBound(1), GaugeBound(3))); test_gauge_coalesce(Gauge(GaugeBound(2) + GaugeBound(-2, x), GaugeBound(3) + GaugeBound(-2, x)), x, 1, ZBound(3), Gauge(GaugeBound(-4), GaugeBound(1))); test_gauge_coalesce(Gauge(GaugeBound(2) + GaugeBound(-2, x) + GaugeBound(3, y), GaugeBound(3) + GaugeBound(-2, x) + GaugeBound(3, y)), x, 1, ZBound(3), Gauge(GaugeBound(-4) + GaugeBound(3, y), GaugeBound(1) + GaugeBound(3, y))); test_gauge_coalesce(Gauge(GaugeBound(2) + GaugeBound(-2, x), GaugeBound(3) + GaugeBound(2, x)), x, 1, ZBound::plus_infinity(), Gauge::top()); test_gauge_coalesce(Gauge(GaugeBound(2) + GaugeBound(-2, x) + GaugeBound(3, y), GaugeBound(3) + GaugeBound(2, x) + GaugeBound(3, y)), x, 1, ZBound::plus_infinity(), Gauge::top()); } #define test_gauge_counter_incr(x, v, k, y) \ BOOST_CHECK((x).counter_incr(v, ZNumber(k)) == (y)) BOOST_AUTO_TEST_CASE(gauge_counter_incr) { VariableFactory vfac; Variable i(vfac.get("i")); Variable k(vfac.get("k")); test_gauge_counter_incr(Gauge::top(), i, 1, Gauge::top()); test_gauge_counter_incr(Gauge::bottom(), i, 1, Gauge::bottom()); test_gauge_counter_incr(Gauge(GaugeBound(0), GaugeBound(1)), i, 1, Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_counter_incr(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), i, 1, Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_counter_incr(Gauge(GaugeBound(1) + GaugeBound(2, i), GaugeBound::plus_infinity()), i, 1, Gauge(GaugeBound(-1) + GaugeBound(2, i), GaugeBound::plus_infinity())); test_gauge_counter_incr(Gauge(GaugeBound::minus_infinity(), GaugeBound(1)), i, 1, Gauge(GaugeBound::minus_infinity(), GaugeBound(1))); test_gauge_counter_incr(Gauge(GaugeBound::minus_infinity(), GaugeBound(1) + GaugeBound(2, i)), i, 1, Gauge(GaugeBound::minus_infinity(), GaugeBound(-1) + GaugeBound(2, i))); test_gauge_counter_incr(Gauge(GaugeBound(i)), i, 1, Gauge(GaugeBound(-1) + GaugeBound(i), GaugeBound(-1) + GaugeBound(i))); test_gauge_counter_incr(Gauge(GaugeBound(0), GaugeBound(2, i)), i, 1, Gauge(GaugeBound(-2), GaugeBound(2, i))); test_gauge_counter_incr(Gauge(GaugeBound(1), GaugeBound(2) + GaugeBound(3, i)), i, 1, Gauge(GaugeBound(-1), GaugeBound(1) + GaugeBound(3, i))); test_gauge_counter_incr(Gauge(GaugeBound(-2) + GaugeBound(2, i) + GaugeBound(2, k), GaugeBound(2) + GaugeBound(3, i) + GaugeBound(3, k)), i, 1, Gauge(GaugeBound(-4) + GaugeBound(2, i) + GaugeBound(2, k), GaugeBound(-1) + GaugeBound(3, i) + GaugeBound(3, k))); test_gauge_counter_incr(Gauge(GaugeBound(-2) + GaugeBound(2, i) + GaugeBound(2, k), GaugeBound(2) + GaugeBound(3, i) + GaugeBound(3, k)), i, 2, Gauge(GaugeBound(-6) + GaugeBound(2, i) + GaugeBound(2, k), GaugeBound(-4) + GaugeBound(3, i) + GaugeBound(3, k))); } #define test_gauge_widening_interpol(x, y, k, u, v, z) \ BOOST_CHECK((x).widening_interpol((y), k, ZNumber(u), v) == (z)) BOOST_AUTO_TEST_CASE(gauge_widening_interpol) { VariableFactory vfac; Variable i(vfac.get("i")); Variable k(vfac.get("k")); test_gauge_widening_interpol(Gauge::top(), Gauge::bottom(), i, 0, ZConstant::top(), Gauge::top()); test_gauge_widening_interpol(Gauge::top(), Gauge::top(), i, 0, ZConstant::top(), Gauge::top()); test_gauge_widening_interpol(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), i, 0, ZConstant::top(), Gauge::top()); test_gauge_widening_interpol(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, i)), i, 0, ZConstant::top(), Gauge::top()); test_gauge_widening_interpol(Gauge::bottom(), Gauge::bottom(), i, 0, ZConstant::top(), Gauge::bottom()); test_gauge_widening_interpol(Gauge::bottom(), Gauge::top(), i, 0, ZConstant::top(), Gauge::top()); test_gauge_widening_interpol(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), i, 0, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_widening_interpol(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, i)), i, 0, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(0), Gauge(1), i, 0, ZConstant(1), Gauge(GaugeBound(i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(0), GaugeBound(1)), i, 0, ZConstant(1), Gauge(GaugeBound(0), GaugeBound(i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(0), GaugeBound(2)), i, 0, ZConstant(1), Gauge(GaugeBound(0), GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(0), GaugeBound(3)), i, 0, ZConstant(1), Gauge(GaugeBound(0), GaugeBound(3, i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(-2), GaugeBound(2)), i, 0, ZConstant(1), Gauge(GaugeBound(-2, i), GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(0), Gauge(4), i, 0, ZConstant(3), Gauge(GaugeBound(i), GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(1), Gauge(2), i, 0, ZConstant(1), Gauge(GaugeBound(1) + GaugeBound(i))); test_gauge_widening_interpol(Gauge(1), Gauge(-2), i, 0, ZConstant(1), Gauge(GaugeBound(1) + GaugeBound(-3, i))); test_gauge_widening_interpol(Gauge(GaugeBound(4, i)), Gauge(GaugeBound(1) + GaugeBound(4, i)), k, 0, ZConstant(1), Gauge(GaugeBound(4, i) + GaugeBound(k))); test_gauge_widening_interpol(Gauge(0), Gauge(1), i, 2, ZConstant(3), Gauge(GaugeBound(-2) + GaugeBound(i))); test_gauge_widening_interpol(Gauge(0), Gauge(3), i, 2, ZConstant(3), Gauge(GaugeBound(-6) + GaugeBound(3, i))); test_gauge_widening_interpol(Gauge(0), Gauge(-3), i, 2, ZConstant(3), Gauge(GaugeBound(6) + GaugeBound(-3, i))); test_gauge_widening_interpol(Gauge(GaugeBound(1) + GaugeBound(2, i)), Gauge(GaugeBound(1) + GaugeBound(2, i)), i, 2, ZConstant(3), Gauge(GaugeBound(1) + GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(GaugeBound(1) + GaugeBound(2, i)), Gauge(GaugeBound(2) + GaugeBound(2, i)), i, 2, ZConstant(3), Gauge(GaugeBound(-1) + GaugeBound(3, i))); test_gauge_widening_interpol(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(2, i)), Gauge(GaugeBound(2), GaugeBound(2) + GaugeBound(2, i)), i, 2, ZConstant(3), Gauge(GaugeBound(-1) + GaugeBound(i), GaugeBound(-1) + GaugeBound(3, i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(2), GaugeBound::plus_infinity()), i, 0, ZConstant(1), Gauge(GaugeBound(2, i), GaugeBound::plus_infinity())); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound::minus_infinity(), GaugeBound(2)), i, 0, ZConstant(1), Gauge(GaugeBound::minus_infinity(), GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(0), Gauge::top(), i, 0, ZConstant(1), Gauge::top()); test_gauge_widening_interpol(Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(1), i, 0, ZConstant(1), Gauge(GaugeBound::minus_infinity(), GaugeBound(i))); test_gauge_widening_interpol(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(1), i, 0, ZConstant(1), Gauge(GaugeBound(i), GaugeBound::plus_infinity())); test_gauge_widening_interpol(Gauge::top(), Gauge(1), i, 0, ZConstant(1), Gauge::top()); test_gauge_widening_interpol(Gauge(0), Gauge(1), i, 0, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(0), GaugeBound(1)), i, 0, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(0), GaugeBound(2)), i, 0, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound(2))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(-2), GaugeBound(2)), i, 0, ZConstant::top(), Gauge(GaugeBound(-2), GaugeBound(2))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(0), GaugeBound(2)), i, 1, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound(2))); test_gauge_widening_interpol(Gauge(GaugeBound(4, k)), Gauge(GaugeBound(2) + GaugeBound(4, k)), i, 0, ZConstant::top(), Gauge(GaugeBound(4, k), GaugeBound(2) + GaugeBound(4, k))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(i)), i, 0, ZConstant::top(), Gauge(GaugeBound(i))); test_gauge_widening_interpol(Gauge(1), Gauge(GaugeBound(i)), i, 0, ZConstant::top(), Gauge(GaugeBound(i), GaugeBound(1) + GaugeBound(i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(i), GaugeBound(2, i)), i, 0, ZConstant::top(), Gauge(GaugeBound(i), GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(i), GaugeBound(2, i)), i, 2, ZConstant::top(), Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(2, i))); test_gauge_widening_interpol(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i)), i, 0, ZConstant::top(), Gauge(GaugeBound(i), GaugeBound(3) + GaugeBound(3, i))); test_gauge_widening_interpol(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i)), i, 2, ZConstant::top(), Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i))); test_gauge_widening_interpol(Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(4) + GaugeBound(3, i)), Gauge(GaugeBound(2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i)), i, 0, ZConstant::top(), Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(4) + GaugeBound(3, i))); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound(2), GaugeBound::plus_infinity()), i, 0, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interpol(Gauge(0), Gauge(GaugeBound::minus_infinity(), GaugeBound(2)), i, 0, ZConstant::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(2))); test_gauge_widening_interpol(Gauge(0), Gauge::top(), i, 0, ZConstant::top(), Gauge::top()); test_gauge_widening_interpol(Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(1), i, 0, ZConstant::top(), Gauge(GaugeBound::minus_infinity(), GaugeBound(1))); test_gauge_widening_interpol(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(1), i, 0, ZConstant::top(), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interpol(Gauge::top(), Gauge(1), i, 0, ZConstant::top(), Gauge::top()); } #define test_gauge_widening_interval(x, y, z) \ BOOST_CHECK((x).widening_interval(y) == (z)) BOOST_AUTO_TEST_CASE(gauge_widening_interval) { VariableFactory vfac; Variable i(vfac.get("i")); test_gauge_widening_interval(Gauge::top(), Gauge::bottom(), Gauge::top()); test_gauge_widening_interval(Gauge::top(), Gauge::top(), Gauge::top()); test_gauge_widening_interval(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge::top()); test_gauge_widening_interval(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, i)), Gauge::top()); test_gauge_widening_interval(Gauge::bottom(), Gauge::bottom(), Gauge::bottom()); test_gauge_widening_interval(Gauge::bottom(), Gauge::top(), Gauge::top()); test_gauge_widening_interval(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_widening_interval(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, i)), Gauge(GaugeBound(0), GaugeBound(2, i))); test_gauge_widening_interval(Gauge(0), Gauge(1), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound(0), GaugeBound(2)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound(0), GaugeBound(3)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound(-2), GaugeBound(2)), Gauge(GaugeBound::minus_infinity(), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(GaugeBound(0), GaugeBound(4)), Gauge(4), Gauge(GaugeBound(0), GaugeBound(4))); test_gauge_widening_interval(Gauge(1), Gauge(2), Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(1), Gauge(-2), Gauge(GaugeBound::minus_infinity(), GaugeBound(1))); test_gauge_widening_interval(Gauge(GaugeBound(4, i)), Gauge(GaugeBound(1) + GaugeBound(4, i)), Gauge(GaugeBound(4, i), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(2, i)), Gauge(GaugeBound(2), GaugeBound(2) + GaugeBound(2, i)), Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound(i)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(1), Gauge(GaugeBound(i)), Gauge::top()); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound(i), GaugeBound(2, i)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i)), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(4) + GaugeBound(3, i)), Gauge(GaugeBound(2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i)), Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(4) + GaugeBound(3, i))); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound(2), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge(0), Gauge(GaugeBound::minus_infinity(), GaugeBound(2)), Gauge::top()); test_gauge_widening_interval(Gauge(0), Gauge::top(), Gauge::top()); test_gauge_widening_interval(Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(1), Gauge::top()); test_gauge_widening_interval(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(1), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval(Gauge::top(), Gauge(1), Gauge::top()); } #define test_gauge_widening_interval_threshold(x, y, t, z) \ BOOST_CHECK((x).widening_interval_threshold(y, t) == (z)) BOOST_AUTO_TEST_CASE(gauge_widening_interval_threshold) { VariableFactory vfac; Variable i(vfac.get("i")); test_gauge_widening_interval_threshold(Gauge::top(), Gauge::bottom(), ZNumber(10), Gauge::top()); test_gauge_widening_interval_threshold(Gauge::top(), Gauge::top(), ZNumber(10), Gauge::top()); test_gauge_widening_interval_threshold(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), ZNumber(10), Gauge::top()); test_gauge_widening_interval_threshold(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, i)), ZNumber(10), Gauge::top()); test_gauge_widening_interval_threshold(Gauge::bottom(), Gauge::bottom(), ZNumber(10), Gauge::bottom()); test_gauge_widening_interval_threshold(Gauge::bottom(), Gauge::top(), ZNumber(10), Gauge::top()); test_gauge_widening_interval_threshold(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_widening_interval_threshold(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, i)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(2, i))); test_gauge_widening_interval_threshold(Gauge(0), Gauge(1), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound(0), GaugeBound(1)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound(0), GaugeBound(2)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound(0), GaugeBound(3)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound(-2), GaugeBound(2)), ZNumber(10), Gauge(GaugeBound::minus_infinity(), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(GaugeBound(0), GaugeBound(4)), Gauge(4), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(4))); test_gauge_widening_interval_threshold(Gauge(1), Gauge(2), ZNumber(10), Gauge(GaugeBound(1), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(1), Gauge(-2), ZNumber(-10), Gauge(GaugeBound(-10), GaugeBound(1))); test_gauge_widening_interval_threshold(Gauge(GaugeBound(4, i)), Gauge(GaugeBound(1) + GaugeBound(4, i)), ZNumber(10), Gauge(GaugeBound(4, i), GaugeBound::plus_infinity())); test_gauge_widening_interval_threshold(Gauge(GaugeBound(1), GaugeBound(1) + GaugeBound(2, i)), Gauge(GaugeBound(2), GaugeBound(2) + GaugeBound(2, i)), ZNumber(10), Gauge(GaugeBound(1), GaugeBound::plus_infinity())); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound(i)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval_threshold(Gauge(1), Gauge(GaugeBound(i)), ZNumber(10), Gauge::top()); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound(i), GaugeBound(2, i)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval_threshold(Gauge(GaugeBound(0), GaugeBound(1)), Gauge(GaugeBound(2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval_threshold(Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(4) + GaugeBound(3, i)), Gauge(GaugeBound(2) + GaugeBound(i), GaugeBound(3) + GaugeBound(3, i)), ZNumber(10), Gauge(GaugeBound(-2) + GaugeBound(i), GaugeBound(4) + GaugeBound(3, i))); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound(2), GaugeBound::plus_infinity()), ZNumber(10), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval_threshold(Gauge(0), Gauge(GaugeBound::minus_infinity(), GaugeBound(2)), ZNumber(10), Gauge(GaugeBound::minus_infinity(), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(0), Gauge::top(), ZNumber(10), Gauge::top()); test_gauge_widening_interval_threshold(Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(1), ZNumber(10), Gauge(GaugeBound::minus_infinity(), GaugeBound(10))); test_gauge_widening_interval_threshold(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(1), ZNumber(10), Gauge(GaugeBound(0), GaugeBound::plus_infinity())); test_gauge_widening_interval_threshold(Gauge::top(), Gauge(1), ZNumber(10), Gauge::top()); } #define test_gauge_narrowing_interval_threshold(x, y, t, z) \ BOOST_CHECK((x).narrowing_interval_threshold(y, t) == (z)) BOOST_AUTO_TEST_CASE(gauge_narrowing_interval_threshold) { VariableFactory vfac; Variable i(vfac.get("i")); test_gauge_narrowing_interval_threshold(Gauge::top(), Gauge::bottom(), ZNumber(10), Gauge::bottom()); test_gauge_narrowing_interval_threshold(Gauge::top(), Gauge::top(), ZNumber(10), Gauge::top()); test_gauge_narrowing_interval_threshold(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(1)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(1))); test_gauge_narrowing_interval_threshold(Gauge::top(), Gauge(GaugeBound(0), GaugeBound(2, i)), ZNumber(10), Gauge(GaugeBound(0), GaugeBound(2, i))); test_gauge_narrowing_interval_threshold(Gauge::bottom(), Gauge::bottom(), ZNumber(10), Gauge::bottom()); test_gauge_narrowing_interval_threshold(Gauge::bottom(), Gauge::top(), ZNumber(10), Gauge::bottom()); test_gauge_narrowing_interval_threshold(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(1)), ZNumber(10), Gauge::bottom()); test_gauge_narrowing_interval_threshold(Gauge::bottom(), Gauge(GaugeBound(0), GaugeBound(2, i)), ZNumber(10), Gauge::bottom()); test_gauge_narrowing_interval_threshold(Gauge(0), Gauge(1), ZNumber(10), Gauge(0)); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(0), GaugeBound::plus_infinity()), Gauge(GaugeBound(0), GaugeBound(90)), ZNumber(100), Gauge(GaugeBound(0), GaugeBound(90))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(0), GaugeBound(100)), Gauge(GaugeBound(0), GaugeBound(90)), ZNumber(100), Gauge(GaugeBound(0), GaugeBound(90))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(0), GaugeBound(110)), Gauge(GaugeBound(0), GaugeBound(90)), ZNumber(100), Gauge(GaugeBound(0), GaugeBound(110))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound::minus_infinity(), GaugeBound(0)), Gauge(GaugeBound(-90), GaugeBound(0)), ZNumber(-100), Gauge(GaugeBound(-90), GaugeBound(0))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(-100), GaugeBound(0)), Gauge(GaugeBound(-90), GaugeBound(0)), ZNumber(-100), Gauge(GaugeBound(-90), GaugeBound(0))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(-110), GaugeBound(0)), Gauge(GaugeBound(-90), GaugeBound(0)), ZNumber(-100), Gauge(GaugeBound(-110), GaugeBound(0))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(4, i), GaugeBound::plus_infinity()), Gauge(GaugeBound(4, i), GaugeBound(90)), ZNumber(100), Gauge(GaugeBound(4, i), GaugeBound(90))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(0), GaugeBound(4, i)), Gauge(GaugeBound(0), GaugeBound(3, i)), ZNumber(100), Gauge(GaugeBound(0), GaugeBound(4, i))); test_gauge_narrowing_interval_threshold(Gauge(GaugeBound(4, i)), Gauge(GaugeBound(3, i), GaugeBound(4, i)), ZNumber(100), Gauge(GaugeBound(4, i))); } NASA-SW-VnV-ikos-1d98c65/core/test/unit/value/numeric/interval.cpp000066400000000000000000000717361473507761200246300ustar00rootroot00000000000000/******************************************************************************* * * Tests for Interval * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #define BOOST_TEST_MODULE test_interval #define BOOST_TEST_DYN_LINK #include #include #include #include using namespace ikos::core; using namespace ikos::core::numeric; BOOST_AUTO_TEST_CASE(test_division) { BOOST_CHECK(ZInterval(4) / ZInterval::bottom() == ZInterval::bottom()); BOOST_CHECK(ZInterval::bottom() / ZInterval(2) == ZInterval::bottom()); BOOST_CHECK(ZInterval::top() / ZInterval(0) == ZInterval::bottom()); BOOST_CHECK(ZInterval(4) / ZInterval(2) == ZInterval(2)); BOOST_CHECK(ZInterval(3) / ZInterval(2) == ZInterval(1)); BOOST_CHECK(ZInterval(-3) / ZInterval(2) == ZInterval(-1)); BOOST_CHECK(ZInterval(ZBound(1), ZBound(3)) / ZInterval(2) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) / ZInterval(2) == ZInterval(ZBound(1), ZBound(3))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound(3)) / ZInterval(2) == ZInterval(ZBound(-1), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound::plus_infinity()) / ZInterval(2) == ZInterval(ZBound(-1), ZBound::plus_infinity())); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(3)) / ZInterval(2) == ZInterval(ZBound::minus_infinity(), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(1), ZBound(3)) / ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(0), ZBound(3))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound(3)) / ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(-3), ZBound(3))); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) / ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-7), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) / ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-7), ZBound(7))); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(7)) / ZInterval(ZBound(-2), ZBound(3)) == ZInterval::top()); BOOST_CHECK(ZInterval(ZBound(-2), ZBound::plus_infinity()) / ZInterval(ZBound(-2), ZBound(3)) == ZInterval::top()); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) / ZInterval(ZBound::minus_infinity(), ZBound(3)) == ZInterval(ZBound(-7), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) / ZInterval(ZBound(-2), ZBound::plus_infinity()) == ZInterval(ZBound(-7), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(-3)) / ZInterval(ZBound(3), ZBound(9)) == ZInterval(ZBound(-2), ZBound(0))); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(6)) / ZInterval(ZBound(3), ZBound(9)) == ZInterval(ZBound(-2), ZBound(2))); } BOOST_AUTO_TEST_CASE(test_remainder) { BOOST_CHECK(ZInterval(4) % ZInterval::bottom() == ZInterval::bottom()); BOOST_CHECK(ZInterval::bottom() % ZInterval(2) == ZInterval::bottom()); BOOST_CHECK(ZInterval::top() % ZInterval(0) == ZInterval::bottom()); BOOST_CHECK(ZInterval(4) % ZInterval(2) == ZInterval(0)); BOOST_CHECK(ZInterval(3) % ZInterval(2) == ZInterval(1)); BOOST_CHECK(ZInterval(-3) % ZInterval(2) == ZInterval(-1)); BOOST_CHECK(ZInterval(ZBound(1), ZBound(3)) % ZInterval(2) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) % ZInterval(2) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound(3)) % ZInterval(2) == ZInterval(ZBound(-1), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound::plus_infinity()) % ZInterval(2) == ZInterval(ZBound(-1), ZBound(1))); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(3)) % ZInterval(2) == ZInterval(ZBound(-1), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(1), ZBound(3)) % ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound(3)) % ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(-1), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) % ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) % ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-2), ZBound(2))); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(7)) % ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-2), ZBound(2))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound::plus_infinity()) % ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-2), ZBound(2))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) % ZInterval(ZBound::minus_infinity(), ZBound(3)) == ZInterval(ZBound(-7), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) % ZInterval(ZBound(-2), ZBound::plus_infinity()) == ZInterval(ZBound(-7), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(-3)) % ZInterval(ZBound(3), ZBound(9)) == ZInterval(ZBound(-6), ZBound(0))); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(6)) % ZInterval(ZBound(3), ZBound(9)) == ZInterval(ZBound(-6), ZBound(6))); } BOOST_AUTO_TEST_CASE(test_modulo) { BOOST_CHECK(mod(ZInterval(4), ZInterval::bottom()) == ZInterval::bottom()); BOOST_CHECK(mod(ZInterval::bottom(), ZInterval(2)) == ZInterval::bottom()); BOOST_CHECK(mod(ZInterval::top(), ZInterval(0)) == ZInterval::bottom()); BOOST_CHECK(mod(ZInterval(4), ZInterval(2)) == ZInterval(0)); BOOST_CHECK(mod(ZInterval(3), ZInterval(2)) == ZInterval(1)); BOOST_CHECK(mod(ZInterval(-3), ZInterval(2)) == ZInterval(1)); BOOST_CHECK(mod(ZInterval(ZBound(1), ZBound(3)), ZInterval(2)) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(mod(ZInterval(ZBound(2), ZBound(7)), ZInterval(2)) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(mod(ZInterval(ZBound(-3), ZBound(3)), ZInterval(2)) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(mod(ZInterval(ZBound(-3), ZBound::plus_infinity()), ZInterval(2)) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(mod(ZInterval(ZBound::minus_infinity(), ZBound(3)), ZInterval(2)) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK( mod(ZInterval(ZBound(1), ZBound(3)), ZInterval(ZBound(1), ZBound(2))) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK( mod(ZInterval(ZBound(-3), ZBound(3)), ZInterval(ZBound(1), ZBound(2))) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK( mod(ZInterval(ZBound(2), ZBound(7)), ZInterval(ZBound(-2), ZBound(3))) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK( mod(ZInterval(ZBound(-2), ZBound(7)), ZInterval(ZBound(-2), ZBound(3))) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK(mod(ZInterval(ZBound::minus_infinity(), ZBound(7)), ZInterval(ZBound(-2), ZBound(3))) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK(mod(ZInterval(ZBound(-2), ZBound::plus_infinity()), ZInterval(ZBound(-2), ZBound(3))) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK(mod(ZInterval(ZBound(-2), ZBound(7)), ZInterval(ZBound::minus_infinity(), ZBound(3))) == ZInterval(ZBound(0), ZBound::plus_infinity())); BOOST_CHECK(mod(ZInterval(ZBound(-2), ZBound(7)), ZInterval(ZBound(-2), ZBound::plus_infinity())) == ZInterval(ZBound(0), ZBound::plus_infinity())); BOOST_CHECK( mod(ZInterval(ZBound(-6), ZBound(-3)), ZInterval(ZBound(3), ZBound(9))) == ZInterval(ZBound(0), ZBound(8))); BOOST_CHECK( mod(ZInterval(ZBound(-6), ZBound(6)), ZInterval(ZBound(3), ZBound(9))) == ZInterval(ZBound(0), ZBound(8))); BOOST_CHECK(mod(ZInterval(ZBound(2), ZBound(7)), ZInterval(20)) == ZInterval(ZBound(2), ZBound(7))); BOOST_CHECK(mod(ZInterval(ZBound(2), ZBound(21)), ZInterval(20)) == ZInterval(ZBound(0), ZBound(19))); BOOST_CHECK(mod(ZInterval(ZBound(21), ZBound(27)), ZInterval(20)) == ZInterval(ZBound(1), ZBound(7))); BOOST_CHECK(mod(ZInterval(ZBound(21), ZBound(27)), ZInterval(-20)) == ZInterval(ZBound(1), ZBound(7))); BOOST_CHECK(mod(ZInterval(ZBound(-21), ZBound(27)), ZInterval(-20)) == ZInterval(ZBound(0), ZBound(19))); BOOST_CHECK(mod(ZInterval(ZBound(-1), ZBound(7)), ZInterval(20)) == ZInterval(ZBound(0), ZBound(19))); BOOST_CHECK(mod(ZInterval(ZBound(-18), ZBound(0)), ZInterval(ZBound(-20), ZBound(-19))) == ZInterval(ZBound(0), ZBound(19))); } BOOST_AUTO_TEST_CASE(test_bound_shl) { BOOST_CHECK(ZBound::plus_infinity() << ZBound::plus_infinity() == ZBound::plus_infinity()); BOOST_CHECK(ZBound::plus_infinity() << ZBound(2) == ZBound::plus_infinity()); BOOST_CHECK(ZBound::minus_infinity() << ZBound::plus_infinity() == ZBound::minus_infinity()); BOOST_CHECK(ZBound::minus_infinity() << ZBound(2) == ZBound::minus_infinity()); BOOST_CHECK(ZBound(2) << ZBound::plus_infinity() == ZBound::plus_infinity()); BOOST_CHECK(ZBound(0) << ZBound::plus_infinity() == ZBound(0)); BOOST_CHECK(ZBound(-2) << ZBound::plus_infinity() == ZBound::minus_infinity()); BOOST_CHECK(ZBound(0) << ZBound(2) == ZBound(0)); BOOST_CHECK(ZBound(2) << ZBound(3) == ZBound(16)); BOOST_CHECK(ZBound(-2) << ZBound(3) == ZBound(-16)); } BOOST_AUTO_TEST_CASE(test_interval_shl) { BOOST_CHECK(ZInterval(4) << ZInterval::bottom() == ZInterval::bottom()); BOOST_CHECK(ZInterval::bottom() << ZInterval(2) == ZInterval::bottom()); BOOST_CHECK(ZInterval::top() << ZInterval(0) == ZInterval::top()); BOOST_CHECK(ZInterval(4) << ZInterval(2) == ZInterval(16)); BOOST_CHECK(ZInterval(3) << ZInterval(2) == ZInterval(12)); BOOST_CHECK(ZInterval(-3) << ZInterval(2) == ZInterval(-12)); BOOST_CHECK(ZInterval(4) << ZInterval(-2) == ZInterval::bottom()); BOOST_CHECK(ZInterval(ZBound(1), ZBound(3)) << ZInterval(2) == ZInterval(ZBound(4), ZBound(12))); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) << ZInterval(2) == ZInterval(ZBound(8), ZBound(28))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound(3)) << ZInterval(2) == ZInterval(ZBound(-12), ZBound(12))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound::plus_infinity()) << ZInterval(2) == ZInterval(ZBound(-12), ZBound::plus_infinity())); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(3)) << ZInterval(2) == ZInterval(ZBound::minus_infinity(), ZBound(12))); BOOST_CHECK(ZInterval(ZBound(1), ZBound(3)) << ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(2), ZBound(12))); BOOST_CHECK(ZInterval(ZBound(-3), ZBound(3)) << ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(-12), ZBound(12))); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) << ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(2), ZBound(56))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) << ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-16), ZBound(56))); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(7)) << ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound::minus_infinity(), ZBound(56))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound::plus_infinity()) << ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-16), ZBound::plus_infinity())); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) << ZInterval(ZBound::minus_infinity(), ZBound(3)) == ZInterval(ZBound(-16), ZBound(56))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) << ZInterval(ZBound(-2), ZBound::plus_infinity()) == ZInterval::top()); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(-3)) << ZInterval(ZBound(3), ZBound(9)) == ZInterval(ZBound(-3072), ZBound(-24))); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(6)) << ZInterval(ZBound(3), ZBound(9)) == ZInterval(ZBound(-3072), ZBound(3072))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) << ZInterval(ZBound::minus_infinity(), ZBound(-1)) == ZInterval::bottom()); BOOST_CHECK(ZInterval(0) << ZInterval::top() == ZInterval(0)); } BOOST_AUTO_TEST_CASE(test_bound_shr) { BOOST_CHECK(ZBound::plus_infinity() >> ZBound::plus_infinity() == ZBound::plus_infinity()); BOOST_CHECK(ZBound::plus_infinity() >> ZBound(2) == ZBound::plus_infinity()); BOOST_CHECK(ZBound::minus_infinity() >> ZBound::plus_infinity() == ZBound::minus_infinity()); BOOST_CHECK(ZBound::minus_infinity() >> ZBound(2) == ZBound::minus_infinity()); BOOST_CHECK(ZBound(2) >> ZBound::plus_infinity() == ZBound(0)); BOOST_CHECK(ZBound(0) >> ZBound::plus_infinity() == ZBound(0)); BOOST_CHECK(ZBound(-2) >> ZBound::plus_infinity() == ZBound(-1)); BOOST_CHECK(ZBound(0) >> ZBound(2) == ZBound(0)); BOOST_CHECK(ZBound(15) >> ZBound(2) == ZBound(3)); BOOST_CHECK(ZBound(-15) >> ZBound(2) == ZBound(-4)); } BOOST_AUTO_TEST_CASE(test_interval_shr) { BOOST_CHECK(ZInterval(4) >> ZInterval::bottom() == ZInterval::bottom()); BOOST_CHECK(ZInterval::bottom() >> ZInterval(2) == ZInterval::bottom()); BOOST_CHECK(ZInterval::top() >> ZInterval(0) == ZInterval::top()); BOOST_CHECK(ZInterval(15) >> ZInterval(2) == ZInterval(3)); BOOST_CHECK(ZInterval(1) >> ZInterval(2) == ZInterval(0)); BOOST_CHECK(ZInterval(-15) >> ZInterval(2) == ZInterval(-4)); BOOST_CHECK(ZInterval(4) >> ZInterval(-2) == ZInterval::bottom()); BOOST_CHECK(ZInterval(ZBound(1), ZBound(3)) >> ZInterval(2) == ZInterval(0)); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) >> ZInterval(2) == ZInterval(ZBound(0), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(-15), ZBound(15)) >> ZInterval(2) == ZInterval(ZBound(-4), ZBound(3))); BOOST_CHECK(ZInterval(ZBound(-15), ZBound::plus_infinity()) >> ZInterval(2) == ZInterval(ZBound(-4), ZBound::plus_infinity())); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(15)) >> ZInterval(2) == ZInterval(ZBound::minus_infinity(), ZBound(3))); BOOST_CHECK(ZInterval(ZBound(0), ZBound(15)) >> ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(0), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-17), ZBound(15)) >> ZInterval(ZBound(1), ZBound(2)) == ZInterval(ZBound(-9), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(2), ZBound(7)) >> ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(0), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) >> ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-2), ZBound(7))); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(7)) >> ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound::minus_infinity(), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound::plus_infinity()) >> ZInterval(ZBound(-2), ZBound(3)) == ZInterval(ZBound(-2), ZBound::plus_infinity())); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) >> ZInterval(ZBound::minus_infinity(), ZBound(3)) == ZInterval(ZBound(-2), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) >> ZInterval(ZBound(-2), ZBound::plus_infinity()) == ZInterval(ZBound(-2), ZBound(7))); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(-3)) >> ZInterval(ZBound(2), ZBound(3)) == ZInterval(ZBound(-2), ZBound(-1))); BOOST_CHECK(ZInterval(ZBound(-6), ZBound(6)) >> ZInterval(ZBound(2), ZBound(3)) == ZInterval(ZBound(-2), ZBound(1))); BOOST_CHECK(ZInterval(ZBound(-2), ZBound(7)) >> ZInterval(ZBound::minus_infinity(), ZBound(-1)) == ZInterval::bottom()); BOOST_CHECK(ZInterval(0) >> ZInterval::top() == ZInterval(0)); } BOOST_AUTO_TEST_CASE(test_and) { BOOST_CHECK((ZInterval(4) & ZInterval::bottom()) == ZInterval::bottom()); BOOST_CHECK((ZInterval::bottom() & ZInterval(2)) == ZInterval::bottom()); BOOST_CHECK((ZInterval::top() & ZInterval(0)) == ZInterval(0)); BOOST_CHECK((ZInterval(4) & ZInterval(2)) == ZInterval(0)); BOOST_CHECK((ZInterval(3) & ZInterval(2)) == ZInterval(2)); BOOST_CHECK((ZInterval(-3) & ZInterval(2)) == ZInterval(0)); BOOST_CHECK((ZInterval(ZBound(1), ZBound(3)) & ZInterval(2)) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK((ZInterval(ZBound(2), ZBound(7)) & ZInterval(2)) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK((ZInterval(ZBound(-3), ZBound(3)) & ZInterval(2)) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK((ZInterval(ZBound(-3), ZBound::plus_infinity()) & ZInterval(2)) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK((ZInterval(ZBound::minus_infinity(), ZBound(3)) & ZInterval(2)) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK( (ZInterval(ZBound(1), ZBound(3)) & ZInterval(ZBound(1), ZBound(2))) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK( (ZInterval(ZBound(-3), ZBound(3)) & ZInterval(ZBound(1), ZBound(2))) == ZInterval(ZBound(0), ZBound(2))); BOOST_CHECK( (ZInterval(ZBound(2), ZBound(7)) & ZInterval(ZBound(-2), ZBound(3))) == ZInterval(ZBound(0), ZBound(7))); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) & ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound::minus_infinity(), ZBound(7)) & ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound::plus_infinity()) & ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) & ZInterval(ZBound::minus_infinity(), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) & ZInterval(ZBound(-2), ZBound::plus_infinity())) == ZInterval::top()); BOOST_CHECK( (ZInterval(ZBound(-6), ZBound(-3)) & ZInterval(ZBound(3), ZBound(9))) == ZInterval(ZBound(0), ZBound(9))); BOOST_CHECK( (ZInterval(ZBound(-6), ZBound(6)) & ZInterval(ZBound(3), ZBound(9))) == ZInterval(ZBound(0), ZBound(9))); } BOOST_AUTO_TEST_CASE(test_or) { BOOST_CHECK((ZInterval(4) | ZInterval::bottom()) == ZInterval::bottom()); BOOST_CHECK((ZInterval::bottom() | ZInterval(2)) == ZInterval::bottom()); BOOST_CHECK((ZInterval::top() | ZInterval(-1)) == ZInterval(-1)); BOOST_CHECK((ZInterval(-1) | ZInterval::top()) == ZInterval(-1)); BOOST_CHECK((ZInterval(4) | ZInterval(2)) == ZInterval(6)); BOOST_CHECK((ZInterval(3) | ZInterval(2)) == ZInterval(3)); BOOST_CHECK((ZInterval(-3) | ZInterval(2)) == ZInterval(-1)); BOOST_CHECK((ZInterval(ZBound(1), ZBound(3)) | ZInterval(2)) == ZInterval(ZBound(0), ZBound(3))); BOOST_CHECK((ZInterval(ZBound(2), ZBound(7)) | ZInterval(2)) == ZInterval(ZBound(0), ZBound(7))); BOOST_CHECK((ZInterval(ZBound(-3), ZBound(3)) | ZInterval(2)) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-3), ZBound::plus_infinity()) | ZInterval(2)) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound::minus_infinity(), ZBound(3)) | ZInterval(2)) == ZInterval::top()); BOOST_CHECK( (ZInterval(ZBound(1), ZBound(3)) | ZInterval(ZBound(1), ZBound(2))) == ZInterval(ZBound(0), ZBound(3))); BOOST_CHECK((ZInterval(ZBound(-3), ZBound(3)) | ZInterval(ZBound(1), ZBound(2))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(2), ZBound(7)) | ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) | ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound::minus_infinity(), ZBound(7)) | ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound::plus_infinity()) | ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) | ZInterval(ZBound::minus_infinity(), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) | ZInterval(ZBound(-2), ZBound::plus_infinity())) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-6), ZBound(-3)) | ZInterval(ZBound(3), ZBound(9))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-6), ZBound(6)) | ZInterval(ZBound(3), ZBound(9))) == ZInterval::top()); } BOOST_AUTO_TEST_CASE(test_xor) { BOOST_CHECK((ZInterval(4) ^ ZInterval::bottom()) == ZInterval::bottom()); BOOST_CHECK((ZInterval::bottom() ^ ZInterval(2)) == ZInterval::bottom()); BOOST_CHECK((ZInterval::top() ^ ZInterval(-1)) == ZInterval::top()); BOOST_CHECK((ZInterval(-1) ^ ZInterval::top()) == ZInterval::top()); BOOST_CHECK((ZInterval(4) ^ ZInterval(2)) == ZInterval(6)); BOOST_CHECK((ZInterval(3) ^ ZInterval(2)) == ZInterval(1)); BOOST_CHECK((ZInterval(-3) ^ ZInterval(2)) == ZInterval(-1)); BOOST_CHECK((ZInterval(ZBound(1), ZBound(3)) ^ ZInterval(2)) == ZInterval(ZBound(0), ZBound(3))); BOOST_CHECK((ZInterval(ZBound(2), ZBound(7)) ^ ZInterval(2)) == ZInterval(ZBound(0), ZBound(7))); BOOST_CHECK((ZInterval(ZBound(-3), ZBound(3)) ^ ZInterval(2)) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-3), ZBound::plus_infinity()) ^ ZInterval(2)) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound::minus_infinity(), ZBound(3)) ^ ZInterval(2)) == ZInterval::top()); BOOST_CHECK( (ZInterval(ZBound(1), ZBound(3)) ^ ZInterval(ZBound(1), ZBound(2))) == ZInterval(ZBound(0), ZBound(3))); BOOST_CHECK((ZInterval(ZBound(-3), ZBound(3)) ^ ZInterval(ZBound(1), ZBound(2))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(2), ZBound(7)) ^ ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) ^ ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound::minus_infinity(), ZBound(7)) ^ ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound::plus_infinity()) ^ ZInterval(ZBound(-2), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) ^ ZInterval(ZBound::minus_infinity(), ZBound(3))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-2), ZBound(7)) ^ ZInterval(ZBound(-2), ZBound::plus_infinity())) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-6), ZBound(-3)) ^ ZInterval(ZBound(3), ZBound(9))) == ZInterval::top()); BOOST_CHECK((ZInterval(ZBound(-6), ZBound(6)) ^ ZInterval(ZBound(3), ZBound(9))) == ZInterval::top()); } BOOST_AUTO_TEST_CASE(test_mod_to_sub) { BOOST_CHECK(ZInterval(ZBound(1), ZBound(4)).mod_to_sub(ZNumber(8)) == boost::optional< ZNumber >(ZNumber(0))); BOOST_CHECK(ZInterval(ZBound(1), ZBound(8)).mod_to_sub(ZNumber(8)) == boost::none); BOOST_CHECK(ZInterval(ZBound(1), ZBound(9)).mod_to_sub(ZNumber(8)) == boost::none); BOOST_CHECK(ZInterval(ZBound(8), ZBound(9)).mod_to_sub(ZNumber(8)) == boost::optional< ZNumber >(ZNumber(8))); BOOST_CHECK(ZInterval(ZBound(18), ZBound(20)).mod_to_sub(ZNumber(8)) == boost::optional< ZNumber >(ZNumber(16))); BOOST_CHECK(ZInterval(ZBound(18), ZBound(24)).mod_to_sub(ZNumber(8)) == boost::none); BOOST_CHECK(ZInterval(ZBound(-7), ZBound(-1)).mod_to_sub(ZNumber(8)) == boost::optional< ZNumber >(ZNumber(-8))); BOOST_CHECK(ZInterval(ZBound(-9), ZBound(-1)).mod_to_sub(ZNumber(8)) == boost::none); BOOST_CHECK(ZInterval(ZBound(-10), ZBound(-9)).mod_to_sub(ZNumber(8)) == boost::optional< ZNumber >(ZNumber(-16))); } BOOST_AUTO_TEST_CASE(test_widening_threshold) { BOOST_CHECK( ZInterval(ZBound(0), ZBound(0)) .widening_threshold(ZInterval(ZBound(-1), ZBound(0)), ZNumber(-47)) == ZInterval(ZBound(-47), ZBound(0))); BOOST_CHECK( ZInterval(ZBound::minus_infinity(), ZBound(0)) .widening_threshold(ZInterval(ZBound(0), ZBound(1)), ZNumber(3)) == ZInterval(ZBound::minus_infinity(), ZBound(3))); BOOST_CHECK( ZInterval(ZBound::minus_infinity(), ZBound(0)) .widening_threshold(ZInterval(ZBound::minus_infinity(), ZBound(47)), ZNumber(42)) == ZInterval(ZBound::minus_infinity(), ZBound::plus_infinity())); BOOST_CHECK( ZInterval(ZBound(0), ZBound(0)) .widening_threshold(ZInterval(ZBound(-1), ZBound(0)), ZNumber(-1)) == ZInterval(ZBound(-1), ZBound(0))); } BOOST_AUTO_TEST_CASE(test_narrowing_threshold) { BOOST_CHECK( ZInterval(ZBound(0), ZBound::plus_infinity()) .narrowing_threshold(ZInterval(ZBound(0), ZBound(10)), ZNumber(20)) == ZInterval(ZBound(0), ZBound(10))); BOOST_CHECK( ZInterval(ZBound(0), ZBound(20)) .narrowing_threshold(ZInterval(ZBound(0), ZBound(10)), ZNumber(20)) == ZInterval(ZBound(0), ZBound(10))); BOOST_CHECK( ZInterval(ZBound(0), ZBound(30)) .narrowing_threshold(ZInterval(ZBound(0), ZBound(10)), ZNumber(20)) == ZInterval(ZBound(0), ZBound(30))); BOOST_CHECK(ZInterval(ZBound::minus_infinity(), ZBound(0)) .narrowing_threshold(ZInterval(ZBound(-10), ZBound(0)), ZNumber(-20)) == ZInterval(ZBound(-10), ZBound(0))); BOOST_CHECK(ZInterval(ZBound(-20), ZBound(0)) .narrowing_threshold(ZInterval(ZBound(-10), ZBound(0)), ZNumber(-20)) == ZInterval(ZBound(-10), ZBound(0))); BOOST_CHECK(ZInterval(ZBound(-30), ZBound(0)) .narrowing_threshold(ZInterval(ZBound(-10), ZBound(0)), ZNumber(-20)) == ZInterval(ZBound(-30), ZBound(0))); BOOST_CHECK( ZInterval(ZBound::minus_infinity(), ZBound::plus_infinity()) .narrowing_threshold(ZInterval(ZBound(0), ZBound(10)), ZNumber(20)) == ZInterval(ZBound(0), ZBound(10))); BOOST_CHECK( ZInterval(ZBound(-20), ZBound(20)) .narrowing_threshold(ZInterval(ZBound(0), ZBound(10)), ZNumber(20)) == ZInterval(ZBound(-20), ZBound(10))); BOOST_CHECK(ZInterval(ZBound(-20), ZBound(20)) .narrowing_threshold(ZInterval(ZBound(0), ZBound(10)), ZNumber(-20)) == ZInterval(ZBound(0), ZBound(20))); } NASA-SW-VnV-ikos-1d98c65/doc/000077500000000000000000000000001473507761200153635ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/doc/CODING_STANDARDS.md000066400000000000000000000110751473507761200202570ustar00rootroot00000000000000Coding Standards ================ This document describes a few coding standards that are used in IKOS. C++ Standard Version -------------------- IKOS is currently written in C++14. Source Code Formatting ---------------------- * Use 2 spaces for indentation ([Google Style Guide](https://google.github.io/styleguide/cppguide.html#Spaces_vs._Tabs)) * Do not indent inside a namespace ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#namespace-indentation)) * Indent each case in a switch statement ([Google Style Guide](https://google.github.io/styleguide/cppguide.html#Loops_and_Switch_Statements)) * No trailing whitespaces at the end of a line ([Google Style Guide](https://google.github.io/styleguide/cppguide.html#Horizontal_Whitespace)) * Remove unnecessary parenthesis around returned values ([Google Style Guide](https://google.github.io/styleguide/cppguide.html#Return_Values)) * Binary operators usually have spaces around them ([Google Style Guide](https://google.github.io/styleguide/cppguide.html#Horizontal_Whitespace)) * No extra space between a function name and arguments * Do not align variable definitions ([Python Style Guide](https://www.python.org/dev/peps/pep-0008/#pet-peeves)) * Prefix member variables with an underscore (Arnaud's Style) * Do not use `using namespace` in header files ([Google Style Guide](https://google.github.io/styleguide/cppguide.html#Namespaces), [LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#do-not-use-using-namespace-std)) * Sort included headers in the following order: standards, 3rd-party, our own * Use Doxygen comments ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#doxygen-use-in-documentation-comments)) * Each line should fit within 80 columns ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#source-code-width)) * Treat compiler warnings like errors ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#treat-compiler-warnings-like-errors)) * Use `struct` only when all members are public, otherwise use `class` ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#use-of-class-and-struct-keywords)) * Use `auto` to make the code more readable ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#use-auto-type-deduction-to-make-code-more-readable)) * Use early exit and continue ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#use-early-exits-and-continue-to-simplify-code)) * Assert liberally ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#assert-liberally)) * Don't evaluate `end()` every time through a loop ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#don-t-evaluate-end-every-time-through-a-loop)) * Avoid `std::endl` ([LLVM Coding Standards](http://llvm.org/docs/CodingStandards.html#avoid-std-endl)) * Naming conventions are specified in the [.clang-tidy](../.clang-tidy) configuration file * Use K&R style: ```c if (cond) { f(); } else if (cond1) { g(); } else { h(); } ``` Automatic Formatting -------------------- IKOS developers should use [clang-format](https://clang.llvm.org/docs/ClangFormat.html) to format the source code with a predefined set of style rules. See [.clang-format](../.clang-format) for the set of rules. Always run the following command before committing any changes: ``` $ git-clang-format -f ``` To run clang-format on the whole repository, use: ``` $ script/run-clang-format ``` Static Analysis --------------- IKOS developers should use [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) to perform diagnosis for typical programming errors, style violation, interface misuse, etc. See [.clang-tidy](../.clang-tidy) for the set of checks. To run clang-tidy on the whole repository, use: ``` $ mkdir build $ cd build $ cmake .. $ ../script/run-clang-tidy ``` Dynamic Analysis ---------------- IKOS developers should use [clang sanitizers](https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation) to check for undefined behaviors at run-time. To build IKOS with clang sanitizers, use the following cmake options: * `-DUSE_SANITIZER=Address` to use [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) * `-DUSE_SANITIZER=Undefined` to use [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) * `-DUSE_SANITIZER=Memory` to use [Memory Sanitizer](https://clang.llvm.org/docs/MemorySanitizer.html) * `-DUSE_SANITIZER=Thread` to use [Thread Sanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) * `-DUSE_SANITIZER=Leak` to use [Leak Sanitizer](https://clang.llvm.org/docs/LeakSanitizer.html) NASA-SW-VnV-ikos-1d98c65/doc/OVERVIEW.md000066400000000000000000000037721473507761200171640ustar00rootroot00000000000000Overview of the source code =========================== The following illustrates the content of the root directory: ``` . ├── CMakeLists.txt ├── LICENSE.pdf ├── README.md ├── RELEASE_NOTES.md ├── TROUBLESHOOTING.md ├── analyzer ├── ar ├── cmake ├── core ├── doc ├── frontend ├── script └── test ``` * [CMakeLists.txt](../CMakeLists.txt) is the root CMake file. * [LICENSE.pdf](../LICENSE.pdf) contains the NOSA 1.3 license. * [RELEASE_NOTES.md](../RELEASE_NOTES.md) contains the release notes for the latest versions. * [TROUBLESHOOTING.md](../TROUBLESHOOTING.md) contains solution for common issues with IKOS. * [analyzer](../analyzer) contains the implementation of various analyses for specific defect detections. These analyses are implemented on the Abstract Representation and use the fixpoint iterator and abstract domains to perform analysis. More information can be found at [analyzer/README.md](../analyzer/README.md). * [ar](../ar) contains the implementation of the Abstract Representation, a generic assembly language. More information can be found at [ar/README.md](../ar/README.md). * [cmake](../cmake) contains CMake files to search for related software libraries. * [core](../core) contains the implementation of the theory of Abstract Interpretation, which includes the abstract domains, the fixpoint iterator, and various algorithms that support the implementation. More information can be found at [core/README.md](../core/README.md). * [doc/install](../doc/install) contains installation instructions for specific operating systems. * [frontend/llvm](../frontend/llvm) contains the implementation of the translation from LLVM to AR. More information can be found at [frontend/llvm/README.md](../frontend/llvm/README.md). * [script](../script) contains the [bootstrap](../script/bootstrap) script for a rootless installation. * [test/install](../test/install) contains tests for the installation of IKOS on different platforms. NASA-SW-VnV-ikos-1d98c65/doc/contribute/000077500000000000000000000000001473507761200175415ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/doc/contribute/CORPORATE_CONTRIBUTOR_LICENSE_AGREEMENT.pdf000066400000000000000000003021601473507761200262170ustar00rootroot00000000000000%PDF-1.6 % 150 0 obj <> endobj 163 0 obj <>/Encrypt 151 0 R/Filter/FlateDecode/ID[<48FD4509627EF946AA2E90AB1EB6391C>]/Index[150 27]/Info 149 0 R/Length 70/Prev 99044/Root 152 0 R/Size 177/Type/XRef/W[1 2 1]>>stream hbbd``b`z$ n;`67K"X"@D;&qA b``$ U ' endstream endobj startxref 0 %%EOF 176 0 obj <>stream #KMKȉjѓ\ch.dEdbzNԵٱG *H1LE,1I1iͬQ37t猒GsFi&hAdAr}P(W:`>+ӿZ}ۖZK?CSIw<;e476Z;xU'MV endstream endobj 151 0 obj <>>>/Filter/Standard/Length 128/O('=0"t2xAa߉yӚm)/P -1084/R 4/StmF/StdCF/StrF/StdCF/U(qT=rCT)/V 4>> endobj 152 0 obj <>/Metadata 20 0 R/Pages 148 0 R/StructTreeRoot 44 0 R/Type/Catalog>> endobj 153 0 obj <>/MediaBox[0 0 639.96 800.04]/Parent 148 0 R/Resources<>/Font<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Rotate 0/StructParents 0/Tabs/S/Type/Page>> endobj 154 0 obj <>stream I: c;6q$2-:V&~c;$#PQh#Q ?k4!D-U^ovNLg)\ZiP ѷ-P@wAT'>p^71GxZ}8q*N e"IFi'ų4 bY'̑b36W~c.}H3Ln.Փ/xk/ >ufSL~ưԧDAQCNf*dbA ̤M4l5^\e xUnZb->oYk p^S} jmbjAǁ *pހw=xD p NPSF/3+Ao*Ro>T:@+fJw&5x69 I~Y;;:%E#d`)ga ;PfQz­_3k^'H*ŵTXBw͠3y _8ЫW68LYg ;t\kxkJdy_W`foP(YikMW xUK_df*`_3w"ƍu{>ɏkh^A$۰6sZ䌼%06SYgMEjxCu Bȧ &=sz?FA&)`*_KG%,wQ4⌟+3 endstream endobj 155 0 obj <>stream =4/}bPfqQLNflf{'B*B#te_P]'}.oA EߑUj)J?:qSb`X.A:Q:AN'UdF$t]byC#(i ؈gMۧ!{΄:U@;RРv/k!jG7 0\`72_Lȁamx ɋ᫭h>1;-Qm!\9(oo".^K`Y{ DHd8B{R?= ʌ0!o+*~D }hiOH,HEV5~{EC-f0'zJjоVD^^!\&]ixXU!HK|:( RYuHq Xrqjdi{W?ɇ6Cr]Pp_vթW*|@neSxed@ϴv EzJakpX&XKIt 3ERLMʵLtb|>"74|>qyl$((O/:AπT"{Qwg}AJϙ$&Ҡ֋`dhh՜;#33'B0K{|\K~>&^8ˑc7c,?BtsA:LK-Ed8&l$G&}"#=7E@Ogu.l$k0yH8IEi`R(!2۠yzdDkNO7WJ"Y0C&C1"&4mHF۔ȱfH%1%SLc)AiԔq٬u">stream }ȧDhH9[J kNq7ݰd3S%P'_$XcӠG[)G=΢q,0AH#`bՐpIU9슐gA` EW*| cbt\u+Z,oR^Ҍc+yi5ύ+2-YrG*0t~I[kmkK zJc,Ck9ȩ#a?˚!: df# ~(KK(x0*> t焎@A F8w8r6M/%0' jxE`Sp s@.K…fO@HzwK_8ʆ h˧,bR]Vw1OyS,jߑC @oMZ'eD# Ee#qM:Cx U^ m4٦$?2jk.Omo&B7hOfa?4@&9qOUMX_jGNsSgLQMR_oXoXڟ?t/uV^ؼ?;wvNI4Nl~ [AG bj?=.ߴ־XHv-qGGM4-Zphow_v+jҢP63wkqHŁHnꁊ#Q1ի 8FF(h8$6['G wsH?cPiSUCtI*u*:k7>@p+$i/DuOHD WSd9 Y7if}i08}i] zrx?1^Cg޵KH6dBѝ 0.ãZ{]=XC YTJV'=RۡYL^i+P A8[hVէ{ΟѢIcbY}MQd8et˪o%O;m3S 'C 2M6;hTZܼC`X endstream endobj 157 0 obj <>stream xLNE;Kc.: ZG+; .Ls.1լz+^7kܖc,K=¤)80+ڄj 7h J&mBqfʰh/ȼZDsa_nYkoX]`RdrKkK=^EW Ie!ejC]Dُ C3Z[])Q6Nx) (R{ |F?UR^qBT^(/py%K(&V,yTVe)q \bglB*0әbw.{Ba٤fMv!o =u,"8b£y*I`eC|,'Jodf;#Zi "ҳMaQOې**OV41'K=?d_RcIhKiYSRR,wv3A^%,d , m'go4}wH>}B& u ׹P,9@1WG9ƺݤx$[͒ ̘Yޭ[ݴ{^cPm(LE$3)3.p ~ZxaCAuro)qQb&)Lv}@[lÐRF ֆabϵ!=ǏgOHVDkOiz#pPSZ%\r| 6R=q֭g 6L&6$#8BI2lg]Y"MO{pw6< Ze)[<[EXVr帡EI׃qi`Dž:!!yqHڢ(,m6)\=y?.Ո2)$Y#$cNMrUL6~oerWU5Xc,`Պ y b7feJ&WZ\A\w< }F>7OԤ M—ǑzG EAD4I4mʹݯqУk endstream endobj 158 0 obj <>stream 8Ct ؐ5+n LUE{% m~tqжnH?_y}aaD!b9zנ#z{truDed}% ,>5m-CBאHggUU16 XȓCIv-䵭QLU"U%<;*sp@Tِe 9`$]J4m[!!&xV4~v; n܎WESDt3ZL!@L%@%%H dHH|&AS]nIqv-,F?$A<,@+|Omxr2F.*B˫~\< ^MasL jH (SuR @>2!HBp\RO+G&:4c!QaT&|@Ml-?o!a0Q ol3X'of(A$$?v`AҔ(GUY-@;ͽ2qxD<hRsˡִFC*</rL鰈` CO[OdTX:ivs,BbҠ;'9^p a-ҔXb_VkS.L4{0Yѯ5)%c>j8W!YW,8FקMۗfq$^ ݸtSN{9pL̵Zxp5 OUtsFI_hW, D۳ Rԙ];?Ǥ s~wIowv{*z2u ŏLPmW>aL>قd DtbTgκ "N IݻX5Y3_Tֵ69GB >-ݻu8 X-L{G+= "С}CTlZE$\a{+\T~ <(2 endstream endobj 159 0 obj <>stream ;*DV,p]֔2']Yʝ#5K ]MLiϏ.jvkgI!D+f\MYn[Sޭ\A3QlHJv6:PQ*k-:ͤXc=4*Ѱ爍yL>:z6@㶟KrYe8Ttt+ ވ!D5E\#dc$< Zi'u$ۥFg&d%6y0tϦg[/#&U{X-hM^p~Zj{?'߭ Nm8d6eEI8aN\Dvk:>(pY3 @"Rf |,-,_ܢ=U>l!(GΔz&4 >.]u@eJmxvRZ0;[gARϱx^@hA2ꅃ%ڑMDo|>5γHXMq`l5P)TgL.6jFl.:słE-r0[;@D1Ie?qRd>I6Y.(Hx6OU>0 fQl> ] GKc4;vb"5KLj^mc.s 2@\rby9g!>9y ęeכkTQTag?w:+Śu!灰ZjA͘\lv@}%U([%@Q|3y8tvEs?Cksԥݺ YR^X? _ќWH\Tx@eN;ݼ^vbNfw%e3^W8uWGsWV}ыj]iy>stream r^oU3kB H@/7b~{Y-wfg SM@"Txx1~J.bGҢH8I9pi1 \]M+W" Pzꧭ8RO@.#3gIQ֦.bt(DO8-Ob7ЦC$|PzԹ'm.jt2H15l*ȟiAU"ܹۭMKwX8'%)uԒG R׵r)4w̃OƯTÿfvuaj\Ɍ:@1crZ{llLr3Mȳƿ77vt3t >BN9tzrFQ`עq1A6yNTV&$lז}f/78ӏyR--Rj\)''-&(.lzv>5ߒQWy'%h)K~Ŋ}gOַq:XDeYC;rm1lԿ9 ʄT`Jf͑/fĸC|ىsO\hg ]"Ց Xy& ?r؟Tp\ endstream endobj 161 0 obj <>stream CZWda"L1d+ C86ve]Y>3$9JKCH!kD2@6`߽GVS؋|+ 2MMdӽvxbkZ_@`֗^|B ;vNF6(%2ǑٯJ;胳Mhv^!JYI{pTŲ[x:f $rEQ_Wa̾g62`A4产F6"v*_wr2/3Y]in}*mk}ˣcs\ X_yFmaHG+OWܐIŗ g&˼}!:zM6p'd=]¡{?XM۰wQ-2ch(Vv)p(MdHI1O?0lQIU>yjQ"gJqA$m}yFY?#5BOj:D 4_,{V qm%'`hKʲgZN,l]/cLٚGGT_+I{W ̈X+sJQM!bp*d4FbhQ{)sA: ],MǠ u1Z.@0u9[NN:qTTJjNj{u|$V !\BF;ajiuu; c}bKAC0æHIrw:!˚V  .gGPNm %?gAèZvX@x=YDwW6otq#uY4mDj3Pg;5-K.zP:ucƩY$=W3z endstream endobj 162 0 obj <>stream Q7 E|j/Qڬ.'OR$}.,Y1 Y)c԰ۇ/0˙ы0gbtj:։L㈉U߻61tmU"b15RC~}Ɖ=N %TuC#3ųAҝ挫P@Nݔ  \ACeQcob!0IUk :3OGAχ8 ,E;*s+^!o"89J(!`tZb)ijR>/MediaBox[0 0 639.96 800.04]/Parent 148 0 R/Resources<>/Font<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Rotate 0/StructParents 1/Tabs/S/Type/Page>> endobj 2 0 obj <>stream B l(FJ16ZZLL)Ƒ%fe_8Z+q3U[yznZPxjX]npy:]b=#3HmZCV=d1XR|#D#$=?NCBv`~W-Ӗ8ƕt,,Jrc ,B? r5sSTokGAa5c n3/ց <ŇֶnM'},W}zz lo D"A+9 -J[<O6'F 9_#jpǓN{aUOIH]vxI𕘵yY`q|(guRޅ`'ujSit߃Jij =p'YWЏZڌDbm Zi\GQ\$zMI%Yy\z2?Ho!5w ߭uZoO&PڴZ텈SOI)Ū sA1Q׌~2Ş ʰ9نaʣ}a!R_#=;{(YP< *4j$32*]}i"~a6 sO&Yi}@^) D$WO46 7Ghߕ$II9oL7X%bMDgCe}4O鮔2dܼDžlR9 GK$C>S-v/rOAwiW+)rp$!!K;b;5z!Ŗ ٵp$݂S5wO(a:\tC;X>u DF Qv=@'wU2ߤB]e MtDS'"r8SYҳ0k j mӫ&< ߇yYLdȍGRľHKC(.uF*Th.66Mi "(QmaetbDŽ+gp:]fA+3s#zHWwgHn Ά9z{a,J$rÜ"EG.pֻ@'In*)BI,,@ ? `?#dzhztN8սh耘$J[u@¯5iM(@]Rq6-@Ni+gCelr20nj3 &6N׈#1֧QtJ<e{e^߼o\ٶ?r+.atBqW2'X,siu_ҥ21-V?z{3'A|4LuF<жa`hWAΌO?Ձ_UW!0VmG5A߱Lr7f\n.AW Ed*d?e)ц'dƥj$ҳ.-c=eKV @"7jIp~ x.)0 4StMB0YkJM>D 4b2ll ;NgS<R8bU;e}|qNb뿕HCNdɀh(2c5^{,ZvxBxη20xMz~f(ǫ.uחD*7ⓞĻ#P~ җesf//4w롗 Z0DWevWXB O?µx| &P\\`}:h)܋Ed}m|E',TtRLWG/#^s%pq߱:屵9Q#x:dV#<;]u[T;tI)GoswDsAD%b׈Ve= g*Bv1*#+Nֹ`O fb =eD7&@{}%[) iƣBG)'yko߽=7$7MclAu.j 5m6P0pIIqCk"P~VisajHArwftp%ٻLEG݆ZN仐OsZu ?eA{ Kө! lM`Wjggx\}.4~k }%Oq:7" MG=8 D[_)zfS̾oZo3&b2fS9!m~U rGQ)+4![.*h|e %ϕ4-Էwt!ѤT44d|?2D wr tڀ\&rM`Ib6DO )x_qGz\k2*ϱ"b/͍a`GbmV-%{(1פm^ K7~)` Hul;#OavuoIB:~cy `TaIG,(4Ain|]>x˛f6+"[ |nVpt5HĞ;@7@ݮAl5̱ o@'| 32:LӞRtAՀ,CH7?ëlL:aDqSOwDOF·O`uïjLdfqV"<Ȓ< s5Y?{?\M+PJ_x9Ƒ۰HgKI}QeTjőTAnme*1.+AWغĔp x5E@hhYIM*"B@(aGȒ.\?Lf^9 YcN._k&&)KZ +-95"4z`|NEl2řɚY{ ᥨ0畜t y\Ӓޅ6Mj񪵨Nr`ѲZtn¶589|&?c=O+gҠHɮ-$޺m"~p,: %*d}3oܔ !Yb OWpdG%jt b A;Tb)@ \/v8O%B4oh=~ZB{Ζ/mk~RGc]]' ih8wyr^ JdiBl0G<@?_ _Av kƜE}?eQY-6m. fܤ#,\R^.z* )*\r\ 7ED=:aj PwY}Z.+p| Ip1-!"aS՘߼ɾA!p웠i%LH ɸ~.IQoq98T:O߆<1{I<^sɔbȴ(E/uxd褺n *P8_0t8Yw\ԯVʾNGN| [akE>B4?yz|$ 07$wÖB+0Q`8Crz &1O|xhj:ɹ͎Zh]e/1-N%CEH_Nܼ>@woJΥ&ć9GBt'-IYXx1̩'KM@̖|U9Cn?̠~p7 \(އ2Xz N:UQ)mcnn<,ϼeooe{蔟)^ ߐpY+} $,Z%Tw*dX.8.\Wi v\c/9L~h*mWXmMp;i6R97&2IĶ?B#f)v\@?T.&";'^霹>v?ZKkTfq"Sn/G5B5e:H޼ʪی LLu %6>}z,ˮ++L]ȩp$*[oHuǯ]}(pNm)8Bź1Ħ;#[ـYKT-yM`g endstream endobj 3 0 obj <>stream t+kx՚hQLBr53">h;WG]n}d6,ΤY] Fh +Qb_cYk0O{Z?*Y`_{>U;Xv¨$@,'*O K5h;ke j%[Jm T)r ؞':ҙp&;5K?$ܶD4h4qêk_Dۍ835(IhŒT'Xcq3}q/Z|Tr]ϼC^5iD]7pڻ8; [^U0³ i̓m|f԰I_Ge$Ϭ©CDRdn_~w`1Fh&߫SCnHѶgIJ24y܅VIf8'bq0 \ M2 Ue?g,04l:1_<VTx<IC|&CE5SF™޻2(|SIܹBYF^t`SF޲h ̨$Du{2drnvoN%4,L`eo_^cf;D$ץrM b,y`kPR' qlq{;@dH͘VQNxI@Пy ͒"X%q(40ԥwQ:QW;i{ϼg3Ax( lWsJ|]2BXH5N:\lvim8>Br͇H/RuM-־ j-dDO-4}A-q y$n5 Q$4d)~J| u( W.-ig;P:XBmz1u7Ǘ9@1*{9jcS0a\REW5i\ rOЏ.60N!Ϲw>k ΁R9lR)js0tͥsE6#`]fB@Y櫟. 355^09` bẄZ6;WBo]؇}C#4 ͚WSwa6ƊGnkپE$fCh z1$q;5BG/ft=2AnjLAR[} o n,)~[<3tPmE1_Q|zO \nk:{jb?OTJP;NZV_bd}8>"mb = w nz'ofey|?0}T􄺪1ѽ/Na¾Y df64='!)VAN9/n.AbټRse\!q%és[.l{;T T|=(ё@!ɓ)LA7?=ի-] ϚBҀN>|բVS~S׾lKz S$7" ) )[9LP[,ʊR֕ΛnjܨC|5zx_ *ή#57aҊpMKȍYjփ K:Dt ^_?''#dxugx9Ne ;;<^MHH;=e(0ЗB'5<+*!j^`SAJ}._WdV!{"r#!|jQ 9U9PɮTН#c;c*tN˷Eofl哾uk|H`WnIscivN -dڗ^~ta-qkP^࿈)T}+XBG>`r^!p1Ik"%Gg0?#rdGS*~ 5C~2䚉L-(:!pofYq gXzӜA_BgQߗ 3Xl#3T*@XzV%E(ve$U'T|EQE4kڄzP] }(,7ݵv {%^p^24ߗjQ' Cd<;T jAMAg>g\Bb?7ȩ&B!:wga-S0Xڃ̢ͥt+T Ўj|LU`&<;؃1A3zbZrXr֩']>meL2UfXqM,WѼ;޲'*Q}HH/Pņk"%y5sZ"^O2ntsb,2KY{ǖp3$O;SS1Sђ wKx#2V@Gu@?뢽ۺ ҩ%O8;Ը7V x;C,qRB{ IO5(Z{^#=qRԢ ݈@!bcP5e}rZn!"\ɉ %6sJ~rS&|=zOV\:H9:h^r'ǃ&i& 2:W37j 5ծD ʻfhQUBT*#"Ab.#Nq&80T֪z?( :WGMq_ UEjJ-r6]~.!B17zEЂݽB(ekEXuiKM{.kۮ&GR5p]zes7Gkm~^%+p%qq ^<ȹ<trmѕhYZ,Dᐫw 6G)*+1ՏųS l|[vLۻ&I< q*Dm!: ؀~uO~ޅ\)UQelؤ $dpRْǕ\MC dY:YOtٖF(,cgY܍m\!10U7y&4h}:O5\P<^00 !3:m$rX ]Mηl|ocӥ B%ޘZ3~IsЀYBҬi`3#d- Re,&H 3=ɸ waT[0v+atUKYhSQ{hZb+M Za/C>̦A]'5Z4> 8IF̬p:XRܐsЙ'K.A5n |Ov#˺% VokRc,r EY0>F֐,c<[ޔD6Y#NՎg$ 1*``ȓ"$>F9f.Su^H"b)&BRќhO P.Ob~V*c5r)S"a%|)55=~$Twɯ_z6Wvʺbq;~hj|&XR,yA=$;T&{1(Ƈ>yGdNQZiT)=H"ܔ 3 0zM, \i0Ǔu۪kg~9fIp7m `Hv.⯗~3sUUt R 8qktcqH%2>$ihmLOǏB6BI-#OQ-e>r*qdăxn4a^AkFb6]_-KT`H8Mʵr7cQ1iznക$ c`;& LayMTV0%lsŘI\;'o])ycvY g Ԭ30($DtO;)w'_x;X.#Hۛ[#q<~_Kx#զ_2wƏ%~_!u3C_R ~ N;jΉ 1iris)=0*(ٸ;00nJ$|ry*h t`6\M,cS7CextdgݟEKӊ-,߈`{ʦ1Md.l̚ɊJ;o/wݒe۱$pW82i,]X4 Y8i,2AcQq#o$<&Opr>- ٍW.H;Bx<Zr$q⮱1Y@cO }ώX/n)dX$0i: jٺAC"w`G."ahNǨE wEiWu9'"9x,NV!pDm55sy؋1LjB4ڼu\;kgH}leVhcWEcf-ܕ9U$wlHlxw0҈ s +x-nڱ5X.2|I}_y%]lQct)2h9qZ>=rvŜKJmuT&FuO6Gw1;ְ;z"q sK42zMMբ͓ ?_YW.Gf&Lۡ޸iW0T!q]=(y"{lxY4hZ=Zo@GH,hRFvz'RD`H?Z_MZ/U*oz4?R+PV#h8ڎw^7UoSP*V\f;4֕|!#B6Px:zʩlM YDgK-^sW<ZrecX9}ʧG9qR5/ t:Vq1u_c󟅬~%%moX/\QngWɑtkeqZv`3n')n)Zj=baåSS,)Azr2=}u Mgjዪhz="et%|9ޣc'G+!H-Y~UT)[=bцR"w5}Mc`0!^QD&C9R7ީh?8R"S_TG!^~>7ےlbzl]"Ds?O 7U{Ml(|z2o {{Жu%3\q3_%[I𭆗kD5`<=<E7`PCpRWz=dj2ko,%a |T O#4{+9aUJ34U0ReDV Jϝe ild{ƶ7A7Zgu{5kɅ%)1a{!]I4$ ӟ1A0)n3}Hqݎ!RoC޸bu$ꄀGZDA7ƥ#Y¹)Xvj~K ~-LJl `nD}?޳w\oXm5;&3~}TNdK(ww;|)ACyv֘'+cN*H;k׮Ԋ|0[x.$R-C(LچH8<+HHr#h/կ*$X\ݮj*h  =Bpf:ӗqbQЫ'f%qzlRFzVxVՙb̮-7Y%NNz~#}^ =JXmIVqjc kS/;vYK ATX @2l- jpK.޸LʕZW\-*_^ARH;7LA9^um2я4t 0c.9ΠaVoSŻ#a8`3",uJE ڡgli ׬h-Yqp _d{fp iYFc>\cf]XmA@qKК}Bpa| c{ ׹1GM={|#ZN~szul0)&hxi@4#sd/~H?cS[ 챮{{Eiǀ](B\b:'M\|H@*r0ǵEIt˧$$$DbW' B;jeYSR5bF#'=q[ϛPƱ{/!EY˞}N=>u'|TuY˒S j㩰 (޺ڥ=+*\*U&S6U"F9hl|r֤LnNa\ qYE;3Zrj^*6ގsux녿mQ0Vv*(n-끉~s q(X%~`7UG$K˴>G(~_-ΚKK4j [Դ'ZAntpUoI X>ֆoqH#cX%4%'gT%:!zJfm$&*m|TY3e+qI)pk'(w-r΢g:E9G#׌B͢<ؒaxǎlp v"d6K6Kn>q]!dnGyfkrx-4Iڢ byaHPrws^Wݻ85| 1|0Sh Pl:wCQ Oéb `i*s z7ޏ ԋx!E?LvhaȗnH0lϦ6Vq ڼ꼥vty5iAm->*!S)L'㟙%sPiIpD,q>!JZ~Th|If1kaT6ū%"ԡlEЬZƑM< :^0~X04K{BB-$Rn2Q0[PEݮ+-J=YnhʳMO~jsnfgU/ftvV4EQ %AEAPiHQ.=p̭4VzotNG Ȼ?9oaQB Aiz?fۜc̮GG[Y_.aǜt2g`L濂GӘxonËz;L(Iu Ǎ hLU8܄RG6_ ~LO^zyk_\./S| Q] eZSjj=_3Q|A2oxFi-}m E e_P>&fXnd(7 8-[M)m$;bL)x[ 3&*5 ݨ|$k0": `a[?YESJ95T0S^ųt o^k#`c9 ]f(-DY~~tJwv򂠭2螇IM1,r^4t317LXǫ~\X({)M~4zٰi{\'ѓ$4҆44LO.Y|xRW3l&w@D9],a V>NʪΑMo18,3^Xu`׿5„s)!mrMP-3gS&Gmem펉pnVQ#O'X4(4-d[ŕWzUVS?[dY a^nG=BN;rj+QX-Wjc}d*C6xSsO"4\q$BOcÌˬ +>3YqD"QR:$27šz-.|E-x:'ThtP*q~dEx6)EghN-vY+}-޲YK\r 29! 뜂CEoER01 `2G1 m1(<Q* u1\FMu)nr7И??Z~}y g޹pL3U>!{o^^,=(;(/*8<!F@ Eavu]9 D> t,Vxq]-moF c&tUW朢'W5Vl*UoΈGyjMODNb{pQOc|:ߧ"yjpB#58t05ݘkA|(@,CU0_ze%GGo|qQ%MB_g>l- /IUO攃 ,7D ᅦo~ Za 3w5J. Y[K aj<1ǜ;_H~?z=*u1Zv17`7܊qa Xwva􋕱n 8܅a`}ڂ#Vc[L6j=R,sS꿱_(B?OJDKKdW{WB!q2c"#kUzb#OH rղnR9܌_~HfئSV9hE9"ܛYL9۝MmJTT'*') IP ?4dv8I2j~;CĽRS}iKʅnp_M”8l>tnݣ,GDϛ:ƻ)>ѭusJe P[QCvT0런M}@Y^8CB4{D|8SQ& Q4_;7DCneDGsY5 \ą9NP_?FqуrrEɇ.vr\0'\ٶ%6ãj2+;UH3{js [FsҸ#bJF@=>ы oٹo`%ʆ>۰&?8Kk^*1vmMb/Td^:{b.}/K^q,xji:oR t!nTif.]*o lSem~~Hdf IΟ#DB]+5RGRdWrn爼?zŔvQMZ-V-re0((Q8*(V{75t ,څGR5 @}46),@ԗCqCS#*=VUwN;z+"]!<|1Σ]fߗhZEMgdWC0C:Gl;graDC޾gn<6S\ 7\R !R K[נG[ާQT33LZ?Gz?FP]A8 /4S:}Gw˦{b{JT1q~A"A빴<19/ (ʄ.hG_g^&) Ccw9zPWgxG|Y#z>7i@s,0 ۈchԖӽɗKՁ&L{S:9=9o7Zk0N^eMd=k:B/#IV{ C3oܻzdKH!h170,~f.w]BYx!7W,?ط]YzJ(Yר&_n8,[#K1iKG͗[N }ZGeJAq/\L$ެ\+C1 =y%C)=6% z\-WWߦ> 3tJžC.0.|:śʙ^\SP1 lX[0K&ӧ+Jkf-ON9ZT>5=9q1 8CQCozpi.IB-%ŀ]8=AMRt4ҩ#I(7nTrU '!=IcÜ;FW4fl6=,eSӟʐKH)!4{lΡܐVuE2_Jb6փzevj М%NCujݪ5?Zp5LF7TN?MnqJ/PԒ`,k@MKUA_S(pu%z&ʨ1 ydjGrV(bγmąrPIuIR? 8V%llYw}EFPgIC~G(XnVLOCj4eF*_<AcDޣ$wl^OX/L"7}{t[|KPX@y۱me9S:hҥE^1K WCp/S^/0vӻW\Jͦ aEq6}frODWr9=XqFh{مuS|a M -Zp4oI򫙜 XO'm[m(' EPDs8*D]ryj@QǐN`I?3Q_4i ll&?PH .BfW _whgail/Eϲm^4bN_iΣ՜>?8m%Iblx?5q#;g3.p卛uԉ/%5XʁGSؒUw\O$y}9J &NrCrYM#VĒ\_zIuhd'@׭ǰS̢kD;>;[ӢmiG$n(|>j&?5zU[CPmpٝLI5uFw UayӽsJ€v]h-z 3< J~|%H!$a0ݠje[ZԻRCr]0X8re9Z%DRJD~^os?GpIs(۫ D~!z/cTmukѿ`gfKQ[v>_#a8y  wΥ6!=*':-s|wдGdW o R紗uGbĜ ʨ(ջhUnA+lS5&xJ7E/{D_R?_Pݪ\i{vJVexmV 9C[3V3Aiet'}|u`X*yrSVrafԖ, Qb޻vJȕJToZώpqJz XHbiC 5ЃCd#F45ү:HG|T l 1c̬A'K"7 lA~Y?c~ߨa-aY۱B޺? Ͼ`ZqlfXjmTcsr_ ]"* y$sk[pHn3kU_& t ciݓBr3(h`>'>9T[eQ]=Kqyfn $`0 W ڴ&_L7 jG1R57$G(;!jcNw4Kӫ91ŎiMqlB:>@N-NqM=5[ mz#]"Ɍ xs`:OBatPܽdcSښt 5N8on =;FPicIa 3n0>FDACqX(Lyٟjµ \MJ'bHѹr 9 ZIgn˯5+CnkBR*ΥZivdqNjQ?u$Wo\yc( @#m$@O]r\=̠g(s=*G㛕  ؄8샴:|0B^SwJÂ@c,Q/@+qg* IsuU; 憎/-Pv$[!!"@ƨ/lWC<4e⠵z(F_@DfDg[HǬv6p 1fɟiZ@պ}f2e% eSyGW W؆мꁅG(+VYFL@,xL{aM3Ŀ8'aA$ vyr%rCR F!^SFⵁmR4W) eOnt j|ӇyI\FV9b2ܔ$5;T8#HVʳLyx~eWK8il|,vEr#J=8&Jw,l#rMk.qC] v}y-Bfd3:w2h^f&N! ͶO8$b'nyO2~5!k]i`8H67` D^ǀk[-w).YU8W `FГd ʊXG?01r˴cC<гӤff#" 4 'QI420 6"U< :*J{U+B'6R`1-\/IPa6a3Z/c"W%e4qӊhADHF  h喉-Bw NGT!3AWnI< 3݄'O3t#5lן4QE lp=]p+WX6fFN&qR>_tPJ=@b1B!_Jb{+ݮ^y+eР#hb'6'&*/;tA1(m g1 wc0ꅨ" wmAďZ,-9kyF:ЮhatiZ-P a۔kC缹\Om_䗆N*GpDN= Eh5Uk?qyActy g"|+-ډ_}Q Oə+\h\״&3vnyv|Dx!+;ſv^/=D}"qhÏfב0xBjs!SfR,o(5đZr=k@V#C6UmG.!aL%xI s)>5M5'C@ۻoI޵Tcz\9-!acNP=<ĒK>}}].쟐ud~]pKT>WW("{;%MZ ?bauıA:Z% 0UmnSeND}6"i>[yuKկgh pe[~GA" P{9̍۸SA U'\(*IL<-qIQ+#,|< b"$My{c p-u[:=[*$E\o ssYR뤱.yT@%kqSxiIJ4;ls۝h,Q$P!&bʴWdnG^+~OjitYI_[d:+s5ؙ9 %TmP2f[P"u\&=)\C3-?+GS3ާੂfˑ!"]?u4VP CJ %+A7tk. ~2T2V[ OAhֲ0Aа#A gzxUo- 6GxkxDY~ W5"O8=ZDPYuXO86>jyP`ytK(9P8VĘWv\OT g~lI±K5G5+,g#YnX\,TF=#z͢KrO$F8s6|KkkE_;a9y"D jaSd Q5-jae 퀃S"KٱFdɃ)H,  fea  |,FAA/v`vP|^Us9ęgDQzf j6 nڤnΕq1ߏffHvek0%_(+0@K.P)qQL G3LUŝ?o!Za%)zTe xXLKv,i?n\#$>BQ $1(ґu 4>=qN@)sh=/n0Z/zGHþ雪^ϠQ\O,5P,zK򲥘@q)ߕ⻠,;<$$ۍ˽/CuC.ե J>6 $.|-4M[@ n,F8O8 ^7wM!yItQܤo|xip'B ޢ0 Fy N/)Њv\b= qHbpE~ =$;I}WvUGj ٙ% QӺ~ʁQ5-Xll,'"xN!r\唛| iκUIUW{C7vfঊP NSSJ̗y*M=ɺDųRi2LVupek#>W><+#~l{$bOHG%lD&Ý7EjޥK=YG>-9[kE5IR|5swFbm}>mFQ-83Ш$FExTI6ŜJpÚ ߇n㑿M2:6͠xp4X|)8j~۝!V316mk Tv({V4,-SгMywq?._KV֥*,q肯M)N'U>ͳViem%?Cbx JmkS r4U&p(VTIJLžFm0%e#Č;ѣ;lȞ"S-O)MsۂHvl}w m&d9SujaEZh}osؿu3VOt'4m&f́N\6K@z&x Ry2%Dv ֲ:TVfgciPZݶ@4˗ OՔYoLro5.u_~m׼,bDFRi0䵧u /$RjG)@9PuZNQGJ!\|lm~Q,74Q9*췷IG%Paks>b; RiJְP:{Si482[ǡfPO8!x`-'kUʘaho[ 0 9+\"HbhcU*%Xѽp+NtDoX;^5Sn~Qr BJTy!,s[b#G'd_ЙQyl0]d6mTQDf`85E$ +F%,Qc Xt<)jT8̵7~8آ8@%q9N0ݴY BR_/x4NQI_E@nz+xK#kp <Fm^Da!9<}jAF0iK=0M?uU ׃80 ^lVN{x>ߠ16Xp*$_ςKZٍW ~g#^GsFR:JƉ@dLڿS7Vlm=*m ݠUK`Q}P3 ChivP39 #ܥGiJd@ƾc9k5Ϗev[}@CnA#Bh܍4=kxA/Sts$~.9&VOWҮĄڟTF9PݶQpԅ Mr(;Fo{ G({H).s;&v8t*䄵-̰R0VO;6K?6YP nƭy2ENJ{N erG2 tS|Ks&> p^J.3}o])L4ԣn{+S@pmMLD d ?EoU pg0)BO_ c@A}rLrJ9׆@RF^\=jiJ[B BruiuQJX3Pȼ#wwձʀ1/yN/YuUD\\@iuoL6Bo/FU`@қ]N "jb=ג< GhZCI.C'ªJGX5\lAv{#NCT憅 4}Ǣ=١|h w8@ $8EN c[HS* IiO_@ 1 g_EcVdP^lEL"˰'V}\z,Au ]"#jwʀ]] Pk|)d Y'O_.aH 櫁("D}/BȒĤGr)OgJ}OgVz߅7L3XjpP/`},c,$XMa₣PډWrU*9sA)]C=86ӺaRÕLCyp T͔ V>cU% !LSNH07#rC=჉vZSp]Y2*_ ͭ iUYrJGD#!a-^n=66WXZ ReT> Xب03~il5KZްAޅ?FrAG%B9,Yg?)l?1NyE6us G(U'J5cݑJ5A6)[CKaʶ 'eZ,m1\4 [=ԫ.ޠ!?FˬLm %PwoS©(w@PUb(G O>i*XӯNjMBlċ+{5?|d|= &tc@GbLѶRC?3"4tOi UO4-lHEaۑXE;Ӆ.ܕ8%15V+w$T btJ{szpa?h<YɭڀbfrV(e >l {>Tݝm[("{QD`=BmͣRbdC_mKrT4tdil/928jTוE-O$ݞ"C%3h'1K5M(s?~t=S&|w|>0yΗ/ꎊ8t xp#OִW7j2j\3މ 75Tӟ!/AХOaq40_wЧ>M7AQp Zj mGL4s{d *pᓌ8 nH!#s L;13;A++[سP,wA܃W^o~Ȓ^81=N5T^Q;7pXfZKj ~QvHN]Cܷ+r-'\l  F]+]ѷ|xur2%ܗ57VÕ?cSoʦ87vn@ Z ]rk>xn3QPd[:xy'Jec'o" . 4j5nUdp_yyQm?jܡ;GIc0xLIQ!Ò1Fz: dYRnM泆Dس-#pN)k^<:Zo47 c [Q^KVkZ5=xW/ČraA/)-'ԿW=l )D#hC-(,z{U!6BNvALٷ{IFjHrbE>, q)Qh9$A{ҥJgor0B;v.Gwe>?i|.põø0RJ>e@{ntϐl%TӚWѺ&~n!JT'{@'>Q7Cd5eKL:h]s6!2JEਯ $ 6arj2'.T e;JPƥg;뺉7e{_Űl}OcyTp곺Ry[F2vTA1%c¯l90 Zs.Ga$~օ r4R_'7>5p}kԨ簳_Rrw/ik3qDŽ"!OOk;Z#svIDXg _'sR]zAD01Kx`_}sG XA#&WLÂNvwڕ"^$g#*,E/hA$+L[Pᴳ+ɣy"-/7 IZ Arj)@ukɜWYfqw—࿓,b=@RSHXPcBq0,0Ã%_ɭee-: 95%RDc .댦u@Ls$"EhVс)Y4 R'P` q }C).q=ؿz l#<1 zWv}b>aB-P읙W:qQٝgι9NU])DTƙ6mHIq K0:c: NWM7%12лrXt.+ As?4%%ί$UEg 1;2ʂ~T~C2"n܁cf@pfΩJ-FުbӐGبsgCy 2.!k"iuN{IY뽵R'# EQ'}4Jn&#SuI&و16Yhr >"֢yx*4}x_GV6MvQBvw\-tUش ;ib/3#}rl>DzknV_A5 ˦32DHԼOp4jw0z?>t23mkze.QY}hg_]3yxx4Z eX08 ДoIpKO7IMr$ jxZ +(ao1wDʻv{|i3FeN{!gP9inU0 ݊SEŔ"J8GDT6bt ယY ,ik-CG$o4 ߻|tj|t q4MrYoV_ LQSTV_Ƙ~jĞN Ke8(B# TmSw8+!rl40𠂻Qe)Pe,)$Fj&{*yhyEeC v7'E_=Tj'Gl^R/зI4{ U˭ >b:Z VۛnF|m Ba"~9VпoZV^}4fw 툻4F@3_ATO7}w U=i@K g9(IϜ":ov a_E程!@(n,~LTiW"7c1ќẻ" k5x 2F.GQ&x&mLr&o>c,$(LS  juۈI 9(j.z% fL>vA*U>湑gg<,۩x A ̲tQ۳B-M ĦB3l6Vɜ1nfo ,&t=YVZLrP}2zt22Ql85+;a]}ɵOX+^h`F%%qm% MMY˚O՟ŝjrwjodxwrV@ݮTz0+'}(NݴfxVK;|1ˎ]- N`w9q P݀JAh^Ԃ|aQֈvJ%2  z>Tfn #P11KR #-'cѦ׻Zġ+2!:B$,VZ NPEHԠqwIN vRq>q.^X|*qK16)EQi ~uBp}gc5y$4c U er1U%99\@;t ,d(MX&."F"z(XhW5:ܖ!=7%7I(H:A@K񀛓qq՝o {;6m+Q biO6ЮDJ/k%L[41Ԧ(t t<NX}rdct:?wz+Ƌ*nrn*e>k 46dk/Yf!-#w`IENXޛ0c ġ1TXIk5KtX2ٴeT|bjgq~ٙ84  -8T-<Φ /A5Typ$|"TPmygR`E)yDra=wv$PSjFQp:׿4̘&a8c?<4."q_Kg!xuYAX5|bN &FlrR0qU}ltp/?/Z(U!t֒;LI;uZˆnmz^᎑alkߤC-ALHp{]G4LMgn=wfmM{;>OYxo1A\}rB+E]Rgu= aUKzSPI3/ 9}֑*~kBY@.T6C6v5ǤR.02B#M &Zqa U8$,Vf{4Lh- 14^nk|hdoPեԳ̿P ֥\A %C/H' v^Es}@,$nԣ' #ਊ71~z^bKG bKoSP!րWp9Eۃ+?RBnei"Ǭ02%/1|7 `6e#لӾNk^Nќyi,{Lk햹Kt&KZ+]?];p`^+cËdu,>t LM3]mLb2ʎ%Lk:E)ɇ A?0~QoztQHٗqX2zfxR1+~7Bٲ{2$l7F0$^r XYBfLi&W}d|V8MsY{ )R8?GA젮ɡEQIC@20Vs. O'~4':aTqM}vJ 5ҹ2]A 967Vl7\yB_1pF~E>n o:B^Q*<hhCZq1^qhASnj$bL&^ݡ!3.-H 4M3/@6gT?f|[Woy&MW &9B c &\U Џ=;5VbuK) lZCv_,C{X M57#1MJHKy`8ծB;}`VB.7ZB$WNܣKCu^ X,\ F31 fܡ{;/ea߮^0w~A(0]W)(}Uщڽ}/ǫF&2 Ϻ&ɵehߏ//j8OIO$u~._vԄAԧѦ"?D %mߌ ˓/.BešI<3R&B!?@@SHhP7LkB S70Bo-Zn!HmG?5'Ò|FvQܩUә_)^ؽu4B] [CcVcGU!- h=…*22h**. WI[% MZRe6S성n;Иnjf#?"{O"WLi>=X85o(*gɭLOR}]_|~`ȏcG哟֯ފRځ<m B|^4fg̍ο-b'^i7ܻvJi *rQmRi 2՗;Jʷ*j塵;64/ tfFy{gZ:#sy@V0 M [P٩͂H\W&h]ґt=sBꤛnE!QmöK|`WrRy/@R%HZX ގY>ßP4o)GĝhD` K+>q`iS]DH^xQmlqOI}4 ܙ߃xkP[fbeSYAf+\zctl~S٢` W"`Zͮ.c=AfKnrjCI:p!u`d"~91;5ΚHڽrc5/W(7x́T5"Z*F8AS?f#0Ht=|*Q<# f?+ ݀~ndHEh:YK[K.g>+{HqyZ${ !gZe'YWqCF~cUny=őCqLSQ\>N!R"2ǹh!\t@4Ufq9ur9t{WR''0|dZfF7)H`\-ٴ-~&'4pE/e ߍYE'p9za+8Cʘ#KNs}ram**2Or"F]Ed?w1@0vM"lA]r/5`nN2}o ΄["oJvj@j8y& PI$yT[!sw6T{ x-B;v`VW@Rep=S#A4WǧObHEx6}DzCP8Ap Ğ~ä[(\E0"{MmFzWN?+kh`㛐jy6|P6nY=RC!92ԐK%gg2BEQ=XDnK,CƩH&9_K&nTe0[G.Ԏ@|U4!XSAY:AA`jvrL=PqqZ$Y(0iX-`ߖmJ{歓醄,Sm%E3; ̬CEsdzSkɸl9HגcWv6%nZ%OS&di2!!*Rj>s5bi0~(h7@e_[OQ,[0 Z%Á6,׸a>Ҝ?=w|M29{ƕT V`q]xY7D^~wZ3W>!g 7MH׺PH~sYNX8Cf>"t\q[9z+a.ḓQN-|hU * E\h'#sdܤpk6LH_^ckr5]%8豎G)m3hC]UՁ{ᾦ5.tڹΪV1KSv5P{útDEzܖT16^GpYf@zU#2"_c[.!ڄZ1){0k)ejÈ:p;Z̓8>gP{/V롥 V%_{Hu/3"5&w.ޏO#^ϫ4H VehƨCkޠiH5wZk=XV޵(^CCbܬT 4>3Ψ)`K``[bQEOgU!9D2JP'x\ZVa].ߪZA4V{iUWnũ(kF>0_b9oawDAr= g|-%,Ȫ8W0WseboSgx|ƃi)$ٮ_8^٢xNHPU$cHNSdxm*+ik ǭnA#'M:Vq깎E/b?KSLTOTvX:x}9M-ܤ *`ɱ.Yt}߽|*GG'+c x8j:dZ+ ( ^ ޹0yO݊H,xu侏&?*#8^7 *n-A~[gtz)! ۳8kk_wqmIO(!lt?mn< _Pš󿄯1A@p!ܓ~r BOIŧ[b O`<˗1= 4}JE#@@S`[;H N~=XS %=2-$~ ~0$,qvnހ^x誅v y7_/ 0Al]5-vJuЃ[*P5( 'YY=1x9R9Dv>.$eWqD1k jyș{uyc|GK2a(|=_J{8GUkOU+K; k4k̄ [m1]4d Z=]k)yIvr n7U`pURxI\3iL}[‏M $g *wc! S]-!jzB2Щ{=7ν2+*FYe/$6ЁoX12 (oNSrv_'ԵĨ%t,c{wmkdMLA͹9]O;3gQW'֮ rdùWxaZ"YUwKDa j_ǔ[~_8Y7@=0L'h@|c^WBK$؀RO{+ !UM(/-T[d*I MޕM6?{Z@L?Âڳjx1-]Zz- @ROEmgD|5fgGȷj[_3}Qe(z cBïdt:YO=q^`lI9>_%іe~F4R>̭ܣ5+D͇%eK4/O 4cb/U@6C=-9%gȉ8p m 9T|/4,G,K4W!&*}?2p\ *9Þ2Z R0_哳U|t8\_E!hWG.KQ~F}ҩ,*9:oĿJTtQ!2.!啭\J"m3G{G)`YW̳5$BtζBQ' T.om&+‰/\v\$rYY6z$8WLnfj$ TO; Zyxl*9=L'/i0_Kɖn>aXԴa|*K֟N.L>`= ,:*k ;p9A 8-Ü#GʟRnx⩋ejj_Sp T~j.^|EsJ&'rH .__}{}EiP-e38I.$vMB} ,xK>~f+ (Zm MEcajh;wT⋇ǼP4fGTB#Ky"@oxlYDzQc[Ͳ#sH ԫ&p~ZqCj W nd?|^EWXYa-ପ67Wd 0 h5=0;xh,`> IɌF⩏1 -;0̬j@Xf4 2ÿGF3rE4Đ[SɀL7["L}|W0=H RKMOMZdx{5B_U7u ;5˱OH?u_ӘǕ,Pr9.Iюjmj)wӞ27נ6:f`I"(BC6VQ H#0SJ;ygC`tވDeo*!ϳZwgk%6 Ʊ{QEE#hJDxtJm";20#ƍslF7 ʇ&z Y`%9\(V TB* E8'#2%(DRa{$xFze`uw-%J#?Μ-K9(4Nd5ge:cSh/`#9%kףΣM;+ǮԚ>̈J?%CPwMHr 3JOZvN4T @˨#_%}jNq݄e׽)qd`@k_)8BZþtw 2 ƮΕ<` ) ~PT-ON= ntk'ZS.1!Xݒ$ bNd[ǽw]d`ޣB2gqfq~u Cb#O' =Dj[ɂN*M77 3<ǭACYMc"XGdj@'5ͫ$]g#?Z .I5YޒjC./DSO*;|‘eՇXkCF)KG'wHI[yEPhh2m[BU}k[!acBl+ y JQG<Fk M6&; P $hFh6'=  ^ 0Otf0GчfP佷1C!_^rxQX@7Z[4aM cba.aT&1GGTg2,/<).2UU_2̭h#jۨR)]>qX%@uT>rtBSH *)t.sU4qյ+_>4[2 2e(I ,o#Ր{\CUcvE'aU;zש vy:E|LdT$='} ǭba|1S=' OyeͲS[#~Υ| H=#F?9;ʺ֋"ܡ%KVI!nABHVUC! -hK$fl>H_hp?/)"t/@}97IOv+^z??X_[:'N`y s30Y0k91tsʝ7'ŕr~d;QcvP{=~2l݃MZC wNJ ֚*Yۥ/Fm-`2X%e.ImfFWaȘc}pm;Rݧe*DH$S';]a6Jޝ;u牰l5M; t Z9j,FAB+YS~~D&{ؐ(/Â{9Lܼr9Y/H~U`bG,j:&E0-s1J:]a^Ά,sJCX!XbsL7{:ާΦu&kLGl)2#GLGalϊj[O۾oj9tà2+m$H Cuj@ Z70 T:Y R2њMђ5srVΏLЃ?B%:hMI[Szcd:\*pWZ~,C1$@ ﷒HxjJ/ 4I`MoH. \T`58 #Dq?RL "4scf;z*ON#oE9͝1av3aX(|o$DorY:oR ;:[Dz Z;]չY{"wiBh|`~Y=$&wL;c>A0̣m+rԄWDnl^:0|L@l~V-r}:R]E ShTfZaIՠF&~5~I K$!wNdt'~A6'Y6X(Q6/Uϱʮ[r:jdiڀ[-+u/R4= NҀܶy&;#pJoAzc?ܟ *r[D3'Fip_xkYى$A п҃CAܠև pX㝻:lK0Zq>%}ƭ3.qu Kz:%ō6(/ a>r{%)= !ߜMtEO,tzN0K e/9AT Ɖ"Ġ@z]In 3.-6s<({ S!49קX>^|@xj0_ .06E^nU5 "|9r8D\o%D>yP{WBDnu- >g>6kVrW a$唁+W%*{>M ` ,W۪#%2rTJa?:.mY| U>пFxs8y¬䄴Ni\OCrh 7`C_c|wt{NdZہ$.N聎 c}l1W}4iŠXf7e#I6G N{S R\|+T:\5ݞ v0f7ҋC.__r;1n<vV&5hZxd-/J)$P.K},3lcв?KB›Md}fcTzWx2ܠJ$pOТ{>LHFMhؖv%i8i{Rkt:?eq㙄PF'ܱS/)q '~XE2k9_^RvA`@["nnZnI}!Pcq$Q z`_4e F|S 0$zXmXg ]^lU->&vv%J6/]KBY.^ƌox*j]跸̣b% \+ >}ؼe(-|ٳ٢ mu"zY)Oc=/*34!xPK˫~ e734%h3 FG'̳W$AL3^ `ˏ??^( 02 Xi>*Og“:twƪ^⽅f@oqWp_Thȱi1M"ttq9؝sR~0z%(_ݪ+  'ç_V`Lf:k ƽ?g@"yyWGdRq ^Hw09 3y&vTsbul8 >fX׷W0߷^s9x(ŝk*>i ij*MQ Zz5Q:>DTE )R/kn5XuI/% nй>)-ƳRN^"LCw]٧r6s ]VVПt;!2lӥW>1yY rΔKض)a hqf@vRD%"kjTe1]T?M EcܸhiaE(ATRŽ=LdYɆ/>|Ws^?K%*Vo'pjx6}*Nu $B /qWkلIyV#R1L_lah7}cYs3ȬQ)H @j^0iY!dM >eˉSPwxƕ C$kDrc)bұ%L Qe '-z.Ė(T w-eY]/Q8j[Q־1 l+NY}|ڨsG hyn$z[lob./[.PYIЯ<GIP@דX^5t۵! ]# Tre@5@=;WpH ȋ2(3i /A ث6cdީ! N\真&a@rkNB!gwWSFkךLP5^˕"(Ne|.يω8 @2:׎ݭ~"|]nϫ(^eQMxIy6Y9(ۈ2"00^2 Tҿѽë~VS<.ƀaAț~qZ =!8\-C}D`yu〕a WS_n22^g}2GB*@m@Tzq 1U,A.0E2i0)|;n3hG_ sJ*ߡp gY*bSAV{WL9e4jfp(HYʽ`S׃* 7]M߶IIVqTdęƴiؑ,ו?\]4/hPl2j ZONλDԙqD5l0fgJXl,iR7sV '@Rw0Z?tú 04(؃5DK&vWAN$~?ƞhܢ~˰ONOtr1așWHItZ&~uM; 0N)0''mL|̄[i=g[ߘ cLt4vF `0y0lKMs\2THӱ8iX@qMZjB>gμw%f11,8:ou:K]p*8yr;*2z+CY^2D)8> "ں°K0ߡX͇۴Kd@QMGy( [_AҚ(sslM**[qw%B$5wl3 SQ: uXKhnҤeҥB55g׿\qr2fO3}04xך3&,= ! Cݡgۅ0 EY2G8@(/W V㢷m;<S`E %ULwt:TKmW kw/m" Oh'c'ͫKrmH=D*[_BW8rc&|fˣqt'~iY -⦕?b*p"vTXt] rOJ1&szÇ?ϊ<h㝙ihLw>GH*"nΩ[FBJEwYHV.f_FX `0vO)P/pEK} aRLGB.b ea2򙜊>޵s2_ANtjSaRtd iaU!:\K4#7Àdp߅I93}zǒG:8%xKfA c`61k&yTFq^en a ZlZ]f멹rK@D2݉z=3R_m-:q8;] \mh_xNzZ1|!Y%\O@5׷q3$֯+nový:%qS* u[Txd6lOVxc9+3T;F@cPDtWo- Eh HVșlQ Ld l`fsgtt=F͗(En^ʜJ}L23=NFaWC?Ҭ?ݿlVl~iXsAd}}pO sJ J@WﯠȠLVX-͈=l,ͿlDިA= ANk]o5=Q``l۴4B t9"0QїoK#dyJg) o#s 7N=t%\Mm2zDҘ^|R65en[W+U(1c Vh7 X_bSp60\U.o-W ɇ`jk7͢xX; XYLҸCJ85¹ͼf& ̑2T5?D L Oqhٱ* +M|!zh[2BmdHe +":vC*ܲ(h}$\>T }݁xeE ŸSU 5P{ bD# {=T}-Fɪ&y$a[u}~ 7&[-ZHj8KKYQ"wx3kga Zzصl*8VWm2GerBp)mx9s 6U:м4F%R3EV#2qFJ[[N,' =t6);c=AOI$!&k EP,ӂ_ax\ wEN2=.7`yjwSr"6DEZ'K+tb f15<j5%g9^e[ Nj:Ħ֩T80\g=2ƐWՊʓ_A>v q{b2z$ۤqHn^9&VIՆdNVdZ B,Z[A1Gj⧣̃_ö&}_s ӊ"RCTOqۚmX6u~miHxHQDɆ|wShݩqzbJ; Փ&Icu5i+0w2gyar{350$B/lUtJھq(s ?(,Ȼ(]H[yf7f}7uݼʯo ;AF0_,#Բ"}2w˦eieM v`v o:ŝmHq}-ڣ $̈́p%hqx:pXpE (ErԲd"J ̂+q!X 2`jܹhZ p[5x fq:>[}j&3b>DO@4GMGOROEQV!_K)Z=Dh9n +ΤU}ɲv݀QUb\CȊG sALQ qZ Rm}SCRtoh$S߈<TFBqD & 8?uS7 [+UvGVQG^¸TQe?FJyń=sTaI" YAvZmn|ĖKz)Gu>֪os{Tp |0 XY{ [.#w jSx/k z=?(ٛv gA(f5B #pNtSȭܾ/ׅ+w)roM W!YVC[(<3֪4`on^d3t:ĭLV ~ճ LXW cn \_ Ss5G G4ai5IL "((Aqoo&9fn "W ({Җ3GI~Di,)fQfr3/pSOZmD!x'jb*,ag8ixNRV=)}f=j[ ŷ`+Zw:ʣ"KNB/$ZI8Çm?9Mri\d8zw"#8OgqN[+`Ѿ<$k k8q+˦Uͤ&/J> *-Pу$=xa[k`hZ`#-V`3:ح#9#8fO 5UL$YZM9쫔ˬ揿nbn]~]$ 9Aa7}LWdNq: i+Nr9%@ySn\3睭T^laӘ?_h9wӌ {$ZŹG^.e R{R7Oi>K) *8$3dV^,̭oK;} ~@ezByX$NՓ8u {MzW 0 َ۸bdkiQ*3XC MtqTÉ-"$7vٻ@_dMedi&=Yh&  <qew:Y}|;a3iƬÙY!"Sq䚋q9BW9ob~ٺkv60;ghhdL֌L2]9&cgRs+n301f7eM1؂ǟkh4SN*TWjvx=B Kҵys>xfUGc)}|3fT>pGX_fniL+Ⱥ bkz(e-"y(0tzt P.&?tL7 :cFw,DBQCyDE)7!%IYvKEQITs%KTw{ui@9_ -,' Hb86)&ES Nx({Ƶba4RGL<pNC)=~FTl^f,aʩeJ"GY,Ŀ{V J$I#I#W!QsC[NIi`8-<8U+驮4U~CGa̱3!JsbMVme ToXA$H'2}3#wjQ,L_9¯Rٽ#%o8KPc)Tظ8cCR]ІLحfkh YY>ZJz@g L1i>˥쯞N$YoF2I~3u9\F?8ԴV,"Hc96b: x+PS'ҊaXF1ء,z C~B]YyJ>v$^[݆Ze_D4?@Թ| c\" ZM6] C ¡,<|dfK8X|?5 3{&W? Fױ# .؝x3D avÍ Dú¨}Py@_zR P FcTzerU]9kLٰt~7 y|vv|“TZ3۱IS7S j/;k h*G!ۜr Կr~jGRcrKXS0퉠چ>5oS6> xg=6#^{`F+߰EaF $Պ mxz[vƱb1OY"w)v)Z<'z|`,  lC(~RWvaW;^J1|:OD+?ʓy8Ru(jt*I 1njBh}6"%@SP Rp֧}|u`J ِsGn8S 超/Qu^Cf T({)& 4TPZ*ܤr ݽ)ܒ6f)ӳ)cFGXC .[}_ ΍sɢE6Jl, "S-,vUK&Q R(Kj96V QY8g&꓂Aw(}542&W/b|yn `!r8+:h@XZ˝-Kvvpza> [F Zݙӆ۞SP,x?N(SR&2KqEO24Yr%<ŲnbixLfؤFC/ Ƿ#s| Pb=I\>hJq=qKKH86|(۱ScTЖ;x팶ifZ_J? lEej_\Zk\o(lQ&[#3S3loG>Yxg[/KF!zʧ &7fs"mںUC܎B&:Քp8sV z l <"Qit]5l^>U8VX#\V!_ka!COA5DDaA'#mEewni~zO8A8Qd#Ud,`MSmf w>S S]3T!^8*\QMmG}`Kf١զ_X\qҟęZZ'e=2q+7j@ʾg7 ` ;/!sx1(q0%E d&7c9 sF5yJ@ZΞNJWq8?z,Z4Mxn6e`Y=5Rˮw\@l&#ne4"_l}ڠZťGԼyc#eY/?%eV9^1zKJNOC08xɞl?t%"tv =d2u C1JoDVC(0ZAIjړy/o68D,?76h]R'[F,} I g?[=BF{k/;W @u拙ee{ 'prp\[֯u%b}7atlPj9/[Dhk zxE龐/%o,gYm\7] J;KV9Y i^<N 8v<.[hDZjUT}sƇo I/Svwe4H$[nfpֶӥ~pͅJ$+&`q'[^[d&N7h53/U\5ܭ\괱Nf2xaz.ÏJ&<SsWE ^ AhrL,V]G1c+!ĉ;JcP~GxU[OcU%7UT`@5 /`BWYtw _eEsx _s2& d9yoq8jqqLa44l,r_˟ot?D,,]jVgRI:2DQO.;L,͝-2Yb reO<)QGLE6P3yz1sjh!UI¨o:}w^j6 c-K#a$X([pvc64Zpl*(=KeݤtrYfGqS| dnb4TFBrLz*Ux W)IʭgJG CFdj&A?z"/sThc'ypA/|ӕg0-zhMVdW&!R$o<@8RH !"psYCw5)eFO٭9/ӛW|+_ 0=M7S[yFIh!!F28yb*&_kF4d%)>`:m Ÿ1^ih6uMrR~Wz; "QJtys;$S 0˷zyFC#K@rE|o[' Mt9A,Ηa|r7s ך)C}lf<{  Wix*|^r\f_A1>, hN7𕿪镃7a8"ZM&E+ы7Z[(OهR/Ϛ<=q0Vg*K{ԃUH9J~^ko-]A.pέ R1a5ho'S:[=O#vx'ؓ d92j׻[Dl\Q8ڊO=n k _͇ "k역I۩U>X96k yu!P ÙܢunqǫG`Gui(>;! ̏uU"T5Wa;#&bǖIjUrߩ3[]hY\rZr+Ɛk^zum"т.Q׸saû_oЌ;Lg.;aP @{^QU\3k.Fp9QzpƸJVr.,]p@؆hZ7C: k'ӂ׾Ba)F DyRSj3s2햔BR(4M'1GI`kL4Eoʸ T7 xGFyVZ$,Vko=UvJ8Wum2MP)UX~@̶` Bl))J9cpR,KH"zYZ"udu^O5:*h8bRKx!+Oh%V!؎1Bfi ~ok",Y5"TQDUv*""ؾC&a.K6WbYHʅ2>nӗdz@SqxmBtf/;Ȳ&CAwbo"w1%5@E1F6XX_sŊ'<}56 y9)k$(Y;wa+gV]nปxC [ГR-yH 7i.Fn@h?h̤s0VrMd)M4/cM$r #H^.ԖRH Y> CֳUC*< @) 3*5c~$A`YVLqV\c Q*}_9ʝu2Ow3`̔+eQػ{)OB]Pp"a?^|#Hָ{X2y\3n ϰeuL"6>\b%?7 X{QL$cÍ'LCuHE1s4DL=1[];YCbG7?3L{,tq9&!·@Aۢd{ڝvl $ߧg9>#Bq抑A{M{6W#:j* +jɊ{RK$l])df-NXӎ2hÑG2,74# a+ĬwcEn<߬P;eso\DW1Pi^ ڐiXHA<7AYrLa"r?Et]Nfc6(uXgNOJB ǼuaLm2n yu#H\M?bwt T8 4Bs[W_}Af}:D *.O"7=}^|{.%> d@F0O;+cޯu ],Z5gX, i $_sS8)+%^&ékhg@ւ5߱hH,-=CϡP-KWt"fޠјHx^<ކ#=T.r>{,T"yuaBR^~C"Y:FmMAw踴wJyJ{XG!~ڝAT,F6)d}Zk?:'ܱ,+[1%^`bK #P)Q)nqw~>'ℕi|30'$lÒo]9*yDNcUEN=u>"CDiT}?2;ɂĎƑ9Q7h>҃$)Io{L}ytfc2ҕ_]IbEߋPjNCxLw!( +VOƥ=:Ia$u-ɯF9t05b0HJO`ʑ={@q<2)D5jQ( 0TNy{j8RaEM`nx G^5!2v] ӧ.m k`g0븗4kx@]7H\)jsdJv򘢑1,k \EvQ eayZݐ %CpPum(x|"0rpr*% :nAqSL2;SL1#7 2qr9twZ;Lҍo'Cw/PĠB `L^"Yмj?׀=Ѫ-ߖszH G3 }QBBL&}]vv[\ݥ"u7ٷbkoXEtȕsq,͂x# gI&[△N2zsժ&\[գ1m@)cfgٟAT[ٺ6v^!(A&l]Ig3c2jrOx]UWNe }VSʕ7D-*^vLoK Fw3YjYŊ- |{=ys[#~X:GGk ] =}mx6v1MuKVxq-Ǚu=)G:6G7aj(9FuIc]?~hPwj;lmk+AM\7g^B'+Ld He})+-YMFYޫ;R=6®j" ! /;;*7Vcy[MSe}[n^mfM٥mZ/6% tlT}nhܑ}+W(n8GO!$Lf(mVc6'EQPTh}j(z˯Y J1i]IG@(#0amvF( %U j0i2Ǐ1yWdUlRyp}\+xi|(Ed(K%dty7^eZ/,n.=Ix-SAdVt0v!68f s7Ԯ(SR]Jە:%AN+ɽ! 'MJaس endstream endobj 4 0 obj <>stream .C9ޥA\>} qOdIvȘWYx+d#`.{ןYg"̜IO Hd&ɿ_nf\m1к24{LsNDd vb3Zd >t uoXTG&$me^99W }x*Wd3<&В1ؖDd|Yd6ZspkyQ;dh1w{J C>jW` L%Ì0mlz>stream 򈎰udA -bZ476+xWѳ ]-Q9x] z_Jͱo|nJ(w ~ JI Ok)wj 8^~$^~B׺K{U};PWh_I]6Zvdd gzmT /"ӊ2v8nZgMQt,$@wc}Ȏm͢z]ٞNb%+zBwʯ}}<"!@`9ل҅1|qpK4<uJK)3C03H{@"Sez. ϵ٢;S^Ȉy_ 6R*. kޥx@Ϊ`:j=%ACRPу4}mI-wr+pбw~\+Ӕ:/t 2P35Y6ӅVL61U3njs~iX锜 endstream endobj 6 0 obj <>/MediaBox[0 0 639.96 800.04]/Parent 148 0 R/Resources<>/Font<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Rotate 0/StructParents 2/Tabs/S/Type/Page>> endobj 7 0 obj <>stream [ zh|Q=:.MN7lfaC}"p]穉3M!^[p$-6F0,nA~Y`e5@>iRZ2ixSȅ@F)8w, .2ϥ%<(qG(˫̊q9Ҙ"Y4NcspTٯh7U褟BĻyxxCo4;hM`H`):#4,kt 5v !vӤ0 Da_[Zv< gC#%أ@n޳y .r"v$ ?FP#E=;a4ϰ9_e9-y[1Z?}Wt{wQ!T0 endstream endobj 8 0 obj <>/Subtype/Form/Type/XObject>>stream Q3m?:@wJQ 8:_:!Xo. endstream endobj 9 0 obj <>/Subtype/Form/Type/XObject>>stream 5LHSs'.ͽq]o?e/D[ endstream endobj 10 0 obj <>/Subtype/Form/Type/XObject>>stream eվA4T;MF2Ï>u; endstream endobj 11 0 obj <>/Subtype/Form/Type/XObject>>stream ^b/xl{ʊ U֩sfZyD endstream endobj 12 0 obj <>/Subtype/Form/Type/XObject>>stream +=C!Tnť?늉؅ 'mK endstream endobj 13 0 obj <>/Subtype/Form/Type/XObject>>stream {ܽv;-80d^^ endstream endobj 14 0 obj <>/Subtype/Form/Type/XObject>>stream U.9[]?uI <9fj7 , endstream endobj 15 0 obj <>/Subtype/Form/Type/XObject>>stream g81QV䗩5ﶂpsPҭ/) endstream endobj 16 0 obj <>stream @(/G2l:Fs2y-Ïʪ楘n^|a$ۇh9E!q'J1ڲugO,|@>?Q.w|G|_MhtO;{S"͚7(LS 8P7b 3 A3ږT>kJlIaES vqd=Ӡ.WR}HC Cu *~=WQU퓺׋2!(Z!9;NWD?=˹X]_.ķUd%RK⏴pzBv[8۞4o Aj<8$ߌ C'8Z8u=$ īa݋L_ k F1f:o;⏇Cr]Q{S&S B! wؑKG}8dY6*(uo<ٯVPJ}Sjx37tK/cۄ'͏ `ѣ;D xZ[(KWȒ`QԋogΛAϿ%`L'ϭasa46<, Bh]G+;w fa &vvŚCAjhĆ2&r}JOv(u-˹`ȝ g|a?vC(g$H׽*6CB_o֐6ZKxU-{|(x r1r]nY ԧ-UmH?Hͼ0C#dm97FNDsYjt?·/GG[l\H_D%owyb)K|j?Fł=t9oŸ&?,KXmo4+ZhC|;:Q!A򑕇fûg-V"(P(Rv3/~ s!K#^\*"*GD,p<_zQن}Z *%\A?]OfQ{*+g!mёcD05.Zp.ɾ,%m endstream endobj 17 0 obj <>stream jQAL  Gp ?+.I?(NflM:2@\RH5,^^{hl7:RO˖IV{ZP`qHcDh|rלX P(ã2{xT!z.r;c+`^SIF؆&1ΈrMdofx=D$C IJA{.zAm Duݨ!˂V,vliG2.=kȉ[0rb(;pċ]y^xXD|nم*e]Ggݧ[A&,NkȊ'IXшG!O79N27#MO9#t"S<燌c*hzc!f3XH hPj'U%;Kllj]ym&;pGZA }z$QWb(#cr<A(:ZMqm`1.UW>w mmzЧ7bL endstream endobj 18 0 obj <>stream .^>FJv&Թnh0w?]<(RTE3^&wuh yVN9`FF^u2 N #B,SUnnBڝ_(Zí]2Vle&7:2&3P)AdBijsD9sYԐA>PǖǤ(O G|<optm`7 ԗ)Z'sF1kkdQmR %ұbBj-oΘb&S[)mv?D|1aS)5*bP Tnn@9aZj8RH_ӗcT=o-ƁhTAB}J1O. 6=vǟ=^F2İ?h/{>y@R#`[ek5esq3 XZf`̩퇮Iq-vz1U<ʮcaS^ƓBO5bs%΅F8! nl;8emw 7rOk>%Ƌ?5QN_ŗ{wB'7ٖ<[ gXx,"PCcN(Q5XO )DžfnyoK} v'\v$F +Ұ}@uU?Z--&s+^ yq1X*` Ⱥz5=lCI3& _E G€lS!]${ klČ/JErHUMOƄBІzYWLҒ7Cr9ju}h!dx%Gf_em>4T8ZXbfIwMPL7$1 &VC~Pv.tWڐ 9 ?IxH?K1BШ'[c|ݓKLW>lVY׶/ͨBZTdl"'3?sY2$tdp*P+z!!r)=I]mMcghjaYșFI8FLZt l݁zW_܂`]=z.@;^?H=8W8#O;Ϛ"Qh"IwCU. .IQuyNtMH9Th endstream endobj 19 0 obj <>stream U΂J.[5ˎ [i>v4f)!NEfDwiy8褢^>stream N'*rp{|mɅI/U2x7Fd/xIPiD0vu+bQ|=_=EKSۗ*|P<[ndD$Da1PSA}t]A#K9l!1igt)Cse_Xʻ\Q{* niQR܏{82SuCZbH98L f$(R[4!5ӽe UX2:gcc)gd(p<0?ϴ)GURw;?$O|SC!%bk7T! Ξ/gKqޕwVu#5cRuwp4fJۤR*Bq`,Yۧ5RU]h.\/]':raW?ϩ sǪ?4\49 xx)'TޯO\[6+8Qq*/޶g0H<4b>ՓI!R >Êuf|}OBV yQMi;4Z.[kTDkQbq{9L~(IE({z,({[*P7^?i t$.<(2:>Eba߀9vxNG,>S~`!ڿJLJ u7q,r$^-a0ZE&C>hǵvǟ5qGrlϛј(e 89, A+T 7 6L8]OazG7Z%Շq@ZiaFD %pfie:&%֠:YȀiCA7 )j @{ŅE3@2$%&)"d6l/JR\K"f2Bِ >5uyt{L/ YlgSJNꌊnڍwgh,RS]RZE+"yx.ѢG!M͆m)Hz\}vapnI8N]z#=~;uqqcgp@2w,I{= \+vZQ7ʹ{*,׹Lbo}Yl@b^8IY 1`gS]u\|tzݰ_{R ҇|x-)YD;?Xaa0)_%~Fߟpx6ECvBDd 8Nކ蜤y}j:QY RŽgpe7=RXS DAUvrpc#sUUJe55oT.oA$hnq^8.LzE#G^|Bao<X(CeI#b]k.o4Dz ZWrS% zBߑ6.5u$773`1_[U A\J#ވR;]Wd~'lZYW)(tZE9`X^xl̒C95RSX ntӸj@֕J@2(K2 GX=|+y5L}KYh*j̨v eN^b(j0qw/>*Ig\^ qż 3Mj`Y.ݽiwt3,9b,OƼ€8xU!,+v?FK½2q6Rm^(aȷ>1 2v|'OaVzfq3ӻetO=dAqhvvLŧLshGNbh7 Grc<ٞ45?AqH((#.U@0Gt:zUȁ{KܔR{c$p;=*V 3 #Rr1'Ju (q@L>85k.&>!7H֊m>&{FфR+=1x:;e6{1lwt8,tkyҾ6! 2YB>|E)Gl .w&.4]x<;?hJ 5C#̒IN'D̰lړ&;VQtJ Ln4FaZRL.z|R݆$59Qe(moC!?9 b'lco\77aWέ!ߔav?SU6qc0ѧ\;a3#}PELWA]GnPU4HqHˀ{[{&j5OA+>C̑ ?'4 6ƹ8+lVҁuFL@ l\ଈ5 ުy_ρw 6}M9ќLq ^btLYhƁnV{vRu/pEh^rbpN77 +2w> mJjݛR j8jK+Gx U '_\s 'ZM17&ЛL3B F-EN6~aۆ.}hR~ %AՇjfT]Im?_b>(1*@UEfƛGɖIDW5mmaXľkdRHiyHuPW tڪ I$$QF.N Wth)p;=y!H窄:cTe+לJY\VL4~0`Xg"%-֣e>8(iI͙dCw>c;-7鹝)!a:pi s됆BTLߛ4nYiEB_-w[J?]i67i<(1eBjiuxe 8:ZK$ endstream endobj 21 0 obj <>stream 3n7>:YՕ3"UPZP9J'}\^P޸鶤9 6(C4 5xyk" endstream endobj 22 0 obj <>stream |jG kM*%ء܎sYzJvt\sPc蹌<5ꈼp8fpxzrbLVikZc8u6l@>/Encrypt 151 0 R/Filter/FlateDecode/ID[<48FD4509627EF946AA2E90AB1EB6391C>]/Info 149 0 R/Length 121/Root 152 0 R/Size 150/Type/XRef/W[1 3 1]>>stream hbb&F]E&p)z H2L[dX̾ fE n0A2 YA${0{3X\ t:K<|$oj0DQj(9JbIis32,E endstream endobj startxref 116 %%EOF NASA-SW-VnV-ikos-1d98c65/doc/contribute/INDIVIDUAL_CONTRIBUTOR_LICENSE_AGREEMENT.pdf000066400000000000000000003013331473507761200263120ustar00rootroot00000000000000%PDF-1.6 % 141 0 obj <> endobj 154 0 obj <>/Encrypt 142 0 R/Filter/FlateDecode/ID[<09223433A828074EBF2A058EB22B976A>]/Index[141 27]/Info 140 0 R/Length 67/Prev 98647/Root 143 0 R/Size 168/Type/XRef/W[1 2 1]>>stream hbbd``b`z$ H  V"X"@D :&FY ?cWS@ " endstream endobj startxref 0 %%EOF 167 0 obj <>stream W,5i jB&Q={tmCCl.y|m,(8@! ]Çj534E˱XE'8(F endstream endobj 142 0 obj <>>>/Filter/Standard/Length 128/O('=0"t2xAa߉yӚm)/P -1084/R 4/StmF/StdCF/StrF/StdCF/U(Zܽ/G_wFvߛ!)/V 4>> endobj 143 0 obj <>/Metadata 17 0 R/Pages 139 0 R/StructTreeRoot 41 0 R/Type/Catalog>> endobj 144 0 obj <>/MediaBox[0 0 639.96 800.04]/Parent 139 0 R/Resources<>/Font<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Rotate 0/StructParents 0/Tabs/S/Type/Page>> endobj 145 0 obj <>stream ;;\H@v02+;Yf<8:yȑ#:~VBESԵqz9䌒$١KPBWtA? >ApH|,v5O0UWb'<ѫIuhzO"E55i4>ʗCFC%k3ȓg؄ڛ^OKEod++I8~fǫf `xzԏݮ%}%S%7Glu;™#7X(`xt l{2f:?P//^`oO#>K{es{ /f(ǰ_5xU\(ܮ֘ =GټR AÔmEr#.2NTbp.qiEzU;nPbt lU4lc[V.(. Eڨ.+l"oΏ1/C% H <} $J`楞yxYΆO'D endstream endobj 146 0 obj <>stream Mq6i:}.Sh}\,^/obHLu]<_]Q[Ȑ)CAy;i0*^Bk/!c 4zV]?i?f/ "Tl/͂uZ' g[YܚAX8llfQ-V׽8O= VEH{$kI$!5{wYER+dR/*P^ ߘç3,e\QuJK?)zV]β{*p' ֦\3#H:A&+v&)NV٢KD߶>UtK5IZ6~2h|U{ȣb ݞ*Yq;d# o44O&5˝(U;t].6JIgUG!{UOd$AI\w*Vo]](Qipʖ+R}U kakhPƒ*TDK_7޽%b{)c\Ӗp$\tnOwClЭ"7l:ְdJz9%lăØBxq) }#-µԻ"bZeO3HVB $f?Y󬯮VsfǔZf+&Ŵ64.(} sBdZz(3Lc@γ=3ٶ1%=gPns }.2 &#cz֖j %\ e rcfd xq;NWePykar9TOH[_#tJOsPկgT}kYp} endstream endobj 147 0 obj <>stream i$lT+Dds'k?gWi^zguh8θ}'/Tպ#Jx?2#V}30Zo<~M6T^ZMK2VN_,JgH"O噣zi0Xlw^v?bf͵3Zo7mC:J*Jd1&/p?*!rnY tkhb*,AKZbu@ xNnDw6hzٕˮ\!ZA{B\M?0U+'PԻjpMcfU8l2ݟ%O5Pk옲fS0p?ypap?Sy蓡u*jx~t(̮g 4[$ mkI]BJKxaL,  )f=8bq*5BlzŮo}+Xگ/ DcIFHq ؁>okJT抱hS@nv3b@A=8U'm61<.PtՒn cm4<Rl"J<waAEC',u-tV;:mz;jPO]oG p['j1=7q7luzs2TDG9)"un>stream =?R빽~WYX@1*]޳}\ 7H`k8V):bLm7 ɘց0WD)48&ҍ:i ÛXƙ !dlIW90AzTa ŕh.8 rZV%IVοDƓU% [(}եq>~= EZP^_s<.'jt'g7 < X@$$k{ 弉kxģSwpf U bH:.VFV]v0o۩x2aU0C-;#AAې+J\yuulPe691]FM"sg[ "-M0lWK8/Y$_wPY< 杲׶V9oVȜ2&"\EļʂjqhVȖa-pbDhD;ٕJT%r ޘp_/9]oq*2vd31ir$srW 169CGrAm/^'$;+4Zadw4c$l>stream ԕdr=ԕUy@tP$Y.3 hO'3/}%n9F@0*b[,ytcU߉Gmӧ`mmpd4&ی`;:Rr9bKOH~`6ʢg]=ӺEq:pDo[B[︴X {%mP7y:Ԍ.Qf2ZV!`𬆵CLU\^qONgt֏b9Q)oz1 ϸ-(e>@Yn^ZsK1Z2E&+Չ1 ~'v Oa@s eu{:eH=hPgu?SшqL Fx; [AQ4MP z1u|Ufg>`쮆^DP Us/m]ŎW~IË&aۚ`]L endstream endobj 150 0 obj <>stream ߞ4b4B$t)/awFG}ULVoSLG(atzN枆Q+ta^uCdJnB:IU-%ֶ "_?7[ c}:J2X[޲BJV jWd4W"!)DnMiexƮWa>_R\t>̿fjQwDF\Z|WՋo!} Ll1s2xx[TiSF0I *URX%W动B}QBIx{R/ ,AVv؝-U:GC`:@a[3ƪLkz"MWAJ$}@0j*d6sO8mU.ɪ(;4P`tS*up?h ,wnvf>m]<Ϳ>, aKQ}؋.Q%M1Nwϰ 3gN7=eR[!:Іa38 &ty9n{Hsʉz917jF;/>.ԙ$Rֳ=EQ;Cځ=YK FqPܕE0Xt>0s9&_183T]}2mQ0978X, ̀*SD󲼁%X$?42CMLiZ(P7$_ *v_#.Q2Ex ʏ+RnFs!bKP4XTN7R͵a|C42VyLyʜe.*Ud]1"_%# [zN)Y<4u >qw2{ԱΛ &Dikddev(F\U8RAS+2S*u(w>&/h9 qclo{2;),Xc`K]မp59hR endstream endobj 151 0 obj <>stream @t4a5~VG# A׿vIӸTs>}I+>\r>+k$GCuՆqw,cNkr3-th;7v : 5(<[j6ѥZ547p?1|1NW\Kqwek]V(`]:,6d-7p,Q.. %o`O릞 9 ^ьC CnTQi\ !ã"y-tX)#󚰍F^BXJ8F0DS<4\ 3 O:NZ 8 +ݩK OǢʆs^*abU&Lo wd'N Pj j`f./t&'xUqmlq\ypk'+xwh(9 eL܃X o4tj;/_.~GK c m6*܍1"3viK3` s +(;-u @u1e}#_/է3ƷD8$Zz̽(IÆ+ ['2K#G [\wqt qN[DΫAIz <ԲE"rkyï,ySY)EJLDvQ E~Cs.#NjStSkxL!-H J endstream endobj 152 0 obj <>stream J0F׬#x67!rm)rQŮ5W<.Px oPPI ;e":P(6]H-Ƶ.Z46?{lągGtvz !1P8~9(Y%:;Qm<KƼ4J :12"$v[)!n]L;S0HrnLQGˍO(>stream 04jkE4sv@x&Sk  ץh'vP0{_BO 5A$5sX'E9l &ͮ{=*F<[] o 0ӑ10μDFxw8gR\\"Ҡ[xs |w#ԁ |'LYfx Z31*\3^B =[&*'sNݘ`T%"1 \XC$]p>q d8}Uw = bdTǵ֖9vGb+b}$\##"_'Ѧ352㊈-{65uHUV䓫|Қܺ$`[ŷ*LP r`^qD4Qe3~`WAzu`&_#(XR :e086}}au*`,H/o aDYζ]%+d|h^aNwA0͂AB_#EٟR޾Q>iCD6ٲw%]H<1.\+1'.}gqMNJ+ ߨYRg1ӤtUݏcH}^cyYd{sGZdsl5?p-+cx6&IkFky~v+Ux W ] tw\&$ g$rN|JQIէJly_Im z"e! }W/Q-h=e\c9uzCo^uv 6KZ`ⴇ'1уK8iVgl""d?s)ނ;K ڂLD~LD=V&iVHW*OY]qgzco$^o/w͔_~C(o:j.ص$ ')I)S!=$HTC> 7< ư4{;UkYϗ{C?ߜl3>ʍ endstream endobj 1 0 obj <>/MediaBox[0 0 639.96 800.04]/Parent 139 0 R/Resources<>/Font<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Rotate 0/StructParents 1/Tabs/S/Type/Page>> endobj 2 0 obj <>stream 3;ktT ~J̾HhE:Cޢj;KF(1<6œՌdZ$Y%dعI[B?C?$>m]1OUOCQgPF,9$޾_@U:N>%7rkb)VveZz9[ߴu]0~G:uǩ$ {L%RS&Jec/)&7w+W7&q9^EzҎ0,/!6|rҼ|6~WWIx^kWXvnxdmN/3rV~6}uM@(0WAˑעѶA:P!ت>N-+W,/'͓NǾ.jY+Vq]/K&V?07m/PKlf' ?7WW`_m`hq#|b9y"!# k %AFPh$~'faSF8 3oPvPF& |ށ,j9#<{1w:q-Lv5|uϲET-Θ75RL 7LDBh$ΗsC #.,b}VMkpL֑| nspQsj #Y$@ӾrgG\-އA ?B)Pj1ȣ^c7$ u,3Ô,&QC-$cnn>U†X @K r|'(QC[Jr).MY]X#}Ovi)7A ag]S2`<ݚ&>ADbb!y(Mtc$Pwu)*I:D?vM0P;CaPGҺ`g#X Y=쮤Qfx9p6Dزnrޟ2c751dzю!??Hz5@E}:&8p9-JRFl 1?, `wo7Θ4|mf9rU#rTIךTBEfRގS8ӆ1IIIwlWxiywg3V',U@Y&;m,>HI d"=?B\f ihBu#=-?\'j=H8LY{&=m+MhY{qeWlIC!sYُqElaVS<ݛަ}2RX=wrm ilʇH&W|n(ɴR-tjd=D0+RKk;FX &C[ѣS[Wiۍn>oIxXuoa_ceZw8jօl N [m7O0SvJ g+́y$MUWB9/X3 ٕr]+ߤm12='k} 2M`A@IjE׍.,gx9Bf+e[o5*#֠lHkZA%}Aբ<%_Ͻ+)CC3Xa.?!9[a6(\0%0ʻM.B֧AvcwThꩭR tb̿a=M9/f~tE} 8nN>Jv thn K[3C=y!crto41-K--1Z1,KUX$4`k<^oƻc7cekIRM8-/lC0lM='‡TRr]j xړ</KǨ@d_ʌB$zFd}@܁sZ0_x7Jk߱K\}a ڔЉýX!k3W*;M1ؖGd.:$sôqVX3k &Y7e pkg2jgLB)/zĀm%#.(^& @ߣ -KdnDf3^ Y5oۿL@hZw5nI`f't̤c]},kZ";̓51ﶏ!~*B[QȠ-P8{(2$XW|1݉1T~Q;#W\#KJmVwE&󇳠Wo8%r켢T~ķ"{=] ,wcVjsG7 PR˨:pV8aD"2(nߋ/:=5>h:@:v7EJŗ\L5 'I8dq\*p՟.^kEתA_@Niވ0K\̔| ]Vc"}/Km_EZ- ԤޮօDX_s5&3 @vY/#>9X͛Wqfroڡ邸HQG|g f!Q*QH'ߌ5mP :6s %MTY9qlfK*hE!WNZgAtl"-2ٔirJT3.V[鞽b=\l]~^S5 M8`BrqjY@*S+8{W\Z\z}yI&2͚@<\91Q10tX{xQય[܃^?]l,cڑqླྀ,"%)RLl)I'tkT{N4ރY 8Gb#%0̽'\fwȖSs[LS $-p$)y N2]ǪT,TQc4X1INY~0VC2Lz(B^G0,+CŤCZR(ZUK15%\":ScNleߡr/KkOGAΫX\O@X 'ZQi@;Լe,Pů= BƢO'YX# aYTOlβ=)J.o zC^/[u7 >~ULA#awǎ)!3,fz*~R_(LyTĶ H]P5-uka˛>r1\]TD y;wST~bȬsF1f͢mEׅ^v18%X9V 7?2#.#}|"\xL(!S6a>Vլ7,m{wlsxפ^|G̞08$ j5T 8>2c#O {=NIH&ʺ:+)yuHڝٷv(e#jH ֊{osc AGc4ql?MMb IS*GvxJ7h6,dv[_wjYE%PP6 P)=X{G_H'`Џix ż()!KA;bBQHtgjdե_s,<30N8gx1cw|,L ]qiMH}%] OGj*I4^`˞nuhܯ0U0kkxf*FԞt<_fzb;Q;us[Z`=Sݣͪ{z*,JSQ9_Ěh=7{Жy w>|Z гPB #-10z>Ym4r--cni `<ЉAo/@)Q1x[(@|L_daTY'm߄g`J4&Z)\ؐX‡OF9-%fGi 팾:?ojB Ɋ 7,+ aG%R`]}X̭8!ɆdqB1 Ɂx1+5uа;7$O#i endstream endobj 3 0 obj <>stream :{<_p\1>0Qbe艴>\e=#w n#ulcqE誉uUaTs=NWFֺ -UVx*N;ө#!:*K7a&ck.{He!I-A A74B{-7,Ju_5Ԅ{EM+~#S:߽oq*H2)!՝Z.&c(:]D)#E(z1W:5hąAE?GR  "gr 0gbC/2V2"sv@3>:Pjg[ٳ`bemT#'k:b>,& Daɪe(NC9s[5u tFJn􁢧#⥲]tCLWx: w'ir{ zkvr_`CȖğfE4NT{p}Z,m|$yD0twELlvkO4-oZiaDۈspRe8][)FaԢsK5J3cl쳛#sè'n , əwAA>y"GkSn~GnP > =yn;HC)EƮ=-ZR f>K/JFP}12;2!rhb=~zk"?}pKQl=ۿ.Sʲ++/3rAT{?XzQ1ʙ7u E l^QPΥ&{*,B .TXGkӆB4~۱S6'IRXl$mS,0AQ:uCTnJq^q6 8j!mO GDxOkChիKA9pU7ӓ0M/{b},3 % k4{zLƛn>(pFe<[I0e>6Ζ5 [bF/] xQBKEk%QK1ߩe!R!Qt#n:'Iw:؇%)KCDEK׃Busz<{BxB'NO Zc^ɑ>)FY;㻸3f`=8X]zGR0hxh B_ `r$!с-ѴƁl(+~E4"G"Mxokg ضfAIxq͇Ɍ{T0Պ5<Èy6\B\A8ۑs@4Y̝QÖlWp!*&Z_Rꯛ'c^,VŽBRcPT1.+|#19?d7#B'CR̝1T:~jpl{':@ի0CM2=ƞ !*B.V>+\ts)vW.~r5su( UҺy%pۂ9j T$]\nT{j,M0k>:6HS0Q-Xj屌N(hR9UwX9EwD_tVz`GEU2zۄZS{hL`) Řb7! 8ǡC^2~p vN'XPNՂEG=ol>o5/4/!! LH{k5*$QcEpz;1Ea^|C[5^`>R5/x:ŚeUg1-BA&^_n 5+t̜T#1{[_Vt㧫]=_߰C6w?vX|6CF*c-QuJzK'pq{7dݙBV(ߋ;9|[o4-m`2077cZ]?5qmVPߔ{|Iy>`3C.yջIf1mSR 5yBMv9V![pYn5<|'zTZOYwgf_5åޝBϖCm{rx4Vqi 7 JP"b +;-[7@0TlSnS#scaFD֫ԣ/8X1CO1:P`$STяМMe*@Fk9T<9sGt 5dE(6\l]M SdzGS6uWAhTHo D"&F>|[Йe n}%w SqEs`w.~]1]>~xeP:B1K1SR`y Ϩe,#|Ҩ:$1 LSо\~q2QL$Y: ǡyќӦ:i<ČQ][!nl[9Td!E 1-tgvyZ~Y+}#Vsq!g/VeILYjSYmV#KgdwħX~4ts9d-;{y ?'7¡󚻉Nٜ6r[Cg VEcrJ ƹB##Rk *}觌{Yb=dait*0'kD3^Q< ۃۇWvkvPśh?+Cڏ.uϟMJNKف'Vtp:er6LKe>O-w*v8bg+j(\/1{?m!B>Ŗ5^4dՅ`tjDz`R6D#7#E;*\<7x'M1UA8 ~. ea]]GmݘCyd@;e+ L5zv>0gBU= Nyˡ|5''8p='\c).B;btiK[$i?:}Ť*Nu ǦƹY e)57] @ed4 -h&lPڊUj /uKEۚ5mWr+U%'eAͲlO sWπO~R킲` zHq la߉deT݄BDP3<}@!BDժ E" }w2rtLRRW5>RS9:e:AM=,e7T|%T8ϊbmqK:]q%UmnN21T+zb0O m-1~As/k8dfbuӣkdR]0RX@ g!ZnrʡoÕ&sJ +fD c RG3=#4.OǤ% ߙוg8,mx[Ut&kYe(By*BBżÙ-)An/ E"^FN@^{5V0Lu& pU1 p?dЯkWpKEauf0u t].N !{ZWLX&~hiE.nOQ=S*ho i19y#[a:. ސPZ˖TCx/FqC#-P$OF|8a2EJM3byu(G "}#U ~Sn %%c4n˽m^[M2@  h ?r[҅ǤۄQd:mtÚ4MP7ڬ$0ryXjx|O!7IU7Ib&@F>(u(R@gZ892}˚xĬ5rIVn ~E/+Toפ5fX%BV2zust8~9G|64XV;C׈&lwsۭ0 0f;evYO7/wz) U ^cQ'F$^OzU]R-6#lz) :JT J3<1:(C|И"i#VÜec̘7r*M(s`^a=U*rgL$kb*Oa3>.Q/x@F.+pB{G-uAppiWs%s\~ b{q[m<,,%ŅDť;Jxs,f5!ldD̶Mޣne/Rwu\YDԻ]?'p0 ˰'ZaZ脁SC:>M ^8o$N8+&g!:M{[O3vQXiNKz}dGBjhdU{IyHHM!,8bmhkU_EG6j\o}xB A_:qNGKG9'/IT7\Opr"rtCꝩ ݊Bc\ ^ Y]Pi^`<iA%Ք_8SXY F`yc+jTw{| GLK*P=7ـp )/4ObXTƵwұmٜ͌"֜h+G6zpr&A`R|Y>7Y1G}6Z*FZx"Q4ȧۜ(КUN{BmLkb&ܰ9bYƫk; Q2+x${E$NH\t@̞o{yYj&:MO]  :_!#>t g2GkfP~;u"_j8?M܄b |waE:LݕF[%t M9wB0)cTd8|we˘ UV]{gg˧=WkTh4#3t I Mz ~h.INvQfq^xew^d=rΊmn|y>w33!B_ٍrJ~m-Q)f+ay)0ӧ4n~ !wMb3 DrחLIg,b ;}1H:o5:ZIph[4`*4~ECі47sN[9t]##IvK|͉A2_)4 4NR~n) aw5K+{tNzu %baH% Pda` 3r75٥Q +p=X.lNEyܙ(xiTD)i^XRK_:L9s ZR |w޴Iq!H_QY F-L&Wdjsm.6GR]t*3u~L;ads]L2Z΢Հg䭟+",q3!@z) ;1 c Ahq:~ m<7D=5bc%u~`ȋ!l?Lu9>44U~@?[BKe*j6JPc rSR欂uhMeܮ]d9iB[F&/dj20U-E@)/x]L2-|ް]0T t P SD RXUkjRP^Ё&wRf[^W>Ýhtp4Gm<4El DҎv(&4B[ckS3*>5hjMpֿ%G<|qk甸ή%`ÿl:;anĬ \H1lh> 7X4*Ը ^"Ob]óDWOP|-QЧlӴ!nuwzl\MܜgWVd$`t`,=@ 7tDh@@uG~Au6x;2C}! 1Dp\l NPg*zk<o8 䨂!s׫Tw7Sa9-@M+I]YpYW'[лd)N]Ć7Iʚi6oGm+ Sh$oT=S9bHJQa&w1ÉV4! -/f.+ * @⤳Qr6 ǸG`XCaUVͅqnC%UB7z6P9 ͋M|_ᥢJ0lp#6N8j>ΰ49cq2R )z>.O'}Ԁ\_ӠD] jQ1\'R}g|CmmgWC/ce'.%o$c\]MpTwkӹ+~8dpģg}i dO|:}^ߴ maCN79L8;DA%Oz^b 1m KǏSD3:2ԗ/ζŎ2_;GPBJy}:] /ĉIu祋Q*qM_B=v{Vr{wŴ;_/'ӓeB5?%tbR($4)6#&E3riJxw1<_Lqy{8q(u?vÝ+cHp?i.Nd-0A?d2sk!SP}FѦ٬7g RMz~l% B{*lO͏Ȥ"SӸXSK1:'kxC\ 7,u+Dd7ˑ=Ҡ!!'k0Y .A(>ùYfah=U";'EjJ@Nwc(4a KD4wKeJu&$~l4&rp4H"ׇi \Q@{ TnI нg#XID1Vya󉐑]OC[i+%B? =Jaq~Cst1K 2t6}C1{h3d;́L%R)=|!o¹2+.{74 >@`ǚÁ4 Zyh7 aXۺ~#z`?,V<$.g,cDO?0x4u>RPFl/҉CsB|EHM0R&#I VW_ o'q'arE5? O@W1G 2*ӅOL %>q Y^!CN~>9LMқt5rRRbKD%{-ʳW Q{̳ RvZ0_;'Pe`P;/04Ek%DR$fp΢51|tZq$7wikeXz Y ˕Sʐ #]ĺR00^x=G#㿍WdϨLo.˥ru@N W0Tulӧ B=s] C/\8U+agsտVCBCAwHEF0Pz8mOeh"nrP5ZaUP10;n];@asml2ᔴy-1B$fѹS@EZ @KӃóJ4r듕Ey|p]\W &>vrGn\n6۲ 2=<pC I">$m@nbe.:Vy>IYI5rnͻB\/b D jӧw ?+im"H1y]SǑBL;>3;Qzͱ$bnW$Z-ԃ5Z e[i7QГヵ"Tډv@yCn0{jPٵB< 0kJ7C. i Nט^{И(Id΂Iȋs9\M. dVVY:[`C)@s̬}M\ZIᱨ\IkCz$RyȰ!1Ia73~R8?+l.'ɾ?J3p?cX]4a*"FT| {KcMK#8C3~Q,N:<Jmz4HG)Do@F} MY- =\S"#j"xR6Qn\ij؞jQQVrؑd7roK[9kYJ(d V@$/]}x.ۨ7ь<[#uZ;|7^l*'VP9Փ@Sg%lA=q?m|ՆQ]^A)VSyzˀtR<ג\ 1Nf1`/Nh#H'9)yƑp OUlj ۽q̲/i CKnX8I==[W#oS|vT-"xm3lj7%얲dߐ8:a䣯 '>o/$nZWz* #IE'n%$+I.0_)WEgzObw||me]ðč XZoEsN6 k+Zh[J $ ބ$x'0eI)_OjHClM);h(_L8l `x;iux>zbP{F?@Ff/KT6nC$f(7]2Ww{%{2PW&̃hˎXoK&WC[r9 1yA5pl9GJ26d_ b@*ۖ~BvyBUU\Z!LKU͇1-+> iп t/}c(WJ#QU#%1xdsdEIArqE 93$9˓~][Jy1 ޢ((@K 9I;7v &a2|C`c%Q0B@[qS⽪xP#`дo* w$d`øD !&Aŷ7t? L3\uz/3 D5j$fڮ^Wy/-|>GYv'+} SL2a{9Kr@9$ EAT *`. v3,il.e-Jj2/ Smh_<*]%@{ ژ2`0W|flwʎ0N[cx}yPhLfjQ?@.f۰P݈ 2,3Ԃ HMp<4~Sf9.IHv#Ddȣ76؎i&}[3=6zTU4M ࣠wM+stc#Y i:ˎM1&޲IS:niW? 7J鿕!mHpGc@g<:в*-8{~*ʹ$-I.RӨ'Ob8yc 3u %7R# .1i}޶ %pL:pj5m|+`e,G[EZG H1K7j0TiG[;0z+N>{:% k:f6Bϻ3B=Dx^(-6:4Sp["Q)zmk%V%g٩BjBI+: =kc̩ )${ޕ&'n4Ԍ? `D*1+R;BT'd Fwu”ޕOKz t2}O^.=;_j%sNc \ B\2ua0kdicZ抮R[^mo)v|K{NAfˉW2p];*ASC~QϨ|O=Vؔ((T]/ 9q_8*D ָ$QEC没H'0fkh(Jڥ k9o9mtY>_8u75oܫ'͐'K*$;r UUo`6$nJqφ9à {UH+ȺV+EF{ atlj5qĺ'8KYk*kTHQ](džpj:"C͇xCwȪ1G V">8KX5F'Yo"ih(b13i7sVϾ -eA* :Tw]*|_ae+Q'kRELU`WKN"2QN0h{sp f?!&yȷMc!Ҩ!ZC>?RWJ҇bz!\5N=`qS JHNQ >᜗?o)P6~w:4%]ߕUJturQȠ#~J%qKKpD#A7Wn`@sR=Ll`bAZL Xʵ flZfSC*DA#6ryPsbKD >-!1x53Ú2I6 ᚋe֓7=Q`i͔!%jE n~tELb]Ζ 6)2Ur9M0(p%CX-e_e\/ͅ$9Ls{@A\ɞO#Yˍ/dg5(w:>KU5٬Ssg e}$=IFKč<ӚR.pmr$4KP4,z@ё@y}%EGIqPzp.XJxŞ-ħL-p#bJ=нQ̗LA+"m]B#k\N|p nGDcT}( 7Lϸ렚˻oަLuJr nCSn9>jQ3؅jaO`۾PY~Ɇ} h[_٣sȣ1I~?qg=n#p'+^B1ZFMyY(ctLYFs݌}H =kès{uBexiaDCmpd/#Rs&e5"{ឥ$i4k 2Ǎ7JDұݤ%^iZeh8Kr89%ɭW#Əwn;#BlcΔ5/>v_\#e330GdlUo, K9<HZlewj;X6A:E U~W^؝d}*P\:_wy=#7@~"/fi'}d[09v#U9s "d8%qZ i8"~ u6YQ#t2K'I9qY#kiln?\+WFw8W lZ45z_Ł=SHJEB 5 -9 `<|یga05E;eo+ӃViflYzkT j@=x(J1[D sxG1;@j5qP z@d=Y ^Y￙b2TNf ΈMA_6*Wץ@:g gm( ֥`SJEV!Y4~ek/U`&*"v_x ?f 뻎VPJh²Le[[ JIIq?TSV*ה4m^ ۽lrhڲ ]zF4q+iNYYuO ):q.xT 󑠟5Qcf؀Aй" XJފ]K?p$@xdP K;"5$bq_I[S>%u m#I~\e lrvK3mIT>;~NRZ&(f}=9\e(>,CҫB4r, ccYVa R7ƩhiG-RJ\O]Paōd]LhC\^B}nS:\`>B]]ֻ 7 BpmXͩ٥^!`v~w 'ƃ)lB _{$2mu:Ehó^[缷ẽz_qf wLmS!@w/ڰ!tW]^z q)դXSiJW-.ʱ6ػ( ,&Ѻ;,SxUwBKy;*MiPkF\nN}DsvhҬ\;i}nW`n>ߛh*R$җ=*&2GL>TS6@g}M,%`$gU=e~#;J-=& Wg&4rP>+aZ/}ɵ(Er/2%5Yb?Lm"yWv&}Xj7g!gQ*ͮdj1B #?`,r4L T#.~kW.,GC7)gynIO73w/տn&h}'hH42} E5DC ,rܣIDϒcw/^AvRUDo\Ry$L1i$nd"k%ϩx/.ӏ)ctQ$z9 '͹D/ e}ncW|Hf !bG'l _F?Dlyr y6h)KbSL .0 1ŭ4mg>ktheĒp2?l6x\k%(yΌw=Q8w~>)Ä֏ !3d*$*&.77ptfPwUnwM8_Ṣ Yř A{Ř4؁,*C˓ԽZӉ8U$*5?qfDhe#|Ԍ/~k祣bGr'ڌ+`4^AwA ~>uֲ_ZB b;ZRMT#^[)X`߽|ӎK&998RXP(!0(. ECLTr4>;+x'QE%<C{m'5 1~5eFCA4txߗh{wFxth#xB~x'"0EDtD#r~ TƏ}ϝDs>_=&킶Q<ڤ+O:HX°6y?4ϺZD_ ϼv֤2c!kgyՈ<%ѽ#`Džis. S/+auSS_~fVMCS/3lvRN BwW Yi@V0ܰ9wSHr)*(\޼ubJ>u'&.[1#v˶žaF8'U_Ms^Rs`w1)E{hXwj>ԡl9缏.7Dl"~#iU MtX$=a~i7 67:з9K=# ԟ"S>de2rױ* s$׳%p|A[6U(K"5I5*Utie u۳jg<6z5y㴰-+.#ˊ۰oRJƗ$s/|o}ޫ.:rnt.|v9QH C^+Mn% u6][Miuiu1'cP(*10YQȴ=|PhWϧThkyR?7Lrx4fQ?ڈDܛAKTǛBUsr "62P}^r{EY#Sr^Ec%d5 ~q^d lE-7X4|i2 giUC/!p63@x@6P08<-?{Gn/#ngA-[87OAP–%p!!ԫ5&!`ma^:M=,y ،~ kIg ]Ic\2p#ozNCBvEWPxJ3T%4t9L)8U/Q %G\Rnn=&*ޮg0]m@GP$P{N|Gh ؚ\^Sz `$Lvz.',w7Ԕa- ߜ܇*8F j$ 0j|FN@ .4-?bzm@1bGQp\chV>y2YWT3MqPzZ+Ub^.?UHQJ8UO}TFhQ_*F"Z@a(#]B$ĿtT\8RDm\n֯iSJq oU.)ӄrHaGx)m#+aRҋ_zBvI˭6B>vSRw#8^8kAǙtו.LH2hN"J֐,t8 KJMbJ1T*BC׶o;kRݏxۏa/򩋓eiPl\n4'X&taޝkWaNu@TѩIiD4:@4Uz $#[sxV3|@jçC&..IV,nw#TrtARNvRҍWGbJ2KĤ Fޜ!8}.Y7Ժ䓒Gg eJ {o*!BFWD+90`a?6Ȏ״oRThA>J0ti Z2st0M"CVU6_ vNBdl9:)<{x\G./.QJ,|kH׮|E1( _5)!uG*elk ɀ;v̏c`םl<6sɎcޓ/{%Vx^K*%{cD1Ef؇rEmPZ!HPJo'”`w&[k@IP+-??VoC6Zq=ժ$f!ސ2FEugK7zMкG,Ԣr00ԧ}8džHF_ki|; #V|6y ctq rϲPŮq u3Ɲo{@fLE(]ALCt6G(vrGjүf$^J'1G~x elVFgƳƘ.W꟯Jiw䃋U Tgq5/䭆sS[E+޶ӋΔ|?xci3 !J8BRe1zĸ岧EcUYU(D4v0: ψ^u|?;!HĹt-&F2M9Y3nx}Ig@Ɵ1yῢ=^]ljτ C+eHU9嫅nT`ȕ~o'yH$]NJ3;1"fɯMh;2`9Cl^a8T5yeHH8d/AZI~\ވgCf2ƺ(KeG9a Q-k{Dv7ulAɞC.~Hn0kȊoNw>,=p<ۂ~Eh߇OCe*1%/,yS؎SǁO"me_1uVYY]y-?QuV]B1Uc[֫O)%0)(v.1:ԮYFm.64!K݄ T-l~O%z _H2 v{/yD|:&1aǦpsPm MM_Gsmv_Aڦ4`Gwaٱ 𮅿Μk] ps_b38F@K9(WV`y`sqE9n]I&V==򿹖=FC5z3pθxZ|v=$u e, +U:O\O<=}1Z$#, h@y#qȩ8k*ߙ;'K己wDiq6-(( <6\ԾzXn?]LJ8wbve3>Z>eS75x׺V-W ;Uвv6Ywڳ<2a4|DSW;o-n#Dr{;BR[-q(UN"nup/pKLTv'THP:1QV;o #N32m&g8鮗}9Q2jX>/U^(ӭЬ }zO+n,amϿlxWecpˑv-B@9xNx;@(rȡDpKˈFhYsQ@ȍ$ǧNKf-vpO78c7e+sycHdb!Wv(m6؄9AHy%7ԡ9R3y*gN7 7^D9R0P{G~IkX4X,p^?&K.u&Î/=j룒G IcB"Ґ.΂{˥AZD),fC] qd?P5z&C\ 38 #m{n`]N}g8wZPp&bN$1Kjkn8]@'IKޘM= Vv?ۍ,!wa^Qܷg슔qzr$HIR ^cb k5?8=Zqۉ_ۣmzk%˚DUgwD ^CF) JSza\N$b% xl+СR|n9W|c]?aPE4If*ېgLH-S c/>`Q{lچ1)y.3@?|CE֮~\3nWʼnO7/HDlnsjŠ: k)xdGf'=APU$Cra5)P!; %A#$O:q7YEd]^O T~a$/ ց+hsyAkPSԾT4hòY 9T a\ `e;gPؐSGST`eӽ*繯Uz3ƍMvRbTl qԩMOM>;30GB|2Ug5EWEUTswЩy\RDbJF_kʫ֑ tTFr/2(}3u63Rc\qT;? _`@Ѩ6xS^l_5̡Pӝj)Zv#9Lģ %˃*Buf)꣈kUм"=M,Q;pi?3zV5@zs̷D%+aV1O6.o8&B]8L~/F|tweYK;S+p!,"Ÿ,[]X' )թV`(:2hdg)dns"6p?y؃LPv@s0FH95V1̞ U`cHPJJXRHtͥN "Yue}H A&[i4 Kӣɐ\}HnFAh$t6(j>Hmf/#%/k2F=U&(8mȄA! 5G@)b - {Ի$K>4}kS)jA.u("oG6xX "48=Ġ1[0X*eb &ѠVy5L6/d"~J8U\hR_qͤ͢1x(^`ftktmncM} (fW@7 axrAJyoIhH:I!gg\>mXrU֞P Q!/e5`i<]97<^/~A!w]OKLSxk3  I+ ]K؃ .vXX7YapܪCA0wGlyl "C_g굟8)X3b|:Cu6,_1vp;Ƥ,059c =!0Gt8 K>eDn|(Zis٭MPzOˠBhtcux)]:_jL>Xwڻm5eI/ ٽ5wo#1]?QRdzkzfkoqgؖ7^Z;S[yRrz?r{"@?t]yc~{2#>ۅnl3ζx; %TGwAB3n,Y8M5N_]Uw"ЋFjIRޡ,ףS}؜ISSWdsfVEΈ\Zz{ay05 uTż!e:s.h*BQ=j4/\vAv (̢+SF)Pw5+4!M R/YGi6)E AD^[zx)  t*,Yq?< 6R,EKਬ|׀[R\[bvS3ʚƆfe+H`9䆮_bf#tJ}[ɆRוC%K—Pw;=yb,¡j~N&b(m0O%.t&Pϔ>VPA,֎~^H\Xb.&b`^@Za티!,Yei$1ufY`"<dT:lMװ&O5/;ugv1۸ XL %NveU,^x?R^^xhuYfiioBdca?f ipWNg.@g:Bs `@hpJa!;<J:g wAw3V̰jIHt/&,eP7 ™A& sHe3u)}a@?ҟ}}I Z )O 2),Q3q|SQ FKN${4)UKi)o:$I|!PNUfҰ.*EmiVMǒ]T4 ;=J8-?xg$ F(f`Mo:3,|~9!R)]Ϭ`> ѠΙNد7tO ِ_NrJnk|fGqϤV`|M}:{u[^ ήKX\,X|7FyTS1DyYAe4lK@,R"s5,w6IQ]P_\.jyߙ\;OpjdK>F`do,$de1)I<+ BoS452&ϹZci,ۺVWʼEiVKar Fd[BVQ0w b gãyS[="T9KOZb+#: HI^cE/X1jl ] fe/*h 1nOF9Է!ś6a_[Ld'>J ,Ԫ s[LQ(c\?(ht@u6<*F\n>y?4"-WSw`5kDaF(IXaWU*Yn* c/nP(X|$6 G{vSp+`٘/=,ʃ^Ly.2ӣVYL,ߙzK<{sƱSe1':+g7{DQrJ&_ʗ fߔ< E1[@fY !G- u1YõRs iy`bf͘dr& sn ?֗^v% rg#~r>z"LTT|= `l੅V):F03R^6Ffv)szr8[J5t/ ֪aF1<#Y@)ڞ6!UP\]V,'=Jo!wAff\zdXe$;"$w>vXh,%&BCxz,4S .#Jt. H[1`z:GޢϊBɚ9kSkQ>{Eu}l*AꟘyorod 8j_ vM"d@##|mZ %:$K%3*h+-PZRlpXy5q kJ*$; T5'&< LY9>Bj @vN 6SVƜu>W\~(M´`1Oo"BVtOV~xKٸG;n_VG8zǖ&t{ C 4R0s/.LZ=#P`0*eh5"AP;Eora) lv`bCfr7iqW 1ax x Lx6f wXF) U`gB?,$YXx]6jxW%9l6!ukLKfu8J Mky# tML"Rּ$[lu5q"3Z С ]:jDze!! 5%VaJEN->#bКl!Kӧb YbmdWEN~Bv4]^iW|"I+-kԧRM}wH(e`G~XdTSKEu '$]paͽ?v?Ye 'p|(`Zh#kCWsSo7gO9Nle c7> E XTRş@Z;6V{Q.6 j"5XN9;BG8#te!Wjo#8f j{wnXa4|R ex%ecq"Pb tx+ۥj»h^d؎(n/uB#aNnh1BLnDB(+z5ˉ/:כA;wqJ|1}>}kJg{t6總_F=&EՄ_:{Y U BH(\j0T/cI♥CLA@"Yza67Uy}$XEP5μu-[L X0 InV,u+SE*;4^yn׾xΆܬlSY%ji̿ٛ u>KHe%cocBNzy1XbQfPy--vs.Ԣ-z(/A2N[?gsP )P_-qMנ5j[[ԋznu(:)X(%F81;WKwb&Dr@wl. F]>DÉpB:G) l+B2 40܁@2(f$顉r В3m')o6 cؙ,s/|BEzmZ<${}C{#o J*5 S~ 4! EMΈ@üĻ@#&?h RYG=LW[ӣAUV!:x-$$}!Me/2jY}үD4v{Okiwnp5$y͇ހu_Ő\<ٖ#_YCIbtQR7vu، `m [m] #o-m)~gj=_Ѯ'=HKF~& ߝAM언V 2-oMf }Um- $<43%ݐX>ZTh1Ժ1zLcpE*ܱ=^0Q[m#Q#Y}1bi$H덛޿5j'k}C -% v<痡[ʟb JG԰7Rҷ!P_ĆOq`~P`FL:̿`*^\b[R\|8XtO˸b ]o*% [َ˨f-4>Oe],o?L^J7C _?óD ͿF yƷ(:ZH l+*&i<[%( !@'ʥWfZpDæA4ಎ6c1Kį[{45sמɌT$@iwu @h08R9zwBq!if"(Ij_>7=(#2B'&ī2 ʑ&[{8#VfDߙ~,'żY8v.(Bbtñ?};w uȷ(; jp8MK9Gr%A0E*@kԏ va-|⫹0P4TjE|:N8LH^e1$!> "XGz!#M*n0_DŽ QiVu7f?iCtņ>OP&$7lgĬ'n ?O):=p̘, 8'Yw>X1ukX's{ ^vVUk+{f ]l.ˍr#DhD+*9qcPp9MJvtHw7_]#S췷RO޾.O)].V5^ᎃ2J9n&R\ V7׃4NZ+9W \HD{SQt\.44?ѝK)(EtL<x^Op"Uh8&ϥs1H"ly-E*jtY#Z\5x]Ĝ ـ/D:c .DY4S g[HNKT̕VYbZǴإ̅bNUGeG[~z뫤Ans4"];{J+DI6# B@$Ž3!&?V*bo鶀6Ek7m氵؆ͤƹ! DϮFdyymma'Z_1 BŠ_2a('՝OӶl?g{{ְ*bԂ̺/h򫣬A+ESv1mwKpSڜCQu_`CKkQe ݲ٥P7# HxJ#U;UEj1e(ǰ ''T6/) Ŷ'}|Ha)(qN'7 7p0F`ɖO?] C`8"=AqpJ&N$& ) \] G i-;Zp5Juu"mnkޠ/GU64!Y1$)u֊2UD*/Xlsd@pII{@?r t5vHiaA&若 حTn Y+,4%#8&bVf1@bP=rI[rj@NƃH D,!oٝ菈A[GByIbd1f~ACsOoYle6Jh~ O0TɍM_m^G|c'~24Lcqbռ:+< T7Y3PUu P|, %,ӌ:%3]X ځ & $pa$&$]i>IA#qSÂ2yfz8dER]ʲ hy:a^2ͅW_>Ey] $ڟyNNfbe]VfځՑV40ɢ4>t!*ڌqV/#N={"/b`KbCb_4nAѐ`v UCQW=ݚ3&3LF`w$@:UDC/&▤Q4ww(D(7V˕.W_@ Ocwt\J0U+Y]b }asun<4HN.=Wر5]EwP^UY¦UPppP\d0<W`}HW)8zbi:vwD>ɆΏ"n] yoC#WCJ~}ϰj>*&@8- :[oοg(6Jh7I/jKOτKà'P{ɖamEVZ&k)>-2EV' Ɵdo5аqi@eK`.],30/M(*2D]ʮH{Y㌏Clc]*طފκ\H'Um'}zcݮ3a\>=vp V0%t 5e˦_J L~Q_|Hr p%} 8]2Зvjo;U:GD,-fLOfZDf=kҘ`/J>S*4&(65T?0g kh> b]taJ)޾dC_e>g\9ΘL$އY^+PNK|CÌJf5 #xJkqDֱ,h͚l zDUNwsL t1Q  õΗR) ';C=sq9Ok 'pX4AWpX-T\ŠR9Si z cyfJXH DEЖ"u{`UMR}T@}Ӵhio֩c!:8'#e#iYddf7 ={ܙֺU*)]CAlI7 Pԛo  Pj`n2\ 8rqgzgِOlY/4q(x~4a8CVDO CD4t lqjʕt%.4e9 ,c:B}`%( g< x;L`Fssp9~+F`mIW!$FXMxa%$a|g[]lY1aXG׏ vaw`T"t\A&$?tPevB5XuӪF ]v!|]`Ӟğ XT XIbUۡ"oC-Op'^(%KgJ 6yž=熟uqwHӇ^-+]?p"uh`H…U=CK6ႄcX?7xJkQR,Zg(X*|+d'3)uhI]j {/,N۪= Ws~m;w5^䞫dr״迼(ȰKBሚ_Hd Q^ƢdHLn+2y5QxG~v?u>SmkLV_pݯ&zhPcb4@ki ![ hJ-ɒ^7u\Sw`ĠS`<7G$3q˚O,;#%B́rJ~U|.ǘWGN] Z \ ,2q3I$9;${ϰz&b蛁-Ȩ3(= Kv3<=O~=lw\,{JgM VTY:AnvI(2a k|0@LX\I*T^jOzE{ AEݵY wRnS$@D$nR)t Bu?}`"M$1e:=D1 :K%Q!u ĸeJ+?%alovRJ Һ۾ԕR"]/s i"(҉u#R+bb*oP`5Ks% sa#WYrE1 Hg9rcm16 ,|%r8K_%iTn4>j2Ѷ3K3tC, n +Z% p?*Z^>1E:2>.rHAAwty6U0?jQL$] -a!pHٖ\pUxGƈ\hKZ/ա;^נ(Lnkë"Fů]u󥇑 T@ao$t8lS8b9ը\ꪬV`D}ОFIB-г2hw\ܴc/ W~ZR=")&B6?ؼ,rAwիL4\*SL2Iq4[:)y"&VK>6)|3?;^Pb%sy݉z; x$+J 4K*hD(Zc')7%h DUv0QH>q{W ~z-7C8i̓MoT/2d +p|NO`Tp(ڐ`@!;ʜ:W+=ip-Ok'.BVQ\"pe7,8."Rhc|&qgt.Y +mGS:̘LO@#@sxYF `;FI__P/8ͼSP ,07ս[ͅZ¾@ߊRTBXr$ eq5b<}Yfwꍥ uDP?w }OIƳ+ba"̭LZOe(<2W>@7 @8G'.~=}~Cdޞv9{xロL9_)mU3#!8 R)Z[CEϙ9;ka !XԹFWvD[1Hw';~nb\NXn7$pto~2]=Wϴn# T H1X-|TIe[ lBN7QͽԙEmfS1mI!:hˡM%+~ 3ڕ)H l72$a"G32hN0Ig~Bp(e8qK2ľION氺%?k<}7Z0.xw4VIuPպzzn8ư ɢޥT+ ve}< tUEx}./˛Fw/#wu:H(8y[/0  *)ߞO yV'Y fdSBI^a%إ)gbC7~ /WK:`Gۣts&Vљ<*3b*NPJhrnL=w-VV%>K]kƴ܏s6=#8(L':t/Ra;F%>"]-Q)O]sZko} FZ5N> Rw^RP~oz>y;&Z}\FZ0=k>䥧Ts ݓ,j9K;W7y=6_fډQ5$Hby|%Lï)!n o)r#[f͢s|yGp iOxvl"7C{mY!s3e]? uXC[M-\-s;pXKq $vfԑ{zԷ- H#3~ҭ'A}h0V2-#R<2,y]Ei|WWˌ[7̏ l[OR=IkiuyE-=R9h!|Wz63D׉cHd5 yT16ukzYZ!YXe߱;*sR܏(x?IQBs-zvu#\ bAtvf3`Y)[pp90hw8wON#V4: [<&MhtGU/_8Rdb `--,gYAd"\^bҬg{>eĴJiL[ϭ0߻xѷD;w}mf0OoT"Pub5C_leI@mCNޚ)$fX%JoSeK>6t\jԝd敝ޭ՚+K_r^[̸{#2*Uu'5 OEt&/4Fޖ\Knd0[M ml}ɟ/윁\£VSW:&RvТC=Ay~ov73(D"bn>FvY2KDs?g@mȿ-tI"R_^09Ȓ[on2 L70H~[K*Z+"~_Q|' T޼M?CtK3)ׁ37\V^F?` M HAA5,'9bJ%(o%3 FbB 753 { B>+NrbYT-r&.pu<{ `BVFBuILW% ;֝Iڠr8bÅ@D!pFD[Y^J#4&%CtIj'ׄ}#(e5`i:p;GK.Zc/7>>{ͮy% Z*+=Fy32˪`1wb!(Uȭ\_ mCpN~ўltйxEs6suvVD2eqK>֦]!(Ou<\XT&[3A;فgRwb Bq4Ap9@j\U##*\YAD#WDe>eZqω|K΢W0*Kkl=a}INߩ.4zŚqs|d'Xoiɷu=弲ݡXa'ۊ.ķ b#1%_On,~/&+N;K77wiE/!d&ZClⲽ[10O̙SC% J~W^h#\F81%EIYuݟ$=F<  AP%ՂOނy8nE\VJQ-d#X2W| eŚݒ,QuS=kt7>1me|= c\* dJ)̶͡G1ɳf=p&a z>^?Z1<_s$S,.1L+nVŊhh|BIE|Sa;2ݾ5Tv$(K$;۸>̍Kd6DqVOEsS,^詸>L.߻D8)`.h=EBx"D5DlfQW@F$v-~Eə1:m ]%D$˯="aI!vKw#Ks.uiS}]"#ד$*{KzX2(nZA5< ^ڀC?X#TKWC il M< Sq:ԞM_Rݧw,"*bI{4d0ų=VT׸Zia+tS(4Ӻ4^ P8SE#yhTtvvbhL£ E+_]n/0|q5-.UX:/Vj=\cƞ=CȰv+&ʻؘ)ɐ ?I#a숝1aiTNv~y`m3 k,4 aħ+pW3/efL@0g}9nwp"!<6.~!m$Qزa{bykm,KOHo!RǗd*us:LvO|EٕH=5 ycYCwX!)dfsUAhкeq_h~(m. >#2[ٱu\~ K7Va >2^2[D9WQ@*kT`Ta)(UV I|"#Ʒ5Қ2C1IsO`eu.x’U FmH>B76Н6.eYPwЁ/W|S6\t*Dƫ=L'?02m 48:X kGmq2e{SqwCxse#EcB/W~rw-$DI-txg4:P&siJIw>%D `ͧMmP "x.깪)ܥ p?vc,׏sbȠTXS>z"K2($ѝ0#ظ~&G<"4d=01 2 ٤y?%b9MKddL@syr&q>s-7pV3z ?KA%°42RD9s¦lϋ]>n.nxoKJvԃ~ "/FLNs-*P&휑1+ ~6%˕R%; ﭽe"p@fP'ir"zn5jK@ `lKf*o ,W:QW_s6Rm*֙.t[FX,6?T@s,6!Kv'MMFT;B.%\F `GUvlX$6v% "gͩz`./~xi25q(8i2<{ޱ=~D'S`lȭg[B g>*fOdr?I0i[U22-z1_l`mnBv]# QގC:= '=^ش+{=.׈߼1@fUk .^GWr{:5qH? e[l@RCNsxspC[|{<q)dc j=js #nT ( DlGM'KN7ookԄ\Kc/ௐgv_o%.lVuŎꖫMaHX|n֗Q-f({q~kdfVENSePz$gE14Tڎ1n;Ho/6ZҬiw g͈甋˥Cx#YϷ}aAz/GjRVͿ8<,2T OIlC9$(y ʧX&ύԃb6N*=OhWU/;W$ @%³G!LX,TpafjfL)Ϟ73# &N{̚qi~r~"VQ?tñҗbgCS )Y47-~nuC$zgpfSyhyKz1Ƹ3M0[TA,ʓ;C2QVTen`Q'm%VͯmG!N>??|mLjƑ~t ÒB8y"c![~[z:^a8Kx"[^,"r^mi/80 =#*(u)}jXx0f`B uŢt_r.?^MهaBo~~gdUk|2Y )KtnP{Wƻl9!RCBdno^>8{x#ۿ^{iw kPA#/M7kK2 ;f2B-]}p{el!!xR{P7 X#SƾZ^X7;iv#2A_Y }Zn܈b4V_DžT8ղm-@  &1V8N,~.(ձuxqS;wn=e.xJ|CS -@ɋsTWBd!t3~rj oWL[^-0A7$zԮu>=%6 toC@ q]vaONܞv͘3DT{AMƒۘB-󊼦46)/l\ԙj& bgPw9xTr!DWmGqÝ뢹,wBt }! yBXK ԷCyo]l4n 7?n5Ua!}t4^ X/.ԗ}n3lK_zYg]<Ӊ1Jrc/ŨAGEؗ5Ccd1->!;6x~`ʝTau/(bDayJ~~!'9bEzʇʹ9oZ~P㤣~ņaԄaط\! \ f1o. T/vg4%XZMʡǖR̮1rʣdMش|Ss]X̛Mi$aFPMsyp 6Z ȍ`U\MLJ2LI9"L\4m!hJ"vR)K "g'W#^v*뱗 J6h!a;1 w^a3mNFEdW}Gz$Cq~N'fBɲ Ӻ^^\[|eB#ʩ:woYf.vTQyGpJ .`Gkk|q$ { 8q^ԜԬGdC0x qp4E'ydOӾzP:  *C1u#a.c"Gj~M,s=E ;Rm{3jB 7HPe֯:@,u6Q` UO"*4 Q^jE[c7۾X 5xTAk>e~%m^~Uo5wXߓ \x}~?`E$uӋPiwI%zN"Tȃ)'M=`QL( Yr i?OF{Vֺs7:|?ʴWs ɰPuIwtмGgѬ9?#OjAKQU%gP iH@1O!KS܏=ژ!BV$'!+h?W)=OkPH|~+ԥ_Х>c}8 ]4ma8ucЍaVWޱQ8>.7y2| , x<8?[l +%孈3łZ&.TnB3 kqs~5QkrTPx`rZ4*='!l6:/*75DчHE ;NPl6p{FCg]6]DDt $\.e~t@Kayصf T:l뫹w}:46R08ȴ؉ q[SR0>j,XۚOsa,8ruFjrVEP)Vko]tWOԛN.rK)GI"wrSY8lzlImS b-^ۍ5mAׇbiFew.fOY`)Tmo" ~tUͥv t("߁lG'3x!xLӃwATTl'zЛY̶ִ4=!:QVYMŝw'[tWGL.1![ bamn!g)ʄQɒN f[B%Zx W{% 2 ߌ>-_m%[9 ׿J 5i -܇wJex/'tR}‡]t8N$c%ۇ=xyI`mq1X87Q5턘o&B <0t͔ 1AVQ :&&!n9YJdUbt5=ocؐͼ|F;<>}:iѣUͳOr@±QՓRI>TbP0F(\7usE6vD;7+ys Dj@RxG^ڊ(f4N5m%ve`ŒKLU;8b|Q EA@Lk#En-m [CY\,}o3XiD|ViDC8 :=pg܉'<|!{V^F"l3`4WL-g# zFh:% 'n:LEǿƚ~),^8%H})Ay(5meK5I^eK`Zt" X ?O=SJ~!13F]ia&.$u6j$2e$+3I`m#igϳRodD{!/ƧLQpx'ܞ-Rbͼ丰9&TEۗ|Nϖ-{g0 JJPE\q}yj]i/Uq #`WwRI-ͣ/ۿ/w^@ہT5p*P]sm~ӹ x BʉUTQ V!(\s$|+9lE A+^j)!8t]NDɾW.C:KTt[ CnRYG-"0MoC e\aNj&|^Ԑ@1\Oqdku&9̎':EvtelUE%lXؠFR@lt[7f#Iy-ՁէРwԌNR; Ϗ[PH"LLÝ^šCM1+dO҉| dTvhw)O=`Pp'S⨪ܿ; 4ۓlZ0-^q:m|yl| J@<\ 9AR qO ᦬ՙ-wUTIg86 |] qGEi1+e)"f4BY' nH 8#CtnXiF_fSY\WFm?鐺ԣ&AaHHq'"!f ֛%SDJ3scIKj)AɅv녪9f]+M"H?ԤrdkhNC+S9^HNT3~drvni{8ıHgm m8MR)($ƚpdb5gL'c-{ lT>*,\@=:/ӂʨI[G[8si>@v?tTg*>1ХBn@Ԉ?_do*`{j3c6h H؈ξ .PÚ(ձ62 =FGi'M1@2Er:6ȯYl8m@v*V1Iz3Jm!8N 6 '5yCd6=P.JrYMT$*$>s5F $A!P8tϖ +Nr&‹B?Xp4q=oתb˻zk#ZWWȟҥ b҅M<29D]: &)fXFBh6 9~8owx擻ss\]B'+#{dLyEū[}td^ .wqqsT23utME !ӧ*l-ypyMsSYf)?e]U8*YwY*۰gnsUeJ+_;^jq4vJ,;_vG,-kq]j&BǞ;W7 [^*xDܛQB.mt`F=q W\hEVlRBuWnxB82MV9GfF/;|m(@1囄RΚ_$SsuHH&ރ5BdJ"ӥT=c(M#'2_fivhO`lz)%Gpv/eS? Jt QۻX/U|ٞ+N zbq_EebRG, |IC]~JhI!rYKȥl b,cÙ̘ĞaW2X et:c[-75}ݟJHzNNO%5y8HT` +0꿶eWhȪ aBO1'3&.zpFhz/x3M9{ClRMd*"<ɹ\"q xޡw'֎8FLqxɏ,*s^#2F by'@*§v78ȸ%P3BuD&9ÃJhK_g&X"#j֍i"wʼn6츛`5 '=E$3scW mmorT/G:絞z6.l WEZ٢`;R '\2h ~jwc2Aoa'a2Ll :T`%E[9!i* vJN2l Y]^};r| u 7tbQݙvqpCAYJ̦M tAE6 skCCk@G4H7Cl&@kԓuH*lܦ۷FJs7'0hE!%X5>X 4Z,9DD@rgJIe_~qQm,GA/ɸg|p \>2*Ilv;# GyRu#Zd,?`uЂσKbr!f\~hi: ʰ֞(1/vH(,vf'Qzlb2A;r綪)F)R8}r͜ԉjt|Yg{/0䵣X 0/nLSrW~w jJr2^^]aJI5Y >@ٙ f7xB%L9PR!7#  |6[ W H%w۪M50I[C!YTnO÷ ?cRd-Ҋ݅IvI#v!,?@g:mc6!rN C枉oԯh A (G9> !:B_2ѥ¾:ݡBbV:†ƛx,☮yHpo֮U GD6=(ͼRq>q{o06 &ЪHPjkspF8}{uٹj8<7iuC=9M|$e*Y/˥ńʣZݵ!GF BLޝ`)ػǒhW(l d{#QhMhMgV}86MսVˏ|wܖs$0~OޥzhyAiezC:r,L#tJ(YF2ڭV/iGЉgzR`2 "F7'1OVsF1ɡ| q/d%ٷ 9_l#6K$d-1b#}*GE7n FDs kHaRgp`ʟ=o|I!cƺ]!5I .F!5RV$zTsä8$_opD`0(,ѥ\]RbߩMsv_ ;Ufn|h, ~as/t%ީ )Ih[qTQB;d%r2N&%'~ET9t]=&nHXa~`[q`y9loc r>SvvLx&ZՍV"̺$Df `Ҩ7d^H!.~iSy}hSx\:)hɮ0jp-m?% >m~ptL5Ʉ |3J`#j/c)FFI[cq : 95aщ%( .u( oU(z|*Ojv1Cm:2U<3^|C67*web:FG0<?pM=|?6&o9RHe`w{ĂO* :y+(OUoq.ž ȵPavyRtxM^J|U`K~nUt2Îbfa͐* 8_%+8y#ivȓHOgT} IU&gD{2XfMʭ@fGi@tLKi.kSy\5/YmYL6*.CX{zqa6<͍9o!)NѠ3nf$0-Z|+1V`N|8.._%\X>-r9ʜiKW2JN}ټ~tpjP~+>^Mt_w ZKl3RuVLjE;fUv]V#:KG1jՖTF4̜ÙH`m#QiB(b w&BM~LuVBR`diM;Tvz$ nDwΡF`.'L"H!ewm`6? cic֏ KU%FSׇ~hZuZKMQ 4#O. cvkZ;|̈́@]+R wN:6=гry.ajCE`ICk' k:] _V*pY>oxcג0"fbU? klXq> #maW3&vb@UСWOJ&})bY#6Lяg=Ly5:jylDU6wXS^h~uB*OةZt=T0!YxB)c:P>zFfOfCqHyΪpP߲@$=ɞ[ qs_oG+m0$R~"2xR'+BF1Eg`U+Wgwj0@rlUeqm(5Ue6حaO"dF׳bKefSd9xe,ؽcFߛkc.R9=Z]CѢog3.U]CZ7d+'e>Rq/}B؟sQNb7l}tp)Dq3]kqʅ 9QEg Ǻ)sLS to%R^oQ}_״yެ4dƌtQ =7!rl]COc0^49iEf\`SG@Hq^MrA{ #[l*xY }@n1B襕|BI$3nMO u˻6zVaeEf+Rim@Nn[1 (fBWMe! h)C(I&Ƣ6^m(%Q)gաJP Y4iM2*6? 囋p(LŸ^'DAPYlǾ`U;(Y\aU |daj0 ΃c~l;S}V@H066%2cꦩ溝v8.ngMdrZTUY1~;" z z]Au̓ R tyx !w( qlMy %G_H[Lp bwOg;kT ۟4R<50wj 4+HH˼)˗ F9a1F1KJTMuF,k3@h ~bPO.XT 溙=Ɨ,< Qn|J\ߪߘJpWHUxvDnd/|FhG_(~ eg8nܯj58{00ǪZ\올$ubŏX1ʹqK: axyV/]ãZ2Ţ{ZaF>qvHm nH!H7 z{`ioQ=Ook4,ğQ6{'MXfS x1^NmH84Qg`|6=jp7gΒDqOQKQܳǝ&ߝX\Nc`l<%HJsiKǁg/M^62{\)ڞ1-yF`0T`7/^y:T::lzsX-]tGJ/08_DR8k≳]KBrih u26<f:$-g O10Ge-S%p=6BZf}O_bPĝexk b!%w5 o 윋$VQz.>|~<.ڙՂ9Atm&->wier+ uQ07kzV\k>H,o 7EG?rokY}44 Lqnfi~gJ?G=ֆC.NPW U4qZhagČ9)>jͦ m&HPgДZ_I<(s{e/!t5m{s;NAD~/rxyk*%i\&LC&$PVdiP=mW~lg*,{c`SNAܽGaƺ~@`<"XEJ$ށhReF^taWC  /cԲnK*ܤ^q:J#65FD.Lf+Q^T8V@AiL |B^:{6CAp8YQ]S!7k0aJ{`@X傈? 5WU0NF.ɈuŒ`Dwͬ UGikdDl&EqL}645P}.#`vWޖw#mT0ê]|.`=QYxn5ۍ ayBGXSMKP@ cQM|]l΁cxAzi˫=.C[X7OⱢpq 6SCq&7owN-K(up,xj|%2] n6Tv Лdg^~06WV4rGWdjtgUa:oW@f>UʔG2o(= vLT x:?HO3O(b@Z_x@cX^\$U8 "+΃X-NƫP,1]y[ǣ,ĻH3osE$dRknvѤ)Z+C3SCv/sqP}UFc샍.!j`Őmx U[X;m:*˩p#zYeMw採^lֲA)دCf?UK6Y glg3/ZtD8StX83D,?vO"=pPtq#'5SL@BPa_xo_a%ض F{>0ǃ~(u$Z*eA#SDdcFV ;K#Ͷ)CAAL(h }pd s@^&aқv 4]QˬO!'A1xmޱO#c0rPBɋ ޗQwM'"Oߣ.lZr:n$Ml+f pz }4ñ/76F-IS(=2RI=b/%TD( (N>2p-^6=]cV̿x,bZo XȮi+g<*D=K}(zNr[$V,w E=*cTS+6oinU:a?D6YaU!2%9mn1m(?n(NjsX\XkIe<$7}]Ǥ^y'բ-n<oC S2 .yK%i䊚nдnr>V⬢Y79^L)5 $ܭu5YQf uۂ|s5$}FC%9Z jH S2M,"IDj~lf^N.2g|a%3'+KjKWn$5V&R:^4.EoT0˟qsY%,J 0f> 穮s_L&Ƶ/&/b(%He l{ Tfa =)P2&V-:M{68u!ah8lLLBߌ\ Q;kg\!8 K-H)#էԮBYypn'rB6CJtIPyNGJ"{w[Ch&l*:y܁獷̣/QSv_ /}4.f+W%-T2_^G} UVfhC)wnIղrX )9>jG8/Kt썱=\] Ug\Xϼ_Ϋ$*߅Zn޶sU^G7k5V `Tﬔ|80A6PNAYC߀A'ˎL嗉 3TvJ4K v `t٠a] !m I07̚ n4p{:dlOtw hNRh[SӠ`:E3 룖(bc Iqp(dəMٍ8U,4˅Wg]ޔyҏ3D竬C4Kp(Jn_pmPǠ>Ѡ6MAR `gzk6G'0.$F)( FtVǔAxR+W>_k$B~|qKbk2| \nWW?lem~:lK a\.E2dmbdƞNdpA@fG{C̼PFӖs|_]V% F^L]ٹUa_0΄jRjA92xmNB,=cJвx66a/֪ԕ!C7w hO6b&I/(D s5H&4@rʃ9;pKy'(RzS-t ;4Nx݈14 UKUBXVC1-cpz)W{+jxo1Dړ[:ȁ5dWZN0uʏӆuG7͡Lݫ$0*04c@%M / a/Ny\~\9dR4ZfԢ.)TWnax(@_H!&^Es֑8$<D2M.(^\#Gia"ph,_ll r޲rv^t' gWNH"YM[r )8>vIi`^. q[צڶ5Xs$ژ 77x,E ) SWIz"Sfcu.E Z]UZ;/'d?5!vكN]C1+h92mZ""ٴSNF,+$n$v!J/jd:j$8#\iJSs=?CcƧgZ/9gk[%**!T?f\l5)i&9qdvqg< 0aly{q({^qQi"F͘>`G:;",H$GO" 6?So|Y[]oB<'n*݊Ԥg]( ։[ !/A]SCPb7(!O&\Umɠ_PBd`PVrBH-ڏU.Ÿv?;Gg!rӍp&iB.Uo{xK9ܳ9Eyjk7(8 ߛ^r >/\_yd$4bSVwbreUZ]'0gث WG;@B>N~>kϬf Z0awlm2Żܭg@ry,SR1bWnŠUƶ8K_v߻Tx/֋:K MdR\ U?2o /V Q~} Y+Gc\y`O-_PO)SlU}2Э!PݓK"[v #YU9pdY"k<{z Ypt黐wq;0:]x\c=V”uznԃUgC 2>JX=ω7&vMyl<1g#Δϔ\/kijȖͧ!\VYws|/ -[@ aYv~ymhqPi4Z6椤+H`k}Xklo^l2;I`ٴoTC&09f}(R,/ }ZFnD]~E!l,GD侶fqNPMnb1UDc* JK.,YbG7a9x+:[uO$WWiBwPâ&i2J?Sfe1UXםW6~F6wwPw')&n!u:DzbJc]\ %.h<<ݖvl.rggDH a#9|beJBtDL#w5:6hs^- dSG6Ί/ Itno9w3%nydLZ%s[Lp" <jP?|>tqaC}~9MLhcWhC6ƝH=%ɿdd3D$G vr\e,:;XC}btQ\>ox9=Irs 3SLQ|DDN;LK/C?,J#.ݛ e=.`Ro73ck"<7en鸿QsU-5/\{ ZNkftf8R&k輩΃`w$HR.I zaWC&`KX @&oC/]{<cP_Q,DĐݷQ^ǠdF N"FCg:/9m5$3 ~ PrSڋm?ec_S][IlC(uU7 "`:`<V`az^[a Ikq'/P+j&ol冨: Tt+UEs֔ Րz6/ D\8Z'ļ!\Qڲ48/4/4 R"KUț)܇V8V1w1~u 2ƴHe;GoBqQ\/6\MȍOvM~)f\љcz59^+"kd^BV6B S1/ R,(EeTFҬn>U#0F\o5_ c R:/jʒ<!Z;!j1;Nңۃ:HBAͳF}\NĿp?Pǖ*H=.t酀8ٙykw{<\Tl^Rƨ+J`;|!_{2e$[Z?X! [\.E3QnAAiU JQRBt.bnxF}$IdِHWɬ(P6czizl/\O;<xGH \!&j1rl :'[ s\댆RFIGγ1-r"SʅmNWyI^ԻvsR[(={?}}.vU )"bY9w;h@)laDL|4W*JGp# 9w cu%MV,P^ X mp>1`aQ)!]$`׵;PHH)׭r<+ (e/mTag?P˙^" w^KKSm74iճ. *@ܫ4)b[A}fbޮ\',h~c'Ŭ͘vx24O3R¾M1{P 1:!+8K 3:BDz oSS~/(86RTb[̝RQ dU>w>UWs.rPgiƼ՟2 q.S@-qڴ[C"c%~ՅUz,l.o-lMA>sɭKvUQȥ?pBЙ5 :[zjbR(-.Ad>'G5-Bm}Dܵh/BOz, PeZ *[U8#A67UPȢhLq&2)LVt&R;\(ϲ/eǛ_^TWNkZ!C[v(@YL]=ʼ] bDj2a 0H#԰id![=JAݼl<n.$Ov0CޕϚg)NQD,? "h=1b+ox* hYc#@翕D 3W0ꊝWM*?^GTwqVk!v>\}]]҈J-Fʭ[qP ;M>Ηikg*FkI#l7!wb$TXx}!8>fksl0h`e>LD_k΀r s1υjAr?HD1eQEakP\q);#2۞Dyeqݞgt2leuK2D9eᎢH33&A.`ڤ<=%u@p$8a\-g./vҐ/ eg*<EznEl^h%#\9{t&aJNl R6y"J(50C-osw8AhUD\tyzS#‹4(d=OŠEԐs@7N/+doېPAM;? fE)#7*C py Mf .=oW,`?IrUXǩp%gdIuZR&2hwfxO,!ۇۜ&XFkhiռSxGkaџ#$~8pNADdTеs۳BȊA$N,+~BMii[kdugf^TY19 zגINq1df{7ň>* r"_ !1h6>@YJ"&w]]2/+?"/YJDVƋyT)@JΏ jfZ<ֵjt8z-ye{u5 ?#Yφ豠aOLM0a_,yxD9ZڤcPF~7| XKa5OTC Td!D"#zv@דJV~m q&.-W"]? .jgQ^ )f^I4}~R5f>$#*ʭeO5dODŽ6 9WH01&rA]ƕx{ 8$P!)zDFZl 51d uv>V'ByȞwf0&rn)kk{ܪDzKEg*2 <%rV$9ydv6Z)jsE]ڣ&6c;E<,`Z{¢2s`z\vX'r]@QzGH;gXSL(-AR%uJpݡv$Lغ3hoejO-Ќ6XؐTVKJn1 5uFTJD돖t66\Rwiny& Σ?ryFWObžr }ypWsԞQm؄qqþY >{D:Q":4lCYx_k)H<hփÂΕ 7nN̓9*gL~qOA)=O&1e~ًE|CfۨT.ݓ.k/dZ}kh1!98"H%ɉ.RmJH.u<28mX8n5d@,,i2޾h7ߺ%\X"4I<.%UYl@``H2BconO$d}r+񬷝2f:KU=N@(b oTRyD/BY7 J1.Ӹ}.FA]VRZt+7s1y]NƟՐA>̯D(ayI/ȱS5(垽 n4S􁝂.ʐ4{ZMaSKb0`O{iepfnAH+N?/68eMZ0*:I' swS).'s/S|#KLHR1p_4z_\nT$'=/m]Ql(;q)9 z>cLnH%h%AWa8N莂tbUj!߈[֌u%g+YA*Ċ᠒i~ hkW=0MWL= FOn|pFM" l-L#xDJ?@|{! +G<42KRc㓟g4M넏i}tXA쐶p=Y YP9o,ulMl G\͘ f7]*MX#ṃƀq|fHrd^=:@$Ofj0Z(l&0#= m˩36zO<_Ahp3bm$`=(źi(ʄʭ=0QzEYJ)HW;'t!) T?& E 0Dž?ʛ_kO>rfnMmO4)@'th8B(dOVP2! 414w*t@Y1NQN,5|X'pK+ԭbgro"sq(? \MͻOWv| mw' jdʐ@E;'Ј8,D-LAPBn1J5)`Ty*'4igF'HZtRYd%IcSqy՚C㒗E3fzy0|Te;a:U&Zl'.~_Ęc[+uF]]l>&u&yw$u ?v7JʽD{et-6շ^ NP){7 2)wn*j @~1s=Pc۫ɇḴiԗމc禓BeIileAdDǎmueq_&(vF3Gh zRQ1QFldV3)5 [^.7kP?g`sTҝcY͚!+l g-$Ix m$aȝFiK`1ъƟA5sv>.#j> Ѡl?ieL*tۙn!}P;jί6-]sVxI[v0W?ʡLuU*.0m?":ZWBM^[Yշ#آ鍂aưko3r.U ym'5;N[C-=^%*uEH{7ď"CU+@hIZiEuLt9/tJ aP2%,O[=Hy]\syDXE V$}Ƀe魰( Sx9>q$e`$C猿?`P(<qL*{I$1|el@TY_6>stream X1/"@@31@j` R}Iw#An/Qv%#7}6?jF)-3)s(d֜Qu~8_3 E"/f߳lT]wy6 Em411Y*6rC%/vBv #ɄuO 5ҳ>v|k4O&OH9cUG =*, Lu4ZP>5+' endstream endobj 5 0 obj <>stream %u#ܟyt2z"8Q6XZnH AWJ0 $TLPNP3\c36[r6aZO#"/=XgӶ#hQlf@[B޸~alEpbdRL r@~ Xt~f2b Pr!O.}O@EZ7j䈫n:s;H]`<sb6 إ2^ó#& LRd=!{DT-W"NQ.;.o){ݲP)+75s5 g3u [PȟN|Uv-.#sͲkIƈfyNy8n9V! Q DU A՟kd(q!=˷6RA^RP fw} [".E9~3MiWػBۆ@4:E endstream endobj 6 0 obj <>/Subtype/Form/Type/XObject>>stream ]N"G .Eh Cţ endstream endobj 7 0 obj <>/Subtype/Form/Type/XObject>>stream biHMIo,s8?Rš endstream endobj 8 0 obj <>/Subtype/Form/Type/XObject>>stream X|-fyr 9ܣx=I endstream endobj 9 0 obj <>/Subtype/Form/Type/XObject>>stream zAfar1 %0{fzz)psgQ endstream endobj 10 0 obj <>/Subtype/Form/Type/XObject>>stream ˖1tAC!s_wy_ endstream endobj 11 0 obj <>/Subtype/Form/Type/XObject>>stream vO!.T˟KdY#~f= endstream endobj 12 0 obj <>/Subtype/Form/Type/XObject>>stream k7Xo[@W=i-]Wѿҙ[ endstream endobj 13 0 obj <>/Subtype/Form/Type/XObject>>stream Q4e 2kv4ԧLӇ%~ endstream endobj 14 0 obj <>stream BC Q/rN%)$1+ݼ> lm/y-;t h9t} S ;9}gxHt'.[Nh) mm2 S7^S;[>$nʹN"Tbs_+{qZ1h_0:'r# TT+qUe]HNt/G򤯋EfY? x3-M@ԅ$bK@1VΖ2-WG&y錿#s"MH(p@5BS` Eww1żL!v31/O";}7E` -G{A6\N N+,~ !h2mz<7BclkOe 1#BX}f IpǼ@vƵIk ;Y(o"ϋ.0n5bl}DO) PÜA."ԗR='|*B97#)Kݖ~g[wnV#4\<FGi):Y%("6*N?j#~Y/`(\ơa9|B68phKW/AĢOґi.e 8lT/64rha~bXԅ}d8pFnC58*\.ds5^O>+J#$Z;fQ}s 8叉yt+-N>3Zn"W3u5#-rdDlzKDan/wrz@#(iYq#uz/_ skg:֐x!+ꙋ<U_e?}A~'V՚\++j'$.U@2Q856\K0d#|Ѐ9eÊ_ES*u:l&x0#m޽1\r?; JׁIZGk'Xd gGL$d[(tz;Z h%TUOk1pvIIz\sM=esG !D#v.Q>+"/9fk׀% endstream endobj 15 0 obj <>stream ZR=NJ՚HBqجʏdmEXR2ߟJ*I"vPAwiH?GbZ%Zc6$Zrs EA_)Rٺdח.>AWNqM$AΣ.1lV:Za^#ɨ;-r4 !]F3S`Y3em|+Dby51vF&^#ԕkb5d毣Uah(ƸPc>"- HOs\p8 )CN)2bDͥW74 15*ӄTNY%*~Pyh7jfU{MH+ab$LE`]B]agrx( +}#:Vh` 0h,Sd?K_E(q_؝p6e,&gb_  |<8.; hH@ߴ| vxkKGrf;7XOĶ]~.O]pYWw׵[+Zp-6ݖ4RCl ][G>;JփY)[e8}!E<PlG0e/J㼡ƀDף` endstream endobj 16 0 obj <>stream 戗i`VDF.kٰs]W+yh0@>O6.<jDY@ߪNPc.j%=)LJENr 9qtۑ3vB1BtʌxHgW}$Oa跮S1%=_v%sȾw1+#Ok X" $EBL*&ΐYwuJD (tC8Ϙ8k*zD8~ h=;JG")lLܽߪ@aAϔ$Y z5Tز=0عsk^ij+B\߈Y~-+亀q ۛ#%6AcF66ab0(9i?Y{ReoE"NXBdwȶO̚'&Ao IM}MϚx6V&@4tqf8泟 w{zD5U>ᐅpu`=*3ҋVوzٍ "?ode0ٸ0zp68?K7..qR}#FEAP {m|uF, *`k ߳D VǮӡ$qKp·g`sbJh% Zsz6J3lL޾ _&P_bLx 5P;JA%PEjqN%Ëg|&/-3`$'.6zg.y<˻XRH2PZ3G*-k% !Ow55U/:.?"_s$x5Ƴܨ#N n?ѨPM5i>ȂZz(/E<`ưgi&;i 0^:hf߇"WOYV_lnΐcR搄%ֿz|1kꐣ'[RTyLfHd /b€9'6Pb0X:_jO?gns+Š2ti-R՜ endstream endobj 17 0 obj <>stream RIlm^2, lRC~[ER&/keyiEeH,KTȩʫ0;qAW<ʮM H TY(cl 9'v/bBqm.7}/ -)O͗$D2d{5jmc"Pq 5jNaߖ %Mtn&. m Y5DM4ͣ]B877IFB*<+f) sBaL|a^*$Lwd@RkX >uMgOf 'Hj[T]kH JF$lxV'o&Vm G'?H[.`e +| !]!)rb%Vk?屁*z,"E0wY}Qӓ~|ߟx@$4,s/ѲvNaΦogCෝUf)xL9 SC~Nj)i.:OLd-tIhK=L@>Rl },¾ Ǡ| =5`:8((si,#UohKsȻu*&*CF5f4o˻mT[ʨB ǟ26+UJ-  +P߹Ztt4nĤ>*m\ȍQw-WN0;-:ȰģnVosmE&V_Y~ٔic|hbpi])ʹ;˾XP+}f~ڈZ>M>nY&i'vr؁&N-W/ʣQѽ#beoTz 8"f!nN=}k5UxxbV0h7m&:3~~ݟ|҄}lmt.% T|}19Y1@"FV7DȐKḻ?岶!RF@;hdӋWFCIG XN9嗵/r!?2c's3VI*s5ErP ZBޗ̦}mԙNBuFr|gtRTNb]H#N ibh%`#1MJ J(g,{oCV_f3 sʂ9(BߊH~sOl]CqB_h,Ș)iKߟqy9x⑊W*#",VB"!b2W3|F7H+ltYCH߃v;F R. GkP' eC$;biYKAAq՗Ut㘘~V=)Q] Ck6ͮAV7/&HUp, l#Cj:<V^LwO!w iJ,:1{iSD!!H&*:[UlcK@G+]S$ [V!MsDg+!CBm qh`;t7yH,:6y bFUCALwA;nX abHz,f?= t}`H9.fee>7A\M%ְ?oXF5Bp!`.ؒ2#{vV#zħo܎\r&h'Msj;q=\4jˊ<Hk_ 'eIjP*G*82^W*~O2kV\<^Fʍϋ ƿ?\d^F$* Fbl34}.CB.rM`ctG҅0N;Q$y/-[y =;vAst{QnA97kF]3F;dh'*:T\3d͗EP0(敚YzNN6C>kIoO8#pqInST(H?9A",b+sD 7J]428<-#u[ G?+ږ endstream endobj 18 0 obj <>stream s|<gh$>yR@B"b lOc L9\D˼TIc Q9/k;w):t endstream endobj 19 0 obj <>stream wVɏa0y 1<0׵~\:H]'Y̱624SM m 4a6hT .7[j_`.+I[`{w)([R̺ (G7r?[շ>b2 endstream endobj 20 0 obj <>/Encrypt 142 0 R/Filter/FlateDecode/ID[<09223433A828074EBF2A058EB22B976A>]/Info 140 0 R/Length 113/Root 143 0 R/Size 141/Type/XRef/W[1 3 1]>>stream hbb&F];&p)$"GA$sd l}`>$Y0=d["k?ׁM``Gr&? Cf$dNQ 0 endstream endobj startxref 116 %%EOF NASA-SW-VnV-ikos-1d98c65/doc/install/000077500000000000000000000000001473507761200170315ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/000077500000000000000000000000001473507761200173315ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/ARCHLINUX.md000066400000000000000000000033161473507761200212130ustar00rootroot00000000000000Install IKOS on Arch Linux ========================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS on **[Arch Linux](https://www.archlinux.org/)** using **[AUR](https://aur.archlinux.org/)** (Arch User Repository). First, make sure your system is up-to-date: ``` $ sudo pacman -Syu ``` Then, install the *apron* and *ikos* **[AUR](https://aur.archlinux.org/)** packages. See **[Installing packages](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages)** for detailed instructions. * https://aur.archlinux.org/packages/apron * https://aur.archlinux.org/packages/ikos To be informed on updates by email, click on "Enable notifications" in "Package actions" on the AUR website. You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md Build IKOS from source on Arch Linux ==================================== Here are the steps to install the required dependencies to build IKOS from source on **[Arch Linux](https://www.archlinux.org/)** using **[AUR](https://aur.archlinux.org/)** (Arch User Repository). First, make sure your system is up-to-date: ``` $ sudo pacman -Syu ``` Now, install the following packages using **pacman**: ``` $ sudo pacman -S base-devel cmake gmp boost boost-libs python python-pygments sqlite intel-tbb llvm llvm-libs clang ``` Then, install the *apron-ppl-svn* **[AUR](https://aur.archlinux.org/)** package: * https://aur.archlinux.org/packages/apron-ppl-svn You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/CENTOS_6.10.md000066400000000000000000000072371473507761200213230ustar00rootroot00000000000000Install IKOS on CentOS 6.10 =========================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS and its dependencies on **[CentOS 6.10](https://www.centos.org/)** IKOS requires certain versions of cmake, apron, boost and llvm that are newer than the ones available on the CentOS Yum package manager. Hence the following describes the steps to bootstrap these dependencies on CentOS. First, make sure your system is up-to-date: ``` $ sudo yum update ``` Install the following packages using yum: ``` $ sudo yum install patch bzip2 xz zlib-devel libedit-devel make m4 sqlite-devel tbb-devel ``` We will use [CentOS Sofware Collections (CSL)](https://wiki.centos.org/AdditionalResources/Repositories/SCL) to get a more recent version of gcc and python. Enable the CSL by running: ``` $ sudo yum install centos-release-scl ``` Now, you can install the following packages: ``` $ sudo yum install devtoolset-8-gcc devtoolset-8-gcc-c++ python27 ``` You need to update your `PATH` and `LD_LIBRARY_PATH` to use devtoolset-8 and python27. Use the following commands (consider adding this in your `.bashrc`): ``` $ PATH="/opt/rh/python27/root/usr/bin:/opt/rh/devtoolset-8/root/usr/bin:$PATH" $ export LD_LIBRARY_PATH="/opt/rh/python27/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ``` In the next step, we will use the bootstrap script to build and install cmake, apron, boost, llvm and IKOS. Here, we will use `/path/to/ikos-install` as the installation directory and `/path/to/ikos-build` as the build directory. Replace it with the location where you want to put IKOS and its dependencies (for instance, `~/ikos-install` and `~/ikos-build`). In IKOS root directory, run: ``` $ cd script $ ./bootstrap --prefix=/path/to/ikos-install --builddir=/path/to/ikos-build ``` You can also specify the number of CPU you want to use with `--jobs=N`. By default, it will use **all available CPU**. Note: Try to avoid whitespaces in the installation path, as it might fail. This script will also build, install and run the tests of IKOS for you. After installation, the install directory will contain the following structure: ``` . ├── activate-full ├── activate-minimal ├── apron-0.9.10 │ ├── bin │ ├── include │ └── lib ├── boost-1.70.0 │ ├── include │ └── lib ├── cmake-3.15.2 │ ├── bin │ ├── doc │ └── share ├── gmp-6.1.2 │ ├── include │ ├── lib │ └── share ├── ikos-3.0 │ ├── bin │ ├── include │ ├── lib │ └── share ├── llvm-9.0.0 │ ├── bin │ ├── include │ ├── lib │ ├── libexec │ └── share ├── mpfr-4.0.2 │ ├── include │ ├── lib │ └── share └── ppl-1.2 ├── bin ├── include ├── lib └── share ``` During its execution, the **bootstrap** script creates a special environment with all the required dependencies for IKOS. To enter that environment, simply run the following command (consider adding this in your `.bashrc`): ``` source /path/to/ikos-install/activate-minimal ``` For short, it adds the necessary directories to your `PATH` and your `LD_LIBRARY_PATH`. For more information about the **bootstrap** script and how to run the tests, see [ROOTLESS.md](ROOTLESS.md). You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/CENTOS_7.6.md000066400000000000000000000067021473507761200212450ustar00rootroot00000000000000Install IKOS on CentOS 7.6 ========================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS and its dependencies on **[CentOS 7.6](https://www.centos.org/)** IKOS requires certain versions of cmake, apron, boost and llvm that are newer than the ones available on the CentOS Yum package manager. Hence the following describes the steps to bootstrap these dependencies on CentOS. First, make sure your system is up-to-date: ``` $ sudo yum update ``` Install the following packages using yum: ``` $ sudo yum install which patch bzip2 xz zlib-devel libedit-devel make m4 gmp-devel mpfr-devel python python-pygments sqlite-devel tbb-devel ``` We will use [CentOS Sofware Collections (CSL)](https://wiki.centos.org/AdditionalResources/Repositories/SCL) to get a more recent version of gcc. Enable the CSL by running: ``` $ sudo yum install centos-release-scl ``` Now, you can install the following packages: ``` $ sudo yum install devtoolset-8-gcc devtoolset-8-gcc-c++ ``` You need to update your `PATH` and `LD_LIBRARY_PATH` to use devtoolset-7. Use the following commands (consider adding this in your `.bashrc`): ``` $ PATH="/opt/rh/devtoolset-8/root/usr/bin:$PATH" $ export LD_LIBRARY_PATH="/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ``` In the next step, we will use the bootstrap script to build and install cmake, apron, boost, llvm and IKOS. Here, we will use `/path/to/ikos-install` as the installation directory and `/path/to/ikos-build` as the build directory. Replace it with the location where you want to put IKOS and its dependencies (for instance, `~/ikos-install` and `~/ikos-build`). In IKOS root directory, run: ``` $ cd script $ ./bootstrap --prefix=/path/to/ikos-install --builddir=/path/to/ikos-build ``` You can also specify the number of CPU you want to use with `--jobs=N`. By default, it will use **all available CPU**. Note: Try to avoid whitespaces in the installation path, as it might fail. This script will also build, install and run the tests of IKOS for you. After installation, the install directory will contain the following structure: ``` . ├── activate-full ├── activate-minimal ├── apron-0.9.10 │ ├── bin │ ├── include │ └── lib ├── boost-1.70.0 │ ├── include │ └── lib ├── cmake-3.15.2 │ ├── bin │ ├── doc │ └── share ├── ikos-3.0 │ ├── bin │ ├── include │ ├── lib │ └── share ├── llvm-9.0.0 │ ├── bin │ ├── include │ ├── lib │ ├── libexec │ └── share └── ppl-1.2 ├── bin ├── include ├── lib └── share ``` During its execution, the **bootstrap** script creates a special environment with all the required dependencies for IKOS. To enter that environment, simply run the following command (consider adding this in your `.bashrc`): ``` source /path/to/ikos-install/activate-minimal ``` For short, it adds the necessary directories to your `PATH` and your `LD_LIBRARY_PATH`. For more information about the **bootstrap** script and how to run the tests, see [ROOTLESS.md](ROOTLESS.md). You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/DEBIAN_10.md000066400000000000000000000026611473507761200211020ustar00rootroot00000000000000Install IKOS dependencies on Debian Buster ========================================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install the required dependencies of IKOS on **[Debian 10 (Buster)](https://wiki.debian.org/DebianBuster)**. First, make sure your system is up-to-date: ``` $ sudo apt-get update $ sudo apt-get upgrade ``` Now, you will need to add the LLVM repository to your apt `sources.list`: ``` $ echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-9 main" | sudo tee -a /etc/apt/sources.list ``` You also need to trust the LLVM repository key: ``` $ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - ``` Then, run the following commands: ``` $ sudo apt-get update $ sudo apt-get install gcc g++ cmake libgmp-dev libboost-dev libboost-filesystem-dev \ libboost-thread-dev libboost-test-dev python python-pygments libsqlite3-dev libtbb-dev \ libz-dev libedit-dev llvm-9 llvm-9-dev llvm-9-tools clang-9 ``` When running cmake to build IKOS, you will need to define `LLVM_CONFIG_EXECUTABLE`: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/DEBIAN_9.md000066400000000000000000000026661473507761200210370ustar00rootroot00000000000000Install IKOS dependencies on Debian Stretch =========================================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install the required dependencies of IKOS on **[Debian 9 (Stretch)](https://wiki.debian.org/DebianStretch)**. First, make sure your system is up-to-date: ``` $ sudo apt-get update $ sudo apt-get upgrade ``` Now, you will need to add the LLVM repository to your apt `sources.list`: ``` $ echo "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-9 main" | sudo tee -a /etc/apt/sources.list ``` You also need to trust the LLVM repository key: ``` $ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - ``` Then, run the following commands: ``` $ sudo apt-get update $ sudo apt-get install gcc g++ cmake libgmp-dev libboost-dev libboost-filesystem-dev \ libboost-thread-dev libboost-test-dev python python-pygments libsqlite3-dev libtbb-dev \ libz-dev libedit-dev llvm-9 llvm-9-dev llvm-9-tools clang-9 ``` When running cmake to build IKOS, you will need to define `LLVM_CONFIG_EXECUTABLE`: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/FEDORA_29.md000066400000000000000000000050731473507761200211320ustar00rootroot00000000000000Install IKOS dependencies on Fedora 29 ====================================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS and its dependencies on **[Fedora 29](https://getfedora.org/)**. IKOS requires a specific version of llvm and clang that are not available on the Fedora package manager. Hence the following describes the steps to bootstrap these dependencies. First, make sure your system is up-to-date: ``` $ sudo dnf update ``` Now, install the following packages: ``` $ sudo dnf install which findutils patch bzip2 xz zlib-devel libedit-devel \ gcc gcc-c++ make cmake m4 gmp-devel mpfr-devel ppl-devel boost-devel \ python python-pygments sqlite-devel tbb-devel ``` In the next step, we will use the bootstrap script to build and install llvm, clang and IKOS. Here, we will use `/path/to/ikos-install` as the installation directory and `/path/to/ikos-build` as the build directory. Replace it with the location where you want to put IKOS and its dependencies (for instance, `~/ikos-install` and `~/ikos-build`). In IKOS root directory, run: ``` $ cd script $ ./bootstrap --prefix=/path/to/ikos-install --builddir=/path/to/ikos-build ``` You can also specify the number of CPU you want to use with `--jobs=N`. By default, it will use **all available CPU**. Note: Try to avoid whitespaces in the installation path, as it might fail. This script will also build, install and run the tests of IKOS for you. After installation, the install directory will contain the following structure: ``` . ├── activate-full ├── activate-minimal ├── apron-0.9.10 │ ├── bin │ ├── include │ └── lib ├── ikos-3.0 │ ├── bin │ ├── include │ ├── lib │ └── share └── llvm-9.0.0 ├── bin ├── include ├── lib ├── libexec └── share ``` During its execution, the **bootstrap** script creates a special environment with all the required dependencies for IKOS. To enter that environment, simply run the following command (consider adding this in your `.bashrc`): ``` source /path/to/ikos-install/activate-minimal ``` For short, it adds the necessary directories to your `PATH` and your `LD_LIBRARY_PATH`. For more information about the **bootstrap** script and how to run the tests, see [ROOTLESS.md](ROOTLESS.md). You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/FEDORA_30.md000066400000000000000000000050731473507761200211220ustar00rootroot00000000000000Install IKOS dependencies on Fedora 30 ====================================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS and its dependencies on **[Fedora 30](https://getfedora.org/)**. IKOS requires a specific version of llvm and clang that are not available on the Fedora package manager. Hence the following describes the steps to bootstrap these dependencies. First, make sure your system is up-to-date: ``` $ sudo dnf update ``` Now, install the following packages: ``` $ sudo dnf install which findutils patch bzip2 xz zlib-devel libedit-devel \ gcc gcc-c++ make cmake m4 gmp-devel mpfr-devel ppl-devel boost-devel \ python python-pygments sqlite-devel tbb-devel ``` In the next step, we will use the bootstrap script to build and install llvm, clang and IKOS. Here, we will use `/path/to/ikos-install` as the installation directory and `/path/to/ikos-build` as the build directory. Replace it with the location where you want to put IKOS and its dependencies (for instance, `~/ikos-install` and `~/ikos-build`). In IKOS root directory, run: ``` $ cd script $ ./bootstrap --prefix=/path/to/ikos-install --builddir=/path/to/ikos-build ``` You can also specify the number of CPU you want to use with `--jobs=N`. By default, it will use **all available CPU**. Note: Try to avoid whitespaces in the installation path, as it might fail. This script will also build, install and run the tests of IKOS for you. After installation, the install directory will contain the following structure: ``` . ├── activate-full ├── activate-minimal ├── apron-0.9.10 │ ├── bin │ ├── include │ └── lib ├── ikos-3.0 │ ├── bin │ ├── include │ ├── lib │ └── share └── llvm-9.0.0 ├── bin ├── include ├── lib ├── libexec └── share ``` During its execution, the **bootstrap** script creates a special environment with all the required dependencies for IKOS. To enter that environment, simply run the following command (consider adding this in your `.bashrc`): ``` source /path/to/ikos-install/activate-minimal ``` For short, it adds the necessary directories to your `PATH` and your `LD_LIBRARY_PATH`. For more information about the **bootstrap** script and how to run the tests, see [ROOTLESS.md](ROOTLESS.md). You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/MAC_OS_X.md000066400000000000000000000026141473507761200211460ustar00rootroot00000000000000Install IKOS on Mac OS X ======================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS on **[MAC OS X](https://www.apple.com/macos/high-sierra/)** using **[Homebrew](https://brew.sh/)**. First, make sure your system is up-to-date: ``` $ brew upgrade ``` Now, install IKOS: ``` $ brew install nasa-sw-vnv/core/ikos ``` You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md Build IKOS from source on Mac OS X ================================== Here are the steps to install the required dependencies to build IKOS from source on **[MAC OS X](https://www.apple.com/macos/high-sierra/)** using **[Homebrew](https://brew.sh/)**. First, make sure your system is up-to-date: ``` $ brew upgrade ``` Now, install the following packages: ``` $ brew install cmake gmp boost tbb llvm@14 ``` When running cmake to build IKOS, you will need to define `LLVM_CONFIG_EXECUTABLE`: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -DLLVM_CONFIG_EXECUTABLE="$(brew --prefix)/opt/llvm@14/bin/llvm-config" \ -DSQLITE3_ROOT="$(brew --prefix)/opt/sqlite3" .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/RHEL_6.10.md000066400000000000000000000067131473507761200210600ustar00rootroot00000000000000Install IKOS on Red Hat Enterprise Linux 6.10 ============================================= **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS and its dependencies on **[Red Hat Enterprise Linux 6.10](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux)** IKOS requires certain versions of gcc, cmake, apron, boost and llvm that are newer than the ones available on the Red Hat Yum package manager. Hence the following describes the steps to bootstrap these dependencies on Red Hat. **Warning**: You will need **at least 10 Gb** of disk space and a **few hours**. First, make sure your system is up-to-date: ``` $ sudo yum update ``` Now, install the following packages using yum: ``` $ sudo yum install which file patch tar bzip2 xz zlib-devel ncurses-devel \ gcc gcc-c++ make m4 python34 python34-pygments sqlite-devel tbb-devel ``` In the next step, we will use the bootstrap script to build and install gcc, cmake, apron, boost, llvm and IKOS. Here, we will use `/path/to/ikos-install` as the installation directory and `/path/to/ikos-build` as the build directory. Replace it with the location where you want to put IKOS and its dependencies (for instance, `~/ikos-install` and `~/ikos-build`). In IKOS root directory, run: ``` $ cd script $ ./bootstrap --prefix=/path/to/ikos-install --builddir=/path/to/ikos-build ``` You can also specify the number of CPU you want to use with `--jobs=N`. By default, it will use **all available CPU**. Note: Try to avoid whitespaces in the installation path, as it might fail. This script will also build, install and run the tests of IKOS for you. After installation, the install directory will contain the following structure: ``` . ├── activate-full ├── activate-minimal ├── apron-0.9.10 │ ├── bin │ ├── include │ └── lib ├── boost-1.70.0 │ ├── include │ └── lib ├── cmake-3.15.2 │ ├── bin │ ├── doc │ └── share ├── gcc-9.2.0 │ ├── bin │ ├── include │ ├── lib │ ├── lib64 │ ├── libexec │ └── share ├── gmp-6.1.2 │ ├── include │ ├── lib │ └── share ├── ikos-3.0 │ ├── bin │ ├── include │ ├── lib │ └── share ├── libedit-2.11 │ ├── include │ ├── lib │ └── share ├── llvm-9.0.0 │ ├── bin │ ├── include │ ├── lib │ ├── libexec │ └── share ├── mpfr-4.0.2 │ ├── include │ ├── lib │ └── share ├── ppl-1.2 │ ├── bin │ ├── include │ ├── lib │ └── share └── python-3.4.10 └── bin ``` During its execution, the **bootstrap** script creates a special environment with all the required dependencies for IKOS. To enter that environment, simply run the following command (consider adding this in your `.bashrc`): ``` source /path/to/ikos-install/activate-minimal ``` For short, it adds the necessary directories to your `PATH` and your `LD_LIBRARY_PATH`. For more information about the **bootstrap** script and how to run the tests, see [ROOTLESS.md](ROOTLESS.md). You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/RHEL_7.7.md000066400000000000000000000063521473507761200210060ustar00rootroot00000000000000Install IKOS on Red Hat Enterprise Linux 7.7 ============================================ **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install IKOS and its dependencies on **[Red Hat Enterprise Linux 7.7](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux)** IKOS requires certain versions of gcc, cmake, apron, boost and llvm that are newer than the ones available on the Red Hat Yum package manager. Hence the following describes the steps to bootstrap these dependencies on Red Hat. **Warning**: You will need **at least 10 Gb** of disk space and a **few hours**. First, make sure your system is up-to-date: ``` $ sudo yum update ``` Now, install the following packages using yum: ``` $ sudo yum install which file patch tar bzip2 xz zlib-devel ncurses-devel \ gcc gcc-c++ make m4 gmp-devel mpfr-devel python sqlite-devel tbb-devel ``` In the next step, we will use the bootstrap script to build and install gcc, cmake, apron, boost, llvm and IKOS. Here, we will use `/path/to/ikos-install` as the installation directory and `/path/to/ikos-build` as the build directory. Replace it with the location where you want to put IKOS and its dependencies (for instance, `~/ikos-install` and `~/ikos-build`). In IKOS root directory, run: ``` $ cd script $ ./bootstrap --prefix=/path/to/ikos-install --builddir=/path/to/ikos-build ``` You can also specify the number of CPU you want to use with `--jobs=N`. By default, it will use **all available CPU**. Note: Try to avoid whitespaces in the installation path, as it might fail. This script will also build, install and run the tests of IKOS for you. After installation, the install directory will contain the following structure: ``` . ├── activate-full ├── activate-minimal ├── apron-0.9.10 │ ├── bin │ ├── include │ └── lib ├── boost-1.70.0 │ ├── include │ └── lib ├── cmake-3.15.2 │ ├── bin │ ├── doc │ └── share ├── gcc-9.2.0 │ ├── bin │ ├── include │ ├── lib │ ├── lib64 │ ├── libexec │ └── share ├── ikos-3.0 │ ├── bin │ ├── include │ ├── lib │ └── share ├── libedit-2.11 │ ├── include │ ├── lib │ └── share ├── llvm-9.0.0 │ ├── bin │ ├── include │ ├── lib │ ├── libexec │ └── share └── ppl-1.2 ├── bin ├── include ├── lib └── share ``` During its execution, the **bootstrap** script creates a special environment with all the required dependencies for IKOS. To enter that environment, simply run the following command (consider adding this in your `.bashrc`): ``` source /path/to/ikos-install/activate-minimal ``` For short, it adds the necessary directories to your `PATH` and your `LD_LIBRARY_PATH`. For more information about the **bootstrap** script and how to run the tests, see [ROOTLESS.md](ROOTLESS.md). You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/ROOTLESS.md000066400000000000000000000102621473507761200211260ustar00rootroot00000000000000Install IKOS without root access ================================ **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are instructions to install IKOS and its dependencies without sudo or root access. IKOS provides a **bootstrap** script that is able to detect your current configuration. It will check for all IKOS dependencies. All missing dependencies are automatically downloaded, built and installed. Minimal requirements -------------------- The **bootstrap** script should work on any UNIX environment. It has been tested under Arch Linux, CentOS, Debian, Fedora, Mac OS X, Red Hat and Ubuntu. The script requires some binary utilities to work properly. It assumes you have the following commands: `bash`, `basename`, `dirname`, `mkdir`, `touch`, `sed` and `date`. If you don't, you should install them manually. The script automatically checks for all the other required utilities (such as `uname`, `which`, `patch`, etc.). Just install the missing dependencies manually whenever the script tells you a tool is missing. You will need a **C/C++ compiler**. The version of the compiler does not matter. If you have an old compiler that does not support C++ 14, the script will automatically download, build and install **gcc 9.2.0**. You will also need a tool to download tarballs, such as **curl** or **wget**. Disk space and time ------------------- The script might take a lot of disk space and a lot of time to complete. If your compiler does not support C++ 14 (ie. gcc < 4.9.2 or clang < 3.4), you will need **at least 10 Gb**. The script might run for a **few hours**, depending on your number of CPU. Otherwise, **3 to 5 Gb** should be enough, and it should be done in at most **1 to 2 hours**. How to build IKOS ----------------- First, move in the `script` directory: ``` $ cd script ``` We will use the **bootstrap** script. Run `./bootstrap -h` to get all available options. Here, we will use `/path/to/ikos-install` as the installation directory and `/path/to/ikos-build` as the build directory. Replace it with the location where you want to put IKOS and its dependencies (for instance, `~/ikos-install` and `~/ikos-build`). To build IKOS and its dependencies, run: ``` $ ./bootstrap --prefix=/path/to/ikos-install --builddir=/path/to/ikos-build ``` You can also specify the number of CPU you want to use with `--jobs=N`. By default, it will use **all available CPU**. Note: Try to avoid whitespaces in the installation path, as it might fail. How to use IKOS after installation ---------------------------------- After installation, the install directory will contain the following structure: ``` . ├── activate-full ├── activate-minimal ├── [...] ├── ikos-3.0 │ ├── bin │ ├── include │ ├── lib │ └── share └── llvm-9.0.0 ├── bin ├── include ├── lib ├── libexec └── share ``` Note that after installation, the build directory is only necessary if you want to run the tests again. During its execution, the **bootstrap** script creates a special environment with all the required dependencies for IKOS. To enter that environment, simply run the following command (consider adding this in your `.bashrc`): ``` $ source /path/to/ikos-install/activate-minimal ``` For short, it adds the necessary directories to your `PATH` and your `[DY]LD_LIBRARY_PATH`. The difference between `activate-minimal` and `activate-full` is that `activate-minimal` only adds the necessary directories to run IKOS. `activate-full` also adds the directories required to build IKOS (for instance, cmake). You are now ready to use IKOS. Go to the section [How to Run IKOS](../../../README.md#how-to-run-ikos) in README.md How to run the tests -------------------- The bootstrap script automatically runs the tests. If you want to run the tests again, you first need to enter the build environment using: ``` $ source /path/to/ikos-install/activate-full ``` To run the tests: ``` $ cd /path/to/ikos-build/ikos-3.0 $ make check ``` Note that you can safely remove the build directory if you don't want to run the tests anymore. NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/UBUNTU_16.04.md000066400000000000000000000026571473507761200214370ustar00rootroot00000000000000Install IKOS dependencies on Ubuntu 16.04 ========================================= **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install the required dependencies of IKOS on **[Ubuntu 16.04 (Xenial)](http://releases.ubuntu.com/16.04/)**. First, make sure your system is up-to-date: ``` $ sudo apt-get update $ sudo apt-get upgrade ``` Now, you will need to add the LLVM repository to your apt `sources.list`: ``` $ echo "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" | sudo tee -a /etc/apt/sources.list ``` You also need to trust the LLVM repository key: ``` $ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - ``` Then, run the following commands: ``` $ sudo apt-get update $ sudo apt-get install gcc g++ cmake libgmp-dev libboost-dev libboost-filesystem-dev \ libboost-thread-dev libboost-test-dev python python-pygments libsqlite3-dev libtbb-dev \ libz-dev libedit-dev llvm-9 llvm-9-dev llvm-9-tools clang-9 ``` When running cmake to build IKOS, you will need to define `LLVM_CONFIG_EXECUTABLE`: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/UBUNTU_18.04.md000066400000000000000000000026661473507761200214410ustar00rootroot00000000000000Install IKOS dependencies on Ubuntu 18.04 ========================================= **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install the required dependencies of IKOS on **[Ubuntu 18.04 (Bionic Beaver)](http://releases.ubuntu.com/18.04/)**. First, make sure your system is up-to-date: ``` $ sudo apt-get update $ sudo apt-get upgrade ``` Now, you will need to add the LLVM repository to your apt `sources.list`: ``` $ echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main" | sudo tee -a /etc/apt/sources.list ``` You also need to trust the LLVM repository key: ``` $ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - ``` Then, run the following commands: ``` $ sudo apt-get update $ sudo apt-get install gcc g++ cmake libgmp-dev libboost-dev libboost-filesystem-dev \ libboost-thread-dev libboost-test-dev python python-pygments libsqlite3-dev libtbb-dev \ libz-dev libedit-dev llvm-9 llvm-9-dev llvm-9-tools clang-9 ``` When running cmake to build IKOS, you will need to define `LLVM_CONFIG_EXECUTABLE`: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/UBUNTU_19.04.md000066400000000000000000000026621473507761200214360ustar00rootroot00000000000000Install IKOS dependencies on Ubuntu 19.04 ========================================= **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install the required dependencies of IKOS on **[Ubuntu 19.04 (Disco Dingo)](http://releases.ubuntu.com/19.04/)**. First, make sure your system is up-to-date: ``` $ sudo apt-get update $ sudo apt-get upgrade ``` Now, you will need to add the LLVM repository to your apt `sources.list`: ``` $ echo "deb http://apt.llvm.org/disco/ llvm-toolchain-disco-9 main" | sudo tee -a /etc/apt/sources.list ``` You also need to trust the LLVM repository key: ``` $ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - ``` Then, run the following commands: ``` $ sudo apt-get update $ sudo apt-get install gcc g++ cmake libgmp-dev libboost-dev libboost-filesystem-dev \ libboost-thread-dev libboost-test-dev python python-pygments libsqlite3-dev libtbb-dev \ libz-dev libedit-dev llvm-9 llvm-9-dev llvm-9-tools clang-9 ``` When running cmake to build IKOS, you will need to define `LLVM_CONFIG_EXECUTABLE`: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/UBUNTU_20.04.md000066400000000000000000000021301473507761200214140ustar00rootroot00000000000000Install IKOS dependencies on Ubuntu 20.04 ========================================= **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install the required dependencies of IKOS on **[Ubuntu 20.04 LTS (Focal Fossa)](http://releases.ubuntu.com/20.04/)**. First, make sure your system is up-to-date: ``` $ sudo apt-get update $ sudo apt-get upgrade ``` Then, run the following commands: ``` $ sudo apt-get install gcc g++ cmake libgmp-dev libboost-dev libboost-filesystem-dev \ libboost-thread-dev libboost-test-dev python3 python3-pygments libsqlite3-dev libtbb-dev \ libz-dev libedit-dev llvm-9 llvm-9-dev llvm-9-tools clang-9 ``` When running cmake to build IKOS, you will need to define `LLVM_CONFIG_EXECUTABLE`: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -DLLVM_CONFIG_EXECUTABLE="/usr/bin/llvm-config-9" \ .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/doc/install/3.0/WINDOWS.md000066400000000000000000000024501473507761200210060ustar00rootroot00000000000000Install IKOS dependencies on Windows ==================================== **NOTE: These instructions are for IKOS 3.0 with LLVM 9 and are not actively maintained. Please see the main [README.md](../../../README.md)** Here are the steps to install the required dependencies of IKOS on **[Windows](https://www.microsoft.com/en-us/windows)** using **[MSYS2](https://www.msys2.org/)**. First, install **MSYS2** by following the instructions at https://www.msys2.org/ Then, use the "MSYS2 MinGW 64-bit" terminal from the Start menu. Make sure your system is up-to-date: ``` $ pacman -Syu ``` Now, install the following packages: ``` $ pacman -S \ mingw-w64-x86_64-gcc \ make \ mingw-w64-x86_64-cmake \ mingw-w64-x86_64-gmp \ mingw-w64-x86_64-boost \ mingw-w64-x86_64-python3 \ mingw-w64-x86_64-python3-pygments \ mingw-w64-x86_64-sqlite3 \ mingw-w64-x86_64-intel-tbb \ mingw-w64-x86_64-llvm \ mingw-w64-x86_64-clang \ mingw-w64-x86_64-polly ``` When running cmake to build IKOS, you will need to provide the following parameters: ``` $ cmake \ -DCMAKE_INSTALL_PREFIX="/path/to/ikos-install-directory" \ -G "MSYS Makefiles" \ .. ``` You are now ready to build IKOS. Go to the section [Build and Install](../../../README.md#build-and-install) in README.md NASA-SW-VnV-ikos-1d98c65/frontend/000077500000000000000000000000001473507761200164355ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/000077500000000000000000000000001473507761200174075ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/CMakeLists.txt000066400000000000000000000201401473507761200221440ustar00rootroot00000000000000#******************************************************************************* # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # #*****************************************************************************/ cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR) if (POLICY CMP0074) cmake_policy(SET CMP0074 NEW) endif() if (POLICY CMP0077) cmake_policy(SET CMP0077 NEW) endif() project(ikos-frontend-llvm) # # Build settings # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "In-source builds are not allowed. Please clean your source tree and try again.") endif() if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build" FORCE) endif() if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "Install directory" FORCE) endif() if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "CMake generator: ${CMAKE_GENERATOR}") endif() # # Dependency checks # # Add path for custom modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake") set(CUSTOM_BOOST_ROOT "" CACHE PATH "Path to custom boost installation") if (CUSTOM_BOOST_ROOT) set(BOOST_ROOT "${CUSTOM_BOOST_ROOT}") set(Boost_NO_SYSTEM_PATHS TRUE) endif() find_package(Boost 1.55.0 REQUIRED COMPONENTS filesystem system) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) find_package(GMP REQUIRED) include_directories(SYSTEM ${GMP_INCLUDE_DIR}) include_directories(SYSTEM ${GMPXX_INCLUDE_DIR}) find_package(Core REQUIRED) include_directories(${CORE_INCLUDE_DIR}) find_package(AR REQUIRED) include_directories(${AR_INCLUDE_DIR}) find_package(LLVM REQUIRED) include_directories(SYSTEM ${LLVM_INCLUDE_DIR}) if ((LLVM_VERSION VERSION_LESS "14") OR (NOT (LLVM_VERSION VERSION_LESS "15"))) message(FATAL_ERROR "LLVM 14 is required.") endif() # Add path to llvm cmake modules list(APPEND CMAKE_MODULE_PATH ${LLVM_CMAKE_DIR}) include(LLVMConfig) if ((NOT LLVM_ENABLE_RTTI) AND (NOT WIN32)) message(WARNING "LLVM was built without run-time type information (RTTI)") endif() set(LLVM_ENABLE_WARNINGS TRUE) set(LLVM_REQUIRES_EH TRUE) set(LLVM_REQUIRES_RTTI TRUE) include(HandleLLVMOptions) include(AddLLVM) option(IKOS_LINK_LLVM_DYLIB "Link IKOS against the libLLVM dynamic library" OFF) # # Compiler flags # include(AddFlagUtils) add_compiler_flag(REQUIRED "CXX14" "-std=c++1y") add_compiler_flag(REQUIRED "FVISIBILITY_INLINES_HIDDEN" "-fvisibility-inlines-hidden") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compiler_flag(REQUIRED "WEVERYTHING" "-Weverything") add_compiler_flag(OPTIONAL "WNO_SWITCH_ENUM" "-Wno-switch-enum") add_compiler_flag(OPTIONAL "WNO_PADDED" "-Wno-padded") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT" "-Wno-c++98-compat") add_compiler_flag(OPTIONAL "WNO_CXX98_COMPAT_PEDANTIC" "-Wno-c++98-compat-pedantic") add_compiler_flag(OPTIONAL "WNO_EXIT_TIME_DESTRUCTORS" "-Wno-exit-time-destructors") add_compiler_flag(OPTIONAL "WNO_GLOBAL_CONSTRUCTORS" "-Wno-global-constructors") add_compiler_flag(OPTIONAL "WNO_WEAK_VTABLES" "-Wno-weak-vtables") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") add_compiler_flag(REQUIRED "WALL" "-Wall") add_compiler_flag(REQUIRED "WEXTRA" "-Wextra") endif() # # Targets # include_directories(include) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.hpp" ) # ikos-pp passes add_library(ikos-pp-lib src/pass/initialize.cpp src/pass/lower_cst_expr.cpp src/pass/lower_select.cpp src/pass/mark_internal_inline.cpp src/pass/name_values.cpp src/pass/remove_printf_calls.cpp src/pass/remove_unreachable_blocks.cpp ) if (IKOS_LINK_LLVM_DYLIB) set(IKOS_PP_LIB_LLVM_LIBS "LLVM") else() llvm_map_components_to_libnames(IKOS_PP_LIB_LLVM_LIBS core support transformutils ) endif() target_link_libraries(ikos-pp-lib ${IKOS_PP_LIB_LLVM_LIBS}) set_target_properties(ikos-pp-lib PROPERTIES OUTPUT_NAME ikos-pp) install(TARGETS ikos-pp-lib ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) # ikos-pp binary add_executable(ikos-pp src/ikos_pp.cpp) if (IKOS_LINK_LLVM_DYLIB) set(IKOS_PP_BIN_LLVM_LIBS "LLVM") else() llvm_map_components_to_libnames(IKOS_PP_BIN_LLVM_LIBS aggressiveinstcombine analysis asmparser bitreader bitwriter codegen core coroutines instcombine instrumentation ipo irreader mc objcarcopts scalaropts support target transformutils vectorize ) endif() target_link_libraries(ikos-pp ikos-pp-lib ${IKOS_PP_BIN_LLVM_LIBS} ${Boost_LIBRARIES} ) install(TARGETS ikos-pp RUNTIME DESTINATION bin) # llvm-to-ar lib add_library(ikos-llvm-to-ar src/import/bundle.cpp src/import/constant.cpp src/import/data_layout.cpp src/import/exception.cpp src/import/function.cpp src/import/importer.cpp src/import/library_function.cpp src/import/source_location.cpp src/import/type.cpp ) if (IKOS_LINK_LLVM_DYLIB) set(IKOS_LLVM_TO_AR_LLVM_LIBS "LLVM") else() llvm_map_components_to_libnames(IKOS_LLVM_TO_AR_LLVM_LIBS core support transformutils ) endif() target_link_libraries(ikos-llvm-to-ar ${IKOS_LLVM_TO_AR_LLVM_LIBS} ${AR_LIB} ${Boost_LIBRARIES} ${GMP_LIB} ${GMPXX_LIB} ) install(TARGETS ikos-llvm-to-ar ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) # ikos-import binary add_executable(ikos-import src/ikos_import.cpp) if (IKOS_LINK_LLVM_DYLIB) set(IKOS_IMPORT_LLVM_LIBS "LLVM") else() llvm_map_components_to_libnames(IKOS_IMPORT_LLVM_LIBS core ipo irreader support transformutils ) endif() target_link_libraries(ikos-import ikos-llvm-to-ar ${IKOS_IMPORT_LLVM_LIBS} ${AR_LIB} ${Boost_LIBRARIES} ${GMP_LIB} ${GMPXX_LIB} ) install(TARGETS ikos-import RUNTIME DESTINATION bin) # # Regression tests # enable_testing() add_custom_target(build-frontend-llvm-tests) add_subdirectory(test/regression/pass EXCLUDE_FROM_ALL) add_subdirectory(test/regression/import EXCLUDE_FROM_ALL) # # If it's the top level CMakeLists.txt, Add some aliases # if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS build-frontend-llvm-tests) endif() NASA-SW-VnV-ikos-1d98c65/frontend/llvm/README.md000066400000000000000000000062321473507761200206710ustar00rootroot00000000000000IKOS LLVM Frontend ================== This folder contains implementation of the LLVM frontend for IKOS. Introduction ------------ The LLVM frontend implements: * `ikos-pp`, a LLVM bitcode pre-processor for static analysis * `llvm-to-ar`, a library to translate LLVM bitcode to Abstract Representation (AR) * `ikos-import`, a translator from LLVM bitcode to AR, used for debugging purpose. Installation ------------ IKOS LLVM Frontend contains a C++ library and executables. It can be installed independently from the other components. ### Dependencies To build IKOS LLVM Frontend, you will need the following dependencies: * A C++ compiler that supports C++14 (gcc >= 4.9.2 or clang >= 3.4) * CMake >= 3.4.3 * GMP >= 4.3.1 * Boost >= 1.55 * LLVM 14.0.x * IKOS Core * IKOS AR ### Build and Install To build and install IKOS LLVM Frontend, run the following commands in the `frontend/llvm` directory: ``` $ mkdir build $ cd build $ cmake \ -DCMAKE_INSTALL_PREFIX=/path/to/frontend-llvm-install-directory \ -DLLVM_CONFIG_EXECUTABLE=/path/to/llvm/bin/llvm-config \ -DCORE_ROOT=/path/to/core-install-directory \ -DAR_ROOT=/path/to/ar-install-directory \ .. $ make $ make install ``` ### Tests To build and run the tests, simply type: ``` $ make check ``` Running the LLVM Frontend Tools ------------------------------- ### lib/libikos-llvm-to-ar.a `llvm-to-ar` is a library to translate LLVM bitcode to AR, used by the analyzer and `ikos-import`. ### ikos-pp `ikos-pp` is a LLVM bitcode pre-processor for static analysis. It is similar to the LLVM `opt` command, see https://llvm.org/docs/CommandGuide/opt.html See `ikos-pp -help` for more information. ### ikos-import `ikos-import` is a translator from LLVM bitcode to AR, used for debugging purpose. See `ikos-import -help` for more information. Overview of the source code --------------------------- The following illustrates the directory structure of this folder: ``` . ├── include │ └── ikos │ └── frontend │ └── llvm │ └── import ├── src │ ├── import │ └── pass └── test └── regression ├── import │ ├── aggressive_optimization │ ├── basic_optimization │ └── no_optimization └── pass ├── lower_cst_expr ├── lower_select ├── remove_printf_calls └── remove_unreachable_blocks ``` #### include/ * [include/ikos/frontend/llvm/import](include/ikos/frontend/llvm/import) contains definition of the translation from LLVM to AR. * [include/ikos/frontend/llvm/pass.hpp](include/ikos/frontend/llvm/pass.hpp) contains definition of LLVM passes for helping static analysis. #### src/ * [src/ikos_import.cpp](src/ikos_import.cpp) contains implementation of `ikos-import`. * [src/ikos_pp.cpp](src/ikos_pp.cpp) contains implementation of `ikos-pp`. * [src/import](src/import) contains implementation of the translation from LLVM to AR. * [src/pass](src/pass) contains implementation of LLVM passes for helping static analysis. #### test/ Contains regression tests. NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/000077500000000000000000000000001473507761200210325ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/000077500000000000000000000000001473507761200217775ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/000077500000000000000000000000001473507761200236165ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/llvm/000077500000000000000000000000001473507761200245705ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/llvm/import.hpp000066400000000000000000000045551473507761200266240ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generate an AR bundle from a LLVM module * * For convenience, this header includes: * * ikos/frontend/llvm/import/exception.hpp * * ikos/frontend/llvm/import/importer.hpp * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/llvm/import/000077500000000000000000000000001473507761200261025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/llvm/import/exception.hpp000066400000000000000000000117061473507761200306160ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Exception definitions * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace frontend { namespace import { /// \brief Exception for import errors class ImportError : public core::Exception { private: /// \brief Explanatory message /// /// See https://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html std::shared_ptr< const std::string > _msg; public: /// \brief Constructor /// /// \param msg Explanatory message explicit ImportError(const std::string& msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief Constructor /// /// \param msg Explanatory message explicit ImportError(const char* msg) : _msg(std::make_shared< const std::string >(msg)) {} /// \brief No default constructor ImportError() = delete; /// \brief Copy constructor ImportError(const ImportError&) noexcept = default; /// \brief Move constructor ImportError(ImportError&&) noexcept = default; /// \brief Copy assignment operator ImportError& operator=(const ImportError&) noexcept = default; /// \brief Move assignment operator ImportError& operator=(ImportError&&) noexcept = default; /// \brief Get the explanatory string const char* what() const noexcept override; /// \brief Destructor ~ImportError() override; }; // end class ImportError /// \brief Exception for a mismatch between LLVM type and LLVM debug info class TypeDebugInfoMismatch : public ImportError { public: /// \brief Constructor /// /// \param msg Explanatory message explicit TypeDebugInfoMismatch(const std::string& msg) : ImportError(msg) {} /// \brief Constructor /// /// \param msg Explanatory message explicit TypeDebugInfoMismatch(const char* msg) : ImportError(msg) {} /// \brief No default constructor TypeDebugInfoMismatch() = delete; /// \brief Copy constructor TypeDebugInfoMismatch(const TypeDebugInfoMismatch&) noexcept = default; /// \brief Move constructor TypeDebugInfoMismatch(TypeDebugInfoMismatch&&) noexcept = default; /// \brief Copy assignment operator TypeDebugInfoMismatch& operator=(const TypeDebugInfoMismatch&) noexcept = default; /// \brief Move assignment operator TypeDebugInfoMismatch& operator=(TypeDebugInfoMismatch&&) noexcept = default; /// \brief Destructor ~TypeDebugInfoMismatch() override; }; // end class TypeDebugInfoMismatch /// \brief Check that a condition holds, otherwise throw ImportError inline void check_import(bool condition, const char* msg) { if (ikos_unlikely(!condition)) { throw ImportError(msg); } } /// \brief Check that a condition holds, otherwise throw TypeDebugInfoMismatch inline void check_match(bool condition, const char* msg) { if (ikos_unlikely(!condition)) { throw TypeDebugInfoMismatch(msg); } } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/llvm/import/importer.hpp000066400000000000000000000105151473507761200304560ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generate an AR bundle from a LLVM module * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include namespace ikos { namespace frontend { namespace import { /// \brief Check if the given module has debug information bool has_debug_info(llvm::Module&); /// \brief Import from LLVM to AR class Importer { public: /// \brief Import options enum ImportOption : unsigned { NoOption = 0x0, /// \brief Use ikos intrinsics (such as ar.ikos.assert, etc.) EnableLibIkos = 0x1, /// \brief Use libc intrinsics (such as ar.libc.malloc, etc.) EnableLibc = 0x2, /// \brief Use libcpp intrinsics (such as ar.libcpp.new, etc.) EnableLibcpp = 0x4, /// \brief Allow incorrect debug information /// /// Allow mismatch of llvm types (llvm::Type) and debug info types /// (llvm::DIType). /// /// For instance, the associated llvm::DIType of a llvm.dbg.value might not /// match the llvm::Type of the associated llvm::Value. This happens because /// of aggressive optimizations or ABI requirements. /// /// Enable this option if `ikos-pp -opt=aggressive` was used. AllowMismatchDebugInfo = 0x8, /// \brief Default options DefaultOptions = EnableLibIkos | EnableLibc | EnableLibcpp | AllowMismatchDebugInfo, }; /// \brief Import options using ImportOptions = ar::Flags< ImportOption >; private: // AR Context ar::Context& _context; public: /// \brief Public constructor explicit Importer(ar::Context& ctx) : _context(ctx) {} /// \brief Copy constructor Importer(const Importer&) noexcept = default; /// \brief Move constructor Importer(Importer&&) noexcept = default; /// \brief No copy assignment operator Importer& operator=(const Importer&) = delete; /// \brief No move assignment operator Importer& operator=(Importer&&) = delete; /// \brief Destructor ~Importer() = default; /// \brief Generate an AR bundle from a LLVM module /// /// \throws ImportError on errors ar::Bundle* import(llvm::Module&, ImportOptions opts = DefaultOptions); }; IKOS_DECLARE_OPERATORS_FOR_FLAGS(Importer::ImportOptions) } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/llvm/import/source_location.hpp000066400000000000000000000105031473507761200320020ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Source location for AR statements generated from LLVM * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include namespace ikos { namespace frontend { namespace import { /// \brief Return the absolute path of the given source file boost::filesystem::path source_path(llvm::DIFile* file); /// \brief Represents a source code location class SourceLocation { private: /// \brief Debug Information Location llvm::DILocation* _loc = nullptr; public: /// \brief Create a null source location SourceLocation() = default; /// \brief Create a source location from an llvm::DILocation* explicit SourceLocation(llvm::DILocation* loc) : _loc(loc) { ikos_assert(loc != nullptr && loc->isResolved()); } /// \brief Copy constructor SourceLocation(const SourceLocation&) noexcept = default; /// \brief Move constructor SourceLocation(SourceLocation&&) noexcept = default; /// \brief Copy assignment operator SourceLocation& operator=(const SourceLocation&) noexcept = default; /// \brief Move assignment operator SourceLocation& operator=(SourceLocation&&) noexcept = default; /// \brief Destructor ~SourceLocation() = default; /// \brief Return true if the source location is null bool is_null() const { return this->_loc == nullptr; } /// \brief Return true if the source location is not null explicit operator bool() const { return this->_loc != nullptr; } /// \brief Return the file llvm::DIFile* file() const { ikos_assert(this->_loc != nullptr); return this->_loc->getFile(); } /// \brief Return the line unsigned line() const { ikos_assert(this->_loc != nullptr); return this->_loc->getLine(); } /// \brief Return the column unsigned column() const { ikos_assert(this->_loc != nullptr); return this->_loc->getColumn(); } /// \brief Return the absolute path to the filename boost::filesystem::path path() const { return source_path(this->file()); } }; // end class SourceLocation /// \brief Return the source location of the given statement SourceLocation source_location(ar::Statement* stmt); } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/include/ikos/frontend/llvm/pass.hpp000066400000000000000000000074741473507761200262630ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Functions to create various ikos-specific llvm passes * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include namespace ikos { namespace frontend { namespace pass { /// \brief Lower constant expressions into instructions llvm::FunctionPass* create_lower_cst_expr_pass(); /// \brief Lower select instructions /// /// Lower select instructions to three new basic blocks and a phi instruction. llvm::FunctionPass* create_lower_select_pass(); /// \brief Mark all internal functions with the AlwaysInline attribute llvm::ModulePass* create_mark_internal_inline_pass(); /// \brief Name all unnamed values llvm::ModulePass* create_name_values_pass(); /// \brief Remove printf-like function calls llvm::FunctionPass* create_remove_printf_calls_pass(); /// \brief Remove blocks that are not reachable, including dead cycles llvm::FunctionPass* create_remove_unreachable_blocks_pass(); /// \brief Initialize all passes linked into the ikos-pp library void initialize_ikos_passes(llvm::PassRegistry&); } // end namespace pass } // end namespace frontend } // end namespace ikos namespace llvm { /// \brief Initialize the LowerCstExprPass void initializeLowerCstExprPassPass(llvm::PassRegistry&); /// \brief Initialize the LowerSelectPass void initializeLowerSelectPassPass(llvm::PassRegistry&); /// \brief Initialize the MarkInternalInlinePass void initializeMarkInternalInlinePassPass(llvm::PassRegistry&); /// \brief Initialize the NameValuesPass void initializeNameValuesPassPass(llvm::PassRegistry&); /// \brief Initialize the RemovePrintfCallsPass void initializeRemovePrintfCallsPassPass(llvm::PassRegistry&); /// \brief Initialize the RemoveUnreachableBlocksPass void initializeRemoveUnreachableBlocksPassPass(llvm::PassRegistry&); } // end namespace llvm NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/000077500000000000000000000000001473507761200201765ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/ikos_import.cpp000066400000000000000000000235741473507761200232540ustar00rootroot00000000000000/******************************************************************************* * * ikos-import -- Translate LLVM bitcode into AR * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ar = ikos::ar; namespace llvm_to_ar = ikos::frontend::import; static llvm::cl::opt< std::string > InputFilename( llvm::cl::Positional, llvm::cl::desc(""), llvm::cl::Required, llvm::cl::value_desc("filename")); static llvm::cl::opt< std::string > OutputFilename( "o", llvm::cl::desc("Override output filename"), llvm::cl::value_desc("filename")); static llvm::cl::opt< bool > NoVerify( "no-verify", llvm::cl::desc("Do not run the LLVM bitcode verifier")); static llvm::cl::opt< bool > NoLibIkos( "no-libikos", llvm::cl::desc("Do not use ikos intrinsics (__ikos_assert, etc.)")); static llvm::cl::opt< bool > NoLibc( "no-libc", llvm::cl::desc("Do not use libc intrinsics (malloc, free, etc.)")); static llvm::cl::opt< bool > NoLibcpp( "no-libcpp", llvm::cl::desc("Do not use libcpp intrinsics (__cxa_throw, etc.)")); static llvm::cl::opt< bool > AllowDebugInfoMismatch( "allow-dbg-mismatch", llvm::cl::desc("Allow incorrect debug information in the module")); static llvm::cl::opt< bool > NoTypeCheck( "no-type-check", llvm::cl::desc("Do not run the AR type checker")); static llvm::cl::opt< bool > NoSimplifyCFG( "no-simplify-cfg", llvm::cl::desc("Do not run the simplify-cfg pass")); enum OutputFormatType { None, Text, Dot }; static llvm::cl::opt< OutputFormatType > OutputFormat( "format", llvm::cl::desc("Output format:"), llvm::cl::values(clEnumValN(None, "no", "Disable output"), clEnumValN(Text, "text", "Text format"), clEnumValN(Dot, "dot", "Dot format")), llvm::cl::init(Text)); static llvm::cl::opt< bool > NoShowResultType( "no-show-result-type", llvm::cl::desc("Do not show the result type of statements")); static llvm::cl::opt< bool > ShowOperandTypes( "show-operand-types", llvm::cl::desc("Show the operand types of statements")); static llvm::cl::opt< bool > OrderGlobals( "order-globals", llvm::cl::desc("Order global variables and functions by name")); /// \brief Build import options from command line arguments static llvm_to_ar::Importer::ImportOptions make_import_options() { llvm_to_ar::Importer::ImportOptions opts; opts.set(llvm_to_ar::Importer::EnableLibIkos, !NoLibIkos); opts.set(llvm_to_ar::Importer::EnableLibc, !NoLibc); opts.set(llvm_to_ar::Importer::EnableLibcpp, !NoLibcpp); opts.set(llvm_to_ar::Importer::AllowMismatchDebugInfo, AllowDebugInfoMismatch); return opts; } /// \brief Build format options from command line arguments static ar::Formatter::FormatOptions make_format_options() { ar::Formatter::FormatOptions opts; opts.set(ar::Formatter::ShowResultType, !NoShowResultType); opts.set(ar::Formatter::ShowOperandTypes, ShowOperandTypes); opts.set(ar::Formatter::OrderGlobals, OrderGlobals); return opts; } /// \brief Main for ikos-import int main(int argc, char** argv) { llvm::InitLLVM x(argc, argv); // Program name // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) std::string progname = boost::filesystem::path(argv[0]).filename().string(); // Enable debug stream buffering llvm::EnableDebugBuffering = true; // LLVM context llvm::LLVMContext llvm_context; /* * Parse parameters */ const char* overview = "ikos-import -- Translate LLVM bitcode into AR"; llvm::cl::ParseCommandLineOptions(argc, argv, overview); try { // Error diagnostic llvm::SMDiagnostic err; // Load the input module std::unique_ptr< llvm::Module > module = llvm::parseIRFile(InputFilename, err, llvm_context); if (!module) { err.print(progname.c_str(), llvm::errs()); return 1; } // Immediately run the verifier to catch any problems if (!NoVerify && verifyModule(*module, &llvm::errs())) { llvm::errs() << progname << ": " << InputFilename << ": error: input module is broken!\n"; return 2; } // Check for debug information if (!llvm_to_ar::has_debug_info(*module)) { // Warn but allow to proceed. llvm::errs() << progname << ": " << InputFilename << ": warning: input module has no debug information\n"; llvm::errs() << "... Output may be less user friendly.\n"; } // AR context ar::Context ar_context; // Translate LLVM bitcode into AR ar::Bundle* bundle = nullptr; try { llvm_to_ar::Importer importer(ar_context); bundle = importer.import(*module, make_import_options()); } catch (llvm_to_ar::ImportError& err) { llvm::errs() << progname << ": " << InputFilename << ": error: " << err.what() << "\n"; return 3; } // Run type checker ar::TypeVerifier verifier(/*all = */ true); if (!NoTypeCheck && !verifier.verify(bundle, std::cerr)) { llvm::errs() << progname << ": " << InputFilename << ": error: type checker\n"; return 4; } // Simplify the control flow graph if (!NoSimplifyCFG) { ar::SimplifyCFGPass().run(bundle); } // Generate output if (OutputFormat == Text) { ar::TextFormatter formatter(make_format_options()); if (OutputFilename.empty() || OutputFilename == "-") { // Default to standard output formatter.format(std::cout, bundle); } else { boost::filesystem::ofstream output(OutputFilename.getValue()); if (!output.is_open()) { llvm::errs() << progname << ": " << OutputFilename << ": " << strerror(errno) << "\n"; return 5; } formatter.format(output, bundle); } } else if (OutputFormat == Dot) { ar::DotFormatter formatter(make_format_options()); if (OutputFilename.empty()) { // Default to current directory OutputFilename = "."; } boost::system::error_code ec; boost::filesystem::path output_dir(OutputFilename.getValue()); if (!boost::filesystem::exists(output_dir)) { if (!boost::filesystem::create_directories(output_dir, ec)) { llvm::errs() << progname << ": " << OutputFilename << ": " << ec.message() << "\n"; return 5; } } if (!boost::filesystem::is_directory(output_dir, ec)) { llvm::errs() << progname << ": " << OutputFilename << ": Not a directory\n"; return 5; } for (auto it = bundle->function_begin(), et = bundle->function_end(); it != et; ++it) { ar::Function* fun = *it; if (!fun->is_definition()) { continue; } std::string filename = fun->name() + ".dot"; std::cout << "creating " << filename; if (OutputFilename != ".") { std::cout << " in directory " << OutputFilename; } std::cout << "\n"; boost::filesystem::ofstream output(output_dir / filename); if (!output.is_open()) { llvm::errs() << progname << ": " << OutputFilename << "/" << filename << ": " << strerror(errno) << "\n"; return 5; } formatter.format(output, fun); } } return 0; } catch (std::exception& err) { llvm::errs() << progname << ": " << InputFilename << ": error: " << err.what() << "\n"; return 6; } } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/ikos_pp.cpp000066400000000000000000000414741473507761200223600ustar00rootroot00000000000000/******************************************************************************* * * ikos-pp -- LLVM bitcode Pre-Processor for Static Analysis * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ikos_pp = ikos::frontend::pass; static llvm::cl::opt< std::string > InputFilename( llvm::cl::Positional, llvm::cl::desc(""), llvm::cl::Required, llvm::cl::value_desc("filename")); static llvm::cl::opt< std::string > OutputFilename( "o", llvm::cl::desc("Override output filename"), llvm::cl::value_desc("filename")); static llvm::cl::opt< bool > OutputAssembly( "S", llvm::cl::desc("Write output as LLVM assembly")); static llvm::cl::list< std::string > EntryPoints( "entry-points", llvm::cl::desc("List of program entry points"), llvm::cl::CommaSeparated, llvm::cl::value_desc("function")); static llvm::cl::opt< bool > InlineAll("inline-all", llvm::cl::desc("Inline all functions")); static llvm::cl::opt< bool > NoVerify( "no-verify", llvm::cl::desc("Do not run the LLVM bitcode verifier")); static llvm::cl::opt< bool > DiscardValueNames( "discard-value-names", llvm::cl::desc("Discard names from Value (other than GlobalValue)."), llvm::cl::init(false), llvm::cl::Hidden); static llvm::cl::opt< bool > PreserveBitcodeUseListOrder( "preserve-bc-uselistorder", llvm::cl::desc("Preserve use-list order when writing LLVM bitcode."), llvm::cl::init(true), llvm::cl::Hidden); static llvm::cl::opt< bool > PreserveAssemblyUseListOrder( "preserve-ll-uselistorder", llvm::cl::desc("Preserve use-list order when writing LLVM assembly."), llvm::cl::init(false), llvm::cl::Hidden); enum OptLevelType { None, Basic, Aggressive, Custom }; static llvm::cl::opt< OptLevelType > OptLevel( "opt", llvm::cl::desc("Optimization level:"), llvm::cl::values( clEnumValN(None, "none", "Only passes required for the translation to AR"), clEnumValN(Basic, "basic", "Basic set of optimizations (recommended)"), clEnumValN(Aggressive, "aggressive", "Aggressive optimizations (not recommended)"), clEnumValN(Custom, "custom", "Use a custom set of llvm passes")), llvm::cl::init(Basic)); /// \brief Set of custom passes /// /// Automatically populated with the registered Passes by the PassNameParser static llvm::cl::list< const llvm::PassInfo*, bool, llvm::PassNameParser > CustomPassList(llvm::cl::desc("Custom Optimizations available:")); /// \brief Main for ikos-pp int main(int argc, char** argv) { llvm::InitLLVM x(argc, argv); // Program name // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) std::string progname = boost::filesystem::path(argv[0]).filename().string(); // Enable debug stream buffering llvm::EnableDebugBuffering = true; // Global context llvm::LLVMContext context; /* * Initialize and register all passes */ llvm::PassRegistry& registry = *llvm::PassRegistry::getPassRegistry(); llvm::initializeCore(registry); llvm::initializeCoroutines(registry); llvm::initializeScalarOpts(registry); llvm::initializeObjCARCOpts(registry); llvm::initializeVectorization(registry); llvm::initializeIPO(registry); llvm::initializeAnalysis(registry); llvm::initializeTransformUtils(registry); llvm::initializeInstCombine(registry); llvm::initializeAggressiveInstCombine(registry); llvm::initializeInstrumentation(registry); llvm::initializeTarget(registry); llvm::initializeExpandMemCmpPassPass(registry); llvm::initializeCodeGenPreparePass(registry); llvm::initializeAtomicExpandPass(registry); llvm::initializeRewriteSymbolsLegacyPassPass(registry); llvm::initializeWinEHPreparePass(registry); llvm::initializeSafeStackLegacyPassPass(registry); llvm::initializeSjLjEHPreparePass(registry); llvm::initializeStackProtectorPass(registry); llvm::initializePreISelIntrinsicLoweringLegacyPassPass(registry); llvm::initializeGlobalMergePass(registry); llvm::initializeIndirectBrExpandPassPass(registry); llvm::initializeInterleavedLoadCombinePass(registry); llvm::initializeInterleavedAccessPass(registry); llvm::initializeEntryExitInstrumenterPass(registry); llvm::initializePostInlineEntryExitInstrumenterPass(registry); llvm::initializeUnreachableBlockElimLegacyPassPass(registry); llvm::initializeExpandReductionsPass(registry); llvm::initializeWasmEHPreparePass(registry); llvm::initializeWriteBitcodePassPass(registry); llvm::initializeHardwareLoopsPass(registry); ikos_pp::initialize_ikos_passes(registry); /* * Parse parameters */ const char* overview = "ikos-pp -- LLVM bitcode Pre-Processor for Static Analysis\n"; llvm::cl::ParseCommandLineOptions(argc, argv, overview); // Error diagnostic llvm::SMDiagnostic err; // If -discard-value-names, discard all the names (except for GlobalValue) context.setDiscardValueNames(DiscardValueNames); // Load the input module std::unique_ptr< llvm::Module > module = llvm::parseIRFile(InputFilename, err, context); if (!module) { err.print(progname.c_str(), llvm::errs()); return 1; } // Immediately run the verifier to catch any problems if (!NoVerify && verifyModule(*module, &llvm::errs())) { llvm::errs() << progname << ": " << InputFilename << ": error: input module is broken!\n"; return 1; } // Default to standard output if (OutputFilename.empty()) { OutputFilename = "-"; } // Output stream std::error_code ec; std::unique_ptr< llvm::ToolOutputFile > output = std::make_unique< llvm::ToolOutputFile >(OutputFilename, ec, llvm::sys::fs::OF_None); if (ec) { llvm::errs() << progname << ": " << ec.message() << '\n'; return 1; } /* * Build a PassManager */ llvm::legacy::PassManager pass_manager; if (OptLevel == None) { // Remove switch constructions (opt -lowerswitch) pass_manager.add(llvm::createLowerSwitchPass()); // Lower down atomic instructions (opt -loweratomic) pass_manager.add(llvm::createLowerAtomicPass()); // Lower constant expressions to instructions (ikos-pp -lower-cst-expr) pass_manager.add(ikos_pp::create_lower_cst_expr_pass()); // Lower down select instructions (ikos-pp -lower-select) pass_manager.add(ikos_pp::create_lower_select_pass()); // Ensure one single exit point per function (opt -mergereturn) pass_manager.add(llvm::createUnifyFunctionExitNodesPass()); } else if (OptLevel == Basic) { // SSA (opt -mem2reg) pass_manager.add(llvm::createPromoteMemoryToRegisterPass()); // Global dead code elimination (opt -globaldce) // note: unfortunately, it removes some debug info about global variables pass_manager.add(llvm::createGlobalDCEPass()); // Dead code elimination (opt -dce) pass_manager.add(llvm::createDeadCodeEliminationPass()); // Remove switch constructions (opt -lowerswitch) pass_manager.add(llvm::createLowerSwitchPass()); // Remove unreachable blocks also dead cycles pass_manager.add(ikos_pp::create_remove_unreachable_blocks_pass()); // Lower down atomic instructions (opt -loweratomic) pass_manager.add(llvm::createLowerAtomicPass()); // Lower constant expressions to instructions (ikos-pp -lower-cst-expr) pass_manager.add(ikos_pp::create_lower_cst_expr_pass()); // Dead code elimination (opt -dce) pass_manager.add(llvm::createDeadCodeEliminationPass()); // Lower down select instructions (ikos-pp -lower-select) pass_manager.add(ikos_pp::create_lower_select_pass()); // Ensure one single exit point per function (opt -mergereturn) pass_manager.add(llvm::createUnifyFunctionExitNodesPass()); } else if (OptLevel == Aggressive) { // Turn all functions internal so that we can apply some global // optimizations inline them if requested (opt -internalize) llvm::StringSet<> exclude_set; if (EntryPoints.empty()) { exclude_set.insert("main"); } else { for (const auto& entry_point : EntryPoints) { exclude_set.insert(entry_point); } } if (exclude_set.count("*") == 0) { pass_manager.add( llvm::createInternalizePass([=](const llvm::GlobalValue& gv) { return exclude_set.find(gv.getName()) != exclude_set.end(); })); } // Kill unused internal global (opt -globaldce) // note: unfortunately, it removes some debug info about global variables pass_manager.add(llvm::createGlobalDCEPass()); // Remove unreachable blocks pass_manager.add(ikos_pp::create_remove_unreachable_blocks_pass()); // Global optimizations (opt -globalopt) pass_manager.add(llvm::createGlobalOptimizerPass()); // SSA (opt -mem2reg) pass_manager.add(llvm::createPromoteMemoryToRegisterPass()); // Cleanup after SSA (opt -instcombine) // disabled, bad for static analysis // pass_manager.add(llvm::createInstructionCombiningPass()); // Simplification (opt -simplifycfg) pass_manager.add(llvm::createCFGSimplificationPass()); // Break aggregates (opt -sroa) pass_manager.add(llvm::createSROAPass()); // Global value numbering and redundant load elimination (opt -gvn) // note: unfortunately, it removes some debug information pass_manager.add(llvm::createGVNPass()); // Cleanup after breaking aggregates (opt -instcombine) // (bad for static analysis) pass_manager.add(llvm::createInstructionCombiningPass()); // Global dead code elimination (opt -globaldce) pass_manager.add(llvm::createGlobalDCEPass()); // Simplification (opt -simplifycfg) pass_manager.add(llvm::createCFGSimplificationPass()); // Jump threading (opt -jump-threading) // (conditional) constant propagation always help analyzers pass_manager.add(llvm::createJumpThreadingPass()); // Sparse conditional constant propagation (opt -sccp) pass_manager.add(llvm::createSCCPPass()); // Dead code elimination (opt -dce) pass_manager.add(llvm::createDeadCodeEliminationPass()); // Lower invoke's (opt -lowerinvoke) pass_manager.add(llvm::createLowerInvokePass()); // Cleanup after lowering invoke's (opt -simplifycfg) pass_manager.add(llvm::createCFGSimplificationPass()); if (InlineAll) { // Mark all functions always_inline (ikos-pp -mark-internal-inline) pass_manager.add(ikos_pp::create_mark_internal_inline_pass()); // Inline always_inline functions (opt -always-inline) pass_manager.add(llvm::createAlwaysInlinerLegacyPass()); // Kill unused internal global (opt -globaldce) pass_manager.add(llvm::createGlobalDCEPass()); } // Remove unreachable blocks pass_manager.add(ikos_pp::create_remove_unreachable_blocks_pass()); // Dead code elimination (opt -dce) pass_manager.add(llvm::createDeadCodeEliminationPass()); // Canonical form for loops (opt -loop-simplify) pass_manager.add(llvm::createLoopSimplifyPass()); // Cleanup unnecessary blocks (opt -simplifycfg) pass_manager.add(llvm::createCFGSimplificationPass()); // Loop-closed SSA (opt -lcssa) pass_manager.add(llvm::createLCSSAPass()); // Loop invariant code motion (opt -licm) pass_manager.add(llvm::createLICMPass()); // SSA (opt -mem2reg) pass_manager.add(llvm::createPromoteMemoryToRegisterPass()); // Dead loop elimination (opt -loop-deletion) pass_manager.add(llvm::createLoopDeletionPass()); // Cleanup unnecessary blocks (opt -simplifycfg) pass_manager.add(llvm::createCFGSimplificationPass()); // Global dead code elimination (opt -globaldce) pass_manager.add(llvm::createGlobalDCEPass()); // Dead code elimination (opt -dce) pass_manager.add(llvm::createDeadCodeEliminationPass()); // Remove unreachable blocks also dead cycles pass_manager.add(ikos_pp::create_remove_unreachable_blocks_pass()); // Remove switch constructions (opt -lowerswitch) pass_manager.add(llvm::createLowerSwitchPass()); // Lower down atomic instructions (opt -loweratomic) pass_manager.add(llvm::createLowerAtomicPass()); // Lower constant expressions to instructions (ikos-pp -lower-cst-expr) pass_manager.add(ikos_pp::create_lower_cst_expr_pass()); // Dead code elimination (opt -dce) pass_manager.add(llvm::createDeadCodeEliminationPass()); // After lowering constant expressions we remove all // side-effect-free printf-like functions. This can trigger the // removal of global strings that only feed them. pass_manager.add(ikos_pp::create_remove_printf_calls_pass()); // Dead code elimination (opt -dce) pass_manager.add(llvm::createDeadCodeEliminationPass()); // Global dead code elimination (opt -globaldce) pass_manager.add(llvm::createGlobalDCEPass()); // Lower down select instructions (ikos-pp -lower-select) pass_manager.add(ikos_pp::create_lower_select_pass()); // Ensure one single exit point per function (opt -mergereturn) pass_manager.add(llvm::createUnifyFunctionExitNodesPass()); } else { ikos_assert(OptLevel == Custom); for (std::size_t i = 0; i < CustomPassList.size(); ++i) { const llvm::PassInfo* pass_info = CustomPassList[i]; if (pass_info->getNormalCtor() != nullptr) { llvm::Pass* pass = pass_info->getNormalCtor()(); pass_manager.add(pass); } else { llvm::errs() << progname << ": cannot create pass: " << pass_info->getPassName() << "\n"; } } } // Check that the module is well formed on completion of optimization if (!NoVerify) { pass_manager.add(llvm::createVerifierPass()); } // Output pass if (OutputAssembly) { pass_manager.add(llvm::createPrintModulePass(output->os(), "", PreserveAssemblyUseListOrder)); } else { pass_manager.add( createBitcodeWriterPass(output->os(), PreserveBitcodeUseListOrder)); } // Run all the passes pass_manager.run(*module); output->keep(); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/000077500000000000000000000000001473507761200215105ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/bundle.cpp000066400000000000000000000343361473507761200234760ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate a LLVM module and Debug Information into an AR bundle * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include "bundle.hpp" #include "constant.hpp" #include "function.hpp" #include "library_function.hpp" #include "type.hpp" namespace ikos { namespace frontend { namespace import { ar::GlobalVariable* BundleImporter::translate_global_variable( llvm::GlobalVariable* gv) { auto it = this->_globals.find(gv); if (it != this->_globals.end()) { return it->second; } // Build the ar::GlobalVariable std::string name; if (gv->hasName()) { name = gv->getName().str(); } else { name = this->_bundle->find_available_name("__unnamed_global_var"); } // Special names for intrinsic global variables (such as llvm.global_ctors) if (name.rfind("llvm.", 0) == 0) { name = "ar." + name.substr(5); } llvm::PointerType* type = gv->getType(); // Extract the DWARF type from debug information llvm::SmallVector< llvm::DIGlobalVariableExpression*, 1 > dbgs; gv->getDebugInfo(dbgs); ar::Type* ar_pointee_type = nullptr; if (dbgs.empty()) { // No debug info // Prefer signed integers, because most global variables without // debug information are strings (const char*) ar_pointee_type = _ctx.type_imp->translate_type(type->getPointerElementType(), ar::Signed); } else { // Use debug information to build the exact type llvm::DIGlobalVariable* di_gv = dbgs[0]->getVariable(); auto di_type = llvm::cast_or_null< llvm::DIType >(di_gv->getRawType()); try { ar_pointee_type = _ctx.type_imp->translate_type(type->getPointerElementType(), di_type); } catch (const TypeDebugInfoMismatch&) { if (!this->_allow_debug_info_mismatch) { throw; } ar_pointee_type = _ctx.type_imp->translate_type(type->getPointerElementType(), ar::Signed); } } // Create the ar::GlobalVariable ikos_assert(ar_pointee_type); ar::PointerType* ar_type = ar::PointerType::get(this->_context, ar_pointee_type); ar::GlobalVariable* ar_gv = ar::GlobalVariable::create(this->_bundle, ar_type, name, /*is_definition = */ !gv->isDeclaration(), gv->getAlignment()); ar_gv->set_frontend(gv); this->_globals.try_emplace(gv, ar_gv); return ar_gv; } ar::Code* BundleImporter::translate_global_variable_initializer( llvm::GlobalVariable* gv) { ar::GlobalVariable* ar_gv = this->translate_global_variable(gv); ikos_assert(ar_gv->is_definition()); // Initialize the ar::Code initializer ar::Code* init = ar_gv->initializer(); ar::BasicBlock* bb = ar::BasicBlock::create(init); init->set_entry_block(bb); init->set_exit_block(bb); // Translate the llvm::Constant ar::Value* cst = _ctx.constant_imp->translate_constant(gv->getInitializer(), ar_gv->type()->pointee(), bb); // Insert statement *gv = cst bb->push_back(ar::Store::create(ar_gv, cst, 1, false)); return init; } // This is used in the case where there is no debug information. ar::Function* BundleImporter::translate_internal_function(llvm::Function* fun) { ikos_assert(!fun->isDeclaration()); ar::Function* ar_fun = nullptr; // Use int for the type since it is more common than unsigned in C llvm::FunctionType* type = fun->getFunctionType(); auto ar_type = ar::cast< ar::FunctionType >( _ctx.type_imp->translate_type(type, ar::Signed)); ar_fun = ar::Function::create(this->_bundle, ar_type, fun->getName().str(), /*is_definition = */ true); ikos_assert(ar_fun); return ar_fun; } ar::Function* BundleImporter::translate_function(llvm::Function* fun) { auto it = this->_functions.find(fun); if (it != this->_functions.end()) { return it->second; } // Build the ar function if (!fun->hasName()) { throw ImportError("llvm function has no name"); } // Extract the DWARF type from debug information llvm::DISubprogram* dbg = fun->getSubprogram(); ar::Function* ar_fun = nullptr; if (dbg != nullptr) { // Debug information available ar_fun = this->translate_function_di(fun, dbg); } else if (fun->isDeclaration()) { // No debug information on external function ar_fun = this->translate_extern_function(fun); } else if (this->is_clang_generated_function(fun)) { // Auto-generated by clang ar_fun = this->translate_clang_generated_function(fun); } else { // No debug information on internal function ar_fun = this->translate_internal_function(fun); } if (ar_fun != nullptr) { ar_fun->set_frontend(fun); } this->_functions.try_emplace(fun, ar_fun); return ar_fun; } ar::Function* BundleImporter::translate_function_di(llvm::Function* fun, llvm::DISubprogram* dbg) { ikos_assert_msg(dbg != nullptr, "no debug info"); ikos_assert_msg(!fun->isIntrinsic(), "unexpected intrinsic with debug info"); // Use debug information to build the exact type llvm::DISubroutineType* di_type = dbg->getType(); // Translate the function type ar::FunctionType* type = nullptr; try { type = _ctx.type_imp->translate_function_type(fun, di_type); } catch (const TypeDebugInfoMismatch&) { if (!this->_allow_debug_info_mismatch) { throw; } type = ar::cast< ar::FunctionType >( _ctx.type_imp->translate_type(fun->getFunctionType(), ar::Signed)); } // Create the ar::Function return ar::Function::create(this->_bundle, type, fun->getName().str(), /*is_definition = */ !fun->isDeclaration()); } ar::Function* BundleImporter::translate_extern_function(llvm::Function* fun) { ikos_assert(fun->isDeclaration()); ar::Function* ar_fun = nullptr; llvm::Intrinsic::ID id = fun->getIntrinsicID(); // Not translated if (this->ignore_intrinsic(id)) { return nullptr; } // Translate an intrinsic function if (ar_fun == nullptr && fun->isIntrinsic()) { ar_fun = this->translate_intrinsic_function(fun, id); } // Translate known library functions (e.g, malloc, printf, etc.) if (ar_fun == nullptr) { ar_fun = this->translate_library_function(fun); } if (ar_fun == nullptr) { // Otherwise, just prefer signed integers, // because int is more common than unsigned in C llvm::FunctionType* type = fun->getFunctionType(); auto ar_type = ar::cast< ar::FunctionType >( _ctx.type_imp->translate_type(type, ar::Signed)); ar_fun = ar::Function::create(this->_bundle, ar_type, fun->getName().str(), /*is_definition = */ false); } ikos_assert(ar_fun); return ar_fun; } bool BundleImporter::ignore_intrinsic(llvm::Intrinsic::ID id) { return id == llvm::Intrinsic::dbg_value || id == llvm::Intrinsic::dbg_declare || id == llvm::Intrinsic::dbg_label || id == llvm::Intrinsic::prefetch; } ar::Function* BundleImporter::translate_intrinsic_function( llvm::Function* fun, llvm::Intrinsic::ID id) { ar::Function* ar_fun = nullptr; if (id == llvm::Intrinsic::memcpy) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::MemoryCopy); } else if (id == llvm::Intrinsic::memmove) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::MemoryMove); } else if (id == llvm::Intrinsic::memset) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::MemorySet); } else if (id == llvm::Intrinsic::vastart) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::VarArgStart); } else if (id == llvm::Intrinsic::vaend) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::VarArgEnd); } else if (id == llvm::Intrinsic::vacopy) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::VarArgCopy); } else if (id == llvm::Intrinsic::stacksave) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::StackSave); } else if (id == llvm::Intrinsic::stackrestore) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::StackRestore); } else if (id == llvm::Intrinsic::lifetime_start) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::LifetimeStart); } else if (id == llvm::Intrinsic::lifetime_end) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::LifetimeEnd); } else if (id == llvm::Intrinsic::eh_typeid_for) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::EhTypeidFor); } else if (id == llvm::Intrinsic::trap) { ar_fun = this->_bundle->intrinsic_function(ar::Intrinsic::Trap); } else { // No equivalent AR intrinsic, translate into a normal external function ar_fun = nullptr; } // Sanity check, should never happen // Skip for memcpy, memmove and memset because of the alignment parameter if (id != llvm::Intrinsic::memcpy && id != llvm::Intrinsic::memmove && id != llvm::Intrinsic::memset && ar_fun != nullptr && !_ctx.type_imp->match_extern_function_type(fun->getFunctionType(), ar_fun->type())) { std::ostringstream buf; buf << "llvm intrinsic " << fun->getName().str() << " and ar intrinsic " << ar_fun->name() << " have a different type"; throw ImportError(buf.str()); } return ar_fun; } ar::Function* BundleImporter::translate_library_function(llvm::Function* fun) { ar::Function* ar_fun = _ctx.lib_fun_imp->function(fun->getName()); // Sanity check, can happen if the user uses C/C++ standard library names if (ar_fun != nullptr && !_ctx.type_imp->match_extern_function_type(fun->getFunctionType(), ar_fun->type())) { std::ostringstream buf; if (ar_fun->is_ikos_intrinsic()) { buf << "function definition of " << fun->getName().str() << " does not match the expected ikos intrinsic definition"; } else if (ar_fun->is_libc_intrinsic()) { buf << "function definition of " << fun->getName().str() << " does not match the expected C Standard Library definition"; } else if (ar_fun->is_libcpp_intrinsic()) { buf << "function definition of " << fun->getName().str() << " does not match the expected C++ Standard Library definition"; } else { buf << "llvm function " << fun->getName().str() << " and ar intrinsic " << ar_fun->name() << " have a different type"; } std::cerr << "Warning: " << buf.str() << "\n"; std::cerr << "LLVM function declaration\n"; std::cerr << "ikos ar expected function declaration\n"; std::cerr << "Expected signature will be ignored.\n"; ar_fun = nullptr; } return ar_fun; } bool BundleImporter::is_clang_generated_function(llvm::Function* fun) { if (fun->isDeclaration()) { return false; } if (fun->getName() == "__clang_call_terminate") { // Terminate function return true; } if (fun->getName().startswith("_ZTW")) { // Thread-local wrapper function return true; } return false; } ar::Function* BundleImporter::translate_clang_generated_function( llvm::Function* fun) { llvm::FunctionType* type = fun->getFunctionType(); // Translate the function type auto ar_type = ar::cast< ar::FunctionType >( _ctx.type_imp->translate_type(type, ar::Signed)); return ar::Function::create(this->_bundle, ar_type, fun->getName().str(), /*is_definition = */ !fun->isDeclaration()); } ar::Code* BundleImporter::translate_function_body(llvm::Function* fun) { ar::Function* ar_fun = this->translate_function(fun); ikos_assert(ar_fun->is_definition()); FunctionImporter function_imp(_ctx, fun, ar_fun); return function_imp.translate_body(); } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/bundle.hpp000066400000000000000000000134341473507761200234770ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate a LLVM module and Debug Information into an AR bundle * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include "import_context.hpp" namespace ikos { namespace frontend { namespace import { /// \brief Helper class to translate global values and functions class BundleImporter { private: // Import context ImportContext& _ctx; // AR context ar::Context& _context; // AR bundle ar::Bundle* _bundle; // Map from LLVM global variables to AR global variables llvm::DenseMap< llvm::GlobalVariable*, ar::GlobalVariable* > _globals; // Map from LLVM functions to AR functions llvm::DenseMap< llvm::Function*, ar::Function* > _functions; // Allow mismatch of LLVM types (llvm::Type) and Debug Info types // (llvm::DIType) // // See `Importer::ImportOption`. bool _allow_debug_info_mismatch; public: /// \brief Public constructor explicit BundleImporter(ImportContext& ctx) : _ctx(ctx), _context(ctx.ar_context), _bundle(ctx.bundle), _allow_debug_info_mismatch( ctx.opts.test(Importer::AllowMismatchDebugInfo)) {} /// \brief Translate a llvm::GlobalVariable* into an ar::GlobalVariable* ar::GlobalVariable* translate_global_variable(llvm::GlobalVariable*); /// \brief Translate the initializer of a llvm::GlobalVariable* into an /// ar::Code* ar::Code* translate_global_variable_initializer(llvm::GlobalVariable*); /// \brief Translate a llvm::Function* into an ar::Function* /// /// Returns nullptr for intrinsics that should not be translated (e.g, /// llvm.dbg.* functions) ar::Function* translate_function(llvm::Function*); private: /// \brief Translate a llvm::Function* with debug info into an ar::Function* ar::Function* translate_function_di(llvm::Function*, llvm::DISubprogram*); /// \brief Translate an external llvm::Function* into an ar::Function* /// /// Returns nullptr for intrinsics that should not be translated (e.g, /// llvm.dbg.* functions) ar::Function* translate_extern_function(llvm::Function*); /// \brief Translate an internal llvm::Function* into an ar::Function* /// /// This is used when no debug information is available. ar::Function* translate_internal_function(llvm::Function*); public: /// \brief Return true if the given intrinsic should not be translated bool ignore_intrinsic(llvm::Intrinsic::ID); private: /// \brief Translate an intrinsic llvm::Function* into an ar::Function* /// /// Returns nullptr if the function cannot be translated into an AR intrinsic /// (such as llvm.fabs, etc.) ar::Function* translate_intrinsic_function(llvm::Function*, llvm::Intrinsic::ID); /// \brief Translate a library llvm::Function* into an ar::Function* /// /// Returns nullptr if the function is not a well-known library function ar::Function* translate_library_function(llvm::Function*); /// \brief Return true if the given llvm::Function* has been auto-generated by /// clang bool is_clang_generated_function(llvm::Function*); /// \brief Translate a llvm::Function* generated by clang into an /// ar::Function* ar::Function* translate_clang_generated_function(llvm::Function*); public: /// \brief Translate the body of a llvm::Function* into an ar::Code* ar::Code* translate_function_body(llvm::Function*); }; // end class BundleImporter } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/constant.cpp000066400000000000000000000563431473507761200240600ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM constants into AR values * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include "bundle.hpp" #include "constant.hpp" #include "type.hpp" namespace ikos { namespace frontend { namespace import { /// \brief Convert a llvm::APInt with the given signedness into an /// ar::MachineInt static ar::MachineInt to_machine_int(const llvm::APInt& n, ar::Signedness sign) { if (n.getBitWidth() <= 64) { if (sign == ar::Signed) { return ar::MachineInt(n.getSExtValue(), n.getBitWidth(), sign); } else { return ar::MachineInt(n.getZExtValue(), n.getBitWidth(), sign); } } else { llvm::SmallString< 16 > str; n.toString(str, /*radix = */ 10, /*signed = */ (sign == ar::Signed)); return ar::MachineInt(ar::ZNumber::from_string(str.c_str(), /*base = */ 10), n.getBitWidth(), sign); } } ar::Value* ConstantImporter::translate_constant(llvm::Constant* cst, ar::Type* type, ar::BasicBlock* bb) { // List of constant expressions to handle llvm::SmallVector< ConstantExpression, 4 > exprs; // Translate the constant and fill exprs ar::Value* ar_cst = this->translate_constant(cst, type, bb, exprs); if (!exprs.empty()) { llvm::SmallVector< std::unique_ptr< ar::Statement >, 4 > stmts; // Build the statements for (std::size_t i = 0; i < exprs.size(); i++) { const ConstantExpression& cst_expr = exprs[i]; std::unique_ptr< ar::Statement > stmt = this->translate_constant_expr_to_stmt(cst_expr.var, cst_expr.expr, bb, exprs); stmt->set_frontend< llvm::Value >(cst_expr.expr); stmts.push_back(std::move(stmt)); } // Insert all the statements, in reverse order while (!stmts.empty()) { bb->push_back(std::move(stmts.back())); stmts.pop_back(); } } return ar_cst; } ar::Value* ConstantImporter::translate_constant(llvm::Constant* cst, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { auto it = this->_constants.find({cst, type}); if (it != this->_constants.end()) { return it->second; } ar::Value* ar_cst = nullptr; ar::Type* orig_type = type; if (llvm::isa< llvm::BlockAddress >(cst)) { throw ImportError("llvm blockaddress is not supported"); } else if (llvm::isa< llvm::ConstantTokenNone >(cst)) { throw ImportError("llvm token 'none' is not supported"); } else if (llvm::isa< llvm::GlobalIFunc >(cst)) { throw ImportError("indirect functions (ifunc) are not supported"); } else if (auto gv_alias = llvm::dyn_cast< llvm::GlobalAlias >(cst)) { ar_cst = this->translate_global_alias(gv_alias, type, bb, exprs); } else if (auto gv = llvm::dyn_cast< llvm::GlobalVariable >(cst)) { ar_cst = this->translate_global_variable(gv, type, bb, exprs); } else if (auto fun = llvm::dyn_cast< llvm::Function >(cst)) { ar_cst = this->translate_function(fun, type, bb, exprs); } else { // If no specific type is needed, just use translate_type(cst->getType()) if (type == nullptr) { type = _ctx.type_imp->translate_type(cst->getType(), ar::Signed); } if (auto cst_int = llvm::dyn_cast< llvm::ConstantInt >(cst)) { ar_cst = this->translate_constant_int(cst_int, ar::cast< ar::IntegerType >(type)); } else if (auto cst_fp = llvm::dyn_cast< llvm::ConstantFP >(cst)) { ar_cst = this->translate_constant_fp(cst_fp, ar::cast< ar::FloatType >(type)); } else if (auto cst_null = llvm::dyn_cast< llvm::ConstantPointerNull >(cst)) { ar_cst = this->translate_constant_ptr_null(cst_null, ar::cast< ar::PointerType >(type)); } else if (auto cst_undef = llvm::dyn_cast< llvm::UndefValue >(cst)) { ar_cst = this->translate_constant_undef(cst_undef, type); } else if (auto cst_agg_zero = llvm::dyn_cast< llvm::ConstantAggregateZero >(cst)) { ar_cst = this->translate_constant_agg_zero(cst_agg_zero, ar::cast< ar::AggregateType >( type)); } else if (auto cst_array = llvm::dyn_cast< llvm::ConstantArray >(cst)) { ar_cst = this->translate_constant_array(cst_array, ar::cast< ar::ArrayType >(type), bb, exprs); } else if (auto cst_struct = llvm::dyn_cast< llvm::ConstantStruct >(cst)) { ar_cst = this->translate_constant_struct(cst_struct, ar::cast< ar::StructType >(type), bb, exprs); } else if (auto cst_vector = llvm::dyn_cast< llvm::ConstantVector >(cst)) { ar_cst = this->translate_constant_vector(cst_vector, ar::cast< ar::VectorType >(type), bb, exprs); } else if (auto cst_data_array = llvm::dyn_cast< llvm::ConstantDataArray >(cst)) { ar_cst = this->translate_constant_data_array(cst_data_array, ar::cast< ar::ArrayType >(type), bb, exprs); } else if (auto cst_data_vector = llvm::dyn_cast< llvm::ConstantDataVector >(cst)) { ar_cst = this->translate_constant_data_vector(cst_data_vector, ar::cast< ar::VectorType >(type), bb, exprs); } else if (auto cst_expr = llvm::dyn_cast< llvm::ConstantExpr >(cst)) { ar_cst = this->translate_constant_expr_to_var(cst_expr, type, bb, exprs); } else { throw ImportError("unexpected llvm constant [1]"); } } ikos_assert(ar_cst); if (exprs.empty()) { // only if the constant is free of llvm::ConstantExpr this->_constants.try_emplace({cst, orig_type}, ar_cst); } return ar_cst; } ar::IntegerConstant* ConstantImporter::translate_constant_int( llvm::ConstantInt* cst, ar::IntegerType* type) { ar::MachineInt n = to_machine_int(cst->getValue(), type->sign()); return ar::IntegerConstant::get(this->_context, type, n); } ar::FloatConstant* ConstantImporter::translate_constant_fp( llvm::ConstantFP* cst, ar::FloatType* type) { const llvm::APFloat& f = cst->getValueAPF(); llvm::SmallString< 16 > str; f.toString(str, /*FormatPrecision = */ 0, /*FormatMaxPadding = */ 0); return ar::FloatConstant::get(this->_context, type, str.c_str()); } ar::NullConstant* ConstantImporter::translate_constant_ptr_null( llvm::ConstantPointerNull* /*cst*/, ar::PointerType* type) { return ar::NullConstant::get(this->_context, type); } ar::UndefinedConstant* ConstantImporter::translate_constant_undef( llvm::UndefValue* /*cst*/, ar::Type* type) { return ar::UndefinedConstant::get(this->_context, type); } ar::AggregateZeroConstant* ConstantImporter::translate_constant_agg_zero( llvm::ConstantAggregateZero* /*cst*/, ar::AggregateType* type) { return ar::AggregateZeroConstant::get(this->_context, type); } ar::ArrayConstant* ConstantImporter::translate_constant_array( llvm::ConstantArray* cst, ar::ArrayType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { ar::ArrayConstant::Values values; ikos_assert(cst->getNumOperands() == type->num_elements()); values.reserve(cst->getNumOperands()); for (auto it = cst->op_begin(), et = cst->op_end(); it != et; ++it) { auto element = llvm::cast< llvm::Constant >(*it); ar::Value* ar_element = this->translate_constant(element, type->element_type(), bb, exprs); values.push_back(ar_element); } return ar::ArrayConstant::get(this->_context, type, values); } ar::StructConstant* ConstantImporter::translate_constant_struct( llvm::ConstantStruct* cst, ar::StructType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { ar::StructConstant::Values fields; ikos_assert(cst->getNumOperands() == type->num_fields()); fields.reserve(cst->getNumOperands()); auto op_it = cst->op_begin(); auto op_et = cst->op_end(); auto type_it = type->field_begin(); auto type_et = type->field_end(); for (; op_it != op_et && type_it != type_et; ++op_it, ++type_it) { auto element = llvm::cast< llvm::Constant >(*op_it); ar::Value* ar_element = this->translate_constant(element, type_it->type, bb, exprs); fields.push_back({type_it->offset, ar_element}); } return ar::StructConstant::get(this->_context, type, fields); } ar::VectorConstant* ConstantImporter::translate_constant_vector( llvm::ConstantVector* cst, ar::VectorType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { ar::VectorConstant::Values values; values.reserve(cst->getNumOperands()); for (auto it = cst->op_begin(), et = cst->op_end(); it != et; ++it) { auto element = llvm::cast< llvm::Constant >(*it); ar::Value* ar_element = this->translate_constant(element, type->element_type(), bb, exprs); values.push_back(ar_element); } return ar::VectorConstant::get(this->_context, type, values); } ar::ArrayConstant* ConstantImporter::translate_constant_data_array( llvm::ConstantDataArray* cst, ar::ArrayType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { ar::ArrayConstant::Values values; ikos_assert(cst->getNumElements() == type->num_elements()); values.reserve(cst->getNumElements()); for (unsigned i = 0; i < cst->getNumElements(); i++) { llvm::Constant* element = cst->getElementAsConstant(i); ar::Value* ar_element = this->translate_constant(element, type->element_type(), bb, exprs); values.push_back(ar_element); } return ar::ArrayConstant::get(this->_context, type, values); } ar::VectorConstant* ConstantImporter::translate_constant_data_vector( llvm::ConstantDataVector* cst, ar::VectorType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { ar::VectorConstant::Values values; ikos_assert(cst->getNumElements() == type->num_elements()); values.reserve(cst->getNumElements()); for (unsigned i = 0; i < cst->getNumElements(); i++) { llvm::Constant* element = cst->getElementAsConstant(i); ar::Value* ar_element = this->translate_constant(element, type->element_type(), bb, exprs); values.push_back(ar_element); } return ar::VectorConstant::get(this->_context, type, values); } ar::Value* ConstantImporter::translate_global_alias( llvm::GlobalAlias* cst, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { return this->translate_constant(cst->getAliasee(), type, bb, exprs); } ar::InternalVariable* ConstantImporter::translate_constant_expr_to_var( llvm::ConstantExpr* cst, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { // Create an internal variable containing the result of the ConstantExpr ar::InternalVariable* iv = ar::InternalVariable::create(bb->code(), type); // Set the origin of the variable iv->set_frontend< llvm::Value >(cst); // Add it in the list exprs.push_back({iv, cst}); return iv; } ar::Value* ConstantImporter::translate_global_variable( llvm::GlobalVariable* gv, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { ar::GlobalVariable* ar_gv = _ctx.bundle_imp->translate_global_variable(gv); if (type == nullptr || ar_gv->type() == type) { return ar_gv; } else { // Add a cast from ar_gv->type() to type // Create an internal variable containing the result of the cast ar::InternalVariable* iv = ar::InternalVariable::create(bb->code(), type); // Set the origin of the variable iv->set_frontend< llvm::Value >(gv); // Add it in the list exprs.push_back({iv, gv}); return iv; } } ar::Value* ConstantImporter::translate_function(llvm::Function* fun, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs) { ar::Function* ar_fun = _ctx.bundle_imp->translate_function(fun); ikos_assert(ar_fun != nullptr); ar::FunctionPointerConstant* ar_fun_ptr = ar_fun->pointer(); if (type == nullptr || ar_fun_ptr->type() == type) { return ar_fun_ptr; } else { // Add a cast from ar_fun_ptr->type() to type // Create an internal variable containing the result of the cast ar::InternalVariable* iv = ar::InternalVariable::create(bb->code(), type); // Set the origin of the variable iv->set_frontend< llvm::Value >(fun); // Add it in the list exprs.push_back({iv, fun}); return iv; } } std::unique_ptr< ar::Statement > ConstantImporter:: translate_constant_expr_to_stmt(ar::InternalVariable* result, llvm::Constant* cst, ar::BasicBlock* bb, ConstantExpressionList& exprs) { if (auto gv = llvm::dyn_cast< llvm::GlobalVariable >(cst)) { return this->translate_global_variable_cast(result, gv); } else if (auto fun = llvm::dyn_cast< llvm::Function >(cst)) { return this->translate_function_ptr_cast(result, fun); } else if (auto expr = llvm::dyn_cast< llvm::ConstantExpr >(cst)) { // We only need to support constant expressions that appear in initializer // of global variables, because we assume the user lowered down // all constant expressions as instructions (using the lower-cst-expr pass) auto inst_deleter = [](llvm::Instruction* inst) { inst->deleteValue(); }; std::unique_ptr< llvm::Instruction, decltype(inst_deleter) > inst(expr->getAsInstruction(), inst_deleter); if (auto gep = llvm::dyn_cast< llvm::GetElementPtrInst >(inst.get())) { return this->translate_getelementptr(result, gep, bb, exprs); } else if (auto bitcast = llvm::dyn_cast< llvm::BitCastInst >(inst.get())) { return this->translate_bitcast(result, bitcast, bb, exprs); } else if (auto inttoptr = llvm::dyn_cast< llvm::IntToPtrInst >(inst.get())) { return this->translate_inttoptr(result, inttoptr, bb, exprs); } else if (auto ptrtoint = llvm::dyn_cast< llvm::PtrToIntInst >(inst.get())) { return this->translate_ptrtoint(result, ptrtoint, bb, exprs); } else { throw ImportError("unexpected llvm constant expression"); } } else { throw ImportError("unexpected llvm constant [2]"); } } std::unique_ptr< ar::UnaryOperation > ConstantImporter:: translate_global_variable_cast(ar::InternalVariable* result, llvm::GlobalVariable* gv) { // Create a cast statement from ar_gv->type() to result->type() ar::GlobalVariable* ar_gv = _ctx.bundle_imp->translate_global_variable(gv); return ar::UnaryOperation::create(ar::UnaryOperation::Bitcast, result, ar_gv); } std::unique_ptr< ar::UnaryOperation > ConstantImporter:: translate_function_ptr_cast(ar::InternalVariable* result, llvm::Function* fun) { // Create a cast statement from ar_fun_ptr->type() to result->type() ar::Function* ar_fun = _ctx.bundle_imp->translate_function(fun); ikos_assert(ar_fun != nullptr); ar::FunctionPointerConstant* ar_fun_ptr = ar_fun->pointer(); return ar::UnaryOperation::create(ar::UnaryOperation::Bitcast, result, ar_fun_ptr); } std::unique_ptr< ar::PointerShift > ConstantImporter::translate_getelementptr( ar::InternalVariable* result, llvm::GetElementPtrInst* gep, ar::BasicBlock* bb, ConstantExpressionList& exprs) { // Translate base auto pointer = llvm::cast< llvm::Constant >(gep->getPointerOperand()); ar::Value* ar_pointer = this->translate_constant(pointer, nullptr, bb, exprs); // Translate operands std::vector< ar::PointerShift::Term > terms; terms.reserve(gep->getNumOperands() - 1); ar::IntegerType* size_type = ar::IntegerType::size_type(this->_bundle); for (auto it = llvm::gep_type_begin(gep), et = llvm::gep_type_end(gep); it != et; ++it) { auto op = llvm::cast< llvm::Constant >(it.getOperand()); if (llvm::StructType* struct_type = it.getStructTypeOrNull()) { // Shift to get a struct field llvm::APInt value = llvm::cast< llvm::ConstantInt >(op)->getValue(); ikos_assert(value.getBitWidth() <= 64 && value.getZExtValue() <= std::numeric_limits< unsigned >::max()); auto uint_value = static_cast< unsigned >(value.getZExtValue()); uint64_t offset = this->_llvm_data_layout.getStructLayout(struct_type) ->getElementOffset(uint_value); ar::IntegerConstant* ar_op = ar::IntegerConstant::get(this->_context, size_type, ar::MachineInt(offset, size_type->bit_width(), size_type->sign())); terms.emplace_back(ar::MachineInt(1, size_type->bit_width(), size_type->sign()), ar_op); } else { // Shift in a sequential type uint64_t size = this->_llvm_data_layout.getTypeAllocSize(it.getIndexedType()); ar::Value* ar_op = this->translate_constant(op, nullptr, bb, exprs); terms.emplace_back(ar::MachineInt(size, size_type->bit_width(), size_type->sign()), ar_op); } } return ar::PointerShift::create(result, ar_pointer, terms); } std::unique_ptr< ar::UnaryOperation > ConstantImporter::translate_bitcast( ar::InternalVariable* result, llvm::BitCastInst* inst, ar::BasicBlock* bb, ConstantExpressionList& exprs) { auto op = llvm::cast< llvm::Constant >(inst->getOperand(0)); ar::Value* ar_op = this->translate_constant(op, nullptr, bb, exprs); return ar::UnaryOperation::create(ar::UnaryOperation::Bitcast, result, ar_op); } std::unique_ptr< ar::UnaryOperation > ConstantImporter::translate_inttoptr( ar::InternalVariable* result, llvm::IntToPtrInst* inst, ar::BasicBlock* bb, ConstantExpressionList& exprs) { auto op = llvm::cast< llvm::Constant >(inst->getOperand(0)); ar::Value* ar_op = this->translate_constant(op, nullptr, bb, exprs); auto type = ar::cast< ar::IntegerType >(ar_op->type()); return ar::UnaryOperation::create(type->is_signed() ? ar::UnaryOperation::SIToPtr : ar::UnaryOperation::UIToPtr, result, ar_op); } std::unique_ptr< ar::UnaryOperation > ConstantImporter::translate_ptrtoint( ar::InternalVariable* result, llvm::PtrToIntInst* inst, ar::BasicBlock* bb, ConstantExpressionList& exprs) { auto op = llvm::cast< llvm::Constant >(inst->getOperand(0)); ar::Value* ar_op = this->translate_constant(op, nullptr, bb, exprs); auto type = ar::cast< ar::IntegerType >(result->type()); return ar::UnaryOperation::create(type->is_signed() ? ar::UnaryOperation::PtrToSI : ar::UnaryOperation::PtrToUI, result, ar_op); } ar::Value* ConstantImporter::translate_cast_integer_constant( llvm::Constant* cst, ar::IntegerType* type) { ikos_assert(type != nullptr); auto it = this->_constants.find({cst, type}); if (it != this->_constants.end()) { return it->second; } ar::Value* ar_cst = nullptr; if (auto cst_int = llvm::dyn_cast< llvm::ConstantInt >(cst)) { ar::MachineInt n = to_machine_int(cst_int->getValue(), type->sign()); ar::MachineInt m = n.cast(type->bit_width(), type->sign()); ar_cst = ar::IntegerConstant::get(this->_context, type, m); } else if (llvm::isa< llvm::UndefValue >(cst)) { ar_cst = ar::UndefinedConstant::get(this->_context, type); } else { throw ImportError("unexpected llvm constant [3]"); } ikos_assert(ar_cst != nullptr); this->_constants.try_emplace({cst, type}, ar_cst); return ar_cst; } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/constant.hpp000066400000000000000000000256531473507761200240650ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM constants into AR values * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "import_context.hpp" namespace ikos { namespace frontend { namespace import { /// \brief Helper class to translate constants class ConstantImporter { private: // Import context ImportContext& _ctx; // AR context ar::Context& _context; // AR bundle ar::Bundle* _bundle; // LLVM data layout const llvm::DataLayout& _llvm_data_layout; // Map from LLVM Constant + AR type to AR value llvm::DenseMap< std::pair< llvm::Constant*, ar::Type* >, ar::Value* > _constants; public: /// \brief Public constructor explicit ConstantImporter(ImportContext& ctx) : _ctx(ctx), _context(ctx.ar_context), _bundle(ctx.bundle), _llvm_data_layout(ctx.llvm_data_layout) {} public: /// \brief Translate a llvm::Constant into an ar::Value /// /// This will add statements at the end of the basic block if the /// llvm::Constant contains constant expressions (see llvm::ConstantExpr). /// /// Note: If non-null, the `type` parameter should be compatible with the /// constant: `TypeImporter::match_ar_type(cst->getType(), type)` should be /// true. /// /// \param cst The constant to translate /// \param type The required ar::Type, or null if no specific type is needed /// \param bb The basic block that will use the constant ar::Value* translate_constant(llvm::Constant* cst, ar::Type* type, ar::BasicBlock* bb); private: /* * Implementation of translation of llvm::Constant */ struct ConstantExpression { ar::InternalVariable* var; llvm::Constant* expr; }; using ConstantExpressionList = llvm::SmallVectorImpl< ConstantExpression >; private: /// \brief Translate a llvm::Constant into an ar::Value /// /// This also produces a list of llvm::ConstantExpr that needs to be /// translated into ar::Statement /// /// \param cst The constant to translate /// \param type The required ar::Type, or null if no specific type is needed /// \param bb The basic block that will use the constant /// \param exprs The list of llvm::ConstantExpr to handle later ar::Value* translate_constant(llvm::Constant* cst, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantInt into an ar::IntegerConstant ar::IntegerConstant* translate_constant_int(llvm::ConstantInt* cst, ar::IntegerType* type); /// \brief Translate a llvm::ConstantFP into ar ar::FloatConstant ar::FloatConstant* translate_constant_fp(llvm::ConstantFP* cst, ar::FloatType* type); /// \brief Translate a llvm::ConstantPointerNull into an ar::NullConstant ar::NullConstant* translate_constant_ptr_null(llvm::ConstantPointerNull* cst, ar::PointerType* type); /// \brief Translate a llvm::UndefValue into an ar::UndefinedConstant ar::UndefinedConstant* translate_constant_undef(llvm::UndefValue* cst, ar::Type* type); /// \brief Translate a llvm::ConstantAggregateZero into an /// ar::AggregateZeroConstant ar::AggregateZeroConstant* translate_constant_agg_zero( llvm::ConstantAggregateZero* cst, ar::AggregateType* type); /// \brief Translate a llvm::ConstantArray into an ar::ArrayConstant ar::ArrayConstant* translate_constant_array(llvm::ConstantArray* cst, ar::ArrayType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantStruct into an ar::StructConstant ar::StructConstant* translate_constant_struct(llvm::ConstantStruct* cst, ar::StructType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantVector into an ar::VectorConstant ar::VectorConstant* translate_constant_vector(llvm::ConstantVector* cst, ar::VectorType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantDataArray into an ar::ArrayConstant ar::ArrayConstant* translate_constant_data_array( llvm::ConstantDataArray* cst, ar::ArrayType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantDataVector into an ar::VectorConstant ar::VectorConstant* translate_constant_data_vector( llvm::ConstantDataVector* cst, ar::VectorType* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::GlobalAlias into an ar::Value ar::Value* translate_global_alias(llvm::GlobalAlias* cst, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantExpr* into a ar::InternalVariable ar::InternalVariable* translate_constant_expr_to_var( llvm::ConstantExpr* cst, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::GlobalVariable into an ar::Value ar::Value* translate_global_variable(llvm::GlobalVariable* gv, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::Function into an ar::Value ar::Value* translate_function(llvm::Function* fun, ar::Type* type, ar::BasicBlock* bb, ConstantExpressionList& exprs); private: /* * Implementation of translation of llvm::ConstantExpr */ /// \brief Translate a llvm::ConstantExpr into an ar::Statement std::unique_ptr< ar::Statement > translate_constant_expr_to_stmt( ar::InternalVariable* result, llvm::Constant* cst, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Create a cast from a llvm::GlobalVariable to an /// ar::InternalVariable std::unique_ptr< ar::UnaryOperation > translate_global_variable_cast( ar::InternalVariable* result, llvm::GlobalVariable* gv); /// \brief Create a cast from a llvm::Function to an ar::InternalVariable std::unique_ptr< ar::UnaryOperation > translate_function_ptr_cast( ar::InternalVariable* result, llvm::Function* fun); /// \brief Translate a llvm::ConstantExpr into an ar::PointerShift std::unique_ptr< ar::PointerShift > translate_getelementptr( ar::InternalVariable* result, llvm::GetElementPtrInst* gep, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantExpr into an ar::UnaryOperation std::unique_ptr< ar::UnaryOperation > translate_bitcast( ar::InternalVariable* result, llvm::BitCastInst* inst, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantExpr into an ar::UnaryOperation std::unique_ptr< ar::UnaryOperation > translate_inttoptr( ar::InternalVariable* result, llvm::IntToPtrInst* inst, ar::BasicBlock* bb, ConstantExpressionList& exprs); /// \brief Translate a llvm::ConstantExpr into an ar::UnaryOperation std::unique_ptr< ar::UnaryOperation > translate_ptrtoint( ar::InternalVariable* result, llvm::PtrToIntInst* inst, ar::BasicBlock* bb, ConstantExpressionList& exprs); public: /// \brief Translate an integer llvm::Constant into an ar::Value and cast it /// to the given ar::IntegerType /// /// This will throw an exception if the constant is a llvm::ConstantExpr. /// /// \param cst The constant to translate /// \param type The required ar::IntegerType ar::Value* translate_cast_integer_constant(llvm::Constant* cst, ar::IntegerType* type); }; // end class ConstantImporter } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/data_layout.cpp000066400000000000000000000107621473507761200245300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM data layout into AR data layout * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include "data_layout.hpp" namespace ikos { namespace frontend { namespace import { static ar::DataLayoutInfo translate_data_layout_info( const llvm::DataLayout& data_layout, llvm::Type* type) { uint64_t bit_width = type->getPrimitiveSizeInBits(); uint64_t abi_alignment = data_layout.getABITypeAlignment(type); uint64_t pref_alignment = data_layout.getPrefTypeAlignment(type); return {bit_width, abi_alignment, pref_alignment}; } std::unique_ptr< ar::DataLayout > translate_data_layout( const llvm::DataLayout& llvm_data_layout, llvm::LLVMContext& ctx) { // Translate endianness ar::Endianness endianness = llvm_data_layout.isLittleEndian() ? ar::LittleEndian : ar::BigEndian; // Translate pointer size and alignments ar::DataLayoutInfo pointers(llvm_data_layout.getPointerSizeInBits(), llvm_data_layout.getPointerABIAlignment(0).value(), llvm_data_layout.getPointerPrefAlignment().value()); // Create ar::DataLayout std::unique_ptr< ar::DataLayout > ar_data_layout = ar::DataLayout::create(endianness, pointers); // Set alignments of integers for (unsigned bit_width : std::array< unsigned, 5 >{{1, 8, 16, 32, 64}}) { ar_data_layout->set_integer_alignment( translate_data_layout_info(llvm_data_layout, llvm::IntegerType::get(ctx, bit_width))); } // Set alignments of floating points ar_data_layout->set_float_alignment( translate_data_layout_info(llvm_data_layout, llvm::Type::getHalfTy(ctx))); ar_data_layout->set_float_alignment( translate_data_layout_info(llvm_data_layout, llvm::Type::getFloatTy(ctx))); ar_data_layout->set_float_alignment( translate_data_layout_info(llvm_data_layout, llvm::Type::getDoubleTy(ctx))); ar_data_layout->set_float_alignment( translate_data_layout_info(llvm_data_layout, llvm::Type::getX86_FP80Ty(ctx))); ar_data_layout->set_float_alignment( translate_data_layout_info(llvm_data_layout, llvm::Type::getFP128Ty(ctx))); ar_data_layout->set_float_alignment( translate_data_layout_info(llvm_data_layout, llvm::Type::getPPC_FP128Ty(ctx))); return ar_data_layout; } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/data_layout.hpp000066400000000000000000000051311473507761200245270ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM data layout into AR data layout * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include namespace ikos { namespace frontend { namespace import { /// \brief Translate a llvm::DataLayout into ar ar::DataLayout std::unique_ptr< ar::DataLayout > translate_data_layout(const llvm::DataLayout&, llvm::LLVMContext&); } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/exception.cpp000066400000000000000000000047741473507761200242260ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Exception implementation * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include namespace ikos { namespace frontend { namespace import { // ImportError const char* ImportError::what() const noexcept { return this->_msg->c_str(); } ImportError::~ImportError() = default; // TypeDebugInfoMismatch TypeDebugInfoMismatch::~TypeDebugInfoMismatch() = default; } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/function.cpp000066400000000000000000002773541473507761200240630ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM functions into AR functions * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "bundle.hpp" #include "constant.hpp" #include "function.hpp" #include "type.hpp" namespace ikos { namespace frontend { namespace import { ar::Code* FunctionImporter::translate_body() { // Translate parameters this->translate_parameters(); // Translate control flow graph this->translate_control_flow_graph(); // Unify the exit blocks this->unify_exit_blocks(); return this->_body; } void FunctionImporter::mark_variable_mapping(llvm::Value* llvm_val, ar::Variable* ar_var) { // Set name if (llvm_val->hasName()) { ar_var->set_name(llvm_val->getName().str()); } // Add pointer to frontend object ar_var->set_frontend(llvm_val); // Add in the mapping this->_variables.try_emplace(llvm_val, ar_var); } void FunctionImporter::translate_parameters() { // Internal variables for parameters are automatically created by // ar::Function::create(). Here, we just need to store the mapping with // mark_variable_mapping. auto param_it = this->_llvm_fun->arg_begin(); auto param_et = this->_llvm_fun->arg_end(); auto ar_param_it = this->_ar_fun->param_begin(); for (; param_it != param_et; ++param_it, ++ar_param_it) { llvm::Argument* llvm_param = &*param_it; ar::InternalVariable* ar_param = *ar_param_it; this->mark_variable_mapping(llvm_param, ar_param); } } void FunctionImporter::translate_control_flow_graph() { // Translate all basic blocks translate_basic_blocks(); // Handle phi nodes // Add assignments in input blocks of BasicBlockTranslations translate_phi_nodes(); // Set the predecessors/successors link_basic_blocks(); } void FunctionImporter::translate_basic_blocks() { std::deque< llvm::BasicBlock* > worklist; // Start at the entry block worklist.push_back(&this->_llvm_fun->getEntryBlock()); while (!worklist.empty()) { // Pop the front element llvm::BasicBlock* bb = worklist.front(); worklist.pop_front(); // If already translated if (this->_blocks.find(bb) != this->_blocks.end()) { continue; } // Translate the basic block this->translate_basic_block(bb); // Add successors in the worklist for (auto it = succ_begin(bb), et = succ_end(bb); it != et; ++it) { worklist.push_back(*it); } } } void FunctionImporter::translate_basic_block(llvm::BasicBlock* llvm_bb) { ikos_assert(this->_blocks.find(llvm_bb) == this->_blocks.end()); // Create the main ar::BasicBlock ar::BasicBlock* ar_main_bb = ar::BasicBlock::create(this->_body); // Set name if (llvm_bb->hasName()) { ar_main_bb->set_name(llvm_bb->getName().str()); } // Add pointer to frontend object ar_main_bb->set_frontend(llvm_bb); // Initialize a BasicBlockTranslation auto bb_translation = std::make_unique< BasicBlockTranslation >(llvm_bb, ar_main_bb); // Set the entry block if (llvm_bb == &this->_llvm_fun->getEntryBlock()) { this->_body->set_entry_block(ar_main_bb); } // Translate instructions for (llvm::Instruction& inst : *llvm_bb) { this->translate_instruction(bb_translation.get(), &inst); } // Add it in the map this->_blocks.try_emplace(llvm_bb, std::move(bb_translation)); } void FunctionImporter::translate_phi_nodes() { // Iterate over llvm basic blocks instead of this->_blocks, // because we want a deterministic output (for testing purposes). for (llvm::BasicBlock& bb : *this->_llvm_fun) { auto it = this->_blocks.find(&bb); if (it == this->_blocks.end()) { continue; } BasicBlockTranslation* bb_translation = it->second.get(); this->translate_phi_nodes(bb_translation, &bb); } } void FunctionImporter::translate_phi_nodes( BasicBlockTranslation* bb_translation, llvm::BasicBlock* bb) { for (llvm::Instruction& inst : *bb) { if (auto phi = llvm::dyn_cast< llvm::PHINode >(&inst)) { this->translate_phi_late(bb_translation, phi); } } } void FunctionImporter::link_basic_blocks() { // Iterate over llvm basic blocks instead of this->_blocks, // because we want a deterministic output (for testing purposes). for (llvm::BasicBlock& bb : *this->_llvm_fun) { auto it = this->_blocks.find(&bb); if (it == this->_blocks.end()) { continue; } BasicBlockTranslation* bb_translation = it->second.get(); this->link_basic_block(bb_translation); } } void FunctionImporter::link_basic_block(BasicBlockTranslation* bb_translation) { llvm::BasicBlock* llvm_block = bb_translation->source; for (const BasicBlockOutput& output : bb_translation->outputs) { // Connect this output to the right basic block ar::BasicBlock* ar_block = output.block; llvm::BasicBlock* llvm_succ = output.succ; if (llvm_succ == nullptr) { // No successor (ret, resume, unreachable, etc.) continue; } // Destination basic block translation BasicBlockTranslation* succ_translation = this->_blocks[llvm_succ].get(); if (succ_translation->inputs.empty()) { // No input blocks (probably because there is no phi instruction), // Connect it to the main basic block ar_block->add_successor(succ_translation->main); } else { ikos_assert(succ_translation->inputs.find(llvm_block) != succ_translation->inputs.end()); ar::BasicBlock* ar_succ = succ_translation->inputs[llvm_block]; ar_block->add_successor(ar_succ); } } } void FunctionImporter::unify_exit_blocks() { // Check that there is at most one LLVM return block llvm::SmallVector< llvm::BasicBlock*, 1 > llvm_return_blocks; for (llvm::BasicBlock& bb : *this->_llvm_fun) { if (llvm::isa< llvm::ReturnInst >(bb.getTerminator())) { llvm_return_blocks.push_back(&bb); } } if (llvm_return_blocks.size() > 1) { // This should not happen if the 'mergereturn' pass was used std::ostringstream buf; buf << "llvm function " << this->_ar_fun->name() << " has more than one return block"; throw ImportError(buf.str()); } // Check that there is at most one AR return block llvm::SmallVector< ar::BasicBlock*, 1 > ar_return_blocks; for (ar::BasicBlock* bb : *this->_body) { if (!bb->empty() && ar::isa< ar::ReturnValue >(bb->back())) { ar_return_blocks.push_back(bb); } } if (ar_return_blocks.size() > 1) { std::ostringstream buf; buf << "ar function " << this->_ar_fun->name() << " has more than one return block"; throw ImportError(buf.str()); } // Merge all the exit blocks llvm::SmallVector< ar::BasicBlock*, 3 > ar_exit_blocks; for (ar::BasicBlock* bb : *this->_body) { if (!bb->empty() && (ar::isa< ar::ReturnValue >(bb->back()) || ar::isa< ar::Unreachable >(bb->back()) || ar::isa< ar::Resume >(bb->back()))) { ar_exit_blocks.push_back(bb); } } if (ar_exit_blocks.empty()) { return; } else if (ar_exit_blocks.size() == 1) { this->_body->set_exit_block(ar_exit_blocks[0]); } else { ar::BasicBlock* unified_exit = ar::BasicBlock::create(this->_body); unified_exit->set_name("unified-exit"); for (ar::BasicBlock* bb : ar_exit_blocks) { bb->add_successor(unified_exit); } this->_body->set_exit_block(unified_exit); } } void FunctionImporter::translate_instruction( BasicBlockTranslation* bb_translation, llvm::Instruction* inst) { // If we have more than one output block, merge them. // // A few exceptions are CmpInst, BinaryOperator and BranchInst. // We want to avoid a diamond shape in the graph: // // A // / \ // B C // \ / // D // // With this shape, we would lose precision in the analysis, // because of abstract join operations. if (bb_translation->outputs.size() > 1 && !llvm::isa< llvm::CmpInst >(inst) && !llvm::isa< llvm::BinaryOperator >(inst) && !llvm::isa< llvm::BranchInst >(inst)) { bb_translation->merge_outputs(); } if (auto alloca = llvm::dyn_cast< llvm::AllocaInst >(inst)) { this->translate_alloca(bb_translation, alloca); } else if (auto store = llvm::dyn_cast< llvm::StoreInst >(inst)) { this->translate_store(bb_translation, store); } else if (auto load = llvm::dyn_cast< llvm::LoadInst >(inst)) { this->translate_load(bb_translation, load); } else if (auto call = llvm::dyn_cast< llvm::CallInst >(inst)) { this->translate_call(bb_translation, call); } else if (auto invoke = llvm::dyn_cast< llvm::InvokeInst >(inst)) { this->translate_invoke(bb_translation, invoke); } else if (auto bitcast = llvm::dyn_cast< llvm::BitCastInst >(inst)) { this->translate_bitcast(bb_translation, bitcast); } else if (auto cast = llvm::dyn_cast< llvm::CastInst >(inst)) { this->translate_cast(bb_translation, cast); } else if (auto gep = llvm::dyn_cast< llvm::GetElementPtrInst >(inst)) { this->translate_getelementptr(bb_translation, gep); } else if (auto binary_op = llvm::dyn_cast< llvm::BinaryOperator >(inst)) { this->translate_binary_operator(bb_translation, binary_op); } else if (auto cmp = llvm::dyn_cast< llvm::CmpInst >(inst)) { this->translate_cmp(bb_translation, cmp); } else if (auto br = llvm::dyn_cast< llvm::BranchInst >(inst)) { this->translate_branch(bb_translation, br); } else if (auto ret = llvm::dyn_cast< llvm::ReturnInst >(inst)) { this->translate_return(bb_translation, ret); } else if (auto phi = llvm::dyn_cast< llvm::PHINode >(inst)) { this->translate_phi(bb_translation, phi); } else if (auto extractvalue = llvm::dyn_cast< llvm::ExtractValueInst >(inst)) { this->translate_extractvalue(bb_translation, extractvalue); } else if (auto insertvalue = llvm::dyn_cast< llvm::InsertValueInst >(inst)) { this->translate_insertvalue(bb_translation, insertvalue); } else if (auto extractelement = llvm::dyn_cast< llvm::ExtractElementInst >(inst)) { this->translate_extractelement(bb_translation, extractelement); } else if (auto insertelement = llvm::dyn_cast< llvm::InsertElementInst >(inst)) { this->translate_insertelement(bb_translation, insertelement); } else if (auto shufflevector = llvm::dyn_cast< llvm::ShuffleVectorInst >(inst)) { this->translate_shufflevector(bb_translation, shufflevector); } else if (auto unreachable = llvm::dyn_cast< llvm::UnreachableInst >(inst)) { this->translate_unreachable(bb_translation, unreachable); } else if (auto landingpad = llvm::dyn_cast< llvm::LandingPadInst >(inst)) { this->translate_landingpad(bb_translation, landingpad); } else if (auto resume = llvm::dyn_cast< llvm::ResumeInst >(inst)) { this->translate_resume(bb_translation, resume); } else if (llvm::isa< llvm::SelectInst >(inst)) { // The preprocessor should use the -lower-select pass throw ImportError("llvm select instructions are not supported"); } else if (llvm::isa< llvm::SwitchInst >(inst)) { // The preprocessor should use the -lowerswitch pass throw ImportError("llvm switch instructions are not supported"); } else { std::ostringstream buf; buf << "unsupported llvm instruction: " << inst->getOpcodeName() << " [1]"; throw ImportError(buf.str()); } } void FunctionImporter::translate_alloca(BasicBlockTranslation* bb_translation, llvm::AllocaInst* alloca) { // Translate types check_import(alloca->getType()->getPointerElementType() == alloca->getAllocatedType(), "unexpected allocated type in llvm alloca"); auto var_type = ar::cast< ar::PointerType >(this->infer_type(alloca)); ar::Type* allocated_type = var_type->pointee(); // Translate local variable ar::LocalVariable* var = ar::LocalVariable::create(this->_ar_fun, var_type, alloca->getAlign().value()); this->mark_variable_mapping(alloca, var); // Translate array size auto array_size_type = ar::IntegerType::size_type(this->_bundle); auto array_size = this->translate_cast_integer_value(bb_translation, alloca->getArraySize(), array_size_type); auto stmt = ar::Allocate::create(var, allocated_type, array_size); stmt->set_frontend< llvm::Value >(alloca); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_store(BasicBlockTranslation* bb_translation, llvm::StoreInst* store) { // Translate pointer ar::Value* pointer = this->translate_value(bb_translation, store->getPointerOperand(), nullptr); auto ptr_type = ar::cast< ar::PointerType >(pointer->type()); // Translate stored value ar::Value* value = this->translate_value(bb_translation, store->getValueOperand(), ptr_type->pointee()); auto stmt = ar::Store::create(pointer, value, store->getAlign().value(), store->isVolatile()); stmt->set_frontend< llvm::Value >(store); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_load(BasicBlockTranslation* bb_translation, llvm::LoadInst* load) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(load)); this->mark_variable_mapping(load, var); // Translate pointer ar::PointerType* ptr_type = ar::PointerType::get(this->_context, var->type()); ar::Value* pointer = this->translate_value(bb_translation, load->getPointerOperand(), ptr_type); auto stmt = ar::Load::create(var, pointer, load->getAlign().value(), load->isVolatile()); stmt->set_frontend< llvm::Value >(load); bb_translation->add_statement(std::move(stmt)); } /// \brief Eliminate any intermediate alias by returning the aliasee static llvm::Value* unalias(llvm::Value* value) { while (auto alias = llvm::dyn_cast< llvm::GlobalAlias >(value)) { value = alias->getAliasee(); } return value; } void FunctionImporter::translate_call(BasicBlockTranslation* bb_translation, llvm::CallInst* call) { if (auto intrinsic = llvm::dyn_cast< llvm::IntrinsicInst >(call)) { this->translate_intrinsic_call(bb_translation, intrinsic); return; } // Add a explicit cast for the return value, if needed const bool force_return_cast = true; // If this is a direct call, force exact types of arguments // Otherwise, it's a call on a function pointer, we allow implicit casts // (signed/unsigned and between pointer types) const bool force_args_cast = llvm::isa< llvm::Function >(unalias(call->getCalledOperand())); this->translate_call_helper(bb_translation, call, force_return_cast, force_args_cast, [](ar::InternalVariable* result, ar::Value* called, const std::vector< ar::Value* >& arguments) { return ar::Call::create(result, called, arguments); }); } void FunctionImporter::translate_intrinsic_call( BasicBlockTranslation* bb_translation, llvm::IntrinsicInst* call) { ar::IntegerType* si8_ty = ar::IntegerType::si8(this->_context); ar::PointerType* void_ptr_ty = ar::PointerType::get(this->_context, si8_ty); ar::IntegerType* size_ty = ar::IntegerType::size_type(this->_bundle); if (_ctx.bundle_imp->ignore_intrinsic(call->getIntrinsicID())) { return; // ignored intrinsic (llvm.dbg.value, etc.) } else if (auto memcpy = llvm::dyn_cast< llvm::MemCpyInst >(call)) { ar::Value* dest = this->translate_value(bb_translation, memcpy->getRawDest(), void_ptr_ty); ar::Value* src = this->translate_value(bb_translation, memcpy->getRawSource(), void_ptr_ty); ar::Value* length = this->translate_value(bb_translation, memcpy->getLength(), size_ty); auto stmt = ar::MemoryCopy::create(this->_bundle, dest, src, length, memcpy->getDestAlignment(), memcpy->getSourceAlignment(), memcpy->isVolatile()); stmt->set_frontend< llvm::Value >(memcpy); bb_translation->add_statement(std::move(stmt)); } else if (auto memmove = llvm::dyn_cast< llvm::MemMoveInst >(call)) { ar::Value* dest = this->translate_value(bb_translation, memmove->getRawDest(), void_ptr_ty); ar::Value* src = this->translate_value(bb_translation, memmove->getRawSource(), void_ptr_ty); ar::Value* length = this->translate_value(bb_translation, memmove->getLength(), size_ty); auto stmt = ar::MemoryMove::create(this->_bundle, dest, src, length, memmove->getDestAlignment(), memmove->getSourceAlignment(), memmove->isVolatile()); stmt->set_frontend< llvm::Value >(memmove); bb_translation->add_statement(std::move(stmt)); } else if (auto memset = llvm::dyn_cast< llvm::MemSetInst >(call)) { ar::Value* dest = this->translate_value(bb_translation, memset->getRawDest(), void_ptr_ty); ar::Value* value = this->translate_value(bb_translation, memset->getValue(), si8_ty); ar::Value* length = this->translate_value(bb_translation, memset->getLength(), size_ty); auto stmt = ar::MemorySet::create(this->_bundle, dest, value, length, memset->getDestAlignment(), memset->isVolatile()); stmt->set_frontend< llvm::Value >(memset); bb_translation->add_statement(std::move(stmt)); } else if (call->getIntrinsicID() == llvm::Intrinsic::vastart) { ar::Value* operand = this->translate_value(bb_translation, call->getArgOperand(0), void_ptr_ty); auto stmt = ar::VarArgStart::create(this->_bundle, operand); stmt->set_frontend< llvm::Value >(call); bb_translation->add_statement(std::move(stmt)); // Note that there is no intrinsic for VarArgGet. // There is a special instruction va_arg, // but it is never generated by clang. // Instead, clang generates load instructions that are ABI-specific. } else if (call->getIntrinsicID() == llvm::Intrinsic::vaend) { ar::Value* operand = this->translate_value(bb_translation, call->getArgOperand(0), void_ptr_ty); auto stmt = ar::VarArgEnd::create(this->_bundle, operand); stmt->set_frontend< llvm::Value >(call); bb_translation->add_statement(std::move(stmt)); } else if (call->getIntrinsicID() == llvm::Intrinsic::vacopy) { ar::Value* dest = this->translate_value(bb_translation, call->getArgOperand(0), void_ptr_ty); ar::Value* src = this->translate_value(bb_translation, call->getArgOperand(1), void_ptr_ty); auto stmt = ar::VarArgCopy::create(this->_bundle, dest, src); stmt->set_frontend< llvm::Value >(call); bb_translation->add_statement(std::move(stmt)); } else { this->translate_call_helper(bb_translation, call, /*force_return_cast = */ true, /*force_args_cast = */ true, [](ar::InternalVariable* result, ar::Value* called, const std::vector< ar::Value* >& arguments) { return ar::Call::create(result, called, arguments); }); } } void FunctionImporter::translate_invoke(BasicBlockTranslation* bb_translation, llvm::InvokeInst* invoke) { // Do not add an explicit cast, we want invoke to be the last statement const bool force_return_cast = false; // If this is a direct call, force exact types of arguments // Otherwise, it's a call on a function pointer, we allow implicit casts // (signed/unsigned and between pointer types) const bool force_args_cast = llvm::isa< llvm::Function >(unalias(invoke->getCalledOperand())); // Translate the invoke // // Use bb_translation->main as the normal and exception dest for now, // it will be updated later in BasicBlockTranslation::add_invoke_branching() this->translate_call_helper(bb_translation, invoke, force_return_cast, force_args_cast, [=](ar::InternalVariable* result, ar::Value* called, const std::vector< ar::Value* >& arguments) { return ar::Invoke::create(result, called, arguments, bb_translation->main, bb_translation->main); }); // Add output basic blocks bb_translation->add_invoke_branching(invoke->getNormalDest(), invoke->getUnwindDest()); } template < typename CallInstType, typename CreateStmtFun > void FunctionImporter::translate_call_helper( BasicBlockTranslation* bb_translation, CallInstType* call, bool force_return_cast, bool force_args_cast, CreateStmtFun create_stmt) { // Translate called value ar::Value* called = this->translate_value(bb_translation, call->getCalledOperand(), nullptr); auto called_type = ar::cast< ar::PointerType >(called->type()); auto fun_type = ar::cast< ar::FunctionType >(called_type->pointee()); const bool has_return_value = !call->getType()->isVoidTy(); // Sanity check ikos_assert(call->getType()->isVoidTy() == fun_type->return_type()->is_void()); // Translate result variable ar::InternalVariable* var = nullptr; if (has_return_value) { var = ar::InternalVariable::create(this->_body, force_return_cast ? this->infer_type(call) : fun_type->return_type()); this->mark_variable_mapping(call, var); } // Result of the ar::Call // If we need a cast, this is a temporary variable ar::InternalVariable* result = var; if (has_return_value && force_return_cast && fun_type->return_type() != var->type()) { result = ar::InternalVariable::create(this->_body, fun_type->return_type()); result->set_frontend< llvm::Value >(call); } // Translate parameters std::vector< ar::Value* > arguments; arguments.reserve(call->arg_size()); for (unsigned i = 0; i < call->arg_size(); i++) { llvm::Value* arg = call->getArgOperand(i); if (i < fun_type->num_parameters() && (force_args_cast || (llvm::isa< llvm::Constant >(arg) && !llvm::isa< llvm::GlobalValue >(arg)))) { ar::Type* arg_type = fun_type->param_type(i); arguments.push_back(this->translate_value(bb_translation, arg, arg_type)); } else { arguments.push_back(this->translate_value(bb_translation, arg, nullptr)); } } auto stmt = create_stmt(result, called, arguments); stmt->template set_frontend< llvm::Value >(call); bb_translation->add_statement(std::move(stmt)); // Add a cast from result to var, if required if (has_return_value && force_return_cast && fun_type->return_type() != var->type()) { this->add_bitcast(bb_translation, var, result); } } void FunctionImporter::translate_bitcast(BasicBlockTranslation* bb_translation, llvm::BitCastInst* bitcast) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(bitcast)); this->mark_variable_mapping(bitcast, var); // Translate operand ar::Value* operand = this->translate_value(bb_translation, bitcast->getOperand(0), nullptr); // Create statement auto stmt = ar::UnaryOperation::create(ar::UnaryOperation::Bitcast, var, operand); stmt->set_frontend< llvm::Value >(bitcast); bb_translation->add_statement(std::move(stmt)); } static ar::UnaryOperation::Operator convert_unary_op( llvm::Instruction::CastOps op, ar::Signedness sign) { switch (op) { case llvm::Instruction::Trunc: if (sign == ar::Unsigned) { return ar::UnaryOperation::UTrunc; } else { return ar::UnaryOperation::STrunc; } case llvm::Instruction::ZExt: return ar::UnaryOperation::ZExt; case llvm::Instruction::SExt: return ar::UnaryOperation::SExt; case llvm::Instruction::FPToUI: return ar::UnaryOperation::FPToUI; case llvm::Instruction::FPToSI: return ar::UnaryOperation::FPToSI; case llvm::Instruction::UIToFP: return ar::UnaryOperation::UIToFP; case llvm::Instruction::SIToFP: return ar::UnaryOperation::SIToFP; case llvm::Instruction::FPTrunc: return ar::UnaryOperation::FPTrunc; case llvm::Instruction::FPExt: return ar::UnaryOperation::FPExt; case llvm::Instruction::PtrToInt: if (sign == ar::Unsigned) { return ar::UnaryOperation::PtrToUI; } else { return ar::UnaryOperation::PtrToSI; } case llvm::Instruction::IntToPtr: if (sign == ar::Unsigned) { return ar::UnaryOperation::UIToPtr; } else { return ar::UnaryOperation::SIToPtr; } case llvm::Instruction::BitCast: return ar::UnaryOperation::Bitcast; case llvm::Instruction::AddrSpaceCast: throw ImportError("llvm addrspace casts are not supported"); default: throw ImportError("unsupported llvm cast [1]"); } } void FunctionImporter::translate_cast(BasicBlockTranslation* bb_translation, llvm::CastInst* cast) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(cast)); this->mark_variable_mapping(cast, var); ar::Signedness sign = ar::Signed; ar::Type* src_type = nullptr; // required type for the operand (or null) ar::Type* dest_type = nullptr; // type of the statement result (or null) ar::Value* operand = nullptr; // operand (null if not yet translated) // Note that dest_type might be different from var->type(), // in this case we need to add a cast. switch (cast->getOpcode()) { case llvm::Instruction::Trunc: { // No sign requirements, use inferred signedness to avoid casts sign = ar::cast< ar::IntegerType >(var->type())->sign(); src_type = _ctx.type_imp->translate_type(cast->getSrcTy(), sign); dest_type = var->type(); } break; case llvm::Instruction::ZExt: { sign = ar::Unsigned; src_type = _ctx.type_imp->translate_type(cast->getSrcTy(), sign); dest_type = _ctx.type_imp->translate_type(cast->getDestTy(), sign); } break; case llvm::Instruction::SExt: { sign = ar::Signed; src_type = _ctx.type_imp->translate_type(cast->getSrcTy(), sign); dest_type = _ctx.type_imp->translate_type(cast->getDestTy(), sign); } break; case llvm::Instruction::FPToUI: { sign = ar::Unsigned; src_type = nullptr; dest_type = _ctx.type_imp->translate_type(cast->getDestTy(), sign); } break; case llvm::Instruction::FPToSI: { sign = ar::Signed; src_type = nullptr; dest_type = _ctx.type_imp->translate_type(cast->getDestTy(), sign); } break; case llvm::Instruction::UIToFP: { sign = ar::Unsigned; src_type = _ctx.type_imp->translate_type(cast->getSrcTy(), sign); dest_type = nullptr; } break; case llvm::Instruction::SIToFP: { sign = ar::Signed; src_type = _ctx.type_imp->translate_type(cast->getSrcTy(), sign); dest_type = nullptr; } break; case llvm::Instruction::FPTrunc: case llvm::Instruction::FPExt: { src_type = dest_type = nullptr; } break; case llvm::Instruction::PtrToInt: { // No sign requirements, use inferred signedness to avoid casts sign = ar::cast< ar::IntegerType >(var->type())->sign(); src_type = nullptr; // No sign requirement on source type dest_type = var->type(); } break; case llvm::Instruction::IntToPtr: { // No sign requirements, use inferred signedness of the operand operand = this->translate_value(bb_translation, cast->getOperand(0), nullptr); sign = ar::cast< ar::IntegerType >(operand->type())->sign(); src_type = operand->type(); dest_type = nullptr; } break; default: { std::ostringstream buf; buf << "unsupported llvm cast: " << cast->getOpcodeName() << " [2]"; throw ImportError(buf.str()); } } // Translate operand if (operand == nullptr) { operand = this->translate_value(bb_translation, cast->getOperand(0), src_type); } // Result of the ar::UnaryOperation // If we need a cast, this is a temporary variable ar::InternalVariable* result = var; if (dest_type != nullptr && dest_type != var->type()) { result = ar::InternalVariable::create(this->_body, dest_type); result->set_frontend< llvm::Value >(cast); } // Create statement auto stmt = ar::UnaryOperation::create(convert_unary_op(cast->getOpcode(), sign), result, operand); stmt->set_frontend< llvm::Value >(cast); bb_translation->add_statement(std::move(stmt)); // Add a cast from result to var, if required if (dest_type != nullptr && dest_type != var->type()) { this->add_bitcast(bb_translation, var, result); } } void FunctionImporter::translate_getelementptr( BasicBlockTranslation* bb_translation, llvm::GetElementPtrInst* gep) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(gep)); this->mark_variable_mapping(gep, var); // Translate base ar::Value* pointer = this->translate_value(bb_translation, gep->getPointerOperand(), nullptr); // Translate operands std::vector< ar::PointerShift::Term > terms; terms.reserve(gep->getNumOperands() - 1); // Preferred type for operands auto size_type = ar::IntegerType::size_type(this->_bundle); for (auto it = llvm::gep_type_begin(gep), et = llvm::gep_type_end(gep); it != et; ++it) { llvm::Value* op = it.getOperand(); if (llvm::StructType* struct_type = it.getStructTypeOrNull()) { // Shift to get a struct field llvm::APInt value = llvm::cast< llvm::ConstantInt >(op)->getValue(); ikos_assert(value.getBitWidth() <= 64 && value.getZExtValue() <= std::numeric_limits< unsigned >::max()); auto uint_value = static_cast< unsigned >(value.getZExtValue()); uint64_t offset = this->_llvm_data_layout.getStructLayout(struct_type) ->getElementOffset(uint_value); ar::IntegerConstant* ar_op = ar::IntegerConstant::get(this->_context, size_type, ar::MachineInt(offset, size_type->bit_width(), size_type->sign())); terms.emplace_back(ar::MachineInt(1, size_type->bit_width(), size_type->sign()), ar_op); } else { // Shift in a sequential type uint64_t size = this->_llvm_data_layout.getTypeAllocSize(it.getIndexedType()); ar::Type* preferred_type = llvm::isa< llvm::Constant >(op) ? _ctx.type_imp->translate_type(op->getType(), ar::Signed) : nullptr; ar::Value* ar_op = this->translate_value(bb_translation, op, preferred_type); terms.emplace_back(ar::MachineInt(size, size_type->bit_width(), size_type->sign()), ar_op); } } // Create statement auto stmt = ar::PointerShift::create(var, pointer, terms); stmt->set_frontend< llvm::Value >(gep); bb_translation->add_statement(std::move(stmt)); } /// \brief Return the signedness of an instruction, based on nsw and nuw flags static ar::Signedness sign_from_wraps(llvm::Instruction* inst) { if (inst->hasNoUnsignedWrap() && !inst->hasNoSignedWrap()) { return ar::Unsigned; } else if (inst->hasNoSignedWrap() && !inst->hasNoUnsignedWrap()) { return ar::Signed; } else if (inst->hasNoSignedWrap() && inst->hasNoUnsignedWrap()) { // This is only introduced by aggressive LLVM optimization passes. // There is no way to get the original attribute, so "signed" is just a // random guess. return ar::Signed; } else { // In C, overflow on signed operations (add,sub) are undefined behaviors, // and overflow on unsigned operations are implemetation defined. // That means operations without nuw or nsw flags are necessary // unsigned operations. return ar::Unsigned; } } static ar::BinaryOperation::Operator convert_int_bin_op( llvm::BinaryOperator::BinaryOps op, ar::Signedness sign) { if (sign == ar::Unsigned) { switch (op) { case llvm::Instruction::Add: return ar::BinaryOperation::UAdd; case llvm::Instruction::Sub: return ar::BinaryOperation::USub; case llvm::Instruction::Mul: return ar::BinaryOperation::UMul; case llvm::Instruction::UDiv: return ar::BinaryOperation::UDiv; case llvm::Instruction::URem: return ar::BinaryOperation::URem; case llvm::Instruction::Shl: return ar::BinaryOperation::UShl; case llvm::Instruction::LShr: return ar::BinaryOperation::ULShr; case llvm::Instruction::AShr: return ar::BinaryOperation::UAShr; case llvm::Instruction::And: return ar::BinaryOperation::UAnd; case llvm::Instruction::Or: return ar::BinaryOperation::UOr; case llvm::Instruction::Xor: return ar::BinaryOperation::UXor; default: throw ImportError("unsupported llvm binary operator [1]"); } } else { switch (op) { case llvm::Instruction::Add: return ar::BinaryOperation::SAdd; case llvm::Instruction::Sub: return ar::BinaryOperation::SSub; case llvm::Instruction::Mul: return ar::BinaryOperation::SMul; case llvm::Instruction::SDiv: return ar::BinaryOperation::SDiv; case llvm::Instruction::SRem: return ar::BinaryOperation::SRem; case llvm::Instruction::Shl: return ar::BinaryOperation::SShl; case llvm::Instruction::LShr: return ar::BinaryOperation::SLShr; case llvm::Instruction::AShr: return ar::BinaryOperation::SAShr; case llvm::Instruction::And: return ar::BinaryOperation::SAnd; case llvm::Instruction::Or: return ar::BinaryOperation::SOr; case llvm::Instruction::Xor: return ar::BinaryOperation::SXor; default: throw ImportError("unsupported llvm binary operator [2]"); } } } static ar::BinaryOperation::Operator convert_float_bin_op( llvm::BinaryOperator::BinaryOps op) { switch (op) { case llvm::Instruction::FAdd: return ar::BinaryOperation::FAdd; case llvm::Instruction::FSub: return ar::BinaryOperation::FSub; case llvm::Instruction::FMul: return ar::BinaryOperation::FMul; case llvm::Instruction::FDiv: return ar::BinaryOperation::FDiv; case llvm::Instruction::FRem: return ar::BinaryOperation::FRem; default: throw ImportError("unsupported llvm binary operator [3]"); } } void FunctionImporter::translate_binary_operator( BasicBlockTranslation* bb_translation, llvm::BinaryOperator* inst) { llvm::Type* llvm_type = inst->getType(); // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(inst)); this->mark_variable_mapping(inst, var); if (llvm_type->isIntOrIntVectorTy()) { // Integer binary operation ar::Signedness sign = ar::Signed; ar::Type* stmt_type = nullptr; // type of the operands (or null) ar::Value* left = nullptr; // left operand (null if not yet translated) ar::Value* right = nullptr; // right operand (null if not yet translated) // Guess the type switch (inst->getOpcode()) { case llvm::Instruction::Add: case llvm::Instruction::Sub: case llvm::Instruction::Mul: { sign = sign_from_wraps(inst); } break; case llvm::Instruction::UDiv: case llvm::Instruction::URem: { sign = ar::Unsigned; } break; case llvm::Instruction::SDiv: case llvm::Instruction::SRem: { sign = ar::Signed; } break; case llvm::Instruction::Shl: case llvm::Instruction::LShr: case llvm::Instruction::AShr: case llvm::Instruction::And: case llvm::Instruction::Or: case llvm::Instruction::Xor: { // No sign requirements, use signedness of first non-constant operand if (!llvm::isa< llvm::Constant >(inst->getOperand(0))) { left = this->translate_value(bb_translation, inst->getOperand(0), nullptr); stmt_type = left->type(); } else { right = this->translate_value(bb_translation, inst->getOperand(1), nullptr); stmt_type = right->type(); } ar::Type* element_type = stmt_type; if (stmt_type->is_vector()) { element_type = ar::cast< ar::VectorType >(stmt_type)->element_type(); } sign = ar::cast< ar::IntegerType >(element_type)->sign(); } break; default: { std::ostringstream buf; buf << "unsupported llvm binary operator:" << inst->getOpcodeName() << " [4]"; throw ImportError(buf.str()); } } if (stmt_type == nullptr) { stmt_type = _ctx.type_imp->translate_type(llvm_type, sign); } // Translate operands if (left == nullptr) { left = this->translate_value(bb_translation, inst->getOperand(0), stmt_type); } if (right == nullptr) { right = this->translate_value(bb_translation, inst->getOperand(1), stmt_type); } // Result of the ar::BinaryOperation // If we need a cast, this is a temporary variable ar::InternalVariable* result = var; if (stmt_type != var->type()) { result = ar::InternalVariable::create(this->_body, stmt_type); result->set_frontend< llvm::Value >(inst); } // Add the no-wrap flag bool no_wrap = false; if (auto wrapping_inst = llvm::dyn_cast< llvm::OverflowingBinaryOperator >(inst)) { no_wrap = wrapping_inst->hasNoSignedWrap() || wrapping_inst->hasNoUnsignedWrap(); } // Add the exact flag bool exact = false; if (auto exact_inst = llvm::dyn_cast< llvm::PossiblyExactOperator >(inst)) { exact = exact_inst->isExact(); } // Create statement auto stmt = ar::BinaryOperation::create(convert_int_bin_op(inst->getOpcode(), sign), result, left, right, no_wrap, exact); stmt->set_frontend< llvm::Value >(inst); bb_translation->add_statement(std::move(stmt)); // Add a cast from result to var, if required if (stmt_type != var->type()) { this->add_bitcast(bb_translation, var, result); } } else if (llvm_type->isFPOrFPVectorTy()) { ar::Value* left = this->translate_value(bb_translation, inst->getOperand(0), nullptr); ar::Value* right = this->translate_value(bb_translation, inst->getOperand(1), nullptr); ikos_assert(left->type() == var->type()); // Create statement auto stmt = ar::BinaryOperation::create(convert_float_bin_op(inst->getOpcode()), var, left, right); stmt->set_frontend< llvm::Value >(inst); bb_translation->add_statement(std::move(stmt)); } else { std::ostringstream buf; buf << "unsupported llvm binary operator: " << inst->getOpcodeName() << " [5]"; throw ImportError(buf.str()); } } static ar::Comparison::Predicate convert_int_predicate( llvm::CmpInst::Predicate pred, ar::Signedness sign) { if (sign == ar::Signed) { switch (pred) { case llvm::CmpInst::ICMP_EQ: return ar::Comparison::SIEQ; case llvm::CmpInst::ICMP_NE: return ar::Comparison::SINE; case llvm::CmpInst::ICMP_SGT: return ar::Comparison::SIGT; case llvm::CmpInst::ICMP_SGE: return ar::Comparison::SIGE; case llvm::CmpInst::ICMP_SLT: return ar::Comparison::SILT; case llvm::CmpInst::ICMP_SLE: return ar::Comparison::SILE; default: { std::ostringstream buf; buf << "unsupported llvm cmp predicate: " << llvm::CmpInst::getPredicateName(pred).str() << " [1]"; throw ImportError(buf.str()); } } } else { switch (pred) { case llvm::CmpInst::ICMP_EQ: return ar::Comparison::UIEQ; case llvm::CmpInst::ICMP_NE: return ar::Comparison::UINE; case llvm::CmpInst::ICMP_UGT: return ar::Comparison::UIGT; case llvm::CmpInst::ICMP_UGE: return ar::Comparison::UIGE; case llvm::CmpInst::ICMP_ULT: return ar::Comparison::UILT; case llvm::CmpInst::ICMP_ULE: return ar::Comparison::UILE; default: { std::ostringstream buf; buf << "unsupported llvm cmp predicate: " << llvm::CmpInst::getPredicateName(pred).str() << " [2]"; throw ImportError(buf.str()); } } } } static ar::Comparison::Predicate convert_ptr_predicate( llvm::CmpInst::Predicate pred) { switch (pred) { case llvm::CmpInst::ICMP_EQ: return ar::Comparison::PEQ; case llvm::CmpInst::ICMP_NE: return ar::Comparison::PNE; case llvm::CmpInst::ICMP_UGT: return ar::Comparison::PGT; case llvm::CmpInst::ICMP_UGE: return ar::Comparison::PGE; case llvm::CmpInst::ICMP_ULT: return ar::Comparison::PLT; case llvm::CmpInst::ICMP_ULE: return ar::Comparison::PLE; default: { std::ostringstream buf; buf << "unsupported llvm cmp predicate: " << llvm::CmpInst::getPredicateName(pred).str() << " [3]"; throw ImportError(buf.str()); } } } static ar::Comparison::Predicate convert_float_predicate( llvm::CmpInst::Predicate pred) { switch (pred) { case llvm::CmpInst::FCMP_OEQ: return ar::Comparison::FOEQ; case llvm::CmpInst::FCMP_OGT: return ar::Comparison::FOGT; case llvm::CmpInst::FCMP_OGE: return ar::Comparison::FOGE; case llvm::CmpInst::FCMP_OLT: return ar::Comparison::FOLT; case llvm::CmpInst::FCMP_OLE: return ar::Comparison::FOLE; case llvm::CmpInst::FCMP_ONE: return ar::Comparison::FONE; case llvm::CmpInst::FCMP_ORD: return ar::Comparison::FORD; case llvm::CmpInst::FCMP_UNO: return ar::Comparison::FUNO; case llvm::CmpInst::FCMP_UEQ: return ar::Comparison::FUEQ; case llvm::CmpInst::FCMP_UGT: return ar::Comparison::FUGT; case llvm::CmpInst::FCMP_UGE: return ar::Comparison::FUGE; case llvm::CmpInst::FCMP_ULT: return ar::Comparison::FULT; case llvm::CmpInst::FCMP_ULE: return ar::Comparison::FULE; case llvm::CmpInst::FCMP_UNE: return ar::Comparison::FUNE; default: { std::ostringstream buf; buf << "unsupported llvm cmp predicate: " << llvm::CmpInst::getPredicateName(pred).str() << " [4]"; throw ImportError(buf.str()); } } } void FunctionImporter::translate_cmp(BasicBlockTranslation* bb_translation, llvm::CmpInst* cmp) { llvm::Type* llvm_type = cmp->getOperand(0)->getType(); if (cmp->isIntPredicate() && llvm_type->isIntegerTy()) { // Integer comparison ar::Signedness sign = ar::Signed; ar::IntegerType* ar_type = nullptr; ar::Value* left = nullptr; ar::Value* right = nullptr; if (cmp->isSigned()) { sign = ar::Signed; } else if (cmp->isUnsigned()) { sign = ar::Unsigned; } else { // Use signedness of the first non-constant operand if (!llvm::isa< llvm::Constant >(cmp->getOperand(0))) { left = this->translate_value(bb_translation, cmp->getOperand(0), nullptr); ar_type = ar::cast< ar::IntegerType >(left->type()); } else { right = this->translate_value(bb_translation, cmp->getOperand(1), nullptr); ar_type = ar::cast< ar::IntegerType >(right->type()); } sign = ar_type->sign(); } if (ar_type == nullptr) { ar_type = ar::cast< ar::IntegerType >( _ctx.type_imp->translate_type(llvm_type, sign)); } // Translate operands if (left == nullptr) { left = this->translate_value(bb_translation, cmp->getOperand(0), ar_type); } if (right == nullptr) { right = this->translate_value(bb_translation, cmp->getOperand(1), ar_type); } // Translate result ar::InternalVariable* result = ar::InternalVariable::create(this->_body, this->infer_type(cmp)); this->mark_variable_mapping(cmp, result); // Create statement auto pred = convert_int_predicate(cmp->getPredicate(), sign); auto stmt = ar::Comparison::create(pred, left, right); stmt->set_frontend< llvm::Value >(cmp); bb_translation->add_comparison(result, std::move(stmt)); } else if ((cmp->isIntPredicate() && llvm_type->isPointerTy()) || cmp->isFPPredicate()) { // Translate operands ar::Value* left = this->translate_value(bb_translation, cmp->getOperand(0), nullptr); ar::Value* right = this->translate_value(bb_translation, cmp->getOperand(1), nullptr); // Translate result ar::InternalVariable* result = ar::InternalVariable::create(this->_body, this->infer_type(cmp)); this->mark_variable_mapping(cmp, result); // Create statement ar::Comparison::Predicate pred; if (llvm_type->isPointerTy()) { pred = convert_ptr_predicate(cmp->getPredicate()); } else { pred = convert_float_predicate(cmp->getPredicate()); } auto stmt = ar::Comparison::create(pred, left, right); stmt->set_frontend< llvm::Value >(cmp); bb_translation->add_comparison(result, std::move(stmt)); } else { std::ostringstream buf; buf << "unsupported llvm cmp instruction with predicate: " << llvm::CmpInst::getPredicateName(cmp->getPredicate()).str() << " [1]"; throw ImportError(buf.str()); } } void FunctionImporter::translate_branch(BasicBlockTranslation* bb_translation, llvm::BranchInst* br) { if (br->isUnconditional()) { bb_translation->add_unconditional_branching(br, br->getSuccessor(0)); } else { // Translate condition (get the associated ar::Variable) llvm::Value* condition = br->getCondition(); if (llvm::isa< llvm::Instruction >(condition) || llvm::isa< llvm::Argument >(condition)) { auto it = this->_variables.find(condition); ikos_assert_msg(it != this->_variables.end(), "condition hasn't been translated yet"); auto var = ar::cast< ar::InternalVariable >(it->second); // Add branch bb_translation->add_conditional_branching(br, var); } else if (auto cst = llvm::dyn_cast< llvm::ConstantInt >(condition)) { bb_translation->add_unconditional_branching(br, br->getSuccessor( cst->isZero() ? 1 : 0)); } else if (llvm::isa< llvm::UndefValue >(condition)) { bb_translation->add_nondeterministic_branching(br); } else { throw ImportError("unsupported condition for llvm branch instruction"); } } } void FunctionImporter::translate_return(BasicBlockTranslation* bb_translation, llvm::ReturnInst* ret) { // Translate operand ar::Value* operand = nullptr; if (ret->getNumOperands() > 0) { operand = this->translate_value(bb_translation, ret->getReturnValue(), this->_ar_fun->type()->return_type()); } // Create statement auto stmt = ar::ReturnValue::create(operand); stmt->set_frontend< llvm::Value >(ret); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_phi(BasicBlockTranslation* /*bb_translation*/, llvm::PHINode* phi) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(phi)); this->mark_variable_mapping(phi, var); // We will add the assignments later, // in translate_phi_late, called by translate_phi_nodes(). } static bool is_valid_bitcast(ar::Type* from, ar::Type* to) { return (from->is_pointer() && to->is_pointer()) || (from->is_primitive() && to->is_primitive() && from->primitive_bit_width() == to->primitive_bit_width()); } void FunctionImporter::translate_phi_late(BasicBlockTranslation* bb_translation, llvm::PHINode* phi) { auto result = ar::cast< ar::InternalVariable >(this->_variables[phi]); for (unsigned i = 0; i < phi->getNumIncomingValues(); i++) { llvm::Value* llvm_value = phi->getIncomingValue(i); llvm::BasicBlock* llvm_bb = phi->getIncomingBlock(i); // Create an ar::BasicBlock ar::BasicBlock* ar_bb = bb_translation->input_basic_block(llvm_bb); // Translate the incoming value ar::Value* ar_value = nullptr; if (llvm::isa< llvm::Constant >(llvm_value) && !llvm::isa< llvm::GlobalValue >(llvm_value)) { ar_value = this->translate_value(bb_translation, llvm_value, result->type()); } else { ar_value = this->translate_value(bb_translation, llvm_value, nullptr); } if (ar_value->type() == result->type()) { // Use an assignment auto stmt = ar::Assignment::create(result, ar_value); stmt->set_frontend< llvm::Value >(phi); ar_bb->push_back(std::move(stmt)); } else if (is_valid_bitcast(ar_value->type(), result->type())) { // Use a bitcast auto stmt = ar::UnaryOperation::create(ar::UnaryOperation::Bitcast, result, ar_value); stmt->set_frontend< llvm::Value >(phi); ar_bb->push_back(std::move(stmt)); } else { throw ImportError("invalid ar bitcast for llvm phi instruction"); } } } void FunctionImporter::translate_extractvalue( BasicBlockTranslation* bb_translation, llvm::ExtractValueInst* inst) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(inst)); this->mark_variable_mapping(inst, var); // Translate aggregate ar::Value* aggregate = this->translate_value(bb_translation, inst->getAggregateOperand(), nullptr); // Translate offset llvm::Type* indexed_type = inst->getAggregateOperand()->getType(); ar::IntegerConstant* offset = this->translate_indexes(indexed_type, inst->idx_begin(), inst->idx_end()); // Create statement auto stmt = ar::ExtractElement::create(var, aggregate, offset); stmt->set_frontend< llvm::Value >(inst); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_insertvalue( BasicBlockTranslation* bb_translation, llvm::InsertValueInst* inst) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(inst)); this->mark_variable_mapping(inst, var); // Translate aggregate ar::Value* aggregate = this->translate_value(bb_translation, inst->getAggregateOperand(), nullptr); // Translate offset llvm::Type* indexed_type = inst->getAggregateOperand()->getType(); ar::IntegerConstant* offset = this->translate_indexes(indexed_type, inst->idx_begin(), inst->idx_end()); // Translate element ar::Value* element = this->translate_value(bb_translation, inst->getInsertedValueOperand(), nullptr); // Create statement auto stmt = ar::InsertElement::create(var, aggregate, offset, element); stmt->set_frontend< llvm::Value >(inst); bb_translation->add_statement(std::move(stmt)); } ar::IntegerConstant* FunctionImporter::translate_indexes( llvm::Type* indexed_type, llvm::ExtractValueInst::idx_iterator begin, llvm::ExtractValueInst::idx_iterator end) { ar::ZNumber offset(0); for (auto it = begin; it != end; ++it) { unsigned idx = *it; if (auto struct_type = llvm::dyn_cast< llvm::StructType >(indexed_type)) { offset += this->_llvm_data_layout.getStructLayout(struct_type) ->getElementOffset(idx); } else if (auto array_type = llvm::dyn_cast< llvm::ArrayType >(indexed_type)) { ar::ZNumber element_size( this->_llvm_data_layout.getTypeAllocSize(array_type->getElementType()) .getFixedSize()); offset += element_size * idx; } else if (auto vector_type = llvm::dyn_cast< llvm::VectorType >(indexed_type)) { ar::ZNumber element_size( this->_llvm_data_layout .getTypeAllocSize(vector_type->getElementType()) .getFixedSize()); offset += element_size * idx; } else { throw ImportError("unsupported operand to llvm extractvalue"); } indexed_type = llvm::GetElementPtrInst::getTypeAtIndex(indexed_type, idx); } auto size_type = ar::IntegerType::size_type(this->_bundle); return ar::IntegerConstant::get(this->_context, size_type, ar::MachineInt(offset, size_type->bit_width(), size_type->sign())); } void FunctionImporter::translate_extractelement( BasicBlockTranslation* bb_translation, llvm::ExtractElementInst* inst) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(inst)); this->mark_variable_mapping(inst, var); // Translate aggregate ar::Value* aggregate = this->translate_value(bb_translation, inst->getVectorOperand(), nullptr); // Translate offset auto index = llvm::dyn_cast< llvm::ConstantInt >(inst->getIndexOperand()); if (index == nullptr) { throw ImportError("unsupported operand to llvm extractelement"); } auto size_type = ar::IntegerType::size_type(this->_bundle); ar::ZNumber element_size( this->_llvm_data_layout .getTypeAllocSize(inst->getVectorOperandType()->getElementType()) .getFixedSize()); ar::ZNumber offset_value = index->getZExtValue() * element_size; auto offset = ar::IntegerConstant::get(this->_context, size_type, ar::MachineInt(offset_value, size_type->bit_width(), size_type->sign())); // Create statement auto stmt = ar::ExtractElement::create(var, aggregate, offset); stmt->set_frontend< llvm::Value >(inst); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_insertelement( BasicBlockTranslation* bb_translation, llvm::InsertElementInst* inst) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(inst)); this->mark_variable_mapping(inst, var); // Translate aggregate ar::Value* aggregate = this->translate_value(bb_translation, inst->getOperand(0), nullptr); // Translate offset auto index = llvm::dyn_cast< llvm::ConstantInt >(inst->getOperand(2)); if (index == nullptr) { throw ImportError("unsupported operand to llvm insertelement"); } auto size_type = ar::IntegerType::size_type(this->_bundle); ar::ZNumber element_size( this->_llvm_data_layout .getTypeAllocSize(inst->getType()->getElementType()) .getFixedSize()); ar::ZNumber offset_value = index->getZExtValue() * element_size; auto offset = ar::IntegerConstant::get(this->_context, size_type, ar::MachineInt(offset_value, size_type->bit_width(), size_type->sign())); // Translate element ar::Value* element = this->translate_value(bb_translation, inst->getOperand(1), nullptr); // Create statement auto stmt = ar::InsertElement::create(var, aggregate, offset, element); stmt->set_frontend< llvm::Value >(inst); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_shufflevector( BasicBlockTranslation* bb_translation, llvm::ShuffleVectorInst* inst) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(inst)); this->mark_variable_mapping(inst, var); // Translate left ar::Value* left = this->translate_value(bb_translation, inst->getOperand(0), var->type()); // Translate right ar::Value* right = this->translate_value(bb_translation, inst->getOperand(1), var->type()); // We do not currently translate the shuffle mask. // Create statement auto stmt = ar::ShuffleVector::create(var, left, right); stmt->set_frontend< llvm::Value >(inst); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_unreachable( BasicBlockTranslation* bb_translation, llvm::UnreachableInst* unreachable) { auto stmt = ar::Unreachable::create(); stmt->set_frontend< llvm::Value >(unreachable); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_landingpad( BasicBlockTranslation* bb_translation, llvm::LandingPadInst* landingpad) { // Translate result variable ar::InternalVariable* var = ar::InternalVariable::create(this->_body, this->infer_type(landingpad)); this->mark_variable_mapping(landingpad, var); // Create statement auto stmt = ar::LandingPad::create(var); stmt->set_frontend< llvm::Value >(landingpad); bb_translation->add_statement(std::move(stmt)); } void FunctionImporter::translate_resume(BasicBlockTranslation* bb_translation, llvm::ResumeInst* resume) { // Translate operand auto operand = ar::cast< ar::InternalVariable >( this->translate_value(bb_translation, resume->getOperand(0), nullptr)); // Create statement auto stmt = ar::Resume::create(operand); stmt->set_frontend< llvm::Value >(resume); bb_translation->add_statement(std::move(stmt)); } ar::Value* FunctionImporter::translate_constant( BasicBlockTranslation* bb_translation, llvm::Constant* cst, ar::Type* type) { return _ctx.constant_imp->translate_constant(cst, type, bb_translation->main); } ar::Value* FunctionImporter::translate_value( BasicBlockTranslation* bb_translation, llvm::Value* value, ar::Type* type) { if (auto cst = llvm::dyn_cast< llvm::Constant >(value)) { return this->translate_constant(bb_translation, cst, type); } else if (llvm::isa< llvm::Instruction >(value) || llvm::isa< llvm::Argument >(value)) { // This value as been translated before auto it = this->_variables.find(value); ikos_assert_msg(it != this->_variables.end(), "value hasn't been translated yet"); ar::Variable* var = it->second; if (type == nullptr || var->type() == type) { return var; } else { // Add a cast from var->type() to type return this->add_bitcast(bb_translation, var, type); } } else if (auto inline_asm = llvm::dyn_cast< llvm::InlineAsm >(value)) { return this->translate_inline_asm(inline_asm, type); } else { throw ImportError("unsupported llvm value [1]"); } } ar::InlineAssemblyConstant* FunctionImporter::translate_inline_asm( llvm::InlineAsm* inline_asm, ar::Type* type) { // If no specific type is needed, just use translate_type(cst->getType()) if (type == nullptr) { type = _ctx.type_imp->translate_type(inline_asm->getType(), ar::Signed); } return ar::InlineAssemblyConstant::get(this->_context, ar::cast< ar::PointerType >(type), inline_asm->getAsmString()); } ar::InternalVariable* FunctionImporter::add_bitcast( BasicBlockTranslation* bb_translation, ar::Variable* var, ar::Type* type) { ikos_assert(type != nullptr); // Create an internal variable containing the result of the cast auto result = ar::InternalVariable::create(this->_body, type); result->set_frontend(*var); return this->add_bitcast(bb_translation, result, var); } ar::InternalVariable* FunctionImporter::add_bitcast( BasicBlockTranslation* bb_translation, ar::InternalVariable* result, ar::Variable* operand) { if (!is_valid_bitcast(operand->type(), result->type())) { throw ImportError("invalid ar bitcast"); } auto stmt = ar::UnaryOperation::create(ar::UnaryOperation::Bitcast, result, operand); if (operand->has_frontend()) { stmt->set_frontend(*operand); } else if (result->has_frontend()) { stmt->set_frontend(*result); } bb_translation->add_statement(std::move(stmt)); return result; } ar::Value* FunctionImporter::translate_cast_integer_value( BasicBlockTranslation* bb_translation, llvm::Value* value, ar::IntegerType* type) { ikos_assert(type != nullptr); if (auto cst = llvm::dyn_cast< llvm::Constant >(value)) { return _ctx.constant_imp->translate_cast_integer_constant(cst, type); } else if (llvm::isa< llvm::Instruction >(value) || llvm::isa< llvm::Argument >(value)) { // This value as been translated before auto it = this->_variables.find(value); ikos_assert_msg(it != this->_variables.end(), "value hasn't been translated yet"); ar::Variable* var = it->second; if (type == nullptr || var->type() == type) { return var; } else { // Add integer casts from var->type() to type return this->add_integer_casts(bb_translation, var, type); } } else { throw ImportError("unsupported llvm value [2]"); } } ar::InternalVariable* FunctionImporter::add_integer_casts( BasicBlockTranslation* bb_translation, ar::Variable* var, ar::IntegerType* type) { ikos_assert(type != nullptr); ar::Value* cur_var = var; auto cur_type = ar::cast< ar::IntegerType >(cur_var->type()); // Truncate or extend if (cur_type->bit_width() != type->bit_width()) { auto res_type = ar::IntegerType::get(this->_context, type->bit_width(), cur_type->sign()); auto res_var = ar::InternalVariable::create(this->_body, res_type); res_var->set_frontend(*var); ar::UnaryOperation::Operator op; if (cur_type->bit_width() < type->bit_width()) { if (cur_type->is_signed()) { op = ar::UnaryOperation::SExt; } else { op = ar::UnaryOperation::ZExt; } } else { if (cur_type->is_signed()) { op = ar::UnaryOperation::STrunc; } else { op = ar::UnaryOperation::UTrunc; } } auto stmt = ar::UnaryOperation::create(op, res_var, cur_var); stmt->set_frontend(*var); bb_translation->add_statement(std::move(stmt)); cur_type = res_type; cur_var = res_var; } // Sign convertion (bitcast) if (cur_type->sign() != type->sign()) { auto res_type = type; auto res_var = ar::InternalVariable::create(this->_body, res_type); res_var->set_frontend(*var); auto stmt = ar::UnaryOperation::create(ar::UnaryOperation::Bitcast, res_var, cur_var); stmt->set_frontend(*var); bb_translation->add_statement(std::move(stmt)); cur_var = res_var; } return ar::cast< ar::InternalVariable >(cur_var); } ar::Type* FunctionImporter::infer_type(llvm::Value* value) { // Use debug information if available if (auto ar_type = this->infer_type_from_dbg(value)) { return ar_type; } // Use heuristics to find a correct type boost::container::flat_map< ar::Type*, unsigned > hints; for (auto it = value->use_begin(), et = value->use_end(); it != et; ++it) { llvm::Use& use = *it; TypeHint hint = this->infer_type_hint_use(use); if (hint.ignore()) { continue; } hints[hint.type] += hint.score; } if (hints.empty()) { // No hints return this->infer_default_type(value); } else { // Find the type with the biggest score auto it = std::max_element(hints.begin(), hints.end(), [](auto& a, auto& b) { return a.second < b.second; }); return it->first; } } ar::Type* FunctionImporter::infer_type_from_dbg(llvm::Value* value) { // Check for llvm.dbg.declare and llvm.dbg.addr if (auto alloca = llvm::dyn_cast< llvm::AllocaInst >(value)) { llvm::TinyPtrVector< llvm::DbgVariableIntrinsic* > dbg_addrs = llvm::FindDbgAddrUses(alloca); auto dbg_addr = std::find_if(dbg_addrs.begin(), dbg_addrs.end(), [](llvm::DbgVariableIntrinsic* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_addr != dbg_addrs.end()) { llvm::DILocalVariable* di_var = (*dbg_addr)->getVariable(); auto di_type = llvm::cast_or_null< llvm::DIType >(di_var->getRawType()); if (!alloca->isArrayAllocation()) { try { ar::Type* pointee = _ctx.type_imp->translate_type(alloca->getAllocatedType(), di_type); return ar::PointerType::get(this->_context, pointee); } catch (const TypeDebugInfoMismatch&) { if (!this->_allow_debug_info_mismatch) { throw; } } } else { try { return _ctx.type_imp->translate_type(alloca->getType(), di_type); } catch (const TypeDebugInfoMismatch&) { if (!this->_allow_debug_info_mismatch) { throw; } } } } } // Check for llvm.dbg.value if (!llvm::isa< llvm::Constant >(value)) { llvm::SmallVector< llvm::DbgValueInst*, 1 > dbg_values; llvm::findDbgValues(dbg_values, value); auto dbg_value = std::find_if(dbg_values.begin(), dbg_values.end(), [](llvm::DbgValueInst* dbg) { return dbg->getExpression()->getNumElements() == 0; }); if (dbg_value != dbg_values.end()) { llvm::DILocalVariable* di_var = (*dbg_value)->getVariable(); auto di_type = llvm::cast_or_null< llvm::DIType >(di_var->getRawType()); try { return _ctx.type_imp->translate_type(value->getType(), di_type); } catch (const TypeDebugInfoMismatch&) { if (!this->_allow_debug_info_mismatch) { throw; } if (auto alloca = llvm::dyn_cast< llvm::AllocaInst >(value)) { try { ar::Type* pointee = _ctx.type_imp->translate_type(alloca->getAllocatedType(), di_type); return ar::PointerType::get(this->_context, pointee); } catch (const TypeDebugInfoMismatch&) { } } } } } return nullptr; } ar::Type* FunctionImporter::infer_default_type(llvm::Value* value) { // No hints were found // Fallback to translate_type() and prefer signed integers ar::Signedness preferred = ar::Signed; if (auto call = llvm::dyn_cast< llvm::CallInst >(value)) { // Use the type of the returned value, if it's a direct call llvm::Value* called = unalias(call->getCalledOperand()); if (auto fun = llvm::dyn_cast< llvm::Function >(called)) { return _ctx.bundle_imp->translate_function(fun)->type()->return_type(); } } else if (auto cast = llvm::dyn_cast< llvm::CastInst >(value)) { preferred = (cast->getOpcode() == llvm::Instruction::ZExt || cast->getOpcode() == llvm::Instruction::FPToUI) ? ar::Unsigned : ar::Signed; } return _ctx.type_imp->translate_type(value->getType(), preferred); } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use( llvm::Use& use) { llvm::Value* user = use.getUser(); if (auto alloca = llvm::dyn_cast< llvm::AllocaInst >(user)) { return this->infer_type_hint_use_alloca(use, alloca); } else if (auto store = llvm::dyn_cast< llvm::StoreInst >(user)) { return this->infer_type_hint_use_store(use, store); } else if (auto load = llvm::dyn_cast< llvm::LoadInst >(user)) { return this->infer_type_hint_use_load(use, load); } else if (auto call = llvm::dyn_cast< llvm::CallInst >(user)) { return this->infer_type_hint_use_call(use, call); } else if (auto invoke = llvm::dyn_cast< llvm::InvokeInst >(user)) { return this->infer_type_hint_use_invoke(use, invoke); } else if (auto cast = llvm::dyn_cast< llvm::CastInst >(user)) { return this->infer_type_hint_use_cast(use, cast); } else if (auto gep = llvm::dyn_cast< llvm::GetElementPtrInst >(user)) { return this->infer_type_hint_use_getelementptr(use, gep); } else if (auto binary_op = llvm::dyn_cast< llvm::BinaryOperator >(user)) { return this->infer_type_hint_use_binary_operator(use, binary_op); } else if (auto cmp = llvm::dyn_cast< llvm::CmpInst >(user)) { return this->infer_type_hint_use_cmp(use, cmp); } else if (auto br = llvm::dyn_cast< llvm::BranchInst >(user)) { return this->infer_type_hint_use_branch(use, br); } else if (auto ret = llvm::dyn_cast< llvm::ReturnInst >(user)) { return this->infer_type_hint_use_return(use, ret); } else if (auto phi = llvm::dyn_cast< llvm::PHINode >(user)) { return this->infer_type_hint_use_phi(use, phi); } else if (llvm::isa< llvm::ExtractValueInst >(user)) { return {}; // no hint } else if (llvm::isa< llvm::InsertValueInst >(user)) { return {}; // no hint } else if (llvm::isa< llvm::ExtractElementInst >(user)) { return {}; // no hint } else if (llvm::isa< llvm::InsertElementInst >(user)) { return {}; // no hint } else if (llvm::isa< llvm::ShuffleVectorInst >(user)) { return {}; // no hint } else if (llvm::isa< llvm::ResumeInst >(user)) { return {}; // no hint } else if (llvm::isa< llvm::SelectInst >(user)) { // The preprocessor should use the -lower-select pass throw ImportError("llvm select instructions are not supported"); } else if (llvm::isa< llvm::SwitchInst >(user)) { // The preprocessor should use the -lowerswitch pass throw ImportError("llvm switch instructions are not supported"); } else if (auto inst = llvm::dyn_cast< llvm::Instruction >(user)) { std::ostringstream buf; buf << "unsupported llvm instruction " << inst->getOpcodeName() << " [2]"; throw ImportError(buf.str()); } else { throw ImportError("unsupported llvm user"); } } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_alloca( llvm::Use& use, llvm::AllocaInst* alloca) { // Alloca array size has to be unsigned ikos_assert(use.getOperandNo() == 0); ikos_ignore(use); llvm::Type* llvm_type = alloca->getArraySize()->getType(); ar::Type* ar_type = _ctx.type_imp->translate_type(llvm_type, ar::Unsigned); return {ar_type, 5}; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_store( llvm::Use& use, llvm::StoreInst* store) { if (use.getOperandNo() == 0) { // value is the stored value TypeHint hint = this->infer_type_hint_operand(store->getPointerOperand()); if (!hint.ignore()) { hint.type = ar::cast< ar::PointerType >(hint.type)->pointee(); } return hint; } else if (use.getOperandNo() == 1) { // value is the pointer operand TypeHint hint = this->infer_type_hint_operand(store->getValueOperand()); if (!hint.ignore()) { hint.type = ar::PointerType::get(this->_context, hint.type); } return hint; } else { throw ImportError("unexpected operand to llvm store"); } } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_load( llvm::Use& /*use*/, llvm::LoadInst* load) { // value is the pointer operand TypeHint hint = this->infer_type_hint_operand(load); if (!hint.ignore()) { hint.type = ar::PointerType::get(this->_context, hint.type); } return hint; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_call( llvm::Use& use, llvm::CallInst* call) { return this->infer_type_hint_use_call_helper(use, call); } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_invoke( llvm::Use& use, llvm::InvokeInst* invoke) { return this->infer_type_hint_use_call_helper(use, invoke); } template < typename CallInstType > FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_call_helper( llvm::Use& use, CallInstType* call) { if (use.getOperandNo() >= call->arg_size()) { // Called function pointer return {}; } llvm::Function* called = call->getCalledFunction(); if (called) { // Direct call ar::Function* ar_fun = _ctx.bundle_imp->translate_function(called); if (ar_fun == nullptr) { // Ignored intrinsic call (such as dbg.declare) return {}; } if (ar_fun->is_var_arg() && use.getOperandNo() >= ar_fun->num_parameters()) { // Variable argument, ignore return {}; } ar::Type* ar_type = ar_fun->type()->param_type(use.getOperandNo()); // Compute a score llvm::DISubprogram* dbg = called->getSubprogram(); unsigned score = (dbg == nullptr) ? 10 : 1000; return {ar_type, score}; } // Indirect call return {}; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_cast( llvm::Use& /*use*/, llvm::CastInst* cast) { ar::Signedness sign = ar::Signed; switch (cast->getOpcode()) { case llvm::Instruction::Trunc: { return {}; // no hint } case llvm::Instruction::ZExt: { sign = ar::Unsigned; } break; case llvm::Instruction::SExt: { sign = ar::Signed; } break; case llvm::Instruction::FPToUI: case llvm::Instruction::FPToSI: { return {}; // no hint } case llvm::Instruction::UIToFP: { sign = ar::Unsigned; } break; case llvm::Instruction::SIToFP: { sign = ar::Signed; } break; case llvm::Instruction::FPTrunc: case llvm::Instruction::FPExt: case llvm::Instruction::PtrToInt: { return {}; // no hint } case llvm::Instruction::IntToPtr: { sign = ar::Unsigned; } break; case llvm::Instruction::BitCast: { return {}; // no hint } default: { std::ostringstream buf; buf << "unsupported llvm cast: " << cast->getOpcodeName() << " [3]"; throw ImportError(buf.str()); } } ar::Type* type = _ctx.type_imp->translate_type(cast->getSrcTy(), sign); return {type, 5}; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_getelementptr( llvm::Use& /*use*/, llvm::GetElementPtrInst* /*gep*/) { // GetElementPtr does not add any restriction on its operand // The first operand can be a pointer on any type // The other operands can be integers of any signedness and bit-width return {}; } FunctionImporter::TypeHint FunctionImporter:: infer_type_hint_use_binary_operator(llvm::Use& use, llvm::BinaryOperator* inst) { ar::Signedness sign = ar::Signed; unsigned score = 5; switch (inst->getOpcode()) { case llvm::Instruction::Add: case llvm::Instruction::Sub: case llvm::Instruction::Mul: { sign = sign_from_wraps(inst); } break; case llvm::Instruction::UDiv: case llvm::Instruction::URem: { sign = ar::Unsigned; } break; case llvm::Instruction::SDiv: case llvm::Instruction::SRem: { sign = ar::Signed; } break; case llvm::Instruction::Shl: { return {}; // no hint } case llvm::Instruction::LShr: { if (use.getOperandNo() == 0) { sign = ar::Unsigned; } else { return {}; // no hint } } break; case llvm::Instruction::AShr: { if (use.getOperandNo() == 0) { sign = ar::Signed; } else { return {}; // no hint } } break; case llvm::Instruction::And: case llvm::Instruction::Or: case llvm::Instruction::Xor: { // prefer unsigned types for bitwise operators sign = ar::Unsigned; score = 1; } break; case llvm::Instruction::FRem: case llvm::Instruction::FAdd: case llvm::Instruction::FSub: case llvm::Instruction::FMul: case llvm::Instruction::FDiv: { return {}; // no hint, sign is irrelevant } default: { std::ostringstream buf; buf << "unsupported llvm binary operator: " << inst->getOpcodeName() << " [6]"; throw ImportError(buf.str()); } } llvm::Type* llvm_type = inst->getOperand(use.getOperandNo())->getType(); ar::Type* ar_type = _ctx.type_imp->translate_type(llvm_type, sign); return {ar_type, score}; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_cmp( llvm::Use& use, llvm::CmpInst* cmp) { llvm::Type* llvm_type = cmp->getOperand(use.getOperandNo())->getType(); if (cmp->isIntPredicate() && llvm_type->isIntegerTy()) { // Integer comparison if (cmp->isSigned()) { ar::Type* ar_type = _ctx.type_imp->translate_type(llvm_type, ar::Signed); return {ar_type, 5}; } else if (cmp->isUnsigned()) { ar::Type* ar_type = _ctx.type_imp->translate_type(llvm_type, ar::Unsigned); return {ar_type, 5}; } else { // Use the other operand type as a hint TypeHint hint = this->infer_type_hint_operand( cmp->getOperand(1 - use.getOperandNo())); hint.set_score(2); return hint; } } else if (cmp->isIntPredicate() && llvm_type->isPointerTy()) { // Pointer comparison // Use the other operand type as a hint TypeHint hint = this->infer_type_hint_operand(cmp->getOperand(1 - use.getOperandNo())); hint.set_score(2); return hint; } else if (cmp->isFPPredicate()) { return {}; // no hint } else { std::ostringstream buf; buf << "unsupported llvm cmp instruction with predicate: " << llvm::CmpInst::getPredicateName(cmp->getPredicate()).str() << " [2]"; throw ImportError(buf.str()); } } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_branch( llvm::Use& use, llvm::BranchInst* br) { // Condition operand ikos_assert(br->isConditional()); ikos_ignore(use); ikos_assert(use.getOperandNo() == 0); llvm::Value* cond = br->getCondition(); // Prefer unsigned ar::Type* type = _ctx.type_imp->translate_type(cond->getType(), ar::Unsigned); return {type, 2}; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_return( llvm::Use& /*use*/, llvm::ReturnInst* /*ret*/) { return {this->_ar_fun->type()->return_type(), 5}; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_use_phi( llvm::Use& /*use*/, llvm::PHINode* phi) { return this->infer_type_hint_operand(phi); } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_operand( llvm::Value* value) { // Use debug information if available if (auto ar_type = this->infer_type_from_dbg(value)) { return {ar_type, 1000}; } if (auto gv = llvm::dyn_cast< llvm::GlobalVariable >(value)) { return this->infer_type_hint_operand_global_variable(gv); } else if (auto gv_alias = llvm::dyn_cast< llvm::GlobalAlias >(value)) { return this->infer_type_hint_operand(gv_alias->getAliasee()); } else if (auto fun = llvm::dyn_cast< llvm::Function >(value)) { return this->infer_type_hint_operand_function(fun); } else if (auto inst = llvm::dyn_cast< llvm::Instruction >(value)) { return this->infer_type_hint_operand_instruction(inst); } else if (auto arg = llvm::dyn_cast< llvm::Argument >(value)) { return this->infer_type_hint_operand_argument(arg); } else if (llvm::isa< llvm::Constant >(value)) { // Cannot deduce sign information from constants return {}; } else { throw ImportError("unsupported llvm value [3]"); } } FunctionImporter::TypeHint FunctionImporter:: infer_type_hint_operand_global_variable(llvm::GlobalVariable* gv) { // Return the ar::GlobalVariable type ar::GlobalVariable* ar_gv = _ctx.bundle_imp->translate_global_variable(gv); // Compute a score llvm::SmallVector< llvm::DIGlobalVariableExpression*, 1 > dbgs; gv->getDebugInfo(dbgs); unsigned score = dbgs.empty() ? 10 : 1000; return {ar_gv->type(), score}; } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_operand_function( llvm::Function* fun) { // Return the pointer on the ar::Function type ar::Function* ar_fun = _ctx.bundle_imp->translate_function(fun); ikos_assert(ar_fun != nullptr); ar::Type* ar_type = ar::PointerType::get(this->_context, ar_fun->type()); // Compute a score llvm::DISubprogram* dbg = fun->getSubprogram(); unsigned score = (dbg == nullptr) ? 10 : 1000; return {ar_type, score}; } FunctionImporter::TypeHint FunctionImporter:: infer_type_hint_operand_instruction(llvm::Instruction* inst) { // If already translated, use it as a hint auto it = this->_variables.find(inst); if (it != this->_variables.end()) { return {it->second->type(), 2}; } // Use the type of the returned value, if it's a direct call if (auto call = llvm::dyn_cast< llvm::CallInst >(inst)) { llvm::Value* called = unalias(call->getCalledOperand()); if (auto fun = llvm::dyn_cast< llvm::Function >(called)) { return {_ctx.bundle_imp->translate_function(fun)->type()->return_type(), 5}; } } // Using this->infer_type() here would cause an infinite recursion. return {}; // no hint } FunctionImporter::TypeHint FunctionImporter::infer_type_hint_operand_argument( llvm::Argument* arg) { // Return the type of the ar::InternalVariable auto ar_arg = ar::cast< ar::InternalVariable >(this->_variables.find(arg)->second); // Compute a score llvm::DISubprogram* dbg = this->_llvm_fun->getSubprogram(); unsigned score = (dbg == nullptr) ? 10 : 1000; return {ar_arg->type(), score}; } BasicBlockTranslation::BasicBlockTranslation(llvm::BasicBlock* source_, ar::BasicBlock* main_) : source(source_), main(main_), outputs{BasicBlockOutput(main)} {} ar::BasicBlock* BasicBlockTranslation::input_basic_block( llvm::BasicBlock* llvm_bb) { auto it = this->inputs.find(llvm_bb); if (it != this->inputs.end()) { return it->second; } // Create basic block ar::BasicBlock* ar_bb = ar::BasicBlock::create(this->main->code()); // Add edge ar_bb->add_successor(this->main); // Add in the input list this->inputs.emplace(llvm_bb, ar_bb); return ar_bb; } ar::BasicBlock* BasicBlockTranslation::add_output_basic_block( ar::BasicBlock* ar_src, llvm::BasicBlock* llvm_dest) { // Create basic block ar::BasicBlock* ar_dest = ar::BasicBlock::create(ar_src->code()); // Add edge ar_src->add_successor(ar_dest); // Add in the output list this->outputs.emplace_back(BasicBlockOutput(ar_dest, llvm_dest)); return ar_dest; } void BasicBlockTranslation::merge_outputs() { if (this->outputs.size() < 2) { return; } ar::BasicBlock* dest = ar::BasicBlock::create(this->main->code()); for (auto it = this->outputs.begin(), et = this->outputs.end(); it != et; ++it) { ar::BasicBlock* bb = it->block; ikos_assert(it->succ == nullptr); this->internals.push_back(bb); bb->add_successor(dest); } this->outputs.clear(); this->outputs.emplace_back(BasicBlockOutput(dest)); } void BasicBlockTranslation::add_statement( std::unique_ptr< ar::Statement > stmt) { if (this->outputs.size() == 1) { // Move the statement in the only output ar::BasicBlock* bb = this->outputs[0].block; bb->push_back(std::move(stmt)); } else { // Copy the statement in all the outputs for (const auto& output : this->outputs) { output.block->push_back(stmt->clone()); } } } void BasicBlockTranslation::add_comparison( ar::InternalVariable* var, std::unique_ptr< ar::Comparison > cmp) { // TODO(marthaud): Add an option that merges the outputs if outputs.size() > 1 if (this->outputs.size() == 1) { ar::BasicBlock* bb = this->outputs[0].block; this->internals.push_back(bb); this->outputs.clear(); ar::Comparison* cmp_ptr = cmp.get(); this->add_comparison_output_bb(bb, std::move(cmp), var, true); this->add_comparison_output_bb(bb, cmp_ptr->inverse(), var, false); } else { std::vector< BasicBlockOutput > prev_outputs; std::swap(prev_outputs, this->outputs); this->outputs.reserve(prev_outputs.size()); for (const auto& output : prev_outputs) { ar::BasicBlock* bb = output.block; this->internals.push_back(bb); this->add_comparison_output_bb(bb, cmp->clone(), var, true); this->add_comparison_output_bb(bb, cmp->inverse(), var, false); } } } /// \brief Create an ar::Assignment `var = value` static std::unique_ptr< ar::Assignment > create_bool_assignment( ar::Context& ctx, ar::InternalVariable* var, bool value) { auto type = ar::cast< ar::IntegerType >(var->type()); ikos_assert_msg(type->bit_width() == 1, "invalid bit-width for boolean"); ar::IntegerConstant* cst = ar::IntegerConstant::get(ctx, type, value ? 1 : 0); return ar::Assignment::create(var, cst); } void BasicBlockTranslation::add_comparison_output_bb( ar::BasicBlock* src, std::unique_ptr< ar::Statement > cmp, ar::InternalVariable* var, bool value) { auto frontend = cmp->frontend< llvm::Value >(); // Create output basic block ar::BasicBlock* dest = this->add_output_basic_block(src); // Push comparison dest->push_back(std::move(cmp)); // Push assignment std::unique_ptr< ar::Assignment > assign = create_bool_assignment(src->context(), var, value); assign->set_frontend(frontend); dest->push_back(std::move(assign)); } void BasicBlockTranslation::add_unconditional_branching( llvm::BranchInst* /*br*/, llvm::BasicBlock* succ) { for (auto& output : this->outputs) { output.succ = succ; } } void BasicBlockTranslation::add_conditional_branching( llvm::BranchInst* br, ar::InternalVariable* cond) { llvm::BasicBlock* true_succ = br->getSuccessor(0); llvm::BasicBlock* false_succ = br->getSuccessor(1); // Check if the condition variable is the result of a CmpInst bool has_assign_preds = std::all_of(this->outputs.begin(), this->outputs.end(), [=](const BasicBlockOutput& output) { ar::BasicBlock* bb = output.block; return !bb->empty() && ar::isa< ar::Assignment >(bb->back()) && ar::cast< ar::Assignment >(bb->back())->result() == cond && ar::isa< ar::IntegerConstant >( ar::cast< ar::Assignment >(bb->back()) ->operand()); }); if (has_assign_preds) { // In this case, just set the successor accordingly // Remove assignment if the variable is only used for the branching // statement llvm::Value* llvm_condition = br->getCondition(); bool remove_assign = llvm_condition->hasOneUse() && *llvm_condition->user_begin() == br; for (auto& output : this->outputs) { ar::BasicBlock* bb = output.block; auto assign = ar::cast< ar::Assignment >(bb->back()); auto cst = ar::cast< ar::IntegerConstant >(assign->operand()); if (cst->value() == 0) { output.succ = false_succ; } else { output.succ = true_succ; } if (remove_assign) { bb->pop_back(); } } } else { // Otherwise, add comparisons std::vector< BasicBlockOutput > prev_outputs; std::swap(prev_outputs, this->outputs); this->outputs.reserve(2 * prev_outputs.size()); for (const auto& output : prev_outputs) { ar::BasicBlock* bb = output.block; this->internals.push_back(bb); this->add_conditional_output_bb(br, bb, true_succ, cond, true); this->add_conditional_output_bb(br, bb, false_succ, cond, false); } } } void BasicBlockTranslation::add_nondeterministic_branching( llvm::BranchInst* br) { std::vector< BasicBlockOutput > prev_outputs; std::swap(prev_outputs, this->outputs); this->outputs.reserve(2 * prev_outputs.size()); for (const auto& output : prev_outputs) { ar::BasicBlock* bb = output.block; this->internals.push_back(bb); this->add_output_basic_block(bb, br->getSuccessor(0)); this->add_output_basic_block(bb, br->getSuccessor(1)); } } /// \brief Create an ar::Comparison `var == value` static std::unique_ptr< ar::Comparison > create_bool_cmp( ar::Context& ctx, ar::InternalVariable* var, bool value) { auto type = ar::cast< ar::IntegerType >(var->type()); ikos_assert_msg(type->bit_width() == 1, "invalid bit-width for boolean"); ar::IntegerConstant* cst = ar::IntegerConstant::get(ctx, type, value ? 1 : 0); return ar::Comparison::create(type->is_signed() ? ar::Comparison::SIEQ : ar::Comparison::UIEQ, var, cst); } void BasicBlockTranslation::add_conditional_output_bb( llvm::BranchInst* br, ar::BasicBlock* src, llvm::BasicBlock* llvm_dest, ar::InternalVariable* cond, bool value) { // Create output basic block ar::BasicBlock* ar_dest = this->add_output_basic_block(src, llvm_dest); // Push comparison std::unique_ptr< ar::Comparison > cmp = create_bool_cmp(src->context(), cond, value); cmp->set_frontend< llvm::Value >(br); ar_dest->push_back(std::move(cmp)); } void BasicBlockTranslation::add_invoke_branching( llvm::BasicBlock* normal_dest, llvm::BasicBlock* exception_dest) { if (this->outputs.size() == 1) { ar::BasicBlock* bb = this->outputs[0].block; this->internals.push_back(bb); this->outputs.clear(); auto invoke = ar::cast< ar::Invoke >(bb->back()); this->add_invoke_normal_output_bb(bb, invoke, normal_dest); this->add_invoke_exception_output_bb(bb, invoke, exception_dest); } else { std::vector< BasicBlockOutput > prev_outputs; std::swap(prev_outputs, this->outputs); this->outputs.reserve(2 * prev_outputs.size()); for (const auto& output : prev_outputs) { ar::BasicBlock* bb = output.block; this->internals.push_back(bb); auto invoke = ar::cast< ar::Invoke >(bb->back()); this->add_invoke_normal_output_bb(bb, invoke, normal_dest); this->add_invoke_exception_output_bb(bb, invoke, exception_dest); } } } void BasicBlockTranslation::add_invoke_normal_output_bb( ar::BasicBlock* src, ar::Invoke* invoke, llvm::BasicBlock* llvm_dest) { // Create output basic block ar::BasicBlock* ar_dest = this->add_output_basic_block(src, llvm_dest); // Set invoke normal destination invoke->set_normal_dest(ar_dest); } void BasicBlockTranslation::add_invoke_exception_output_bb( ar::BasicBlock* src, ar::Invoke* invoke, llvm::BasicBlock* llvm_dest) { // Create output basic block ar::BasicBlock* ar_dest = this->add_output_basic_block(src, llvm_dest); // Set invoke exception destination invoke->set_exception_dest(ar_dest); } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/function.hpp000066400000000000000000000475071473507761200240630ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM functions into AR functions * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include "import_context.hpp" namespace ikos { namespace frontend { namespace import { /// \brief Represents the output of a llvm::BasicBlock struct BasicBlockOutput { /// \brief AR basic block ar::BasicBlock* block; /// \brief LLVM successor llvm::BasicBlock* succ; /// \brief Constructor explicit BasicBlockOutput(ar::BasicBlock* block_) : block(block_), succ(nullptr) {} /// \brief Constructor BasicBlockOutput(ar::BasicBlock* block_, llvm::BasicBlock* succ_) : block(block_), succ(succ_) {} }; // end struct BasicBlockOutput /// \brief Represents the translation of a llvm::BasicBlock struct BasicBlockTranslation { /// \brief LLVM basic block corresponding to this BasicBlockTranslation llvm::BasicBlock* source; /// \brief AR main basic block /// /// This basic block represents the llvm::BasicBlock in AR. /// /// Either it is the first basic block, or it is the successor of all the /// input basic blocks. ar::BasicBlock* main; /// \brief Map from LLVM predecessors to AR basic block /// /// This is only necessary to translate PHI nodes. /// /// These should be linked (set the predecessor) at the end of the /// translation. boost::container::flat_map< llvm::BasicBlock*, ar::BasicBlock* > inputs; /// \brief Internal basic blocks /// /// These are already linked (predecessors/successors) correctly. /// /// This list should be topologically ordered. std::vector< ar::BasicBlock* > internals; /// \brief Output basic blocks /// /// These should be linked (set the successor) at the end of the translation /// /// There is no specific order in this list. /// /// This should never be empty. std::vector< BasicBlockOutput > outputs; /// \brief Constructor BasicBlockTranslation(llvm::BasicBlock* source_, ar::BasicBlock* main_); /// \brief Get or create an input basic block for the given llvm BasicBlock ar::BasicBlock* input_basic_block(llvm::BasicBlock* bb); /// \brief Create an output basic block ar::BasicBlock* add_output_basic_block(ar::BasicBlock* ar_src, llvm::BasicBlock* llvm_dest = nullptr); /// \brief Merge all output basic blocks into one basic block void merge_outputs(); /// \brief Add a statement in the basic block void add_statement(std::unique_ptr< ar::Statement > stmt); /// \brief Add a llvm::CmpInst translated into a variable and a comparison void add_comparison(ar::InternalVariable* var, std::unique_ptr< ar::Comparison > cmp); private: /// \brief Add a new basic block with statements: cmp; var = value; void add_comparison_output_bb(ar::BasicBlock* src, std::unique_ptr< ar::Statement > cmp, ar::InternalVariable* var, bool value); public: /// \brief Add an unconditional branching void add_unconditional_branching(llvm::BranchInst* br, llvm::BasicBlock* succ); /// \brief Add a conditional branching void add_conditional_branching(llvm::BranchInst* br, ar::InternalVariable* cond); /// \brief Add a non-deterministic branching void add_nondeterministic_branching(llvm::BranchInst* br); private: /// \brief Add an output basic block with a "cond == value" statement void add_conditional_output_bb(llvm::BranchInst* br, ar::BasicBlock* src, llvm::BasicBlock* llvm_dest, ar::InternalVariable* cond, bool value); public: /// \brief Add an invoke branching void add_invoke_branching(llvm::BasicBlock* normal_dest, llvm::BasicBlock* exception_dest); private: /// \brief Add an output basic block for an invoke statement void add_invoke_normal_output_bb(ar::BasicBlock* src, ar::Invoke* invoke, llvm::BasicBlock* normal_dest); /// \brief Add an output basic block for an invoke statement void add_invoke_exception_output_bb(ar::BasicBlock* src, ar::Invoke* invoke, llvm::BasicBlock* exception_dest); }; // end struct BasicBlockTranslation /// \brief Helper class to translate the body of a function class FunctionImporter { private: // Import context ImportContext& _ctx; // AR context ar::Context& _context; // AR bundle ar::Bundle* _bundle; // LLVM data layout const llvm::DataLayout& _llvm_data_layout; // LLVM function llvm::Function* _llvm_fun; // AR function ar::Function* _ar_fun; // AR body ar::Code* _body; // Map from LLVM Value to AR Variable llvm::DenseMap< llvm::Value*, ar::Variable* > _variables; // Map from LLVM BasicBlock to BasicBlockTranslation llvm::DenseMap< llvm::BasicBlock*, std::unique_ptr< BasicBlockTranslation > > _blocks; // Allow mismatch of LLVM types (llvm::Type) and Debug Info types // (llvm::DIType) // // See `Importer::ImportOption`. bool _allow_debug_info_mismatch; public: /// \brief Public constructor FunctionImporter(ImportContext& ctx, llvm::Function* llvm_fun, ar::Function* ar_fun) : _ctx(ctx), _context(ctx.ar_context), _bundle(ctx.bundle), _llvm_data_layout(ctx.llvm_data_layout), _llvm_fun(llvm_fun), _ar_fun(ar_fun), _body(ar_fun->body()), _allow_debug_info_mismatch( ctx.opts.test(Importer::AllowMismatchDebugInfo)) {} /// \brief Translate the body of the function ar::Code* translate_body(); private: /// \brief Store the mapping between a llvm::Value and an ar::Variable /// /// It also assigns a nice name to the ar::Variable and set the frontend /// object using ar::Variable::set_frontend. void mark_variable_mapping(llvm::Value*, ar::Variable*); /// \brief Translate LLVM parameters into ar::InternalVariable void translate_parameters(); /// \brief Translate control flow graph /// /// This calls: /// * translate_basic_blocks() /// * translate_phi_nodes() /// * link_basic_blocks() void translate_control_flow_graph(); /// \brief Translate all basic blocks void translate_basic_blocks(); /// \brief Translate a llvm::BasicBlock void translate_basic_block(llvm::BasicBlock* bb); /// \brief Translate all phi nodes once basic blocks are translated void translate_phi_nodes(); /// \brief Translate all phi nodes in `bb` once basic blocks are translated void translate_phi_nodes(BasicBlockTranslation* bb_translation, llvm::BasicBlock* bb); /// \brief Link all basic blocks void link_basic_blocks(); /// \brief Link the given basic block void link_basic_block(BasicBlockTranslation* bb_translation); /// \brief Unify the exit blocks void unify_exit_blocks(); /// \brief Translate a llvm::Instruction void translate_instruction(BasicBlockTranslation* bb_translation, llvm::Instruction* inst); /// \brief Translate a llvm::AllocaInst void translate_alloca(BasicBlockTranslation* bb_translation, llvm::AllocaInst* alloca); /// \brief Translate a llvm::StoreInst void translate_store(BasicBlockTranslation* bb_translation, llvm::StoreInst* store); /// \brief Translate a llvm::LoadInst void translate_load(BasicBlockTranslation* bb_translation, llvm::LoadInst* load); /// \brief Translate a llvm::CallInst void translate_call(BasicBlockTranslation* bb_translation, llvm::CallInst* call); /// \brief Translate a llvm::IntrinsicInst void translate_intrinsic_call(BasicBlockTranslation* bb_translation, llvm::IntrinsicInst* call); /// \brief Translate a llvm::InvokeInst void translate_invoke(BasicBlockTranslation* bb_translation, llvm::InvokeInst* invoke); /// \brief Translate a llvm::CallInst or llvm::InvokeInst template < typename CallInstType, typename CreateStmtFun > void translate_call_helper(BasicBlockTranslation* bb_translation, CallInstType* call, bool force_return_cast, bool force_args_cast, CreateStmtFun create_stmt); /// \brief Translate a llvm::BitCastInst void translate_bitcast(BasicBlockTranslation* bb_translation, llvm::BitCastInst* bitcast); /// \brief Translate a llvm::CastInst void translate_cast(BasicBlockTranslation* bb_translation, llvm::CastInst* cast); /// \brief Translate a llvm::GetElementPtrInst void translate_getelementptr(BasicBlockTranslation* bb_translation, llvm::GetElementPtrInst* gep); /// \brief Translate a llvm::BinaryOperator void translate_binary_operator(BasicBlockTranslation* bb_translation, llvm::BinaryOperator* inst); /// \brief Translate a llvm::CmpInst void translate_cmp(BasicBlockTranslation* bb_translation, llvm::CmpInst* cmp); /// \brief Translate a llvm::BranchInst void translate_branch(BasicBlockTranslation* bb_translation, llvm::BranchInst* br); /// \brief Translate a llvm::ReturnInst void translate_return(BasicBlockTranslation* bb_translation, llvm::ReturnInst* ret); /// \brief Translate a llvm::PHINode /// /// This is called during the basic blocks translation, so not all /// basic blocks are translated yet. void translate_phi(BasicBlockTranslation* bb_translation, llvm::PHINode* phi); /// \brief Translate a llvm::PHINode /// /// This is called once every basic block has been translated. void translate_phi_late(BasicBlockTranslation* bb_translation, llvm::PHINode* phi); /// \brief Translate a llvm::ExtractValueInst void translate_extractvalue(BasicBlockTranslation* bb_translation, llvm::ExtractValueInst* inst); /// \brief Translate a llvm::InsertValueInst void translate_insertvalue(BasicBlockTranslation* bb_translation, llvm::InsertValueInst* inst); /// \brief Translate and indexed type and a list of index into an offset ar::IntegerConstant* translate_indexes( llvm::Type* indexed_type, llvm::ExtractValueInst::idx_iterator begin, llvm::ExtractValueInst::idx_iterator end); /// \brief Translate a llvm::ExtractElementInst void translate_extractelement(BasicBlockTranslation* bb_translation, llvm::ExtractElementInst* inst); /// \brief Translate a llvm::InsertElementInst void translate_insertelement(BasicBlockTranslation* bb_translation, llvm::InsertElementInst* inst); /// \brief Translate a llvm::ShuffleVectorInst void translate_shufflevector(BasicBlockTranslation* bb_translation, llvm::ShuffleVectorInst* inst); /// \brief Translate a llvm::UnreachableInst void translate_unreachable(BasicBlockTranslation* bb_translation, llvm::UnreachableInst* unreachable); /// \brief Translate a llvm::LandingPadInst void translate_landingpad(BasicBlockTranslation* bb_translation, llvm::LandingPadInst* landingpad); /// \brief Translate a llvm::ResumeInst void translate_resume(BasicBlockTranslation* bb_translation, llvm::ResumeInst* resume); /// \brief Translate a llvm::Constant into an ar::Value /// /// This will add statements in the main basic block if the llvm::Constant /// contains constant expressions, or if a bitcast is required. /// /// Note: If non-null, the `type` parameter should be compatible with the /// constant: `TypeImporter::match_ar_type(cst->getType(), type)` should be /// true. /// /// \param bb_translation The current basic block translation /// \param cst The constant to translate /// \param type The required ar::Type, or null if no specific type is needed ar::Value* translate_constant(BasicBlockTranslation* bb_translation, llvm::Constant* cst, ar::Type* type); /// \brief Translate a llvm::Value into an ar::Value /// /// This will add a statement in the basic block if a bitcast is required. /// /// Note: If non-null, the `type` parameter should be compatible with the /// value: `TypeImporter::match_ar_type(value->getType(), type)` should be /// true. /// /// \param bb_translation The current basic block translation /// \param value The value to translate /// \param type The required ar::Type, or null if no specific type is needed ar::Value* translate_value(BasicBlockTranslation* bb_translation, llvm::Value* value, ar::Type* type); /// \brief Translate a llvm::InlineAsm into an ar::InlineAssemblyConstant ar::InlineAssemblyConstant* translate_inline_asm(llvm::InlineAsm* inline_asm, ar::Type* type); /// \brief Add a bitcast from var->type() to type ar::InternalVariable* add_bitcast(BasicBlockTranslation* bb_translation, ar::Variable* var, ar::Type* type); /// \brief Add a bitcast from operand to result ar::InternalVariable* add_bitcast(BasicBlockTranslation* bb_translation, ar::InternalVariable* result, ar::Variable* operand); /// \brief Translate an integer llvm::Value into an ar::Value and cast it to /// the given ar::IntegerType /// /// This will add statements in the main basic block if casts are required. /// /// \param bb_translation The current basic block translation /// \param value The value to translate /// \param type The required ar::IntegerType ar::Value* translate_cast_integer_value(BasicBlockTranslation* bb_translation, llvm::Value* value, ar::IntegerType* type); /// \brief Add integer casts (trunc/ext/sign_cast) from var->type() to type ar::InternalVariable* add_integer_casts(BasicBlockTranslation* bb_translation, ar::Variable* var, ar::IntegerType* type); /* * Implementation of a heuristic algorithm to infer the type (with sign * information) of a llvm::Value */ /// \brief Try to infer the correct type for the given `value` w.r.t the /// signedness ar::Type* infer_type(llvm::Value*); /// \brief Try to infer the correct type for the given `value` using llvm /// debug info /// /// Returns nullptr if the type could not be deduced ar::Type* infer_type_from_dbg(llvm::Value*); /// \brief Infer a default type, if no hints were found ar::Type* infer_default_type(llvm::Value*); /// \brief Hint for a type struct TypeHint { /// \brief The type ar::Type* type = nullptr; /// \brief The score corresponds to the reliability of the hint. /// A big number means the hint is very reliable. /// 0 means the hint should be ignored. unsigned score = 0; /// \brief Constructor TypeHint() = default; /// \brief Constructor TypeHint(ar::Type* type_, unsigned score_) : type(type_), score(score_) {} /// \brief Is it an empty hint? bool ignore() const { return this->score == 0; } /// \brief Update the score void set_score(unsigned new_score) { if (this->type != nullptr) { this->score = new_score; } } }; /* * Get a hint about the type of a llvm::Value using one of its user */ TypeHint infer_type_hint_use(llvm::Use&); TypeHint infer_type_hint_use_alloca(llvm::Use&, llvm::AllocaInst* alloca); TypeHint infer_type_hint_use_store(llvm::Use&, llvm::StoreInst* store); TypeHint infer_type_hint_use_load(llvm::Use&, llvm::LoadInst* load); TypeHint infer_type_hint_use_call(llvm::Use&, llvm::CallInst* call); TypeHint infer_type_hint_use_invoke(llvm::Use&, llvm::InvokeInst* invoke); template < typename CallInstType > TypeHint infer_type_hint_use_call_helper(llvm::Use&, CallInstType* call); TypeHint infer_type_hint_use_cast(llvm::Use&, llvm::CastInst* cast); TypeHint infer_type_hint_use_getelementptr(llvm::Use&, llvm::GetElementPtrInst* gep); TypeHint infer_type_hint_use_binary_operator(llvm::Use&, llvm::BinaryOperator* inst); TypeHint infer_type_hint_use_cmp(llvm::Use&, llvm::CmpInst* cmp); TypeHint infer_type_hint_use_branch(llvm::Use&, llvm::BranchInst* br); TypeHint infer_type_hint_use_return(llvm::Use&, llvm::ReturnInst* ret); TypeHint infer_type_hint_use_phi(llvm::Use&, llvm::PHINode* phi); /* * Get a hint about the type of an operand of a llvm::Instruction */ TypeHint infer_type_hint_operand(llvm::Value*); TypeHint infer_type_hint_operand_global_variable(llvm::GlobalVariable* gv); TypeHint infer_type_hint_operand_function(llvm::Function* fun); TypeHint infer_type_hint_operand_instruction(llvm::Instruction* inst); TypeHint infer_type_hint_operand_argument(llvm::Argument* arg); }; // end class FunctionImporter } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/import_context.hpp000066400000000000000000000110421473507761200252750ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Define the ImportContext * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include namespace ikos { namespace frontend { namespace import { // forward declarations class TypeImporter; class LibraryFunctionImporter; class ConstantImporter; class BundleImporter; /// \brief ImportContext /// /// Hold all the objects and information required during the translation. struct ImportContext { public: using ImportOptions = Importer::ImportOptions; public: /// \brief Import options const ImportOptions opts; /// \brief Imported LLVM module llvm::Module& module; /// \brief AR bundle ar::Bundle* bundle; /// \brief Imported LLVM context llvm::LLVMContext& llvm_context; /// \brief AR context ar::Context& ar_context; /// \brief Imported LLVM data layout const llvm::DataLayout& llvm_data_layout; /// \brief AR data layout const ar::DataLayout& ar_data_layout; /// \brief Helper to translate LLVM types to AR types TypeImporter* type_imp; /// \brief Helper class to find known library functions LibraryFunctionImporter* lib_fun_imp; /// \brief Helper class to translate LLVM constants to AR values ConstantImporter* constant_imp; /// \brief Helper class to translate global values and functions BundleImporter* bundle_imp; public: /// \brief Create an ImportContext ImportContext(llvm::Module& module_, ar::Bundle* bundle_, ImportOptions opts_) : opts(opts_), module(module_), bundle(bundle_), llvm_context(module_.getContext()), ar_context(bundle_->context()), llvm_data_layout(module_.getDataLayout()), ar_data_layout(bundle_->data_layout()), type_imp(nullptr), lib_fun_imp(nullptr), constant_imp(nullptr), bundle_imp(nullptr) {} void set_type_importer(TypeImporter& type_imp_) { this->type_imp = &type_imp_; } void set_library_function_importer(LibraryFunctionImporter& lib_fun_imp_) { this->lib_fun_imp = &lib_fun_imp_; } void set_constant_importer(ConstantImporter& constant_imp_) { this->constant_imp = &constant_imp_; } void set_bundle_importer(BundleImporter& bundle_imp_) { this->bundle_imp = &bundle_imp_; } }; // end struct ImportContext } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/importer.cpp000066400000000000000000000107461473507761200240650ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Generate an AR bundle from a LLVM module * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include "bundle.hpp" #include "constant.hpp" #include "data_layout.hpp" #include "import_context.hpp" #include "library_function.hpp" #include "type.hpp" namespace ikos { namespace frontend { namespace import { // hasDebugInfo bool has_debug_info(llvm::Module& m) { return m.debug_compile_units_begin() != m.debug_compile_units_end(); } // Importer ar::Bundle* Importer::import(llvm::Module& module, ImportOptions opts) { // Create the data layout std::unique_ptr< ar::DataLayout > data_layout = translate_data_layout(module.getDataLayout(), module.getContext()); // Create the bundle ar::Bundle* bundle = ar::Bundle::create(this->_context, std::move(data_layout), module.getTargetTriple()); bundle->set_frontend(&module); // Create an ImportContext and Helper objects ImportContext ctx(module, bundle, opts); TypeImporter type_imp(ctx); ctx.set_type_importer(type_imp); LibraryFunctionImporter lib_fun_imp(ctx); ctx.set_library_function_importer(lib_fun_imp); ConstantImporter constant_imp(ctx); ctx.set_constant_importer(constant_imp); BundleImporter bundle_imp(ctx); ctx.set_bundle_importer(bundle_imp); // Create all the global variables (names and types only) for (auto it = module.global_begin(), et = module.global_end(); it != et; ++it) { llvm::GlobalVariable& gv = *it; bundle_imp.translate_global_variable(&gv); } // Create all the functions (names and types only) for (llvm::Function& fun : module) { bundle_imp.translate_function(&fun); } // Translate all global variable initializers for (auto it = module.global_begin(), et = module.global_end(); it != et; ++it) { llvm::GlobalVariable& gv = *it; if (!gv.isDeclaration()) { bundle_imp.translate_global_variable_initializer(&gv); } } // Translate all function bodies for (llvm::Function& fun : module) { if (!fun.isDeclaration()) { bundle_imp.translate_function_body(&fun); } } return bundle; } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/library_function.cpp000066400000000000000000000301161473507761200255660ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translation for known library functions (ie. malloc, free, etc.) * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include "library_function.hpp" namespace ikos { namespace frontend { namespace import { ar::Function* LibraryFunctionImporter::function(llvm::StringRef name) { // ikos functions if (this->_enable_ikos) { // if (name == "__ikos_assert") { return this->_bundle->intrinsic_function(ar::Intrinsic::IkosAssert); } else if (name == "__ikos_assume") { return this->_bundle->intrinsic_function(ar::Intrinsic::IkosAssume); } else if (name == "__ikos_nondet_int") { return this->_bundle->intrinsic_function(ar::Intrinsic::IkosNonDet, ar::IntegerType::si32( this->_context)); } else if (name == "__ikos_nondet_uint") { return this->_bundle->intrinsic_function(ar::Intrinsic::IkosNonDet, ar::IntegerType::ui32( this->_context)); } else if (name == "__ikos_check_mem_access") { return this->_bundle->intrinsic_function( ar::Intrinsic::IkosCheckMemAccess); } else if (name == "__ikos_check_string_access") { return this->_bundle->intrinsic_function( ar::Intrinsic::IkosCheckStringAccess); } else if (name == "__ikos_assume_mem_size") { return this->_bundle->intrinsic_function( ar::Intrinsic::IkosAssumeMemSize); } else if (name == "__ikos_forget_mem") { return this->_bundle->intrinsic_function(ar::Intrinsic::IkosForgetMemory); } else if (name == "__ikos_abstract_mem") { return this->_bundle->intrinsic_function( ar::Intrinsic::IkosAbstractMemory); } else if (name == "__ikos_watch_mem") { return this->_bundle->intrinsic_function(ar::Intrinsic::IkosWatchMemory); } else if (name == "__ikos_partitioning_var_int") { return this->_bundle ->intrinsic_function(ar::Intrinsic::IkosPartitioningVar, ar::IntegerType::si32(this->_context)); } else if (name == "__ikos_partitioning_join") { return this->_bundle->intrinsic_function( ar::Intrinsic::IkosPartitioningJoin); } else if (name == "__ikos_partitioning_disable") { return this->_bundle->intrinsic_function( ar::Intrinsic::IkosPartitioningDisable); } else if (name == "__ikos_print_invariant") { return this->_bundle->intrinsic_function( ar::Intrinsic::IkosPrintInvariant); } else if (name == "__ikos_print_values") { return this->_bundle->intrinsic_function(ar::Intrinsic::IkosPrintValues); } } // libc functions if (this->_enable_libc) { // if (name == "malloc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcMalloc); } else if (name == "calloc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcCalloc); } else if (name == "valloc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcValloc); } else if (name == "aligned_alloc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcAlignedAlloc); } else if (name == "realloc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcRealloc); } else if (name == "free") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFree); } else if (name == "abs") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcAbs); } else if (name == "rand") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcRand); } else if (name == "srand") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcSrand); } else if (name == "exit") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcExit); } else if (name == "abort") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcAbort); } // if (name == "__errno_location" || name == "__errno" || name == "_errno" || name == "__error") { return this->_bundle->intrinsic_function( ar::Intrinsic::LibcErrnoLocation); } // if (name == "open") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcOpen); } // if (name == "close") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcClose); } else if (name == "read" || name == "\x01_read") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcRead); } else if (name == "write") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcWrite); } // if (name == "gets") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcGets); } else if (name == "fgets") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFgets); } else if (name == "getc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcGetc); } else if (name == "fgetc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFgetc); } else if (name == "getchar") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcGetchar); } else if (name == "puts") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcPuts); } else if (name == "fputs" || name == "\x01_fputs") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFputs); } else if (name == "putc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcPutc); } else if (name == "fputc") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFputc); } else if (name == "printf") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcPrintf); } else if (name == "fprintf") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFprintf); } else if (name == "sprintf") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcSprintf); } else if (name == "snprintf") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcSnprintf); } else if (name == "scanf") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcScanf); } else if (name == "fscanf" || name == "__isoc99_fscanf") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFscanf); } else if (name == "sscanf") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcSscanf); } else if (name == "fopen" || name == "\x01_fopen") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFopen); } else if (name == "fclose") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFclose); } else if (name == "fflush") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcFflush); } // if (name == "strlen") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrlen); } else if (name == "strnlen") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrnlen); } else if (name == "strcpy") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrcpy); } else if (name == "strncpy") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrncpy); } else if (name == "strcat") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrcat); } else if (name == "strncat") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrncat); } else if (name == "strcmp") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrcmp); } else if (name == "strncmp") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrncmp); } else if (name == "strstr") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrstr); } else if (name == "strchr") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrchr); } else if (name == "strdup") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrdup); } else if (name == "strndup") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrndup); } else if (name == "__strcpy_chk") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrcpyCheck); } else if (name == "__memcpy_chk") { return this->_bundle->intrinsic_function( ar::Intrinsic::LibcMemoryCopyCheck); } else if (name == "__memmove_chk") { return this->_bundle->intrinsic_function( ar::Intrinsic::LibcMemoryMoveCheck); } else if (name == "__memset_chk") { return this->_bundle->intrinsic_function( ar::Intrinsic::LibcMemorySetCheck); } else if (name == "__strcat_chk") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcStrcatCheck); } } // libc++ functions if (this->_enable_libcpp) { if (name == "_Znwm" || name == "_Znwy") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcppNew); } else if (name == "_Znam" || name == "_Znay") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcppNewArray); } else if (name == "_ZdlPv") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcppDelete); } else if (name == "_ZdaPv") { return this->_bundle->intrinsic_function( ar::Intrinsic::LibcppDeleteArray); } else if (name == "__cxa_allocate_exception") { return this->_bundle->intrinsic_function( ar::Intrinsic::LibcppAllocateException); } else if (name == "__cxa_free_exception") { return this->_bundle->intrinsic_function( ar::Intrinsic::LibcppFreeException); } else if (name == "__cxa_throw") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcppThrow); } else if (name == "__cxa_begin_catch") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcppBeginCatch); } else if (name == "__cxa_end_catch") { return this->_bundle->intrinsic_function(ar::Intrinsic::LibcppEndCatch); } } // not a known library function return nullptr; } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/library_function.hpp000066400000000000000000000066531473507761200256040ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translation for known library functions (ie. malloc, free, etc.) * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2017-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include "import_context.hpp" namespace ikos { namespace frontend { namespace import { /// \brief Helper class to find known library functions class LibraryFunctionImporter { private: // AR context ar::Context& _context; // AR bundle ar::Bundle* _bundle; // Enable ikos functions bool _enable_ikos; // Enable libc functions bool _enable_libc; // Enable libc++ functions bool _enable_libcpp; public: /// \brief Public constructor explicit LibraryFunctionImporter(ImportContext& ctx) : _context(ctx.ar_context), _bundle(ctx.bundle), _enable_ikos(ctx.opts.test(Importer::EnableLibIkos)), _enable_libc(ctx.opts.test(Importer::EnableLibc)), _enable_libcpp(ctx.opts.test(Importer::EnableLibcpp)) {} /// \brief Get the ar::Function of a known library function /// /// If the given name is the name of a well-known library function (such as /// malloc, free, etc.), returns the corresponding intrinsic ar::Function. /// Otherwise, return nullptr. ar::Function* function(llvm::StringRef name); }; // end class LibraryFunctionImporter } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/source_location.cpp000066400000000000000000000122511473507761200254050ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Source location for AR statements generated from LLVM * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2018-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include namespace ikos { namespace frontend { namespace import { boost::filesystem::path source_path(llvm::DIFile* file) { ikos_assert(file != nullptr); boost::filesystem::path path; boost::filesystem::path filename = file->getFilename().str(); boost::filesystem::path directory = file->getDirectory().str(); if (filename.is_absolute()) { path = filename; } else { path = directory / filename; } if (boost::filesystem::exists(path)) { path = boost::filesystem::canonical(path); } path.make_preferred(); return path; } /// \brief Return the source location of the given instruction static SourceLocation source_location(llvm::Instruction* inst) { ikos_assert(inst != nullptr); for (auto it = inst->getIterator(), et = inst->getParent()->end(); it != et; ++it) { llvm::DILocation* loc = it->getDebugLoc().get(); if (loc != nullptr) { return SourceLocation(loc); } } return {}; // null location } SourceLocation source_location(ar::Statement* stmt) { ikos_assert(stmt != nullptr); if (!stmt->has_frontend()) { return {}; // null location } auto value = stmt->frontend< llvm::Value >(); if (auto inst = llvm::dyn_cast< llvm::Instruction >(value)) { SourceLocation loc = source_location(inst); if (loc) { return loc; } } // No debug information: could be a phi or bitcast of a global value. // Find the next statement with debug info llvm::SmallPtrSet< ar::BasicBlock*, 2 > seen; ar::BasicBlock* bb = stmt->parent(); auto it = stmt->iterator() + 1; auto et = bb->end(); while (true) { // Iterate over the following statements for (; it != et; ++it) { ar::Statement* s = *it; if (s->has_frontend()) { if (auto inst = llvm::dyn_cast< llvm::Instruction >( s->frontend< llvm::Value >())) { SourceLocation loc = source_location(inst); if (loc) { return loc; } } } } if (bb->num_successors() == 1) { // Visit the successor bb = *bb->successor_begin(); if (!seen.insert(bb).second) { return {}; // Already seen } it = bb->begin(); et = bb->end(); continue; } if (bb->num_successors() > 1) { // Basic block has several successors, check for an assert bb = *bb->successor_begin(); if (!bb->empty()) { ar::Statement* s = bb->front(); if (ar::isa< ar::Comparison >(s) && s->has_frontend()) { if (auto inst = llvm::dyn_cast< llvm::Instruction >( s->frontend< llvm::Value >())) { SourceLocation loc = source_location(inst); if (loc) { return loc; } } } } } // Could not find a statement with debug info return {}; } } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/type.cpp000066400000000000000000002112161473507761200232000ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM types and Debug Information into AR types * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include "type.hpp" #ifdef __GLIBCXX__ // Fix for libstdc++, see https://bugs.llvm.org/show_bug.cgi?id=35755 namespace std { template <> struct iterator_traits< llvm::DITypeRefArray::iterator > { using difference_type = std::ptrdiff_t; using value_type = llvm::DIType*; using pointer = void; using reference = llvm::DIType*; using iterator_category = std::input_iterator_tag; }; template <> struct iterator_traits< llvm::TypedMDOperandIterator< llvm::DINode > > { using difference_type = std::ptrdiff_t; using value_type = llvm::DINode*; using pointer = void; using reference = llvm::DINode*; using iterator_category = std::input_iterator_tag; }; } // end namespace std #endif namespace ikos { namespace frontend { namespace import { namespace dwarf = llvm::dwarf; // TypeWithSignImporter TypeWithSignImporter::TypeWithSignImporter(ImportContext& ctx) : _context(ctx.ar_context), _llvm_data_layout(ctx.llvm_data_layout), _ar_data_layout(ctx.ar_data_layout), _translation_depth(0) {} TypeWithSignImporter::~TypeWithSignImporter() = default; ar::Type* TypeWithSignImporter::translate_type(llvm::Type* type, ar::Signedness preferred) { auto it = this->_map.find({type, preferred}); if (it != this->_map.end()) { return it->second; } if (type->isVoidTy()) { return this->translate_void_type(type, preferred); } else if (type->isIntegerTy()) { return this->translate_integer_type(type, preferred); } else if (type->isFloatingPointTy()) { return this->translate_floating_point_type(type, preferred); } else if (type->isPointerTy()) { return this->translate_pointer_type(type, preferred); } else if (type->isArrayTy()) { return this->translate_array_type(type, preferred); } else if (type->isVectorTy()) { return this->translate_vector_type(type, preferred); } else if (type->isStructTy()) { return this->translate_struct_type(type, preferred); } else if (type->isFunctionTy()) { return this->translate_function_type(type, preferred); } else { throw ImportError("unsupported llvm type"); } } void TypeWithSignImporter::store_translation(llvm::Type* type, ar::Signedness preferred, ar::Type* ar_type) { ikos_assert_msg(type, "type is null"); ikos_assert_msg(ar_type, "result is null"); this->_map.try_emplace({type, preferred}, ar_type); } void TypeWithSignImporter::sanity_check_size(llvm::Type* llvm_type, ar::Type* ar_type) { if (this->_translation_depth > 0) { // Disable checks, some types are not complete yet. return; } check_import(this->_llvm_data_layout.getTypeSizeInBits(llvm_type) .getFixedSize() >= this->_ar_data_layout.size_in_bits(ar_type), "llvm type size in bits is smaller than ar type size"); check_import(this->_llvm_data_layout.getTypeAllocSize(llvm_type) .getFixedSize() == this->_ar_data_layout.alloc_size_in_bytes(ar_type), "llvm type and ar type alloc size are different"); } ar::VoidType* TypeWithSignImporter::translate_void_type( llvm::Type* type, ar::Signedness preferred) { ar::VoidType* ar_type = ar::VoidType::get(this->_context); this->store_translation(type, preferred, ar_type); return ar_type; } ar::IntegerType* TypeWithSignImporter::translate_integer_type( llvm::Type* type, ar::Signedness preferred) { auto int_type = llvm::cast< llvm::IntegerType >(type); ar::IntegerType* ar_type = ar::IntegerType::get(this->_context, int_type->getBitWidth(), preferred); this->store_translation(type, preferred, ar_type); return ar_type; } ar::FloatType* TypeWithSignImporter::translate_floating_point_type( llvm::Type* type, ar::Signedness preferred) { ar::FloatType* ar_type = nullptr; if (type->isHalfTy()) { ar_type = ar::FloatType::get(this->_context, ar::Half); } else if (type->isFloatTy()) { ar_type = ar::FloatType::get(this->_context, ar::Float); } else if (type->isDoubleTy()) { ar_type = ar::FloatType::get(this->_context, ar::Double); } else if (type->isX86_FP80Ty()) { ar_type = ar::FloatType::get(this->_context, ar::X86_FP80); } else if (type->isFP128Ty()) { ar_type = ar::FloatType::get(this->_context, ar::FP128); } else if (type->isPPC_FP128Ty()) { ar_type = ar::FloatType::get(this->_context, ar::PPC_FP128); } else { throw ImportError("unsupported llvm floating point type"); } this->store_translation(type, preferred, ar_type); return ar_type; } ar::PointerType* TypeWithSignImporter::translate_pointer_type( llvm::Type* type, ar::Signedness preferred) { auto ptr_type = llvm::cast< llvm::PointerType >(type); ar::Type* ar_pointee_type = this->translate_type(ptr_type->getPointerElementType(), preferred); ar::PointerType* ar_type = ar::PointerType::get(this->_context, ar_pointee_type); this->store_translation(type, preferred, ar_type); return ar_type; } ar::ArrayType* TypeWithSignImporter::translate_array_type( llvm::Type* type, ar::Signedness preferred) { auto array_type = llvm::cast< llvm::ArrayType >(type); ar::Type* ar_element_type = this->translate_type(array_type->getElementType(), preferred); ar::ArrayType* ar_type = ar::ArrayType::get(this->_context, ar_element_type, ar::ZNumber(array_type->getNumElements())); this->store_translation(type, preferred, ar_type); this->sanity_check_size(type, ar_type); return ar_type; } ar::VectorType* TypeWithSignImporter::translate_vector_type( llvm::Type* type, ar::Signedness preferred) { auto vector_type = llvm::cast< llvm::VectorType >(type); ar::Type* ar_element_type = this->translate_type(vector_type->getElementType(), preferred); ar::VectorType* ar_type = ar::VectorType::get(this->_context, ar::cast< ar::ScalarType >(ar_element_type), ar::ZNumber( vector_type->getElementCount().getFixedValue())); this->store_translation(type, preferred, ar_type); this->sanity_check_size(type, ar_type); return ar_type; } ar::Type* TypeWithSignImporter::translate_struct_type( llvm::Type* type, ar::Signedness preferred) { auto struct_type = llvm::cast< llvm::StructType >(type); if (struct_type->isOpaque()) { ar::OpaqueType* ar_type = ar::OpaqueType::create(this->_context); this->store_translation(type, ar::Signed, ar_type); this->store_translation(type, ar::Unsigned, ar_type); return ar_type; } // Structures can be recursive, so create it now, with an empty layout ar::StructType* ar_type = ar::StructType::create(this->_context, struct_type->isPacked()); this->store_translation(type, preferred, ar_type); this->_translation_depth++; // recursive type, not complete yet // Create the layout const llvm::StructLayout* struct_layout = this->_llvm_data_layout.getStructLayout(struct_type); ar::StructType::Layout ar_layout; ar_layout.reserve(struct_type->getNumElements()); for (unsigned i = 0; i < struct_type->getNumElements(); i++) { llvm::Type* element_type = struct_type->getElementType(i); uint64_t element_offset = struct_layout->getElementOffset(i); ar::Type* ar_element_type = this->translate_type(element_type, preferred); ar_layout.push_back({ar::ZNumber(element_offset), ar_element_type}); } ar_type->set_layout(ar_layout); this->_translation_depth--; this->sanity_check_size(struct_type, ar_type); return ar_type; } ar::FunctionType* TypeWithSignImporter::translate_function_type( llvm::Type* type, ar::Signedness preferred) { auto fun_type = llvm::cast< llvm::FunctionType >(type); // Return type ar::Type* ar_return_type = this->translate_type(fun_type->getReturnType(), preferred); // Parameters ar::FunctionType::ParamTypes ar_params; for (llvm::Type* param : fun_type->params()) { ar::Type* ar_param = this->translate_type(param, preferred); ar_params.push_back(ar_param); } ar::FunctionType* ar_type = ar::FunctionType::get(this->_context, ar_return_type, ar_params, fun_type->isVarArg()); this->store_translation(type, preferred, ar_type); return ar_type; } // TypeWithDebugInfoImporter TypeWithDebugInfoImporter::TypeWithDebugInfoImporter( ar::Context& context, const llvm::DataLayout& llvm_data_layout, const ar::DataLayout& ar_data_layout, bool is_c, bool is_cpp, unsigned translation_depth, TypeWithSignImporter& type_sign_imp, const TypeWithDebugInfoImporter* parent) : _context(context), _llvm_data_layout(llvm_data_layout), _ar_data_layout(ar_data_layout), _is_c(is_c), _is_cpp(is_cpp), _translation_depth(translation_depth), _type_sign_imp(type_sign_imp), _parent(parent) {} TypeWithDebugInfoImporter::TypeWithDebugInfoImporter( ImportContext& ctx, TypeWithSignImporter& type_sign_imp) : _context(ctx.ar_context), _llvm_data_layout(ctx.llvm_data_layout), _ar_data_layout(ctx.ar_data_layout), _translation_depth(0), _type_sign_imp(type_sign_imp), _parent(nullptr) { // Get all source languages llvm::SmallSet< llvm::dwarf::SourceLanguage, 2 > languages; for (auto it = ctx.module.debug_compile_units_begin(), et = ctx.module.debug_compile_units_end(); it != et; ++it) { unsigned lang = it->getSourceLanguage(); languages.insert(static_cast< dwarf::SourceLanguage >(lang)); } this->_is_c = languages.count(dwarf::DW_LANG_C) != 0 || languages.count(dwarf::DW_LANG_C89) != 0 || languages.count(dwarf::DW_LANG_C99) != 0 || languages.count(dwarf::DW_LANG_C11) != 0; this->_is_cpp = languages.count(dwarf::DW_LANG_C_plus_plus) != 0 || languages.count(dwarf::DW_LANG_C_plus_plus_03) != 0 || languages.count(dwarf::DW_LANG_C_plus_plus_11) != 0 || languages.count(dwarf::DW_LANG_C_plus_plus_14) != 0; } TypeWithDebugInfoImporter::~TypeWithDebugInfoImporter() = default; ar::Type* TypeWithDebugInfoImporter::translate_type(llvm::Type* type, llvm::DIType* di_type) { // Check if it is already translated in a parent const TypeWithDebugInfoImporter* parent = this->_parent; while (parent != nullptr) { auto it = parent->_map.find({type, di_type}); if (it != parent->_map.end()) { return it->second; } parent = parent->_parent; } // Check if it is already translated here auto it = this->_map.find({type, di_type}); if (it != this->_map.end()) { return it->second; } if (di_type == nullptr) { return this->translate_null_di_type(type); } else if (di_type->isForwardDecl()) { return this->translate_forward_decl_di_type(di_type, type); } else if (auto basic_type = llvm::dyn_cast< llvm::DIBasicType >(di_type)) { return this->translate_basic_di_type(basic_type, type); } else if (auto derived_type = llvm::dyn_cast< llvm::DIDerivedType >(di_type)) { return this->translate_derived_di_type(derived_type, type); } else if (auto composite_type = llvm::dyn_cast< llvm::DICompositeType >(di_type)) { return this->translate_composite_di_type(composite_type, type); } else if (auto subroutine_type = llvm::dyn_cast< llvm::DISubroutineType >(di_type)) { return this->translate_subroutine_di_type(subroutine_type, type); } else { throw ImportError("unsupported llvm DIType"); } } TypeWithDebugInfoImporter TypeWithDebugInfoImporter::fork() const { return TypeWithDebugInfoImporter(this->_context, this->_llvm_data_layout, this->_ar_data_layout, this->_is_c, this->_is_cpp, this->_translation_depth + 1, this->_type_sign_imp, this); } void TypeWithDebugInfoImporter::join(const TypeWithDebugInfoImporter& imp) { for (const auto& e : imp._map) { this->_map.try_emplace(e.first, e.second); } } void TypeWithDebugInfoImporter::store_translation(llvm::Type* type, llvm::DIType* di_type, ar::Type* ar_type) { ikos_assert_msg(type, "type is null"); ikos_assert_msg(ar_type, "result is null"); this->_map.try_emplace({type, di_type}, ar_type); } void TypeWithDebugInfoImporter::sanity_check_size(llvm::Type* llvm_type, ar::Type* ar_type) { if (this->_translation_depth > 0) { // Disable checks, some types are not complete yet. return; } check_import(this->_llvm_data_layout.getTypeSizeInBits(llvm_type) .getFixedSize() >= this->_ar_data_layout.size_in_bits(ar_type), "llvm type size in bits is smaller than ar type size"); check_import(this->_llvm_data_layout.getTypeAllocSize(llvm_type) .getFixedSize() == this->_ar_data_layout.alloc_size_in_bytes(ar_type), "llvm type and ar type alloc size are different"); } ar::Type* TypeWithDebugInfoImporter::translate_null_di_type(llvm::Type* type) { ar::Type* ar_type = nullptr; if (type->isVoidTy()) { ar_type = ar::VoidType::get(this->_context); } else if (type->isIntegerTy(8)) { ar_type = ar::IntegerType::get(this->_context, 8, ar::Signed); } else { throw TypeDebugInfoMismatch( "unexpected llvm type with no debug information"); } this->store_translation(type, nullptr, ar_type); return ar_type; } ar::Type* TypeWithDebugInfoImporter::translate_forward_decl_di_type( llvm::DIType* di_type, llvm::Type* type) { // In this case, guess the type using llvm::Type* ar::Type* ar_type = this->_type_sign_imp.translate_type(type, ar::Signed); this->store_translation(type, di_type, ar_type); return ar_type; } ar::Type* TypeWithDebugInfoImporter::translate_basic_di_type( llvm::DIBasicType* di_type, llvm::Type* type) { ar::Type* ar_type = nullptr; if (di_type->getEncoding() != 0) { auto encoding = static_cast< dwarf::TypeKind >(di_type->getEncoding()); switch (encoding) { case dwarf::DW_ATE_signed: case dwarf::DW_ATE_unsigned: case dwarf::DW_ATE_signed_char: case dwarf::DW_ATE_unsigned_char: { check_match(type->isIntegerTy(), "llvm DIBasicType with integer encoding, but llvm type is " "not an integer type"); auto int_type = llvm::cast< llvm::IntegerType >(type); check_match(di_type->getSizeInBits() == int_type->getBitWidth(), "llvm DIBasicType with integer encoding and llvm integer " "type have a different bit-width"); ar::Signedness sign = (encoding == dwarf::DW_ATE_unsigned || encoding == dwarf::DW_ATE_unsigned_char) ? ar::Unsigned : ar::Signed; ar_type = ar::IntegerType::get(this->_context, int_type->getBitWidth(), sign); } break; case dwarf::DW_ATE_boolean: { check_match(type->isIntegerTy(), "llvm DIBasicType with boolean encoding, but llvm type is " "not an integer type"); auto int_type = llvm::cast< llvm::IntegerType >(type); check_match(di_type->getSizeInBits() == int_type->getBitWidth() || (di_type->getSizeInBits() == 8 && int_type->getBitWidth() == 1), "llvm DIBasicType with boolean encoding and llvm integer " "type have a different bit-width"); ar_type = ar::IntegerType::get(this->_context, int_type->getBitWidth(), ar::Unsigned); } break; case dwarf::DW_ATE_UTF: { check_match(type->isIntegerTy(), "llvm DIBasicType with UTF encoding, but llvm type is " "not an integer type"); auto int_type = llvm::cast< llvm::IntegerType >(type); check_match(di_type->getSizeInBits() == int_type->getBitWidth(), "llvm DIBasicType with UTF encoding and llvm integer " "type have a different bit-width"); ar_type = ar::IntegerType::get(this->_context, int_type->getBitWidth(), ar::Unsigned); } break; case dwarf::DW_ATE_float: { check_match(type->isFloatingPointTy(), "llvm DIBasicType with float encoding, but llvm type is " "not a floating point type"); check_match(di_type->getSizeInBits() == type->getPrimitiveSizeInBits() || (di_type->getSizeInBits() == 128 && type->isX86_FP80Ty()), "llvm DIBasicType with float encoding and llvm floating " "point type have a different bit-width"); if (type->isHalfTy()) { ar_type = ar::FloatType::get(this->_context, ar::Half); } else if (type->isFloatTy()) { ar_type = ar::FloatType::get(this->_context, ar::Float); } else if (type->isDoubleTy()) { ar_type = ar::FloatType::get(this->_context, ar::Double); } else if (type->isX86_FP80Ty()) { ar_type = ar::FloatType::get(this->_context, ar::X86_FP80); } else if (type->isFP128Ty()) { ar_type = ar::FloatType::get(this->_context, ar::FP128); } else if (type->isPPC_FP128Ty()) { ar_type = ar::FloatType::get(this->_context, ar::PPC_FP128); } else { throw ImportError("unsupported llvm floating point type"); } } break; case dwarf::DW_ATE_complex_float: { check_match(type->isStructTy(), "llvm DIBasicType with complex encoding, but llvm type is " "not a structure type"); auto struct_type = llvm::cast< llvm::StructType >(type); check_match(struct_type->getNumElements() == 2 && struct_type->getElementType(0) == struct_type->getElementType(1) && struct_type->getElementType(0)->isFloatingPointTy(), "llvm DIBasicType with complex encoding, but llvm " "structure type does not contain 2 floating points"); check_match(di_type->getSizeInBits() == 2 * struct_type->getElementType(0) ->getPrimitiveSizeInBits(), "llvm DIBasicType with complex encoding and llvm structure " "type have a different bit-width"); ar_type = this->_type_sign_imp.translate_type(type, ar::Signed); } break; default: { throw ImportError("unsupported dwarf encoding for llvm DIBasicType"); } } } else if (di_type->getTag() != 0) { auto tag = static_cast< dwarf::Tag >(di_type->getTag()); if (tag == dwarf::DW_TAG_unspecified_type && di_type->getName() == "decltype(nullptr)") { check_match(type->isPointerTy() && llvm::cast< llvm::PointerType >(type) ->getPointerElementType() ->isIntegerTy(8), "unexpected llvm type for llvm DIBasicType with name " "'decltype(nullptr)'"); ar_type = ar::PointerType::get(this->_context, ar::IntegerType::si8(this->_context)); } else { throw ImportError("unsupported dwarf tag for llvm DIBasicType"); } } else { throw ImportError("unexpected llvm DIBasicType without tag and encoding"); } this->store_translation(type, di_type, ar_type); return ar_type; } ar::Type* TypeWithDebugInfoImporter::translate_derived_di_type( llvm::DIDerivedType* di_type, llvm::Type* type) { if (di_type->getTag() == dwarf::DW_TAG_typedef || di_type->getTag() == dwarf::DW_TAG_const_type || di_type->getTag() == dwarf::DW_TAG_volatile_type || di_type->getTag() == dwarf::DW_TAG_restrict_type || di_type->getTag() == dwarf::DW_TAG_atomic_type || di_type->getTag() == dwarf::DW_TAG_ptr_to_member_type) { return this->translate_qualified_di_type(di_type, type); } else if (di_type->getTag() == dwarf::DW_TAG_pointer_type) { return this->translate_pointer_di_type(di_type, type); } else if (di_type->getTag() == dwarf::DW_TAG_reference_type || di_type->getTag() == dwarf::DW_TAG_rvalue_reference_type) { return this->translate_reference_di_type(di_type, type); } else { throw ImportError("unsupported dwarf tag for llvm DIDerivedType"); } } ar::Type* TypeWithDebugInfoImporter::translate_qualified_di_type( llvm::DIDerivedType* di_type, llvm::Type* type) { auto qualified_type = llvm::cast_or_null< llvm::DIType >(di_type->getRawBaseType()); ar::Type* ar_type = this->translate_type(type, qualified_type); this->store_translation(type, di_type, ar_type); return ar_type; } ar::PointerType* TypeWithDebugInfoImporter::translate_pointer_di_type( llvm::DIDerivedType* di_type, llvm::Type* type) { check_match(type->isPointerTy(), "llvm DIDerivedType with pointer tag, but llvm type is not a " "pointer type"); check_match(di_type->getSizeInBits() == this->_llvm_data_layout.getPointerSizeInBits(), "llvm DIDerivedType with pointer tag and llvm pointer type have " "a different bit-width"); auto ptr_type = llvm::cast< llvm::PointerType >(type); llvm::Type* pointee_type = ptr_type->getPointerElementType(); auto di_pointee_type = llvm::cast_or_null< llvm::DIType >(di_type->getRawBaseType()); ar::Type* ar_pointee_type = this->translate_type(pointee_type, di_pointee_type); ar::PointerType* ar_type = ar::PointerType::get(this->_context, ar_pointee_type); this->store_translation(type, di_type, ar_type); return ar_type; } ar::PointerType* TypeWithDebugInfoImporter::translate_reference_di_type( llvm::DIDerivedType* di_type, llvm::Type* type) { check_match(type->isPointerTy(), "llvm DIDerivedType with reference tag, but llvm type is not a " "pointer type"); check_match(di_type->getSizeInBits() == 0 || di_type->getSizeInBits() == this->_llvm_data_layout.getPointerSizeInBits(), "llvm DIDerivedType with reference tag and llvm pointer type " "have a different bit-width"); auto ptr_type = llvm::cast< llvm::PointerType >(type); llvm::Type* pointee_type = ptr_type->getPointerElementType(); auto di_referred_type = llvm::cast_or_null< llvm::DIType >(di_type->getRawBaseType()); ar::Type* ar_pointee_type = this->translate_type(pointee_type, di_referred_type); ar::PointerType* ar_type = ar::PointerType::get(this->_context, ar_pointee_type); this->store_translation(type, di_type, ar_type); return ar_type; } ar::Type* TypeWithDebugInfoImporter::translate_composite_di_type( llvm::DICompositeType* di_type, llvm::Type* type) { auto tag = static_cast< dwarf::Tag >(di_type->getTag()); if (tag == dwarf::DW_TAG_array_type) { return this->translate_array_di_type(di_type, type); } else if (tag == dwarf::DW_TAG_structure_type || tag == dwarf::DW_TAG_class_type) { return this->translate_struct_di_type(di_type, type); } else if (tag == dwarf::DW_TAG_union_type) { return this->translate_union_di_type(di_type, type); } else if (tag == dwarf::DW_TAG_enumeration_type) { return this->translate_enum_di_type(di_type, type); } else { throw ImportError("unsupported dwarf tag for llvm DICompositeType"); } } ar::Type* TypeWithDebugInfoImporter::translate_array_di_type( llvm::DICompositeType* di_type, llvm::Type* type) { // Check that the elements of di_type and the llvm::Type* match, // and get the final element Type check_import(di_type->getRawElements() != nullptr, "unexpected null pointer for elements in llvm DICompositeType"); llvm::DINodeArray di_elements = di_type->getElements(); llvm::SmallVector< llvm::Type*, 3 > llvm_elements; llvm::Type* current_element = type; // True if the previous element has count = -1 bool prev_no_count = false; for (auto it = di_elements.begin(), et = di_elements.end(); it != et; ++it) { llvm::DINode* di_element = *it; check_import(llvm::isa< llvm::DISubrange >(di_element), "unsupported element in llvm DICompositeType with array tag"); auto subrange = llvm::cast< llvm::DISubrange >(di_element); auto count = subrange->getCount(); if (count.is< llvm::ConstantInt* >() != 0 && !count.get< llvm::ConstantInt* >()->isMinusOne()) { auto count_int = count.get< llvm::ConstantInt* >(); check_import(!count_int->isNegative(), "unexpected negative count for llvm DICompositeType with " "array tag"); if (current_element->isArrayTy()) { auto array_type = llvm::cast< llvm::ArrayType >(current_element); check_match(array_type->getNumElements() == count_int->getZExtValue(), "llvm DICompositeType with array tag and llvm array type " "have a different number of elements"); llvm_elements.push_back(array_type); current_element = array_type->getElementType(); } else if (current_element->isVectorTy()) { auto vector_type = llvm::cast< llvm::VectorType >(current_element); check_match(vector_type->getElementCount().getFixedValue() == count_int->getZExtValue(), "llvm DICompositeType with array tag and llvm vector type " "have a different number of elements"); llvm_elements.push_back(vector_type); current_element = vector_type->getElementType(); } else if (current_element->isStructTy()) { auto struct_type = llvm::cast< llvm::StructType >(current_element); check_match(!struct_type->isOpaque(), "llvm DICompositeType with array tag, but llvm structure " "type is opaque"); check_match(struct_type->isPacked(), "llvm DICompositeType with array tag, but llvm structure " "type is not packed"); check_match(struct_type->getNumElements() == count_int->getZExtValue(), "llvm DICompositeType with array tag and llvm structure " "type have a different number of elements"); check_match(!count_int->isZero(), "llvm DICompositeType with array tag, but llvm structure " "type is empty"); check_match(std::next(it) == et, "llvm DICompositeType with array tag, but llvm structure " "type is not the last element"); llvm_elements.push_back(struct_type); current_element = struct_type->getElementType(0); } else { throw TypeDebugInfoMismatch( "llvm DICompositeType with array tag and positive count, but llvm " "type is not an array, vector or structure type"); } prev_no_count = false; } else { if (prev_no_count) { // Type T[][] is flattened into T*, so skip this element continue; } else if (current_element->isPointerTy()) { auto ptr_type = llvm::cast< llvm::PointerType >(current_element); llvm_elements.push_back(ptr_type); current_element = ptr_type->getPointerElementType(); prev_no_count = true; } else if (current_element->isArrayTy()) { auto array_type = llvm::cast< llvm::ArrayType >(current_element); check_match(array_type->getNumElements() == 0, "llvm DICompositeType with array tag and count -1, but " "llvm array type is not empty"); llvm_elements.push_back(array_type); current_element = array_type->getElementType(); prev_no_count = false; } else { throw TypeDebugInfoMismatch( "llvm DICompositeType with array tag and count -1, but llvm type " "is not a pointer or array type"); } } } llvm::Type* final_element = current_element; auto di_final_element = llvm::cast_or_null< llvm::DIType >(di_type->getRawBaseType()); // Build the ar::Type ar::Type* ar_type = this->translate_type(final_element, di_final_element); for (auto it = llvm_elements.rbegin(), et = llvm_elements.rend(); it != et; ++it) { if (auto array_type = llvm::dyn_cast< llvm::ArrayType >(*it)) { ar_type = ar::ArrayType::get(this->_context, ar_type, ar::ZNumber(array_type->getNumElements())); } else if (auto vector_type = llvm::dyn_cast< llvm::VectorType >(*it)) { ar_type = ar::VectorType::get(this->_context, ar::cast< ar::ScalarType >(ar_type), ar::ZNumber(vector_type->getElementCount() .getFixedValue())); } else if (auto struct_type = llvm::dyn_cast< llvm::StructType >(*it)) { // This is the last element of di_type->getElements() ar::StructType::Layout ar_layout; const llvm::StructLayout* struct_layout = this->_llvm_data_layout.getStructLayout(struct_type); for (unsigned i = 0; i < struct_type->getNumElements(); i++) { ar::ZNumber offset(struct_layout->getElementOffset(i)); ar_type = this->translate_type(struct_type->getElementType(i), di_final_element); ar_layout.push_back({offset, ar_type}); } ar_type = ar::StructType::create(this->_context, ar_layout, true); } else if (llvm::isa< llvm::PointerType >(*it)) { ar_type = ar::PointerType::get(this->_context, ar_type); } else { ikos_unreachable("unreachable"); } this->sanity_check_size(*it, ar_type); } this->store_translation(type, di_type, ar_type); return ar_type; } /* * Helper functions for translate_struct_di_type */ /// \brief Remove any typedef/const/volatile/etc. qualifier static llvm::DIType* remove_di_qualifiers(llvm::DIType* type) { while (type != nullptr && !type->isForwardDecl() && llvm::isa< llvm::DIDerivedType >(type)) { auto derived_type = llvm::cast< llvm::DIDerivedType >(type); if (derived_type->getTag() == dwarf::DW_TAG_typedef || derived_type->getTag() == dwarf::DW_TAG_const_type || derived_type->getTag() == dwarf::DW_TAG_volatile_type || derived_type->getTag() == dwarf::DW_TAG_restrict_type || derived_type->getTag() == dwarf::DW_TAG_atomic_type) { type = llvm::cast_or_null< llvm::DIType >(derived_type->getRawBaseType()); } else { break; } } return type; } /// \brief Return the parent class of a class, given the llvm::DIDerivedType* static llvm::DICompositeType* get_composite_parent( llvm::DIDerivedType* di_member) { ikos_assert(di_member->getTag() == dwarf::DW_TAG_inheritance); check_import(di_member->getRawBaseType() != nullptr, "unexpected null pointer in member of llvm DICompositeType"); auto di_member_base = llvm::cast< llvm::DIType >(di_member->getRawBaseType()); di_member_base = remove_di_qualifiers(di_member_base); check_import(llvm::isa< llvm::DICompositeType >(di_member_base), "llvm DIDerivedType with inheritance tag, but the base type is " "not a DICompositeType"); auto di_parent = llvm::cast< llvm::DICompositeType >(di_member_base); check_import(di_parent->getTag() == dwarf::DW_TAG_structure_type || di_parent->getTag() == dwarf::DW_TAG_class_type, "llvm DIDerivedType with inheritance tag, but the base type " "does not have structure or class tag"); return di_parent; } // forward declaration static bool is_empty_composite(llvm::DICompositeType* di_type); /// \brief Return true if the given list has no non-static member field template < typename Iterator > static bool has_no_member(Iterator begin, Iterator end) { return std::all_of(begin, end, [](llvm::DINode* t) { if (llvm::isa< llvm::DISubprogram >(t)) { return true; } else if (llvm::cast< llvm::DIType >(t)->isStaticMember()) { return true; } else if (llvm::isa< llvm::DIDerivedType >(t)) { auto di_member = llvm::cast< llvm::DIDerivedType >(t); if (di_member->getTag() == dwarf::DW_TAG_member) { return false; } else if (di_member->getTag() == dwarf::DW_TAG_inheritance) { return is_empty_composite(get_composite_parent(di_member)); } else { throw ImportError("unexpected tag for member of llvm DICompositeType"); } } else { throw ImportError("unexpected element in llvm DICompositeType"); } }); } /// \brief Return true if the given llvm::DICompositeType* is an empty /// structure or class (no non-static member field) static bool is_empty_composite(llvm::DICompositeType* di_type) { if (di_type->isForwardDecl()) { return false; // assume it's not empty } check_import(di_type->getRawElements() != nullptr, "unexpected null pointer for elements in llvm DICompositeType"); llvm::DINodeArray di_elements = di_type->getElements(); return has_no_member(di_elements.begin(), di_elements.end()); } enum FieldPosition { Before, Inside, Overlap, After, }; /// \brief Position of B relative to A static FieldPosition get_relative_position(const ar::ZNumber& a_offset, const ar::ZNumber& a_size, const ar::ZNumber& b_offset, const ar::ZNumber& b_size) { if (a_offset <= b_offset) { if ((a_size > 0 && b_offset < (a_offset + a_size)) || (a_size == 0 && b_offset <= a_offset)) { if (b_offset + b_size <= a_offset + a_size) { return Inside; } else { return Overlap; } } else { return After; } } else { if (b_offset + b_size >= a_offset) { return Overlap; } else { return Before; } } } /// \brief Return true if the given llvm::Type is a base subobject static bool is_base_subobject(llvm::DIDerivedType* di_member, llvm::Type* member) { if (di_member->getTag() == dwarf::DW_TAG_inheritance && llvm::isa< llvm::StructType >(member)) { auto struct_type = llvm::cast< llvm::StructType >(member); return struct_type->hasName() && (struct_type->getName().startswith("struct.") || struct_type->getName().startswith("class.")) && struct_type->getName().endswith(".base"); } return false; } ar::StructType* TypeWithDebugInfoImporter::translate_struct_di_type( llvm::DICompositeType* di_type, llvm::Type* type) { check_match(type->isStructTy(), "llvm DICompositeType with structure or class tag, but llvm type " "is not a structure type"); auto struct_type = llvm::cast< llvm::StructType >(type); check_match(!struct_type->isOpaque(), "unexpected opaque llvm structure type"); check_match(struct_type->isSized(), "unexpected unsized llvm structure type"); const llvm::StructLayout* struct_layout = this->_llvm_data_layout.getStructLayout(struct_type); check_match(llvm::alignTo(di_type->getSizeInBits(), static_cast< uint64_t >( struct_layout->getAlignment().value()) * 8) == struct_layout->getSizeInBits(), "llvm DICompositeType and llvm structure type have a different " "bit-width"); // Structures can be recursive, so create it now, with an empty layout ar::StructType* ar_type = ar::StructType::create(this->_context, struct_type->isPacked()); this->store_translation(type, di_type, ar_type); this->_translation_depth++; // recursive type, not complete yet // Create an empty layout ar::StructType::Layout ar_layout; ar_layout.reserve(struct_type->getNumElements()); // Collect debug info members check_import(di_type->getRawElements() != nullptr, "unexpected null pointer for elements in llvm DICompositeType"); llvm::DINodeArray di_elements = di_type->getElements(); std::vector< llvm::DIDerivedType* > di_members; di_members.reserve(di_elements.size()); for (llvm::DINode* di_element : di_elements) { // Skip methods and static members if (llvm::isa< llvm::DISubprogram >(di_element) || llvm::cast< llvm::DIType >(di_element)->isStaticMember()) { continue; } check_import(llvm::isa< llvm::DIDerivedType >(di_element), "unexpected element in llvm DICompositeType"); di_members.push_back(llvm::cast< llvm::DIDerivedType >(di_element)); } // Sort debug info members by offset std::stable_sort(di_members.begin(), di_members.end(), [](llvm::DIDerivedType* a, llvm::DIDerivedType* b) { return a->getOffsetInBits() < b->getOffsetInBits(); }); // Iterate over the struct_type layout, // Matching members from debug info and llvm type llvm::SmallVector< llvm::DIDerivedType*, 3 > di_matching_members; bool has_virtual_bases = false; auto di_member_it = di_members.begin(); for (unsigned i = 0; i < struct_type->getNumElements(); i++) { // llvm struct member llvm::Type* element_type = struct_type->getElementType(i); ar::ZNumber element_offset_bytes(struct_layout->getElementOffset(i)); ar::ZNumber element_size_bytes( this->_llvm_data_layout.getTypeStoreSize(element_type).getFixedSize()); // Find matching debug info di_matching_members.clear(); // Field is a bit-field bool is_bit_field = false; while (di_member_it != di_members.end()) { llvm::DIDerivedType* di_member = *di_member_it; ar::ZNumber di_offset_bits(di_member->getOffsetInBits()); ar::ZNumber di_size_bits; if (di_member->getTag() == dwarf::DW_TAG_member) { di_size_bits = di_member->getSizeInBits(); } else if (di_member->getTag() == dwarf::DW_TAG_inheritance) { llvm::DICompositeType* di_member_base = get_composite_parent(di_member); di_size_bits = di_member_base->getSizeInBits(); // Skip empty classes and structures in C++ if (this->_is_cpp && is_empty_composite(di_member_base)) { ++di_member_it; continue; } // Handle virtual inheritance if (this->_is_cpp && di_member->isVirtual()) { has_virtual_bases = true; ++di_member_it; continue; } } else { throw ImportError("unsupported tag for member of llvm DICompositeType"); } FieldPosition pos = get_relative_position(element_offset_bytes * 8, element_size_bytes * 8, di_offset_bits, di_size_bits); // Base subobject, for virtual inheritance and ABI issues if (this->_is_cpp && is_base_subobject(di_member, element_type)) { has_virtual_bases = true; ++di_member_it; break; } // Field is an empty structure in C // In this case, it overlaps with the next field if (this->_is_c && (pos == Inside || pos == Overlap) && !di_matching_members.empty() && element_size_bytes == 0 && element_offset_bytes * 8 == di_offset_bits && (element_type->isStructTy() || element_type->isArrayTy())) { break; } // Field is an overlapping bit-field if (pos == Overlap && di_member->isBitField()) { is_bit_field = true; di_matching_members.push_back(di_member); ++di_member_it; continue; } if (pos == Inside) { is_bit_field = is_bit_field || di_member->isBitField(); di_matching_members.push_back(di_member); ++di_member_it; } else if (pos == After) { break; } else { throw TypeDebugInfoMismatch( "structure member of llvm DICompositeType does not match any " "member in llvm structure type"); } } if (di_matching_members.size() == 1 && !is_bit_field) { // Only one DIDerivedType matches the structure member llvm::DIDerivedType* di_member = di_matching_members[0]; ar::ZNumber di_offset_bits(di_member->getOffsetInBits()); check_match(di_offset_bits == element_offset_bytes * 8, "llvm DIDerivedType with member or class tag and llvm type " "have a different offset"); auto di_member_base = llvm::cast< llvm::DIType >(di_member->getRawBaseType()); ar::Type* ar_element_type = this->translate_type(element_type, di_member_base); ar_layout.push_back({element_offset_bytes, ar_element_type}); } else if (!di_matching_members.empty() && is_bit_field) { // One or more DIDerivedType matches the structure member, and // One of them has a DIFlagBitField. check_match(element_type->isIntegerTy() || (element_type->isArrayTy() && llvm::cast< llvm::ArrayType >(element_type) ->getElementType() ->isIntegerTy(8)), "llvm structure member matches several bit-field llvm " "DIDerivedType, but llvm type is not iX or [X x i8]"); ar::Type* ar_element_type = this->_type_sign_imp.translate_type(element_type, ar::Unsigned); ar_layout.push_back({element_offset_bytes, ar_element_type}); } else if (!di_matching_members.empty()) { throw TypeDebugInfoMismatch( "llvm structure member matches several llvm DIDerivedType, and none " "of them has a bitfield flag"); } else { // di_matching_members is empty if (has_virtual_bases && element_type->isStructTy()) { ar::Type* ar_element_type = this->_type_sign_imp.translate_type(element_type, ar::Signed); ar_layout.push_back({element_offset_bytes, ar_element_type}); } else if (element_type->isIntegerTy(8) || (element_type->isArrayTy() && llvm::cast< llvm::ArrayType >(element_type) ->getElementType() ->isIntegerTy(8))) { // padding i8 or [n x i8] // // This is added by clang for different reasons: // * Bit-fields // * Packed structures // * Alignment for inheritance // * Empty structure in C++, translated into { i8 } ar::Type* ar_element_type = this->_type_sign_imp.translate_type(element_type, ar::Signed); ar_layout.push_back({element_offset_bytes, ar_element_type}); } else { throw TypeDebugInfoMismatch( "no matching llvm DIDerivedType for llvm structure member"); } } } check_match(has_no_member(di_member_it, di_members.end()), "no matching llvm structure member for llvm DIDerivedType"); ar_type->set_layout(ar_layout); this->_translation_depth--; this->sanity_check_size(struct_type, ar_type); return ar_type; } ar::Type* TypeWithDebugInfoImporter::translate_union_di_type( llvm::DICompositeType* di_type, llvm::Type* type) { check_import(di_type->getRawElements() != nullptr, "unexpected null pointer for elements in llvm DICompositeType"); llvm::DINodeArray di_members = di_type->getElements(); check_match(type->isStructTy(), "llvm DICompositeType with union tag, but llvm type is not a " "structure type"); auto struct_type = llvm::cast< llvm::StructType >(type); check_match(!struct_type->isOpaque(), "unexpected opaque llvm structure type"); check_match(struct_type->isSized(), "unexpected unsized llvm structure type"); if (struct_type->getNumElements() == 0) { // Empty union check_match(di_members.begin() == di_members.end(), "empty llvm structure type, but llvm DICompositeType with " "union tag is not empty"); ar::StructType* ar_type = ar::StructType::create(this->_context, struct_type->isPacked()); this->store_translation(type, di_type, ar_type); return ar_type; } check_match(struct_type->getNumElements() <= 2, "llvm DICompositeType with union tag, but llvm structure type " "has more than 2 members"); llvm::Type* inner_type = struct_type->getElementType(0); llvm::Type* padding_type = nullptr; if (struct_type->getNumElements() == 2) { padding_type = struct_type->getElementType(1); check_match(padding_type->isArrayTy() && llvm::cast< llvm::ArrayType >(padding_type) ->getElementType() ->isIntegerTy(8), "llvm DICompositeType with union tag, but the second member of " "the llvm structure type does not correspond to padding"); } const llvm::StructLayout* struct_layout = this->_llvm_data_layout.getStructLayout(struct_type); check_match(llvm::alignTo(di_type->getSizeInBits(), static_cast< uint64_t >( struct_layout->getAlignment().value()) * 8) == struct_layout->getSizeInBits(), "llvm DICompositeType and llvm structure type have a different " "bit-width"); // Structures can be recursive, so create it now, with an empty layout ar::StructType* ar_type = ar::StructType::create(this->_context, struct_type->isPacked()); // Find the first member matching the llvm::StructType for (llvm::DINode* di_member_node : di_members) { // Skip methods and static members if (llvm::isa< llvm::DISubprogram >(di_member_node) || llvm::cast< llvm::DIType >(di_member_node)->isStaticMember()) { continue; } auto di_member = llvm::cast< llvm::DIDerivedType >(di_member_node); check_import(di_member->getTag() == dwarf::DW_TAG_member, "unsupported tag for union member of llvm DICompositeType"); check_import(di_member->getRawBaseType() != nullptr, "unexpected null pointer in union member of llvm " "DICompositeType"); auto di_member_type = llvm::cast< llvm::DIType >(di_member->getRawBaseType()); // Bit-field in union type if (di_member->isBitField() && llvm::isa< llvm::DIBasicType >(di_member_type) && inner_type->isIntegerTy() && llvm::cast< llvm::IntegerType >(inner_type)->getBitWidth() == di_member->getSizeInBits()) { ar_type = ar::cast< ar::StructType >( this->_type_sign_imp.translate_type(struct_type, ar::Signed)); this->sanity_check_size(struct_type, ar_type); this->store_translation(type, di_type, ar_type); return ar_type; } try { // Try to translate inner_type with di_member_type TypeWithDebugInfoImporter imp = this->fork(); imp.store_translation(type, di_type, ar_type); ar::Type* ar_inner_type = imp.translate_type(inner_type, di_member_type); this->join(imp); ar::StructType::Layout ar_layout; // inner type ar_layout.push_back({ar::ZNumber(0), ar_inner_type}); // padding type, [n x i8] if (padding_type != nullptr) { ar::Type* ar_padding_type = this->_type_sign_imp.translate_type(padding_type, ar::Signed); ar::ZNumber padding_offset_bytes(struct_layout->getElementOffset(1)); ar_layout.push_back({padding_offset_bytes, ar_padding_type}); } ar_type->set_layout(ar_layout); this->sanity_check_size(struct_type, ar_type); return ar_type; } catch (const TypeDebugInfoMismatch&) { } } throw TypeDebugInfoMismatch( "could not translate llvm DICompositeType with union tag"); } ar::Type* TypeWithDebugInfoImporter::translate_enum_di_type( llvm::DICompositeType* di_type, llvm::Type* type) { check_match(type->isIntegerTy(), "llvm DICompositeType with enumeration tag, but llvm type is " "not an integer type"); auto int_type = llvm::cast< llvm::IntegerType >(type); check_match(di_type->getSizeInBits() == int_type->getBitWidth(), "llvm DICompositeType with enumeration tag and llvm integer " "type have a different bit-width"); ar::Type* ar_type = ar::IntegerType::get(this->_context, int_type->getBitWidth(), ar::Unsigned); this->store_translation(type, di_type, ar_type); return ar_type; } /// \brief Return true if the function is a constructor of a structure or class /// with virtual inheritance, such as void f(struct.F*, i8**) static bool is_constructor_with_virtual_base(llvm::FunctionType* fun_type) { if (fun_type->getReturnType()->isVoidTy() && fun_type->getNumParams() == 2) { llvm::Type* fst = fun_type->getParamType(0); llvm::Type* snd = fun_type->getParamType(1); return fst->isPointerTy() && llvm::cast< llvm::PointerType >(fst) ->getPointerElementType() ->isStructTy() && snd->isPointerTy() && llvm::cast< llvm::PointerType >(snd) ->getPointerElementType() ->isPointerTy() && llvm::cast< llvm::PointerType >( llvm::cast< llvm::PointerType >(snd)->getPointerElementType()) ->getPointerElementType() ->isIntegerTy(8); } return false; } ar::Type* TypeWithDebugInfoImporter::translate_subroutine_di_type( llvm::DISubroutineType* di_type, llvm::Type* type) { if (ikos_unlikely(type->isStructTy())) { // This should be very rare, but we can have a function pointer type // translated into a pointer on an empty structure. auto struct_type = llvm::cast< llvm::StructType >(type); check_match(!struct_type->isOpaque() && !struct_type->isPacked() && struct_type->getNumElements() == 0, "llvm DISubroutineType, but llvm type is a non-empty structure " "type"); ar::StructType* ar_type = ar::StructType::create(this->_context, false); this->store_translation(type, di_type, ar_type); this->sanity_check_size(struct_type, ar_type); return ar_type; } check_match(type->isFunctionTy(), "llvm DISubroutineType, but llvm type is not a function type"); auto fun_type = llvm::cast< llvm::FunctionType >(type); llvm::DITypeRefArray di_params = di_type->getTypeArray(); if (di_params.size() == 0) { // Empty debug info parameters check_match(fun_type->getReturnType()->isVoidTy() && fun_type->getNumParams() == 0 && !fun_type->isVarArg(), "llvm DISubroutineType type array is empty but llvm function " "type is not void(*)()"); ar::FunctionType* ar_type = ar::FunctionType::get(this->_context, ar::VoidType::get(this->_context), ar::FunctionType::ParamTypes(), false); this->store_translation(type, di_type, ar_type); return ar_type; } // Function attributes bool var_arg = fun_type->isVarArg(); // Return type llvm::DIType* di_ret_type = di_params[0]; llvm::Type* ret_type = fun_type->getReturnType(); ar::Type* ar_ret_type = nullptr; // Parameters auto param_it = fun_type->param_begin(); auto param_et = fun_type->param_end(); auto di_param_it = di_params.begin(); auto di_param_et = di_params.end(); // Return type if (ret_type->isVoidTy() && remove_di_qualifiers(di_ret_type) != nullptr) { // Structure returned as first parameter (see sret attribute) ar_ret_type = ar::VoidType::get(this->_context); } else { try { TypeWithDebugInfoImporter imp = this->fork(); ar_ret_type = imp.translate_type(ret_type, di_ret_type); this->join(imp); } catch (const TypeDebugInfoMismatch&) { ar_ret_type = this->_type_sign_imp.translate_type(ret_type, ar::Signed); } di_param_it++; } // Parameters ar::FunctionType::ParamTypes ar_params; ar_params.reserve(fun_type->getNumParams()); // If a structure is split into several fields llvm::StructType* split_struct = nullptr; llvm::SmallVector< llvm::Type*, 4 > split_struct_elements; for (; param_it != param_et; ++param_it) { llvm::Type* param_type = *param_it; if (di_param_it == di_param_et && this->_is_cpp && is_constructor_with_virtual_base(fun_type) && std::next(param_it) == param_et) { // Last parameter of a constructor of a structure or class // with virtual inheritance, such as void f(struct.F*, i8**) ar::Type* ar_param = this->_type_sign_imp.translate_type(param_type, ar::Signed); ar_params.push_back(ar_param); break; } check_match(di_param_it != di_param_et, "llvm DISubroutineType and llvm function type have a different " "number of parameters [1]"); llvm::DIType* di_param_type = *di_param_it; di_param_type = remove_di_qualifiers(di_param_type); check_import(di_param_type != nullptr, "unexpected null pointer in parameters of llvm " "DISubroutineType"); if (split_struct != nullptr) { // Current di_param_type is a structure split into several arguments ar::Type* ar_param = this->_type_sign_imp.translate_type(param_type, ar::Signed); ar_params.push_back(ar_param); split_struct_elements.push_back(param_type); split_struct = llvm::StructType::create(split_struct_elements); if (this->_llvm_data_layout.getTypeSizeInBits(split_struct) >= di_param_type->getSizeInBits()) { split_struct = nullptr; split_struct_elements.clear(); ++di_param_it; } continue; } if (auto comp_di_param_type = llvm::dyn_cast< llvm::DICompositeType >(di_param_type)) { auto tag = static_cast< dwarf::Tag >(comp_di_param_type->getTag()); if (tag == dwarf::DW_TAG_structure_type || tag == dwarf::DW_TAG_class_type || tag == dwarf::DW_TAG_union_type) { // Debug info parameter is a structure, class or union if (auto ptr_param_type = llvm::dyn_cast< llvm::PointerType >(param_type)) { llvm::Type* pointee_param_type = ptr_param_type->getPointerElementType(); if (pointee_param_type->isStructTy()) { try { // Structure passed by pointer (see byval attribute) TypeWithDebugInfoImporter imp = this->fork(); ar::Type* ar_pointee_param = imp.translate_type(pointee_param_type, di_param_type); this->join(imp); ar::Type* ar_param = ar::PointerType::get(this->_context, ar_pointee_param); ar_params.push_back(ar_param); ++di_param_it; continue; } catch (const TypeDebugInfoMismatch&) { } } } if (!param_type->isStructTy()) { // Structure split into several arguments ar::Type* ar_param = this->_type_sign_imp.translate_type(param_type, ar::Signed); ar_params.push_back(ar_param); if (this->_llvm_data_layout.getTypeSizeInBits(param_type) >= di_param_type->getSizeInBits()) { ++di_param_it; } else { split_struct_elements.clear(); split_struct_elements.push_back(param_type); split_struct = llvm::StructType::create(split_struct_elements); } continue; } } } // Otherwise ar::Type* ar_param = this->translate_type(param_type, di_param_type); ar_params.push_back(ar_param); ++di_param_it; } check_match(split_struct == nullptr, "llvm DISubroutineType and llvm function type have a different " "number of parameters [2]"); // TODO: In c++, empty structures or classes can be entirely removed from the // interface. We do not currently handle it here. check_match(di_param_it == di_param_et || std::all_of(di_param_it, di_param_et, [](llvm::DIType* di_param) { return di_param == nullptr; }) || this->_is_cpp, "llvm DISubroutineType and llvm function type have a different " "number of parameters [3]"); ar::FunctionType* ar_type = ar::FunctionType::get(this->_context, ar_ret_type, ar_params, var_arg); this->store_translation(type, di_type, ar_type); return ar_type; } ar::FunctionType* TypeWithDebugInfoImporter::translate_function_di_type( llvm::Function* fun, llvm::DISubroutineType* di_type) { check_import(di_type != nullptr, "unexpected null pointer for llvm DISubroutineType of llvm " "function"); return ar::cast< ar::FunctionType >( this->translate_subroutine_di_type(di_type, fun->getFunctionType())); } TypeMatcher::TypeMatcher(ImportContext& ctx) : _llvm_data_layout(ctx.llvm_data_layout) {} TypeMatcher::~TypeMatcher() = default; bool TypeMatcher::match_type(llvm::Type* llvm_type, ar::Type* ar_type) { return this->match_type(llvm_type, ar_type, ARTypeSet{}); } bool TypeMatcher::match_type(llvm::Type* llvm_type, ar::Type* ar_type, ARTypeSet seen) { if (llvm_type->isVoidTy()) { return ar_type->is_void(); } else if (llvm_type->isIntegerTy()) { return this->match_integer_type(llvm_type, ar_type); } else if (llvm_type->isFloatingPointTy()) { return this->match_floating_point_type(llvm_type, ar_type); } else if (llvm_type->isPointerTy()) { return this->match_pointer_type(llvm_type, ar_type, std::move(seen)); } else if (llvm_type->isArrayTy()) { return this->match_array_type(llvm_type, ar_type, std::move(seen)); } else if (llvm_type->isVectorTy()) { return this->match_vector_type(llvm_type, ar_type, std::move(seen)); } else if (llvm_type->isStructTy()) { return this->match_struct_type(llvm_type, ar_type, std::move(seen)); } else if (llvm_type->isFunctionTy()) { return this->match_function_type(llvm_type, ar_type, std::move(seen)); } else { throw ImportError("unsupported llvm type"); } } bool TypeMatcher::match_integer_type(llvm::Type* llvm_type, ar::Type* ar_type) { return ar_type->is_integer() && llvm::cast< llvm::IntegerType >(llvm_type)->getBitWidth() == ar::cast< ar::IntegerType >(ar_type)->bit_width(); } bool TypeMatcher::match_floating_point_type(llvm::Type* llvm_type, ar::Type* ar_type) { if (!ar_type->is_float()) { return false; } auto ar_float_type = ar::cast< ar::FloatType >(ar_type); if (llvm_type->isHalfTy()) { return ar_float_type->float_semantic() == ar::Half; } else if (llvm_type->isFloatTy()) { return ar_float_type->float_semantic() == ar::Float; } else if (llvm_type->isDoubleTy()) { return ar_float_type->float_semantic() == ar::Double; } else if (llvm_type->isX86_FP80Ty()) { return ar_float_type->float_semantic() == ar::X86_FP80; } else if (llvm_type->isFP128Ty()) { return ar_float_type->float_semantic() == ar::FP128; } else if (llvm_type->isPPC_FP128Ty()) { return ar_float_type->float_semantic() == ar::PPC_FP128; } else { throw ImportError("unsupported llvm floating point type"); } } bool TypeMatcher::match_pointer_type(llvm::Type* llvm_type, ar::Type* ar_type, ARTypeSet seen) { if (!ar_type->is_pointer()) { return false; } auto llvm_pointee_type = llvm::cast< llvm::PointerType >(llvm_type)->getPointerElementType(); auto ar_pointee_type = ar::cast< ar::PointerType >(ar_type)->pointee(); return this->match_type(llvm_pointee_type, ar_pointee_type, std::move(seen)); } bool TypeMatcher::match_array_type(llvm::Type* llvm_type, ar::Type* ar_type, ARTypeSet seen) { if (!ar_type->is_array()) { return false; } auto llvm_array_type = llvm::cast< llvm::ArrayType >(llvm_type); auto ar_array_type = ar::cast< ar::ArrayType >(ar_type); return llvm_array_type->getNumElements() == ar_array_type->num_elements() && this->match_type(llvm_array_type->getElementType(), ar_array_type->element_type(), std::move(seen)); } bool TypeMatcher::match_vector_type(llvm::Type* llvm_type, ar::Type* ar_type, ARTypeSet seen) { if (!ar_type->is_vector()) { return false; } auto llvm_vec_type = llvm::cast< llvm::VectorType >(llvm_type); auto ar_vec_type = ar::cast< ar::VectorType >(ar_type); return llvm_vec_type->getElementCount().getFixedValue() == ar_vec_type->num_elements() && this->match_type(llvm_vec_type->getElementType(), ar_vec_type->element_type(), std::move(seen)); } bool TypeMatcher::match_struct_type(llvm::Type* llvm_type, ar::Type* ar_type, ARTypeSet seen) { auto llvm_struct_type = llvm::cast< llvm::StructType >(llvm_type); if (llvm_struct_type->isOpaque()) { return ar_type->is_opaque(); } if (!ar_type->is_struct()) { return false; } auto ar_struct_type = ar::cast< ar::StructType >(ar_type); if (llvm_struct_type->isPacked() != ar_struct_type->packed() || llvm_struct_type->getNumElements() != ar_struct_type->num_fields()) { return false; } // Avoid infinite recursion auto p = seen.insert({llvm_type, ar_type}); if (!p.second) { return true; // already processing } const llvm::StructLayout* llvm_struct_layout = this->_llvm_data_layout.getStructLayout(llvm_struct_type); auto it = ar_struct_type->field_begin(); for (unsigned i = 0; i < llvm_struct_type->getNumElements(); ++i, ++it) { llvm::Type* llvm_element_type = llvm_struct_type->getElementType(i); uint64_t llvm_element_offset = llvm_struct_layout->getElementOffset(i); if (llvm_element_offset != it->offset || !this->match_type(llvm_element_type, it->type, seen)) { return false; } } return true; } bool TypeMatcher::match_function_type(llvm::Type* llvm_type, ar::Type* ar_type, ARTypeSet seen) { auto llvm_fun_type = llvm::cast< llvm::FunctionType >(llvm_type); if (!ar_type->is_function()) { return false; } auto ar_fun_type = ar::cast< ar::FunctionType >(ar_type); if (llvm_fun_type->isVarArg() != ar_fun_type->is_var_arg() || llvm_fun_type->getNumParams() != ar_fun_type->num_parameters()) { return false; } if (!this->match_type(llvm_fun_type->getReturnType(), ar_fun_type->return_type(), seen)) { return false; } return std::equal(llvm_fun_type->param_begin(), llvm_fun_type->param_end(), ar_fun_type->param_begin(), [&](llvm::Type* a, ar::Type* b) { return this->match_type(a, b, seen); }); } bool TypeMatcher::match_extern_function_type(llvm::FunctionType* llvm_type, ar::FunctionType* ar_type) { if (llvm_type->isVarArg() != ar_type->is_var_arg() || llvm_type->getNumParams() != ar_type->num_parameters()) { return false; } if (!this->match_extern_function_param_type(llvm_type->getReturnType(), ar_type->return_type())) { return false; } return std::equal(llvm_type->param_begin(), llvm_type->param_end(), ar_type->param_begin(), [&](llvm::Type* a, ar::Type* b) { return this->match_extern_function_param_type(a, b); }); } bool TypeMatcher::match_extern_function_param_type(llvm::Type* llvm_type, ar::Type* ar_type) { if (llvm_type->isPointerTy()) { // Allow `{}*` to match with `opaque*` if (!ar_type->is_pointer()) { return false; } auto llvm_pointee_type = llvm::cast< llvm::PointerType >(llvm_type)->getPointerElementType(); auto ar_pointee_type = ar::cast< ar::PointerType >(ar_type)->pointee(); return (llvm_pointee_type->isStructTy() && ar_pointee_type->is_opaque()) || this->match_type(llvm_pointee_type, ar_pointee_type); } else { return this->match_type(llvm_type, ar_type); } } TypeImporter::TypeImporter(ImportContext& ctx) : _type_sign_imp(ctx), _type_di_imp(ctx, this->_type_sign_imp), _type_match(ctx) {} ar::Type* TypeImporter::translate_type(llvm::Type* type, ar::Signedness preferred) { return this->_type_sign_imp.translate_type(type, preferred); } ar::Type* TypeImporter::translate_type(llvm::Type* type, llvm::DIType* di_type) { TypeWithDebugInfoImporter imp = this->_type_di_imp.fork(); ar::Type* ar_type = imp.translate_type(type, di_type); this->_type_di_imp.join(imp); return ar_type; } ar::FunctionType* TypeImporter::translate_function_type( llvm::Function* fun, llvm::DISubroutineType* di_type) { TypeWithDebugInfoImporter imp = this->_type_di_imp.fork(); ar::FunctionType* ar_type = imp.translate_function_di_type(fun, di_type); this->_type_di_imp.join(imp); return ar_type; } bool TypeImporter::match_type(llvm::Type* llvm_type, ar::Type* ar_type) { return this->_type_match.match_type(llvm_type, ar_type); } bool TypeImporter::match_extern_function_type(llvm::FunctionType* llvm_type, ar::FunctionType* ar_type) { return this->_type_match.match_extern_function_type(llvm_type, ar_type); } } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/import/type.hpp000066400000000000000000000420171473507761200232060ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Translate LLVM types and Debug Information into AR types * * Author: Maxime Arthaud * Nija Shi * Arnaud Venet * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include "import_context.hpp" namespace llvm { template < typename T > struct DenseMapInfo< std::pair< T, ikos::ar::Signedness > > { using FirstInfo = DenseMapInfo< T >; static inline std::pair< T, ikos::ar::Signedness > getEmptyKey() { return {FirstInfo::getEmptyKey(), ikos::ar::Signed}; } static inline std::pair< T, ikos::ar::Signedness > getTombstoneKey() { return {FirstInfo::getTombstoneKey(), ikos::ar::Signed}; } static unsigned getHashValue(const std::pair< T, ikos::ar::Signedness >& p) { return DenseMapInfo< std::pair< T, char > >::getHashValue( {p.first, static_cast< char >(p.second)}); } static bool isEqual(const std::pair< T, ikos::ar::Signedness >& lhs, const std::pair< T, ikos::ar::Signedness >& rhs) { return FirstInfo::isEqual(lhs.first, rhs.first) && lhs.second == rhs.second; } }; } // end namespace llvm namespace ikos { namespace frontend { namespace import { /// \brief Helper class to translate types with a given signedness class TypeWithSignImporter { private: // AR context ar::Context& _context; // LLVM data layout const llvm::DataLayout& _llvm_data_layout; // AR data layout const ar::DataLayout& _ar_data_layout; // Current call depth of translation // // This is used to know if some types (e.g, structures) are still being build. unsigned _translation_depth; // Map from LLVM type + signedness to AR type llvm::DenseMap< std::pair< llvm::Type*, ar::Signedness >, ar::Type* > _map; public: /// \brief Public constructor explicit TypeWithSignImporter(ImportContext& ctx); /// \brief No default constructor TypeWithSignImporter() = delete; /// \brief No copy constructor TypeWithSignImporter(const TypeWithSignImporter&) = delete; /// \brief No move constructor TypeWithSignImporter(TypeWithSignImporter&&) = delete; /// \brief No copy assignment operator TypeWithSignImporter& operator=(const TypeWithSignImporter&) = delete; /// \brief No move assignment operator TypeWithSignImporter& operator=(TypeWithSignImporter&&) = delete; /// \brief Destructor ~TypeWithSignImporter(); /// \brief Translate a pair (llvm::Type*, ar::Signedness) into an ar::Type /// /// \param type LLVM type /// \param preferred Preferred signedness /// /// \throws ImportError for unsupported types ar::Type* translate_type(llvm::Type* type, ar::Signedness preferred); private: /// \brief Store the translation result from (llvm::Type*, ar::Signedness) to /// ar::Type* void store_translation(llvm::Type*, ar::Signedness, ar::Type*); /// \brief Check that the llvm::Type and ar::Type have the same size void sanity_check_size(llvm::Type*, ar::Type*); /// \brief Translate a llvm::Type* into an ar::VoidType ar::VoidType* translate_void_type(llvm::Type*, ar::Signedness); /// \brief Translate a llvm::Type* into an ar::IntegerType ar::IntegerType* translate_integer_type(llvm::Type*, ar::Signedness); /// \brief Translate a llvm::Type* into an ar::FloatType ar::FloatType* translate_floating_point_type(llvm::Type*, ar::Signedness); /// \brief Translate a llvm::Type* into an ar::PointerType ar::PointerType* translate_pointer_type(llvm::Type*, ar::Signedness); /// \brief Translate a llvm::Type* into an ar::ArrayType ar::ArrayType* translate_array_type(llvm::Type*, ar::Signedness); /// \brief Translate a llvm::Type* into an ar::VectorType ar::VectorType* translate_vector_type(llvm::Type*, ar::Signedness); /// \brief Translate a llvm::Type* into an ar::StructType ar::Type* translate_struct_type(llvm::Type*, ar::Signedness); /// \brief Translate a llvm::Type* into an ar::FunctionType ar::FunctionType* translate_function_type(llvm::Type*, ar::Signedness); }; // end class TypeWithSignImporter /// \brief Helper class to translate types with debug info class TypeWithDebugInfoImporter { private: // AR context ar::Context& _context; // LLVM data layout const llvm::DataLayout& _llvm_data_layout; // AR data layout const ar::DataLayout& _ar_data_layout; // Is C one of the input source languages? bool _is_c; // Is C++ one of the input source languages? bool _is_cpp; // Current call depth of translation // // This is used to know if some types (e.g, structures) are still being build. unsigned _translation_depth; // Helper class to translate types with a given signedness TypeWithSignImporter& _type_sign_imp; // Parent importer, or nullptr // // This contains a map with already translated types const TypeWithDebugInfoImporter* _parent; // Map from LLVM type + LLVM debug info to AR type // // This map might have incomplete types during the translation because of // recursive types (struct or union). If a mismatch occurs, this map should be // discarded. llvm::DenseMap< std::pair< llvm::Type*, llvm::DIType* >, ar::Type* > _map; private: /// \brief Private constructor TypeWithDebugInfoImporter(ar::Context& context, const llvm::DataLayout& llvm_data_layout, const ar::DataLayout& ar_data_layout, bool is_c, bool is_cpp, unsigned translation_depth, TypeWithSignImporter& type_sign_imp, const TypeWithDebugInfoImporter* parent); public: /// \brief Public constructor explicit TypeWithDebugInfoImporter(ImportContext& ctx, TypeWithSignImporter& type_sign_imp); /// \brief No default constructor TypeWithDebugInfoImporter() = delete; private: /// \brief Private copy constructor TypeWithDebugInfoImporter(const TypeWithDebugInfoImporter&) = default; public: /// \brief Move constructor TypeWithDebugInfoImporter(TypeWithDebugInfoImporter&&) = default; /// \brief No copy assignment operator TypeWithDebugInfoImporter& operator=(const TypeWithDebugInfoImporter&) = delete; /// \brief No move assignment operator TypeWithDebugInfoImporter& operator=(TypeWithDebugInfoImporter&&) = delete; /// \brief Destructor ~TypeWithDebugInfoImporter(); /// \brief Translate a pair (llvm::Type*, llvm::DIType*) into an ar::Type /// /// \param type LLVM type /// \param di_type LLVM Debug Info type /// /// \throws TypeDebugInfoMismatch for a mismatch between debug info and type /// \throws ImportError for unsupported types ar::Type* translate_type(llvm::Type* type, llvm::DIType* di_type); /// \brief Create a child TypeWithDebugInfoImporter fork() const; /// \brief Join with a child, saving the internal translation map void join(const TypeWithDebugInfoImporter&); private: /// \brief Store the translation result from (llvm::Type*, llvm::DIType*) /// to ar::Type* void store_translation(llvm::Type*, llvm::DIType*, ar::Type*); /// \brief Check that the llvm::Type and ar::Type have the same size void sanity_check_size(llvm::Type*, ar::Type*); /// \brief Translate a llvm::Type* with no debug info into an ar::Type ar::Type* translate_null_di_type(llvm::Type*); /// \brief Translate (llvm::DIType*, llvm::Type*) into an ar::Type ar::Type* translate_forward_decl_di_type(llvm::DIType*, llvm::Type*); /// \brief Translate (llvm::DIBasicType*, llvm::Type*) into an ar::Type ar::Type* translate_basic_di_type(llvm::DIBasicType*, llvm::Type*); /// \brief Translate (llvm::DIDerivedType*, llvm::Type*) into an ar::Type ar::Type* translate_derived_di_type(llvm::DIDerivedType*, llvm::Type*); /// \brief Translate (llvm::DIDerivedType*, llvm::Type*) into an ar::Type ar::Type* translate_qualified_di_type(llvm::DIDerivedType*, llvm::Type*); /// \brief Translate (llvm::DIDerivedType*, llvm::Type*) into ar::PointerType ar::PointerType* translate_pointer_di_type(llvm::DIDerivedType*, llvm::Type*); /// \brief Translate (llvm::DIDerivedType*, llvm::Type*) into ar::PointerType ar::PointerType* translate_reference_di_type(llvm::DIDerivedType*, llvm::Type*); /// \brief Translate (llvm::DICompositeType*, llvm::Type*) into an ar::Type ar::Type* translate_composite_di_type(llvm::DICompositeType*, llvm::Type*); /// \brief Translate (llvm::DICompositeType*, llvm::Type*) into ar::Type ar::Type* translate_array_di_type(llvm::DICompositeType*, llvm::Type*); /// \brief Translate (llvm::DICompositeType*, llvm::Type*) into ar::StructType ar::StructType* translate_struct_di_type(llvm::DICompositeType*, llvm::Type*); /// \brief Translate (llvm::DICompositeType*, llvm::Type*) into an ar::Type ar::Type* translate_union_di_type(llvm::DICompositeType*, llvm::Type*); /// \brief Translate (llvm::DICompositeType*, llvm::Type*) into an ar::Type ar::Type* translate_enum_di_type(llvm::DICompositeType*, llvm::Type*); /// \brief Translate (llvm::DISubroutineType*, llvm::Type*) into an ar::Type ar::Type* translate_subroutine_di_type(llvm::DISubroutineType*, llvm::Type*); public: /// \brief Translate a llvm::Function's type with debug info into an ar::Type* /// /// This is similar to translate_subroutine_di_type() but it takes the /// llvm::Function* rather than the llvm::Type*, to handle special attributes /// on arguments (e.g, byval). /// /// \param fun LLVM function /// \param di_type LLVM Debug Info type /// /// \throws TypeDebugInfoMismatch for a mismatch between debug info and type /// \throws ImportError for unsupported types ar::FunctionType* translate_function_di_type(llvm::Function* fun, llvm::DISubroutineType* di_type); }; // end class TypeWithDebugInfoImporter /// \brief Helper class to check if a LLVM type matches an AR type class TypeMatcher { private: // LLVM data layout const llvm::DataLayout& _llvm_data_layout; public: /// \brief Public constructor explicit TypeMatcher(ImportContext& ctx); /// \brief No default constructor TypeMatcher() = delete; /// \brief No copy constructor TypeMatcher(const TypeMatcher&) = delete; /// \brief No move constructor TypeMatcher(TypeMatcher&&) = delete; /// \brief No copy assignment operator TypeMatcher& operator=(const TypeMatcher&) = delete; /// \brief No move assignment operator TypeMatcher& operator=(TypeMatcher&&) = delete; /// \brief Destructor ~TypeMatcher(); /// \brief Return true if the llvm::Type matches the ar::Type /// /// \throws ImportError for unsupported types bool match_type(llvm::Type*, ar::Type*); private: using ARTypeSet = boost::container::flat_set< std::pair< llvm::Type*, ar::Type* > >; /// \brief Check whether a llvm::Type matches an ar::Type bool match_type(llvm::Type*, ar::Type*, ARTypeSet); /// \brief Check whether a llvm::IntegerType matches an ar::Type bool match_integer_type(llvm::Type*, ar::Type*); /// \brief Check whether a llvm::Type matches an ar::Type bool match_floating_point_type(llvm::Type*, ar::Type*); /// \brief Check whether a llvm::PointerType matches an ar::Type bool match_pointer_type(llvm::Type*, ar::Type*, ARTypeSet); /// \brief Check whether a llvm::ArrayType matches an ar::Type bool match_array_type(llvm::Type*, ar::Type*, ARTypeSet); /// \brief Check whether a llvm::VectorType matches an ar::Type bool match_vector_type(llvm::Type*, ar::Type*, ARTypeSet); /// \brief Check whether a llvm::StructType matches an ar::Type bool match_struct_type(llvm::Type*, ar::Type*, ARTypeSet); /// \brief Check whether a llvm::FunctionType matches an ar::Type bool match_function_type(llvm::Type*, ar::Type*, ARTypeSet); public: /// \brief Check whether an extern llvm::FunctionType matches an /// ar::FunctionType /// /// This is similar to match_type, but it accepts to match even if a parameter /// is a pointer to a structure on one hand, and a pointer to an opaque type /// on the other hand. /// /// The opaque type is used to model libc parameters such as FILE. /// /// \throws ImportError for unsupported types bool match_extern_function_type(llvm::FunctionType*, ar::FunctionType*); private: /// \brief Check whether a llvm::Type matches an ar::Type /// /// See `match_extern_function_type` bool match_extern_function_param_type(llvm::Type*, ar::Type*); }; // end class TypeMatcher /// \brief Helper class to translate types class TypeImporter { private: // Helper class to translate types with a given signedness TypeWithSignImporter _type_sign_imp; // Helper class to translate types with debug info TypeWithDebugInfoImporter _type_di_imp; // Helper class to check if a LLVM type matches an AR type TypeMatcher _type_match; public: /// \brief Public constructor explicit TypeImporter(ImportContext& ctx); /// \brief Translate a pair (llvm::Type*, ar::Signedness) into an ar::Type /// /// \param type LLVM type /// \param preferred Preferred signedness /// /// \throws ImportError for unsupported types ar::Type* translate_type(llvm::Type* type, ar::Signedness preferred); /// \brief Translate a pair (llvm::Type*, llvm::DIType*) into an ar::Type /// /// \param type LLVM type /// \param di_type LLVM Debug Info type /// /// \throws TypeDebugInfoMismatch for a mismatch between debug info and type /// \throws ImportError for unsupported types ar::Type* translate_type(llvm::Type* type, llvm::DIType* di_type); /// \brief Translate a llvm::Function's type with debug info into an ar::Type* /// /// This is similar to translate_subroutine_di_type() but it takes the /// llvm::Function* rather than the llvm::Type*, to handle special attributes /// on arguments (e.g, byval). /// /// \param fun LLVM function /// \param di_type LLVM Debug Info type /// /// \throws TypeDebugInfoMismatch for a mismatch between debug info and type /// \throws ImportError for unsupported types ar::FunctionType* translate_function_type(llvm::Function* fun, llvm::DISubroutineType* di_type); /// \brief Return true if the llvm::Type matches the ar::Type /// /// \throws ImportError for unsupported types bool match_type(llvm::Type*, ar::Type*); /// \brief Check whether an extern llvm::FunctionType matches an /// ar::FunctionType /// /// This is similar to match_type, but it accepts to match even if a parameter /// is a pointer to a structure on one hand, and a pointer to an opaque type /// on the other hand. /// /// The opaque type is used to model libc parameters such as FILE. /// /// \throws ImportError for unsupported types bool match_extern_function_type(llvm::FunctionType*, ar::FunctionType*); }; // end class TypeImporter } // end namespace import } // end namespace frontend } // end namespace ikos NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/000077500000000000000000000000001473507761200211445ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/initialize.cpp000066400000000000000000000047771473507761200240300ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of initializeIkosPasses * * Author: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include void ikos::frontend::pass::initialize_ikos_passes(llvm::PassRegistry& PR) { llvm::initializeLowerCstExprPassPass(PR); llvm::initializeLowerSelectPassPass(PR); llvm::initializeMarkInternalInlinePassPass(PR); llvm::initializeNameValuesPassPass(PR); llvm::initializeRemovePrintfCallsPassPass(PR); llvm::initializeRemoveUnreachableBlocksPassPass(PR); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/lower_cst_expr.cpp000066400000000000000000000140461473507761200247140ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the LowerCstExprPass * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #define DEBUG_TYPE "lower-cst-expr" // NOLINTNEXTLINE(google-build-using-namespace) using namespace llvm; STATISTIC(TotalLowered, "Number of lowered constant expressions"); namespace { /// \brief Lower Constant Expression Pass /// /// Note that this pass does not lower constant aggregates that contain /// constant expressions. This would require more work, because a constant /// aggregate can only have constant operands. struct LowerCstExprPass final : public FunctionPass { static char ID; // Pass identification LowerCstExprPass() : FunctionPass(ID) {} void getAnalysisUsage(AnalysisUsage&) const override { // All analyses are invalidated } bool runOnFunction(Function& F) override { SmallPtrSet< Instruction*, 8 > worklist; for (auto it = inst_begin(F), et = inst_end(F); it != et; ++it) { Instruction* inst = &*it; if (has_cst_expr(inst)) { worklist.insert(inst); } } bool change = !worklist.empty(); while (!worklist.empty()) { Instruction* inst = *worklist.begin(); worklist.erase(inst); if (auto phi = dyn_cast< PHINode >(inst)) { for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) { Value* incoming_value = phi->getIncomingValue(i); if (auto cst_expr = dyn_cast< ConstantExpr >(incoming_value)) { BasicBlock* incoming_block = phi->getIncomingBlock(i); Instruction* insert_loc = incoming_block->getTerminator(); Instruction* new_inst = lower_cst_expr(cst_expr, insert_loc); for (unsigned j = i; j < phi->getNumIncomingValues(); j++) { if (phi->getIncomingValue(j) == incoming_value && phi->getIncomingBlock(j) == incoming_block) { phi->setIncomingValue(j, new_inst); } } worklist.insert(new_inst); } } } else { for (unsigned i = 0; i < inst->getNumOperands(); ++i) { Value* operand = inst->getOperand(i); if (auto cst_expr = dyn_cast< ConstantExpr >(operand)) { Instruction* new_inst = lower_cst_expr(cst_expr, inst); inst->replaceUsesOfWith(cst_expr, new_inst); worklist.insert(new_inst); } } } } return change; } /// \brief Return true if the given instruction has constant expression /// operands static bool has_cst_expr(Instruction* inst) { if (isa< LandingPadInst >(inst)) { // Skip landingpad (especially the catch clause) // It has to be the first instruction in the basic block, so we won't be // able to insert instructions before it to lower a constant expression. return false; } for (auto it = inst->op_begin(), et = inst->op_end(); it != et; ++it) { if (isa< ConstantExpr >(*it)) { return true; } } return false; } /// \brief Lower the given constant expression static Instruction* lower_cst_expr(ConstantExpr* cst_expr, Instruction* insertion_loc) { Instruction* new_inst = cst_expr->getAsInstruction(); ikos_assert_msg(new_inst, "Unhandled constant expression"); new_inst->setDebugLoc(insertion_loc->getDebugLoc()); new_inst->insertBefore(insertion_loc); TotalLowered++; return new_inst; } }; // end struct LowerCstExprPass } // end anonymous namespace char LowerCstExprPass::ID = 0; INITIALIZE_PASS(LowerCstExprPass, "lower-cst-expr", "Lower constant expressions to instructions", false, false); FunctionPass* ikos::frontend::pass::create_lower_cst_expr_pass() { return new LowerCstExprPass(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/lower_select.cpp000066400000000000000000000151761473507761200243510ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the LowerSelectPass * * Author: Jorge A. Navas * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #include #include #define DEBUG_TYPE "lower-select" // NOLINTNEXTLINE(google-build-using-namespace) using namespace llvm; STATISTIC(TotalLowered, "Number of lowered select instructions"); namespace { struct LowerSelectPass final : public FunctionPass { static char ID; // Pass identification LowerSelectPass() : FunctionPass(ID) {} void getAnalysisUsage(AnalysisUsage&) const override { // All analyses are invalidated } bool runOnFunction(Function& f) override { SmallVector< SelectInst*, 8 > worklist; // Initialization of the worklist with all select instructions within // the function for (auto it = inst_begin(f), et = inst_end(f); it != et; ++it) { Instruction* inst = &*it; if (auto si = dyn_cast< SelectInst >(inst)) { if (!(si->getCondition()->getType()->isIntegerTy(1))) { // note that the flag can be a vector of Boolean dbgs() << "We only lower a select if the flag is Boolean.\n"; ikos_unreachable("unexpected select"); } worklist.push_back(si); } } bool change = !worklist.empty(); for (SelectInst* si : worklist) { process_select_inst(si); } return change; } /// \brief Lower the select instruction into three new blocks. void process_select_inst(SelectInst* si) { BasicBlock* current_block = si->getParent(); Function* f = current_block->getParent(); Value* flag = si->getCondition(); // This splits a basic block into two at the specified instruction. // All instructions BEFORE the specified iterator stay as part of // the original basic block, an unconditional branch is added to // the original BB, and the rest of the instructions in the BB are // moved to the new BB, including the old terminator. // IMPORTANT: this function invalidates the specified iterator. // IMPORTANT: note that the select instructions goes to after_select // Also note that this doesn't preserve any passes. To split blocks // while keeping loop information consistent, use the SplitBlock // utility function. BasicBlock* after_select = current_block->splitBasicBlock(si); BasicBlock* true_block = BasicBlock::Create(f->getContext(), "", f, after_select); BasicBlock* false_block = BasicBlock::Create(f->getContext(), "", f, after_select); if (current_block->hasName()) { after_select->setName(current_block->getName() + ".AfterSelect"); true_block->setName(current_block->getName() + ".TrueSelect"); false_block->setName(current_block->getName() + ".FalseSelect"); } // Wire true_block and false_block to after_select via unconditional branch BranchInst* true_br = BranchInst::Create(after_select, true_block); BranchInst* false_br = BranchInst::Create(after_select, false_block); true_br->setDebugLoc(si->getDebugLoc()); false_br->setDebugLoc(si->getDebugLoc()); // Replace the unconditional branch added by splitBasicBlock // with a conditional branch splitting on flag **at the end** of // current_block current_block->getTerminator()->eraseFromParent(); BranchInst* br = BranchInst::Create(true_block, false_block, flag, current_block); br->setDebugLoc(si->getDebugLoc()); // Insert a phi node just before the select instruction. PHINode* phi = PHINode::Create(si->getOperand(1)->getType(), si->getNumOperands(), "", si); phi->addIncoming(si->getOperand(1), true_block); phi->addIncoming(si->getOperand(2), false_block); if (si->hasName()) { phi->setName(si->getName() + ".phi"); } phi->setDebugLoc(si->getDebugLoc()); // Make sure any users of the select is now an user of the phi node. si->replaceAllUsesWith(phi); // Finally we remove the select instruction si->eraseFromParent(); TotalLowered++; } }; // end struct LowerSelectPass } // end anonymous namespace char LowerSelectPass::ID = 0; INITIALIZE_PASS(LowerSelectPass, "lower-select", "Lower select instructions to branches", false, false); FunctionPass* ikos::frontend::pass::create_lower_select_pass() { return new LowerSelectPass(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/mark_internal_inline.cpp000066400000000000000000000062631473507761200260430ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the MarkInternalInlinePass * * Author: Jorge A. Navas * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include // NOLINTNEXTLINE(google-build-using-namespace) using namespace llvm; namespace { struct MarkInternalInlinePass final : public ModulePass { static char ID; // Pass identification MarkInternalInlinePass() : ModulePass(ID) {} void getAnalysisUsage(AnalysisUsage& AU) const override { AU.setPreservesAll(); } bool runOnModule(Module& m) override { bool change = false; for (Function& f : m) { if (!f.isDeclaration() && f.hasLocalLinkage()) { f.addFnAttr(Attribute::AlwaysInline); change = true; } } return change; } }; // end struct MarkInternalInlinePass } // end anonymous namespace char MarkInternalInlinePass::ID = 0; INITIALIZE_PASS(MarkInternalInlinePass, "mark-internal-inline", "Internalize all functions for enabling inlining", false, false); ModulePass* ikos::frontend::pass::create_mark_internal_inline_pass() { return new MarkInternalInlinePass(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/name_values.cpp000066400000000000000000000077301473507761200241560ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the NameValuesPass * * Author: Jorge A. Navas * * Contributors: Maxime Arthaud * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include // NOLINTNEXTLINE(google-build-using-namespace) using namespace llvm; namespace { struct NameValuesPass final : public ModulePass { static char ID; // Pass identification unsigned global_idx; NameValuesPass() : ModulePass(ID), global_idx(0) {} void getAnalysisUsage(AnalysisUsage& AU) const override { AU.setPreservesAll(); } bool runOnModule(Module& m) override { for (auto it = m.global_begin(), et = m.global_end(); it != et; ++it) { run_on_global(*it); } for (Function& f : m) { run_on_function(f); } return false; } bool run_on_global(GlobalVariable& g) { if (!g.hasName()) { g.setName("gv_" + std::to_string(++global_idx)); } return false; } bool run_on_function(Function& f) { unsigned arg_idx = 1; for (auto it = f.arg_begin(), et = f.arg_end(); it != et; ++it, ++arg_idx) { Argument& a = *it; if (!a.hasName() && !a.getType()->isVoidTy()) { a.setName("arg_" + std::to_string(arg_idx)); } } unsigned block_idx = 0; unsigned inst_idx = 0; for (BasicBlock& bb : f) { if (!bb.hasName()) { bb.setName("bb_" + std::to_string(++block_idx)); } for (Instruction& i : bb) { if (!i.hasName() && !i.getType()->isVoidTy()) { i.setName("_" + std::to_string(++inst_idx)); } } } return false; } }; // end struct NameValuesPass } // end anonymous namespace char NameValuesPass::ID = 0; INITIALIZE_PASS( NameValuesPass, "name-values", "Names all unnamed values", false, false); ModulePass* ikos::frontend::pass::create_name_values_pass() { return new NameValuesPass(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/remove_printf_calls.cpp000066400000000000000000000102571473507761200257120ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the RemovePrintfCallsPass * * Author: Jorge A. Navas * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include #include #include #include #include #include #define DEBUG_TYPE "remove-printf-call" // NOLINTNEXTLINE(google-build-using-namespace) using namespace llvm; STATISTIC(NumKilled, "Number of printf-like calls removed"); namespace { struct RemovePrintfCallsPass final : public FunctionPass { static char ID; // Pass identification RemovePrintfCallsPass() : FunctionPass(ID) {} void getAnalysisUsage(AnalysisUsage&) const override { // All analyses are invalidated } bool runOnFunction(Function& f) override { SmallVector< CallInst*, 8 > to_erase; for (auto it = inst_begin(f), et = inst_end(f); it != et; ++it) { Instruction* inst = &*it; // looking for empty users if (!inst->use_empty()) { continue; } if (auto ci = dyn_cast< CallInst >(inst)) { Function* called = ci->getCalledFunction(); if (called == nullptr) { continue; } if (called->isDeclaration()) { if (called->getName() == "fprintf" || called->getName() == "printf" || called->getName() == "fputc" || called->getName() == "putc" || called->getName() == "fputs" || called->getName() == "puts" || called->getName() == "putchar" || called->getName() == "fwrite" || called->getName() == "write") { to_erase.push_back(ci); ++NumKilled; } } } } for (CallInst* ci : to_erase) { ci->eraseFromParent(); } return !to_erase.empty(); } }; // end struct RemovePrintfCallsPass } // end anonymous namespace char RemovePrintfCallsPass::ID = 0; INITIALIZE_PASS(RemovePrintfCallsPass, "remove-printf-calls", "Remove printf-like calls", false, false); FunctionPass* ikos::frontend::pass::create_remove_printf_calls_pass() { return new RemovePrintfCallsPass(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/src/pass/remove_unreachable_blocks.cpp000066400000000000000000000060611473507761200270360ustar00rootroot00000000000000/******************************************************************************* * * \file * \brief Implementation of the RemoveUnreachableBlocksPass * * Author: Jorge A. Navas * * Contact: ikos@lists.nasa.gov * * Notices: * * Copyright (c) 2011-2019 United States Government as represented by the * Administrator of the National Aeronautics and Space Administration. * All Rights Reserved. * * Disclaimers: * * No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF * ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED * TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, * ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE * ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO * THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN * ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, * RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS * RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY * DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, * IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." * * Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST * THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL * AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS * IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH * USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, * RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD * HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, * AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. * RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, * UNILATERAL TERMINATION OF THIS AGREEMENT. * ******************************************************************************/ #include #include // NOLINTNEXTLINE(google-build-using-namespace) using namespace llvm; namespace { struct RemoveUnreachableBlocksPass final : public FunctionPass { static char ID; // Pass identification RemoveUnreachableBlocksPass() : FunctionPass(ID) {} void getAnalysisUsage(AnalysisUsage&) const override { // All analyses are invalidated } bool runOnFunction(Function& F) override { return removeUnreachableBlocks(F); } }; // end struct RemoveUnreachableBlocksPass } // end anonymous namespace char RemoveUnreachableBlocksPass::ID = 0; INITIALIZE_PASS(RemoveUnreachableBlocksPass, "remove-unreachable-blocks", "Remove blocks that are not reachable", false, false); FunctionPass* ikos::frontend::pass::create_remove_unreachable_blocks_pass() { return new RemoveUnreachableBlocksPass(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/000077500000000000000000000000001473507761200203665ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/000077500000000000000000000000001473507761200225465ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/000077500000000000000000000000001473507761200240605ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/CMakeLists.txt000066400000000000000000000022521473507761200266210ustar00rootroot00000000000000# Dependencies to run the tests add_dependencies(build-frontend-llvm-tests ikos-import) # Try to find bash find_program(BASH_EXECUTABLE CACHE NAMES bash DOC "Path to bash binary") if (NOT BASH_EXECUTABLE) message(WARNING "Could NOT find bash. Tests for llvm-to-ar are disabled.") endif() # Try to find FileCheck find_program(LLVM_FILE_CHECK_EXECUTABLE CACHE NAMES FileCheck HINTS ${LLVM_TOOLS_BINARY_DIR} DOC "Path to FileCheck binary") if (NOT LLVM_FILE_CHECK_EXECUTABLE) message(WARNING "Could NOT find FileCheck. Tests for llvm-to-ar are disabled.") endif() function(add_import_test test_name test_directory) if ((NOT LLVM_FILE_CHECK_EXECUTABLE) OR (NOT BASH_EXECUTABLE)) return() # Skip the test endif() add_test(NAME "import-${test_name}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${test_directory}" COMMAND ${BASH_EXECUTABLE} runtest --ikos-import "$" --file-check "${LLVM_FILE_CHECK_EXECUTABLE}") endfunction() add_import_test(no-optimization no_optimization) add_import_test(basic-optimization basic_optimization) add_import_test(aggressive-optimization aggressive_optimization) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/000077500000000000000000000000001473507761200310255ustar00rootroot00000000000000aggregate-in-reg-1.cpp000066400000000000000000000006461473507761200347230ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationtemplate < typename T > class Vector3 { private: T _x, _y, _z; public: Vector3< T >(T x, T y, T z) : _x(x), _y(y), _z(z) {} }; class Foo { private: Vector3< float > coord; public: Foo(float x, float y, float z) : coord(Vector3< float >(x, y, z)) {} Vector3< float > get_coord() { return coord; } }; int main(int argc, char* argv[]) { Foo f(1, 2, 3); Vector3< float > coord = f.get_coord(); return 0; } aggregate-in-reg-1.ll000066400000000000000000000413171473507761200345500ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'aggregate-in-reg-1.pp.bc' source_filename = "aggregate-in-reg-1.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Foo = type { %class.Vector3 } %class.Vector3 = type { float, float, float } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc { <2 x float>, float } @_ZN3Foo9get_coordEv(%class.Foo*) unnamed_addr #2 align 2 !dbg !54 { call void @llvm.dbg.value(metadata %class.Foo* %0, metadata !55, metadata !DIExpression()), !dbg !56 %.sroa.02.0..sroa_cast = bitcast %class.Foo* %0 to <2 x float>*, !dbg !57 %.sroa.02.0.copyload = load <2 x float>, <2 x float>* %.sroa.02.0..sroa_cast, align 4, !dbg !57 %.sroa.23.0..sroa_idx4 = getelementptr inbounds %class.Foo, %class.Foo* %0, i64 0, i32 0, i32 2, !dbg !57 %.sroa.23.0.copyload = load float, float* %.sroa.23.0..sroa_idx4, align 4, !dbg !57 %.fca.0.insert = insertvalue { <2 x float>, float } undef, <2 x float> %.sroa.02.0.copyload, 0, !dbg !58 %.fca.1.insert = insertvalue { <2 x float>, float } %.fca.0.insert, float %.sroa.23.0.copyload, 1, !dbg !58 ret { <2 x float>, float } %.fca.1.insert, !dbg !58 } ; CHECK: define {0: <2 x float>, 8: float} @_ZN3Foo9get_coordEv({0: {0: float, 4: float, 8: float}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: <2 x float>* %.sroa.02.0..sroa_cast = bitcast %1 ; CHECK: <2 x float> %.sroa.02.0.copyload = load %.sroa.02.0..sroa_cast, align 4 ; CHECK: float* %.sroa.23.0..sroa_idx4 = ptrshift %1, 12 * 0, 1 * 0, 1 * 8 ; CHECK: float %.sroa.23.0.copyload = load %.sroa.23.0..sroa_idx4, align 4 ; CHECK: {0: <2 x float>, 8: float} %.fca.0.insert = insertelement undef, 0, %.sroa.02.0.copyload ; CHECK: {0: <2 x float>, 8: float} %.fca.1.insert = insertelement %.fca.0.insert, 8, %.sroa.23.0.copyload ; CHECK: return %.fca.1.insert ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define internal fastcc void @_ZN3FooC1Efff(%class.Foo*, float, float, float) unnamed_addr #1 align 2 !dbg !45 { call void @llvm.dbg.value(metadata %class.Foo* %0, metadata !46, metadata !DIExpression()), !dbg !48 call void @llvm.dbg.value(metadata float %1, metadata !49, metadata !DIExpression()), !dbg !48 call void @llvm.dbg.value(metadata float %2, metadata !50, metadata !DIExpression()), !dbg !48 call void @llvm.dbg.value(metadata float %3, metadata !51, metadata !DIExpression()), !dbg !48 call fastcc void @_ZN3FooC2Efff(%class.Foo* %0, float %1, float %2, float %3), !dbg !52 ret void, !dbg !53 } ; CHECK: define void @_ZN3FooC1Efff({0: {0: float, 4: float, 8: float}}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN3FooC2Efff(%1, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define internal fastcc void @_ZN3FooC2Efff(%class.Foo*, float, float, float) unnamed_addr #1 align 2 !dbg !59 { call void @llvm.dbg.value(metadata %class.Foo* %0, metadata !60, metadata !DIExpression()), !dbg !61 call void @llvm.dbg.value(metadata float %1, metadata !62, metadata !DIExpression()), !dbg !61 call void @llvm.dbg.value(metadata float %2, metadata !63, metadata !DIExpression()), !dbg !61 call void @llvm.dbg.value(metadata float %3, metadata !64, metadata !DIExpression()), !dbg !61 %5 = getelementptr inbounds %class.Foo, %class.Foo* %0, i64 0, i32 0, !dbg !65 call fastcc void @_ZN7Vector3IfEC1Efff(%class.Vector3* %5, float %1, float %2, float %3), !dbg !66 ret void, !dbg !67 } ; CHECK: define void @_ZN3FooC2Efff({0: {0: float, 4: float, 8: float}}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: float, 4: float, 8: float}* %5 = ptrshift %1, 12 * 0, 1 * 0 ; CHECK: call @_ZN7Vector3IfEC1Efff(%5, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define internal fastcc void @_ZN7Vector3IfEC1Efff(%class.Vector3*, float, float, float) unnamed_addr #1 align 2 !dbg !68 { call void @llvm.dbg.value(metadata %class.Vector3* %0, metadata !69, metadata !DIExpression()), !dbg !71 call void @llvm.dbg.value(metadata float %1, metadata !72, metadata !DIExpression()), !dbg !71 call void @llvm.dbg.value(metadata float %2, metadata !73, metadata !DIExpression()), !dbg !71 call void @llvm.dbg.value(metadata float %3, metadata !74, metadata !DIExpression()), !dbg !71 call fastcc void @_ZN7Vector3IfEC2Efff(%class.Vector3* %0, float %1, float %2, float %3), !dbg !75 ret void, !dbg !76 } ; CHECK: define void @_ZN7Vector3IfEC1Efff({0: float, 4: float, 8: float}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN7Vector3IfEC2Efff(%1, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN7Vector3IfEC2Efff(%class.Vector3*, float, float, float) unnamed_addr #2 align 2 !dbg !77 { call void @llvm.dbg.value(metadata %class.Vector3* %0, metadata !78, metadata !DIExpression()), !dbg !79 call void @llvm.dbg.value(metadata float %1, metadata !80, metadata !DIExpression()), !dbg !79 call void @llvm.dbg.value(metadata float %2, metadata !81, metadata !DIExpression()), !dbg !79 call void @llvm.dbg.value(metadata float %3, metadata !82, metadata !DIExpression()), !dbg !79 %5 = getelementptr inbounds %class.Vector3, %class.Vector3* %0, i64 0, i32 0, !dbg !83 store float %1, float* %5, align 4, !dbg !83 %6 = getelementptr inbounds %class.Vector3, %class.Vector3* %0, i64 0, i32 1, !dbg !84 store float %2, float* %6, align 4, !dbg !84 %7 = getelementptr inbounds %class.Vector3, %class.Vector3* %0, i64 0, i32 2, !dbg !85 store float %3, float* %7, align 4, !dbg !85 ret void, !dbg !86 } ; CHECK: define void @_ZN7Vector3IfEC2Efff({0: float, 4: float, 8: float}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: float* %5 = ptrshift %1, 12 * 0, 1 * 0 ; CHECK: store %5, %2, align 4 ; CHECK: float* %6 = ptrshift %1, 12 * 0, 1 * 4 ; CHECK: store %6, %3, align 4 ; CHECK: float* %7 = ptrshift %1, 12 * 0, 1 * 8 ; CHECK: store %7, %4, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !8 { %3 = alloca %class.Foo, align 4 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata %class.Foo* %3, metadata !18, metadata !DIExpression(DW_OP_deref)), !dbg !16 call fastcc void @_ZN3FooC1Efff(%class.Foo* nonnull %3, float 1.000000e+00, float 2.000000e+00, float 3.000000e+00), !dbg !41 call void @llvm.dbg.value(metadata %class.Foo* %3, metadata !18, metadata !DIExpression(DW_OP_deref)), !dbg !16 %4 = call fastcc { <2 x float>, float } @_ZN3Foo9get_coordEv(%class.Foo* nonnull %3), !dbg !42 call void @llvm.dbg.value(metadata <2 x float> undef, metadata !43, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)), !dbg !16 call void @llvm.dbg.value(metadata float undef, metadata !43, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32)), !dbg !16 ret i32 0, !dbg !44 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: float, 4: float, 8: float}}* $3 = allocate {0: {0: float, 4: float, 8: float}}, 1, align 4 ; CHECK: call @_ZN3FooC1Efff($3, 1.0E+0, 2.0E+0, 3.0E+0) ; CHECK: {0: <2 x float>, 8: float} %4 = call @_ZN3Foo9get_coordEv($3) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #3 attributes #0 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "aggregate-in-reg-1.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 19, type: !9, scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 19, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 19, type: !12) !18 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 20, type: !19) !19 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Foo", file: !1, line: 10, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !20, identifier: "_ZTS3Foo") !20 = !{!21, !34, !38} !21 = !DIDerivedType(tag: DW_TAG_member, name: "coord", scope: !19, file: !1, line: 12, baseType: !22, size: 96) !22 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Vector3", file: !1, line: 2, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !23, templateParams: !32, identifier: "_ZTS7Vector3IfE") !23 = !{!24, !26, !27, !28} !24 = !DIDerivedType(tag: DW_TAG_member, name: "_x", scope: !22, file: !1, line: 4, baseType: !25, size: 32) !25 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !26 = !DIDerivedType(tag: DW_TAG_member, name: "_y", scope: !22, file: !1, line: 4, baseType: !25, size: 32, offset: 32) !27 = !DIDerivedType(tag: DW_TAG_member, name: "_z", scope: !22, file: !1, line: 4, baseType: !25, size: 32, offset: 64) !28 = !DISubprogram(name: "Vector3", scope: !22, file: !1, line: 7, type: !29, scopeLine: 7, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !29 = !DISubroutineType(types: !30) !30 = !{null, !31, !25, !25, !25} !31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !32 = !{!33} !33 = !DITemplateTypeParameter(name: "T", type: !25) !34 = !DISubprogram(name: "Foo", scope: !19, file: !1, line: 15, type: !35, scopeLine: 15, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !35 = !DISubroutineType(types: !36) !36 = !{null, !37, !25, !25, !25} !37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !38 = !DISubprogram(name: "get_coord", linkageName: "_ZN3Foo9get_coordEv", scope: !19, file: !1, line: 16, type: !39, scopeLine: 16, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !39 = !DISubroutineType(types: !40) !40 = !{!22, !37} !41 = !DILocation(line: 20, column: 7, scope: !8) !42 = !DILocation(line: 21, column: 30, scope: !8) !43 = !DILocalVariable(name: "coord", scope: !8, file: !1, line: 21, type: !22) !44 = !DILocation(line: 22, column: 3, scope: !8) !45 = distinct !DISubprogram(name: "Foo", linkageName: "_ZN3FooC1Efff", scope: !19, file: !1, line: 15, type: !35, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !34, retainedNodes: !2) !46 = !DILocalVariable(name: "this", arg: 1, scope: !45, type: !47, flags: DIFlagArtificial | DIFlagObjectPointer) !47 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) !48 = !DILocation(line: 0, scope: !45) !49 = !DILocalVariable(name: "x", arg: 2, scope: !45, file: !1, line: 15, type: !25) !50 = !DILocalVariable(name: "y", arg: 3, scope: !45, file: !1, line: 15, type: !25) !51 = !DILocalVariable(name: "z", arg: 4, scope: !45, file: !1, line: 15, type: !25) !52 = !DILocation(line: 15, column: 69, scope: !45) !53 = !DILocation(line: 15, column: 70, scope: !45) !54 = distinct !DISubprogram(name: "get_coord", linkageName: "_ZN3Foo9get_coordEv", scope: !19, file: !1, line: 16, type: !39, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !38, retainedNodes: !2) !55 = !DILocalVariable(name: "this", arg: 1, scope: !54, type: !47, flags: DIFlagArtificial | DIFlagObjectPointer) !56 = !DILocation(line: 0, scope: !54) !57 = !DILocation(line: 16, column: 41, scope: !54) !58 = !DILocation(line: 16, column: 34, scope: !54) !59 = distinct !DISubprogram(name: "Foo", linkageName: "_ZN3FooC2Efff", scope: !19, file: !1, line: 15, type: !35, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !34, retainedNodes: !2) !60 = !DILocalVariable(name: "this", arg: 1, scope: !59, type: !47, flags: DIFlagArtificial | DIFlagObjectPointer) !61 = !DILocation(line: 0, scope: !59) !62 = !DILocalVariable(name: "x", arg: 2, scope: !59, file: !1, line: 15, type: !25) !63 = !DILocalVariable(name: "y", arg: 3, scope: !59, file: !1, line: 15, type: !25) !64 = !DILocalVariable(name: "z", arg: 4, scope: !59, file: !1, line: 15, type: !25) !65 = !DILocation(line: 15, column: 36, scope: !59) !66 = !DILocation(line: 15, column: 42, scope: !59) !67 = !DILocation(line: 15, column: 70, scope: !59) !68 = distinct !DISubprogram(name: "Vector3", linkageName: "_ZN7Vector3IfEC1Efff", scope: !22, file: !1, line: 7, type: !29, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !28, retainedNodes: !2) !69 = !DILocalVariable(name: "this", arg: 1, scope: !68, type: !70, flags: DIFlagArtificial | DIFlagObjectPointer) !70 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !71 = !DILocation(line: 0, scope: !68) !72 = !DILocalVariable(name: "x", arg: 2, scope: !68, file: !1, line: 7, type: !25) !73 = !DILocalVariable(name: "y", arg: 3, scope: !68, file: !1, line: 7, type: !25) !74 = !DILocalVariable(name: "z", arg: 4, scope: !68, file: !1, line: 7, type: !25) !75 = !DILocation(line: 7, column: 53, scope: !68) !76 = !DILocation(line: 7, column: 54, scope: !68) !77 = distinct !DISubprogram(name: "Vector3", linkageName: "_ZN7Vector3IfEC2Efff", scope: !22, file: !1, line: 7, type: !29, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !28, retainedNodes: !2) !78 = !DILocalVariable(name: "this", arg: 1, scope: !77, type: !70, flags: DIFlagArtificial | DIFlagObjectPointer) !79 = !DILocation(line: 0, scope: !77) !80 = !DILocalVariable(name: "x", arg: 2, scope: !77, file: !1, line: 7, type: !25) !81 = !DILocalVariable(name: "y", arg: 3, scope: !77, file: !1, line: 7, type: !25) !82 = !DILocalVariable(name: "z", arg: 4, scope: !77, file: !1, line: 7, type: !25) !83 = !DILocation(line: 7, column: 33, scope: !77) !84 = !DILocation(line: 7, column: 40, scope: !77) !85 = !DILocation(line: 7, column: 47, scope: !77) !86 = !DILocation(line: 7, column: 54, scope: !77) aggregate-in-reg-2.cpp000066400000000000000000000003501473507761200347140ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include typedef struct { float x; float y; } pos_t; typedef struct { pos_t begin, end; } line_t; line_t f(float y) { return {{0.0, y}, {2.0, 0}}; } int main() { printf("%f\n", f(2.0).begin.y); return 0; } aggregate-in-reg-2.ll000066400000000000000000000132431473507761200345460ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'aggregate-in-reg-2.pp.bc' source_filename = "aggregate-in-reg-2.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc { <2 x float>, <2 x float> } @_Z1ff(float) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata float %0, metadata !22, metadata !DIExpression()), !dbg !23 %.sroa.0.4.vec.insert = insertelement <2 x float> , float %0, i32 1, !dbg !24 %.fca.0.insert = insertvalue { <2 x float>, <2 x float> } undef, <2 x float> %.sroa.0.4.vec.insert, 0, !dbg !25 %.fca.1.insert = insertvalue { <2 x float>, <2 x float> } %.fca.0.insert, <2 x float> , 1, !dbg !25 ret { <2 x float>, <2 x float> } %.fca.1.insert, !dbg !25 } ; CHECK: define {0: <2 x float>, 8: <2 x float>} @_Z1ff(float %1) { ; CHECK: #1 !entry !exit { ; CHECK: <2 x float> %.sroa.0.4.vec.insert = insertelement <0.0E+0, undef>, 4, %1 ; CHECK: {0: <2 x float>, 8: <2 x float>} %.fca.0.insert = insertelement undef, 0, %.sroa.0.4.vec.insert ; CHECK: {0: <2 x float>, 8: <2 x float>} %.fca.1.insert = insertelement %.fca.0.insert, 8, <2.0E+0, 0.0E+0> ; CHECK: return %.fca.1.insert ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() local_unnamed_addr #1 !dbg !26 { %1 = call fastcc { <2 x float>, <2 x float> } @_Z1ff(float 2.000000e+00), !dbg !30 ret i32 0, !dbg !31 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: <2 x float>, 8: <2 x float>} %1 = call @_Z1ff(2.0E+0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "aggregate-in-reg-2.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1ff", scope: !1, file: !1, line: 12, type: !9, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !19} !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "line_t", file: !1, line: 10, baseType: !12) !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 8, size: 128, flags: DIFlagTypePassByValue, elements: !13, identifier: "_ZTS6line_t") !13 = !{!14, !21} !14 = !DIDerivedType(tag: DW_TAG_member, name: "begin", scope: !12, file: !1, line: 9, baseType: !15, size: 64) !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "pos_t", file: !1, line: 6, baseType: !16) !16 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 3, size: 64, flags: DIFlagTypePassByValue, elements: !17, identifier: "_ZTS5pos_t") !17 = !{!18, !20} !18 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !16, file: !1, line: 4, baseType: !19, size: 32) !19 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !20 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !16, file: !1, line: 5, baseType: !19, size: 32, offset: 32) !21 = !DIDerivedType(tag: DW_TAG_member, name: "end", scope: !12, file: !1, line: 9, baseType: !15, size: 64, offset: 64) !22 = !DILocalVariable(name: "y", arg: 1, scope: !8, file: !1, line: 12, type: !19) !23 = !DILocation(line: 0, scope: !8) !24 = !DILocation(line: 13, column: 11, scope: !8) !25 = !DILocation(line: 13, column: 3, scope: !8) !26 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 16, type: !27, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !27 = !DISubroutineType(types: !28) !28 = !{!29} !29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !30 = !DILocation(line: 17, column: 18, scope: !26) !31 = !DILocation(line: 18, column: 3, scope: !26) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/array-init.cpp000066400000000000000000000000551473507761200336100ustar00rootroot00000000000000struct i { unsigned j[16]; } k[]{{}, {2}}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/array-init.ll000066400000000000000000000034551473507761200334440ustar00rootroot00000000000000; ModuleID = 'array-init.pp.bc' source_filename = "array-init.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!16, !17, !18, !19} !llvm.ident = !{!20} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "array-init.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "k", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1024, elements: !14) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "i", file: !1, line: 1, size: 512, flags: DIFlagTypePassByValue, elements: !8, identifier: "_ZTS1i") !8 = !{!9} !9 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !7, file: !1, line: 2, baseType: !10, size: 512) !10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 512, elements: !12) !11 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !12 = !{!13} !13 = !DISubrange(count: 16) !14 = !{!15} !15 = !DISubrange(count: 2) !16 = !{i32 2, !"Dwarf Version", i32 4} !17 = !{i32 2, !"Debug Info Version", i32 3} !18 = !{i32 1, !"wchar_size", i32 4} !19 = !{i32 7, !"PIC Level", i32 2} !20 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/asm.c000066400000000000000000000002631473507761200317520ustar00rootroot00000000000000#include int main() { int src = 1; int dst; asm("mov %1, %0\n\t" "add $1, %0" : "=r"(dst) : "r"(src)); printf("%d\n", dst); return dst; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/asm.ll000066400000000000000000000055641473507761200321500ustar00rootroot00000000000000; ModuleID = 'asm.pp.bc' source_filename = "asm.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 1, metadata !12, metadata !DIExpression()), !dbg !13 %1 = call i32 asm "mov $1, $0\0A\09add $$1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 1) #2, !dbg !14, !srcloc !15 call void @llvm.dbg.value(metadata i32 %1, metadata !16, metadata !DIExpression()), !dbg !13 ret i32 %1, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32 %1 = call asm "mov $1, $0 ; CHECK: add $$1, $0"(1) ; CHECK: return %1 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { nounwind readnone } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "asm.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "src", scope: !8, file: !1, line: 4, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocation(line: 7, column: 3, scope: !8) !15 = !{i32 68, i32 81} !16 = !DILocalVariable(name: "dst", scope: !8, file: !1, line: 5, type: !11) !17 = !DILocation(line: 13, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/atomic.c000066400000000000000000000001101473507761200324350ustar00rootroot00000000000000_Atomic volatile unsigned x; int main() { x = 42; return (int)x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/atomic.ll000066400000000000000000000057301473507761200326370ustar00rootroot00000000000000; ModuleID = 'atomic.pp.bc' source_filename = "atomic.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @x = internal global i32 0, align 4, !dbg !0 ; CHECK: define ui32* @x, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @x, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !16 { store volatile i32 42, i32* @x, align 4, !dbg !18 %1 = load volatile i32, i32* @x, align 4, !dbg !19 ret i32 %1, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: store volatile @x, 42, align 4 ; CHECK: si32* %1 = bitcast @x ; CHECK: si32 %2 = load volatile %1, align 4 ; CHECK: return %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!11, !12, !13, !14} !llvm.ident = !{!15} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !7, nameTableKind: GNU) !3 = !DIFile(filename: "atomic.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !4 = !{} !5 = !{!6} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{!0} !8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !9) !9 = !DIDerivedType(tag: DW_TAG_atomic_type, baseType: !10) !10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !11 = !{i32 2, !"Dwarf Version", i32 4} !12 = !{i32 2, !"Debug Info Version", i32 3} !13 = !{i32 1, !"wchar_size", i32 4} !14 = !{i32 7, !"PIC Level", i32 2} !15 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !16 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !17 = !DISubroutineType(types: !5) !18 = !DILocation(line: 4, column: 5, scope: !16) !19 = !DILocation(line: 5, column: 15, scope: !16) !20 = !DILocation(line: 5, column: 3, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/basic-loop.c000066400000000000000000000001761473507761200332250ustar00rootroot00000000000000double a[10]; int main(int argc, char** argv) { int i; for (i = 0; i < 10; i++) { a[i] = i * 0.88; } a[i] = i; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/basic-loop.ll000066400000000000000000000070631473507761200334140ustar00rootroot00000000000000; ModuleID = 'basic-loop.pp.bc' source_filename = "basic-loop.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !15 { call void @llvm.dbg.value(metadata i32 %0, metadata !22, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i8** %1, metadata !24, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i32 0, metadata !25, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i32 undef, metadata !25, metadata !DIExpression()), !dbg !23 ret i32 0, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!10, !11, !12, !13} !llvm.ident = !{!14} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "basic-loop.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true) !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 640, elements: !8) !7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 10) !10 = !{i32 2, !"Dwarf Version", i32 4} !11 = !{i32 2, !"Debug Info Version", i32 3} !12 = !{i32 1, !"wchar_size", i32 4} !13 = !{i32 7, !"PIC Level", i32 2} !14 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !15 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !16 = !DISubroutineType(types: !17) !17 = !{!18, !18, !19} !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !15, file: !1, line: 3, type: !18) !23 = !DILocation(line: 0, scope: !15) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !15, file: !1, line: 3, type: !19) !25 = !DILocalVariable(name: "i", scope: !15, file: !1, line: 4, type: !18) !26 = !DILocation(line: 9, column: 1, scope: !15) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bit-field-1.c000066400000000000000000000002141473507761200331630ustar00rootroot00000000000000struct info_t { char x : 1; char y : 1; int z : 10; int k : 1; }; int main() { struct info_t info = {0, 0, 42, 1}; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bit-field-1.ll000066400000000000000000000041001473507761200333460ustar00rootroot00000000000000; ModuleID = 'bit-field-1.pp.bc' source_filename = "bit-field-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { ret i32 0, !dbg !12 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bit-field-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !9, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 10, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bit-field-2.c000066400000000000000000000000731473507761200331670ustar00rootroot00000000000000struct { unsigned : 7; unsigned a; } b[6][1] = {{{}}}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bit-field-2.ll000066400000000000000000000032151473507761200333550ustar00rootroot00000000000000; ModuleID = 'bit-field-2.pp.bc' source_filename = "bit-field-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!14, !15, !16, !17} !llvm.ident = !{!18} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "bit-field-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "b", scope: !0, file: !1, line: 4, type: !6, isLocal: false, isDefinition: true) !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 384, elements: !11) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 1, size: 64, elements: !8) !8 = !{!9} !9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !1, line: 3, baseType: !10, size: 32, offset: 32) !10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !11 = !{!12, !13} !12 = !DISubrange(count: 6) !13 = !DISubrange(count: 1) !14 = !{i32 2, !"Dwarf Version", i32 4} !15 = !{i32 2, !"Debug Info Version", i32 3} !16 = !{i32 1, !"wchar_size", i32 4} !17 = !{i32 7, !"PIC Level", i32 2} !18 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} bitwise-cond-1.c000066400000000000000000000001651473507761200336410ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationint foo(int x, int y, int z) { int a = x - y; int b = (z == 0 && a) ? x + y : y + z; return (a > b) ? x : y; } bitwise-cond-1.ll000066400000000000000000000017471473507761200340350ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'bitwise-cond-1.pp.bc' source_filename = "bitwise-cond-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bitwise-cond-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} bitwise-cond-2.c000066400000000000000000000002051473507761200336350ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationint g; int foo(int x, int y) { int z = x - y; int a; if (g == 0 && z) a = x + y; else a = x * y; return a * 42; } bitwise-cond-2.ll000066400000000000000000000023751473507761200340340ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'bitwise-cond-2.pp.bc' source_filename = "bitwise-cond-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "bitwise-cond-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "g", scope: !0, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true) !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bitwise-op.c000066400000000000000000000000641473507761200332530ustar00rootroot00000000000000int main() { int x = 3, y = 5; int z = x | y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bitwise-op.ll000066400000000000000000000054541473507761200334500ustar00rootroot00000000000000; ModuleID = 'bitwise-op.pp.bc' source_filename = "bitwise-op.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 3, metadata !12, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 5, metadata !14, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 3, metadata !15, metadata !DIExpression(DW_OP_constu, 5, DW_OP_or, DW_OP_stack_value)), !dbg !13 ret i32 0, !dbg !16 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bitwise-op.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocalVariable(name: "y", scope: !8, file: !1, line: 2, type: !11) !15 = !DILocalVariable(name: "z", scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 4, column: 1, scope: !8) bool-op-select.cpp000066400000000000000000000003471473507761200343020ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/** * To generate LLVM select instruction, we need to compile * the code with optimization enabled (at least -O1) * * > llvm-g++ -O1 -emit-llvm -o test.bc -g -c test.cpp */ int a; int main() { return a > 0 ? 123 : 321; } bool-op-select.ll000066400000000000000000000045371473507761200341340ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'bool-op-select.pp.bc' source_filename = "bool-op-select.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !12 { ret i32 321, !dbg !15 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 321 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "bool-op-select.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 8, type: !6, isLocal: false, isDefinition: true) !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 10, type: !13, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 11, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bool.cpp000066400000000000000000000000751473507761200324660ustar00rootroot00000000000000bool b = true; int f(bool i) {} int main() { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/bool.ll000066400000000000000000000045771473507761200323260ustar00rootroot00000000000000; ModuleID = 'bool.pp.bc' source_filename = "bool.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !12 { ret i32 0, !dbg !16 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "bool.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "b", scope: !0, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true) !6 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !13, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !13 = !DISubroutineType(types: !14) !14 = !{!15} !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !16 = !DILocation(line: 6, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/branch-undef.c000066400000000000000000000000571473507761200335270ustar00rootroot00000000000000int main() { return main ? 0 % 0 ?: 1 : 2; } branch-undef.ll000066400000000000000000000041021473507761200336300ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'branch-undef.pp.bc' source_filename = "branch-undef.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { ret i32 1, !dbg !12 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 1 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "branch-undef.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 2, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/call-args.c000066400000000000000000000001341473507761200330340ustar00rootroot00000000000000int foo(int i) { return i + 1; } int main(int argc, char** argv) { return foo(argc); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/call-args.ll000066400000000000000000000075531473507761200332350ustar00rootroot00000000000000; ModuleID = 'call-args.pp.bc' source_filename = "call-args.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc i32 @foo(i32) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression()), !dbg !13 %2 = add nsw i32 %0, 1, !dbg !14 ret i32 %2, !dbg !15 } ; CHECK: define si32 @foo(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %2 = %1 sadd.nw 1 ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !16 { call void @llvm.dbg.value(metadata i32 %0, metadata !22, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i8** %1, metadata !24, metadata !DIExpression()), !dbg !23 %3 = call fastcc i32 @foo(i32 %0), !dbg !25 ret i32 %3, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %3 = call @foo(%1) ; CHECK: return %3 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "call-args.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "i", arg: 1, scope: !8, file: !1, line: 1, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocation(line: 2, column: 12, scope: !8) !15 = !DILocation(line: 2, column: 3, scope: !8) !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!11, !11, !19} !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !16, file: !1, line: 5, type: !11) !23 = !DILocation(line: 0, scope: !16) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !16, file: !1, line: 5, type: !19) !25 = !DILocation(line: 6, column: 10, scope: !16) !26 = !DILocation(line: 6, column: 3, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/complex.c000066400000000000000000000001341473507761200326360ustar00rootroot00000000000000#include int main() { double complex c = 1.0 + 2.0 * I; return creal(c); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/complex.ll000066400000000000000000000052431473507761200330310ustar00rootroot00000000000000; ModuleID = 'complex.pp.bc' source_filename = "complex.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata double 1.000000e+00, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 64)), !dbg !14 call void @llvm.dbg.value(metadata double 2.000000e+00, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 64)), !dbg !14 ret i32 1, !dbg !15 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 1 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "complex.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "c", scope: !8, file: !1, line: 4, type: !13) !13 = !DIBasicType(name: "complex", size: 128, encoding: DW_ATE_complex_float) !14 = !DILocation(line: 0, scope: !8) !15 = !DILocation(line: 5, column: 3, scope: !8) constructors.cpp000066400000000000000000000006241473507761200342240ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationextern "C" { extern void __ikos_assert(int); } class Vector { public: int _x; int _y; int _z; Vector(int x, int y, int z) noexcept : _x(x), _y(y), _z(z) {} }; int f(Vector* v) { return v->_y; } class Master { public: Vector* _v; int* _p; Master() { _v = new Vector(1, 2, 3); _p = new int(4); __ikos_assert(f(_v) == 2); } }; int main() { Master master; return 0; } constructors.ll000066400000000000000000000377511473507761200340640ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'constructors.pp.bc' source_filename = "constructors.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Vector = type { i32, i32, i32 } %class.Master = type { %class.Vector*, i32* } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc i32 @_Z1fP6Vector(%class.Vector*) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata %class.Vector* %0, metadata !22, metadata !DIExpression()), !dbg !23 %2 = getelementptr inbounds %class.Vector, %class.Vector* %0, i64 0, i32 1, !dbg !24 %3 = load i32, i32* %2, align 4, !dbg !24 ret i32 %3, !dbg !25 } ; CHECK: define si32 @_Z1fP6Vector({0: si32, 4: si32, 8: si32}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32* %2 = ptrshift %1, 12 * 0, 1 * 4 ; CHECK: si32 %3 = load %2, align 4 ; CHECK: return %3 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define internal fastcc void @_ZN6MasterC1Ev(%class.Master*) unnamed_addr #2 align 2 !dbg !42 { call void @llvm.dbg.value(metadata %class.Master* %0, metadata !43, metadata !DIExpression()), !dbg !45 call fastcc void @_ZN6MasterC2Ev(%class.Master* %0), !dbg !46 ret void, !dbg !47 } ; CHECK: define void @_ZN6MasterC1Ev({0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN6MasterC2Ev(%1) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define internal fastcc void @_ZN6MasterC2Ev(%class.Master*) unnamed_addr #2 align 2 !dbg !48 { call void @llvm.dbg.value(metadata %class.Master* %0, metadata !49, metadata !DIExpression()), !dbg !50 %2 = call i8* @_Znwm(i64 12) #6, !dbg !51 %3 = bitcast i8* %2 to %class.Vector*, !dbg !51 call fastcc void @_ZN6VectorC1Eiii(%class.Vector* %3, i32 1, i32 2, i32 3) #7, !dbg !53 %4 = bitcast %class.Master* %0 to i8**, !dbg !54 store i8* %2, i8** %4, align 8, !dbg !54 %5 = call i8* @_Znwm(i64 4) #6, !dbg !55 %6 = bitcast i8* %5 to i32*, !dbg !55 store i32 4, i32* %6, align 4, !dbg !55 %7 = getelementptr inbounds %class.Master, %class.Master* %0, i64 0, i32 1, !dbg !56 %8 = bitcast i32** %7 to i8**, !dbg !57 store i8* %5, i8** %8, align 8, !dbg !57 %9 = call fastcc i32 @_Z1fP6Vector(%class.Vector* %3), !dbg !58 %10 = icmp eq i32 %9, 2, !dbg !59 %11 = zext i1 %10 to i32, !dbg !58 call void @__ikos_assert(i32 %11), !dbg !60 ret void, !dbg !61 } ; CHECK: define void @_ZN6MasterC2Ev({0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %1) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si8* %2 = call @ar.libcpp.new(12) ; CHECK: {0: si32, 4: si32, 8: si32}* %3 = bitcast %2 ; CHECK: call @_ZN6VectorC1Eiii(%3, 1, 2, 3) ; CHECK: si8** %4 = bitcast %1 ; CHECK: store %4, %2, align 8 ; CHECK: si8* %5 = call @ar.libcpp.new(4) ; CHECK: si32* %6 = bitcast %5 ; CHECK: store %6, 4, align 4 ; CHECK: si32** %7 = ptrshift %1, 16 * 0, 1 * 8 ; CHECK: si8** %8 = bitcast %7 ; CHECK: store %8, %5, align 8 ; CHECK: si32 %9 = call @_Z1fP6Vector(%3) ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %9 sieq 2 ; CHECK: ui1 %10 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %9 sine 2 ; CHECK: ui1 %10 = 0 ; CHECK: } ; CHECK: #4 !exit predecessors={#2, #3} { ; CHECK: ui32 %11 = zext %10 ; CHECK: call @ar.ikos.assert(%11) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN6VectorC1Eiii(%class.Vector*, i32, i32, i32) unnamed_addr #0 align 2 !dbg !62 { call void @llvm.dbg.value(metadata %class.Vector* %0, metadata !63, metadata !DIExpression()), !dbg !64 call void @llvm.dbg.value(metadata i32 %1, metadata !65, metadata !DIExpression()), !dbg !64 call void @llvm.dbg.value(metadata i32 %2, metadata !66, metadata !DIExpression()), !dbg !64 call void @llvm.dbg.value(metadata i32 %3, metadata !67, metadata !DIExpression()), !dbg !64 call fastcc void @_ZN6VectorC2Eiii(%class.Vector* %0, i32 %1, i32 %2, i32 %3) #7, !dbg !68 ret void, !dbg !69 } ; CHECK: define void @_ZN6VectorC1Eiii({0: si32, 4: si32, 8: si32}* %1, si32 %2, si32 %3, si32 %4) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN6VectorC2Eiii(%1, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN6VectorC2Eiii(%class.Vector*, i32, i32, i32) unnamed_addr #0 align 2 !dbg !70 { call void @llvm.dbg.value(metadata %class.Vector* %0, metadata !71, metadata !DIExpression()), !dbg !72 call void @llvm.dbg.value(metadata i32 %1, metadata !73, metadata !DIExpression()), !dbg !72 call void @llvm.dbg.value(metadata i32 %2, metadata !74, metadata !DIExpression()), !dbg !72 call void @llvm.dbg.value(metadata i32 %3, metadata !75, metadata !DIExpression()), !dbg !72 %5 = getelementptr inbounds %class.Vector, %class.Vector* %0, i64 0, i32 0, !dbg !76 store i32 %1, i32* %5, align 4, !dbg !76 %6 = getelementptr inbounds %class.Vector, %class.Vector* %0, i64 0, i32 1, !dbg !77 store i32 %2, i32* %6, align 4, !dbg !77 %7 = getelementptr inbounds %class.Vector, %class.Vector* %0, i64 0, i32 2, !dbg !78 store i32 %3, i32* %7, align 4, !dbg !78 ret void, !dbg !79 } ; CHECK: define void @_ZN6VectorC2Eiii({0: si32, 4: si32, 8: si32}* %1, si32 %2, si32 %3, si32 %4) { ; CHECK: #1 !entry !exit { ; CHECK: si32* %5 = ptrshift %1, 12 * 0, 1 * 0 ; CHECK: store %5, %2, align 4 ; CHECK: si32* %6 = ptrshift %1, 12 * 0, 1 * 4 ; CHECK: store %6, %3, align 4 ; CHECK: si32* %7 = ptrshift %1, 12 * 0, 1 * 8 ; CHECK: store %7, %4, align 4 ; CHECK: return ; CHECK: } ; CHECK: } declare void @__ikos_assert(i32) local_unnamed_addr #4 ; CHECK: declare void @ar.ikos.assert(ui32) ; Function Attrs: nobuiltin declare noalias i8* @_Znwm(i64) local_unnamed_addr #3 ; CHECK: declare si8* @ar.libcpp.new(ui64) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() local_unnamed_addr #1 !dbg !26 { %1 = alloca %class.Master, align 8 call void @llvm.dbg.value(metadata %class.Master* %1, metadata !29, metadata !DIExpression(DW_OP_deref)), !dbg !39 call fastcc void @_ZN6MasterC1Ev(%class.Master* nonnull %1), !dbg !40 ret i32 0, !dbg !41 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* $1 = allocate {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}, 1, align 8 ; CHECK: call @_ZN6MasterC1Ev($1) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #5 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nobuiltin "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #5 = { nounwind readnone speculatable } attributes #6 = { builtin } attributes #7 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "constructors.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fP6Vector", scope: !1, file: !1, line: 14, type: !9, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Vector", file: !1, line: 5, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !14, identifier: "_ZTS6Vector") !14 = !{!15, !16, !17, !18} !15 = !DIDerivedType(tag: DW_TAG_member, name: "_x", scope: !13, file: !1, line: 7, baseType: !11, size: 32, flags: DIFlagPublic) !16 = !DIDerivedType(tag: DW_TAG_member, name: "_y", scope: !13, file: !1, line: 8, baseType: !11, size: 32, offset: 32, flags: DIFlagPublic) !17 = !DIDerivedType(tag: DW_TAG_member, name: "_z", scope: !13, file: !1, line: 9, baseType: !11, size: 32, offset: 64, flags: DIFlagPublic) !18 = !DISubprogram(name: "Vector", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !19 = !DISubroutineType(types: !20) !20 = !{null, !21, !11, !11, !11} !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !22 = !DILocalVariable(name: "v", arg: 1, scope: !8, file: !1, line: 14, type: !12) !23 = !DILocation(line: 0, scope: !8) !24 = !DILocation(line: 15, column: 13, scope: !8) !25 = !DILocation(line: 15, column: 3, scope: !8) !26 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 30, type: !27, scopeLine: 30, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !27 = !DISubroutineType(types: !28) !28 = !{!11} !29 = !DILocalVariable(name: "master", scope: !26, file: !1, line: 31, type: !30) !30 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Master", file: !1, line: 18, size: 128, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !31, identifier: "_ZTS6Master") !31 = !{!32, !33, !35} !32 = !DIDerivedType(tag: DW_TAG_member, name: "_v", scope: !30, file: !1, line: 20, baseType: !12, size: 64, flags: DIFlagPublic) !33 = !DIDerivedType(tag: DW_TAG_member, name: "_p", scope: !30, file: !1, line: 21, baseType: !34, size: 64, offset: 64, flags: DIFlagPublic) !34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !35 = !DISubprogram(name: "Master", scope: !30, file: !1, line: 23, type: !36, scopeLine: 23, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !36 = !DISubroutineType(types: !37) !37 = !{null, !38} !38 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !39 = !DILocation(line: 0, scope: !26) !40 = !DILocation(line: 31, column: 10, scope: !26) !41 = !DILocation(line: 32, column: 3, scope: !26) !42 = distinct !DISubprogram(name: "Master", linkageName: "_ZN6MasterC1Ev", scope: !30, file: !1, line: 23, type: !36, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !35, retainedNodes: !2) !43 = !DILocalVariable(name: "this", arg: 1, scope: !42, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer) !44 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) !45 = !DILocation(line: 0, scope: !42) !46 = !DILocation(line: 23, column: 12, scope: !42) !47 = !DILocation(line: 27, column: 3, scope: !42) !48 = distinct !DISubprogram(name: "Master", linkageName: "_ZN6MasterC2Ev", scope: !30, file: !1, line: 23, type: !36, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !35, retainedNodes: !2) !49 = !DILocalVariable(name: "this", arg: 1, scope: !48, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer) !50 = !DILocation(line: 0, scope: !48) !51 = !DILocation(line: 24, column: 10, scope: !52) !52 = distinct !DILexicalBlock(scope: !48, file: !1, line: 23, column: 12) !53 = !DILocation(line: 24, column: 14, scope: !52) !54 = !DILocation(line: 24, column: 8, scope: !52) !55 = !DILocation(line: 25, column: 10, scope: !52) !56 = !DILocation(line: 25, column: 5, scope: !52) !57 = !DILocation(line: 25, column: 8, scope: !52) !58 = !DILocation(line: 26, column: 19, scope: !52) !59 = !DILocation(line: 26, column: 25, scope: !52) !60 = !DILocation(line: 26, column: 5, scope: !52) !61 = !DILocation(line: 27, column: 3, scope: !48) !62 = distinct !DISubprogram(name: "Vector", linkageName: "_ZN6VectorC1Eiii", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !18, retainedNodes: !2) !63 = !DILocalVariable(name: "this", arg: 1, scope: !62, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) !64 = !DILocation(line: 0, scope: !62) !65 = !DILocalVariable(name: "x", arg: 2, scope: !62, file: !1, line: 11, type: !11) !66 = !DILocalVariable(name: "y", arg: 3, scope: !62, file: !1, line: 11, type: !11) !67 = !DILocalVariable(name: "z", arg: 4, scope: !62, file: !1, line: 11, type: !11) !68 = !DILocation(line: 11, column: 62, scope: !62) !69 = !DILocation(line: 11, column: 63, scope: !62) !70 = distinct !DISubprogram(name: "Vector", linkageName: "_ZN6VectorC2Eiii", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !18, retainedNodes: !2) !71 = !DILocalVariable(name: "this", arg: 1, scope: !70, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) !72 = !DILocation(line: 0, scope: !70) !73 = !DILocalVariable(name: "x", arg: 2, scope: !70, file: !1, line: 11, type: !11) !74 = !DILocalVariable(name: "y", arg: 3, scope: !70, file: !1, line: 11, type: !11) !75 = !DILocalVariable(name: "z", arg: 4, scope: !70, file: !1, line: 11, type: !11) !76 = !DILocation(line: 11, column: 42, scope: !70) !77 = !DILocation(line: 11, column: 49, scope: !70) !78 = !DILocation(line: 11, column: 56, scope: !70) !79 = !DILocation(line: 11, column: 63, scope: !70) empty-array-1.c000066400000000000000000000000731473507761200335220ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationstruct { char a[0]; int* b; double c; } d = {{}, 1}; empty-array-1.ll000066400000000000000000000040101473507761200337020ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'empty-array-1.pp.bc' source_filename = "empty-array-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!18, !19, !20, !21} !llvm.ident = !{!22} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "empty-array-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "d", scope: !0, file: !1, line: 5, type: !6, isLocal: false, isDefinition: true) !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 1, size: 128, elements: !7) !7 = !{!8, !13, !16} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 3, baseType: !14, size: 64) !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !16 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !6, file: !1, line: 4, baseType: !17, size: 64, offset: 64) !17 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !18 = !{i32 2, !"Dwarf Version", i32 4} !19 = !{i32 2, !"Debug Info Version", i32 3} !20 = !{i32 1, !"wchar_size", i32 4} !21 = !{i32 7, !"PIC Level", i32 2} !22 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} empty-array-2.c000066400000000000000000000000771473507761200335270ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationstruct { int a[0]; struct { int b; }; } c = {{}, 6}; empty-array-2.ll000066400000000000000000000036271473507761200337200ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'empty-array-2.pp.bc' source_filename = "empty-array-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!17, !18, !19, !20} !llvm.ident = !{!21} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "empty-array-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 6, type: !6, isLocal: false, isDefinition: true) !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 1, size: 32, elements: !7) !7 = !{!8, !13} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, scope: !6, file: !1, line: 3, baseType: !14, size: 32) !14 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !6, file: !1, line: 3, size: 32, elements: !15) !15 = !{!16} !16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 4, baseType: !10, size: 32) !17 = !{i32 2, !"Dwarf Version", i32 4} !18 = !{i32 2, !"Debug Info Version", i32 3} !19 = !{i32 1, !"wchar_size", i32 4} !20 = !{i32 7, !"PIC Level", i32 2} !21 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} empty-array-3.c000066400000000000000000000000501473507761200335170ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationunion { char a[0]; int b; } c = {}; empty-array-3.ll000066400000000000000000000033721473507761200337160ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'empty-array-3.pp.bc' source_filename = "empty-array-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "empty-array-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 4, type: !6, isLocal: false, isDefinition: true) !6 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 1, size: 32, elements: !7) !7 = !{!8, !13} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 3, baseType: !14, size: 32) !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} empty-function-body.c000066400000000000000000000001131473507761200350210ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationvoid GEN2_w_test2_terminate(void) { /* (no terminate code required) */ } empty-function-body.ll000066400000000000000000000017661473507761200352250ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'empty-function-body.pp.bc' source_filename = "empty-function-body.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "empty-function-body.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} file-intrinsics.c000066400000000000000000000003521473507761200342140ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include int main() { FILE* f = fopen("/tmp/test", "rw"); char buf[1025]; int x; fgets(buf, 1024, f); fgetc(f); fputs("hello world", f); fprintf(f, "%d", 1); fscanf(f, "%d", &x); fflush(f); fclose(f); } file-intrinsics.ll000066400000000000000000000333731473507761200344120ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'file-intrinsics.pp.bc' source_filename = "file-intrinsics.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 } %struct.__sFILEX = type opaque %struct.__sbuf = type { i8*, i32 } @.str = private unnamed_addr constant [10 x i8] c"/tmp/test\00", align 1 ; CHECK: define [10 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [47, 116, 109, 112, 47, 116, 101, 115, 116, 0], align 1 ; CHECK: } ; CHECK: } @.str.1 = private unnamed_addr constant [3 x i8] c"rw\00", align 1 ; CHECK: define [3 x si8]* @.str.1, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.1, [114, 119, 0], align 1 ; CHECK: } ; CHECK: } @.str.2 = private unnamed_addr constant [12 x i8] c"hello world\00", align 1 ; CHECK: define [12 x si8]* @.str.2, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.2, [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0], align 1 ; CHECK: } ; CHECK: } @.str.3 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 ; CHECK: define [3 x si8]* @.str.3, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.3, [37, 100, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @fclose(%struct.__sFILE*) local_unnamed_addr #2 ; CHECK: declare si32 @ar.libc.fclose(opaque*) declare i32 @fflush(%struct.__sFILE*) local_unnamed_addr #2 ; CHECK: declare si32 @ar.libc.fflush(opaque*) declare i32 @fgetc(%struct.__sFILE*) local_unnamed_addr #2 ; CHECK: declare si32 @ar.libc.fgetc(opaque*) declare i8* @fgets(i8*, i32, %struct.__sFILE*) local_unnamed_addr #2 ; CHECK: declare si8* @ar.libc.fgets(si8*, si32, opaque*) declare %struct.__sFILE* @"\01_fopen"(i8*, i8*) local_unnamed_addr #2 ; CHECK: declare opaque* @ar.libc.fopen(si8*, si8*) declare i32 @"\01_fputs"(i8*, %struct.__sFILE*) local_unnamed_addr #2 ; CHECK: declare si32 @ar.libc.fputs(si8*, opaque*) declare i32 @fscanf(%struct.__sFILE*, i8*, ...) local_unnamed_addr #2 ; CHECK: declare si32 @ar.libc.fscanf(opaque*, si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { %1 = alloca [1025 x i8], align 16 %2 = alloca i32, align 4 %3 = getelementptr inbounds [10 x i8], [10 x i8]* @.str, i64 0, i64 0, !dbg !12 %4 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.1, i64 0, i64 0, !dbg !12 %5 = call %struct.__sFILE* @"\01_fopen"(i8* %3, i8* %4) #3, !dbg !12 call void @llvm.dbg.value(metadata %struct.__sFILE* %5, metadata !13, metadata !DIExpression()), !dbg !77 call void @llvm.dbg.declare(metadata [1025 x i8]* %1, metadata !78, metadata !DIExpression()), !dbg !82 %6 = getelementptr inbounds [1025 x i8], [1025 x i8]* %1, i64 0, i64 0, !dbg !83 %7 = call i8* @fgets(i8* nonnull %6, i32 1024, %struct.__sFILE* %5) #3, !dbg !84 %8 = call i32 @fgetc(%struct.__sFILE* %5) #3, !dbg !85 %9 = getelementptr inbounds [12 x i8], [12 x i8]* @.str.2, i64 0, i64 0, !dbg !86 %10 = call i32 @"\01_fputs"(i8* %9, %struct.__sFILE* %5) #3, !dbg !86 call void @llvm.dbg.value(metadata i32* %2, metadata !87, metadata !DIExpression(DW_OP_deref)), !dbg !77 %11 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.3, i64 0, i64 0, !dbg !88 %12 = call i32 (%struct.__sFILE*, i8*, ...) @fscanf(%struct.__sFILE* %5, i8* %11, i32* nonnull %2) #3, !dbg !88 %13 = call i32 @fflush(%struct.__sFILE* %5) #3, !dbg !89 %14 = call i32 @fclose(%struct.__sFILE* %5) #3, !dbg !90 ret i32 0, !dbg !91 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: [1025 x si8]* $1 = allocate [1025 x si8], 1, align 16 ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: si8* %3 = ptrshift @.str, 10 * 0, 1 * 0 ; CHECK: si8* %4 = ptrshift @.str.1, 3 * 0, 1 * 0 ; CHECK: opaque* %5 = call @ar.libc.fopen(%3, %4) ; CHECK: {0: ui8*, 8: si32, 12: si32, 16: si16, 18: si16, 24: {0: ui8*, 8: si32}, 40: si32, 48: si8*, 56: si32 (si8*)*, 64: si32 (si8*, si8*, si32)*, 72: si64 (si8*, si64, si32)*, 80: si32 (si8*, si8*, si32)*, 88: {0: ui8*, 8: si32}, 104: opaque*, 112: si32, 116: [3 x ui8], 119: [1 x ui8], 120: {0: ui8*, 8: si32}, 136: si32, 144: si64}* %6 = bitcast %5 ; CHECK: si8* %7 = ptrshift $1, 1025 * 0, 1 * 0 ; CHECK: opaque* %8 = bitcast %6 ; CHECK: si8* %9 = call @ar.libc.fgets(%7, 1024, %8) ; CHECK: opaque* %10 = bitcast %6 ; CHECK: si32 %11 = call @ar.libc.fgetc(%10) ; CHECK: si8* %12 = ptrshift @.str.2, 12 * 0, 1 * 0 ; CHECK: opaque* %13 = bitcast %6 ; CHECK: si32 %14 = call @ar.libc.fputs(%12, %13) ; CHECK: si8* %15 = ptrshift @.str.3, 3 * 0, 1 * 0 ; CHECK: opaque* %16 = bitcast %6 ; CHECK: si32 %17 = call @ar.libc.fscanf(%16, %15, $2) ; CHECK: opaque* %18 = bitcast %6 ; CHECK: si32 %19 = call @ar.libc.fflush(%18) ; CHECK: opaque* %20 = bitcast %6 ; CHECK: si32 %21 = call @ar.libc.fclose(%20) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "file-intrinsics.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 4, column: 13, scope: !8) !13 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 4, type: !14) !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "FILE", file: !16, line: 157, baseType: !17) !16 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/_stdio.h", directory: "") !17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__sFILE", file: !16, line: 126, size: 1216, elements: !18) !18 = !{!19, !22, !23, !24, !26, !27, !32, !33, !35, !39, !45, !55, !61, !62, !65, !66, !70, !74, !75, !76} !19 = !DIDerivedType(tag: DW_TAG_member, name: "_p", scope: !17, file: !16, line: 127, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !22 = !DIDerivedType(tag: DW_TAG_member, name: "_r", scope: !17, file: !16, line: 128, baseType: !11, size: 32, offset: 64) !23 = !DIDerivedType(tag: DW_TAG_member, name: "_w", scope: !17, file: !16, line: 129, baseType: !11, size: 32, offset: 96) !24 = !DIDerivedType(tag: DW_TAG_member, name: "_flags", scope: !17, file: !16, line: 130, baseType: !25, size: 16, offset: 128) !25 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) !26 = !DIDerivedType(tag: DW_TAG_member, name: "_file", scope: !17, file: !16, line: 131, baseType: !25, size: 16, offset: 144) !27 = !DIDerivedType(tag: DW_TAG_member, name: "_bf", scope: !17, file: !16, line: 132, baseType: !28, size: 128, offset: 192) !28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__sbuf", file: !16, line: 92, size: 128, elements: !29) !29 = !{!30, !31} !30 = !DIDerivedType(tag: DW_TAG_member, name: "_base", scope: !28, file: !16, line: 93, baseType: !20, size: 64) !31 = !DIDerivedType(tag: DW_TAG_member, name: "_size", scope: !28, file: !16, line: 94, baseType: !11, size: 32, offset: 64) !32 = !DIDerivedType(tag: DW_TAG_member, name: "_lbfsize", scope: !17, file: !16, line: 133, baseType: !11, size: 32, offset: 320) !33 = !DIDerivedType(tag: DW_TAG_member, name: "_cookie", scope: !17, file: !16, line: 136, baseType: !34, size: 64, offset: 384) !34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !35 = !DIDerivedType(tag: DW_TAG_member, name: "_close", scope: !17, file: !16, line: 137, baseType: !36, size: 64, offset: 448) !36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !37, size: 64) !37 = !DISubroutineType(types: !38) !38 = !{!11, !34} !39 = !DIDerivedType(tag: DW_TAG_member, name: "_read", scope: !17, file: !16, line: 138, baseType: !40, size: 64, offset: 512) !40 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !41, size: 64) !41 = !DISubroutineType(types: !42) !42 = !{!11, !34, !43, !11} !43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !44, size: 64) !44 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !45 = !DIDerivedType(tag: DW_TAG_member, name: "_seek", scope: !17, file: !16, line: 139, baseType: !46, size: 64, offset: 576) !46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !47, size: 64) !47 = !DISubroutineType(types: !48) !48 = !{!49, !34, !49, !11} !49 = !DIDerivedType(tag: DW_TAG_typedef, name: "fpos_t", file: !16, line: 81, baseType: !50) !50 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_off_t", file: !51, line: 71, baseType: !52) !51 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h", directory: "") !52 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int64_t", file: !53, line: 46, baseType: !54) !53 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/i386/_types.h", directory: "") !54 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) !55 = !DIDerivedType(tag: DW_TAG_member, name: "_write", scope: !17, file: !16, line: 140, baseType: !56, size: 64, offset: 640) !56 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64) !57 = !DISubroutineType(types: !58) !58 = !{!11, !34, !59, !11} !59 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !60, size: 64) !60 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !44) !61 = !DIDerivedType(tag: DW_TAG_member, name: "_ub", scope: !17, file: !16, line: 143, baseType: !28, size: 128, offset: 704) !62 = !DIDerivedType(tag: DW_TAG_member, name: "_extra", scope: !17, file: !16, line: 144, baseType: !63, size: 64, offset: 832) !63 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !64, size: 64) !64 = !DICompositeType(tag: DW_TAG_structure_type, name: "__sFILEX", file: !16, line: 98, flags: DIFlagFwdDecl) !65 = !DIDerivedType(tag: DW_TAG_member, name: "_ur", scope: !17, file: !16, line: 145, baseType: !11, size: 32, offset: 896) !66 = !DIDerivedType(tag: DW_TAG_member, name: "_ubuf", scope: !17, file: !16, line: 148, baseType: !67, size: 24, offset: 928) !67 = !DICompositeType(tag: DW_TAG_array_type, baseType: !21, size: 24, elements: !68) !68 = !{!69} !69 = !DISubrange(count: 3) !70 = !DIDerivedType(tag: DW_TAG_member, name: "_nbuf", scope: !17, file: !16, line: 149, baseType: !71, size: 8, offset: 952) !71 = !DICompositeType(tag: DW_TAG_array_type, baseType: !21, size: 8, elements: !72) !72 = !{!73} !73 = !DISubrange(count: 1) !74 = !DIDerivedType(tag: DW_TAG_member, name: "_lb", scope: !17, file: !16, line: 152, baseType: !28, size: 128, offset: 960) !75 = !DIDerivedType(tag: DW_TAG_member, name: "_blksize", scope: !17, file: !16, line: 155, baseType: !11, size: 32, offset: 1088) !76 = !DIDerivedType(tag: DW_TAG_member, name: "_offset", scope: !17, file: !16, line: 156, baseType: !49, size: 64, offset: 1152) !77 = !DILocation(line: 0, scope: !8) !78 = !DILocalVariable(name: "buf", scope: !8, file: !1, line: 5, type: !79) !79 = !DICompositeType(tag: DW_TAG_array_type, baseType: !44, size: 8200, elements: !80) !80 = !{!81} !81 = !DISubrange(count: 1025) !82 = !DILocation(line: 5, column: 8, scope: !8) !83 = !DILocation(line: 7, column: 9, scope: !8) !84 = !DILocation(line: 7, column: 3, scope: !8) !85 = !DILocation(line: 8, column: 3, scope: !8) !86 = !DILocation(line: 9, column: 3, scope: !8) !87 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 6, type: !11) !88 = !DILocation(line: 11, column: 3, scope: !8) !89 = !DILocation(line: 12, column: 3, scope: !8) !90 = !DILocation(line: 13, column: 3, scope: !8) !91 = !DILocation(line: 14, column: 1, scope: !8) flexible-array-member.c000066400000000000000000000001361473507761200352650ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationstruct line { int length; char contents[]; }; struct line l; int main() { return 0; } flexible-array-member.ll000066400000000000000000000055371473507761200354640ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'flexible-array-member.pp.bc' source_filename = "flexible-array-member.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !20 { ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "flexible-array-member.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "l", scope: !0, file: !1, line: 6, type: !6, isLocal: false, isDefinition: true) !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "line", file: !1, line: 1, size: 32, elements: !7) !7 = !{!8, !10} !8 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !6, file: !1, line: 2, baseType: !9, size: 32) !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !10 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !6, file: !1, line: 3, baseType: !11, offset: 32) !11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, elements: !13) !12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !13 = !{!14} !14 = !DISubrange(count: -1) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !21, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !21 = !DISubroutineType(types: !22) !22 = !{!9} !23 = !DILocation(line: 9, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/gv-init.c000066400000000000000000000004321473507761200325450ustar00rootroot00000000000000int a[100][100]; int b[2] = {1, 2}; int c; int d = 5; extern int e; int main(int argc, char** argv) { int i = 0, j = 0; for (; i < 100; i++) for (; j < 100; j++) if (i % 2 == 0) a[i][j] = b[0] + c - e; else a[i][j] = b[1] + d - e; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/gv-init.ll000066400000000000000000000166701473507761200327450ustar00rootroot00000000000000; ModuleID = 'gv-init.pp.bc' source_filename = "gv-init.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !24 { call void @llvm.dbg.value(metadata i32 %0, metadata !30, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i8** %1, metadata !32, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i32 0, metadata !33, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i32 0, metadata !34, metadata !DIExpression()), !dbg !31 br label %3, !dbg !35 3: ; preds = %8, %2 %.01 = phi i32 [ 0, %2 ], [ %9, %8 ], !dbg !31 %.0 = phi i32 [ 0, %2 ], [ %.1.lcssa, %8 ], !dbg !36 call void @llvm.dbg.value(metadata i32 %.0, metadata !34, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i32 %.01, metadata !33, metadata !DIExpression()), !dbg !31 %4 = icmp ult i32 %.01, 100, !dbg !37 br i1 %4, label %.preheader, label %10, !dbg !40 .preheader: ; preds = %3, %6 %.1 = phi i32 [ %7, %6 ], [ %.0, %3 ], !dbg !31 call void @llvm.dbg.value(metadata i32 %.1, metadata !34, metadata !DIExpression()), !dbg !31 %5 = icmp slt i32 %.1, 100, !dbg !41 br i1 %5, label %6, label %8, !dbg !44 6: ; preds = %.preheader %7 = add nsw i32 %.1, 1, !dbg !45 call void @llvm.dbg.value(metadata i32 %7, metadata !34, metadata !DIExpression()), !dbg !31 br label %.preheader, !dbg !46, !llvm.loop !47 8: ; preds = %.preheader %.1.lcssa = phi i32 [ %.1, %.preheader ], !dbg !31 call void @llvm.dbg.value(metadata i32 %.1.lcssa, metadata !34, metadata !DIExpression()), !dbg !31 %9 = add nuw nsw i32 %.01, 1, !dbg !49 call void @llvm.dbg.value(metadata i32 %9, metadata !33, metadata !DIExpression()), !dbg !31 br label %3, !dbg !50, !llvm.loop !51 10: ; preds = %3 ret i32 0, !dbg !53 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32 %.01 = 0 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #6} successors={#3, #4} { ; CHECK: ui32 %3 = bitcast %.01 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#.preheader} { ; CHECK: %3 uilt 100 ; CHECK: si32 %.1 = %.0 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %3 uige 100 ; CHECK: return 0 ; CHECK: } ; CHECK: #.preheader predecessors={#3, #5} successors={#5, #6} { ; CHECK: } ; CHECK: #5 predecessors={#.preheader} successors={#.preheader} { ; CHECK: %.1 silt 100 ; CHECK: si32 %4 = %.1 sadd.nw 1 ; CHECK: si32 %.1 = %4 ; CHECK: } ; CHECK: #6 predecessors={#.preheader} successors={#2} { ; CHECK: %.1 sige 100 ; CHECK: si32 %.1.lcssa = %.1 ; CHECK: si32 %5 = %.01 sadd.nw 1 ; CHECK: si32 %.01 = %5 ; CHECK: si32 %.0 = %.1.lcssa ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!19, !20, !21, !22} !llvm.ident = !{!23} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "gv-init.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4, !10, !12, !17} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "b", scope: !0, file: !1, line: 2, type: !6, isLocal: false, isDefinition: true) !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !8) !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !8 = !{!9} !9 = !DISubrange(count: 2) !10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) !11 = distinct !DIGlobalVariable(name: "d", scope: !0, file: !1, line: 4, type: !7, isLocal: false, isDefinition: true) !12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression()) !13 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 1, type: !14, isLocal: false, isDefinition: true) !14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 320000, elements: !15) !15 = !{!16, !16} !16 = !DISubrange(count: 100) !17 = !DIGlobalVariableExpression(var: !18, expr: !DIExpression()) !18 = distinct !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 3, type: !7, isLocal: false, isDefinition: true) !19 = !{i32 2, !"Dwarf Version", i32 4} !20 = !{i32 2, !"Debug Info Version", i32 3} !21 = !{i32 1, !"wchar_size", i32 4} !22 = !{i32 7, !"PIC Level", i32 2} !23 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !24 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !25, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !25 = !DISubroutineType(types: !26) !26 = !{!7, !7, !27} !27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64) !28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64) !29 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !30 = !DILocalVariable(name: "argc", arg: 1, scope: !24, file: !1, line: 7, type: !7) !31 = !DILocation(line: 0, scope: !24) !32 = !DILocalVariable(name: "argv", arg: 2, scope: !24, file: !1, line: 7, type: !27) !33 = !DILocalVariable(name: "i", scope: !24, file: !1, line: 8, type: !7) !34 = !DILocalVariable(name: "j", scope: !24, file: !1, line: 8, type: !7) !35 = !DILocation(line: 9, column: 3, scope: !24) !36 = !DILocation(line: 8, column: 14, scope: !24) !37 = !DILocation(line: 9, column: 12, scope: !38) !38 = distinct !DILexicalBlock(scope: !39, file: !1, line: 9, column: 3) !39 = distinct !DILexicalBlock(scope: !24, file: !1, line: 9, column: 3) !40 = !DILocation(line: 9, column: 3, scope: !39) !41 = !DILocation(line: 10, column: 14, scope: !42) !42 = distinct !DILexicalBlock(scope: !43, file: !1, line: 10, column: 5) !43 = distinct !DILexicalBlock(scope: !38, file: !1, line: 10, column: 5) !44 = !DILocation(line: 10, column: 5, scope: !43) !45 = !DILocation(line: 10, column: 22, scope: !42) !46 = !DILocation(line: 10, column: 5, scope: !42) !47 = distinct !{!47, !44, !48} !48 = !DILocation(line: 14, column: 30, scope: !43) !49 = !DILocation(line: 9, column: 20, scope: !38) !50 = !DILocation(line: 9, column: 3, scope: !38) !51 = distinct !{!51, !40, !52} !52 = !DILocation(line: 14, column: 30, scope: !39) !53 = !DILocation(line: 15, column: 3, scope: !24) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/linked-list.c000066400000000000000000000001671473507761200334140ustar00rootroot00000000000000struct node { int value; struct node* next; }; struct node head; int main(int argc, char** argv) { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/linked-list.ll000066400000000000000000000070341473507761200336010ustar00rootroot00000000000000; ModuleID = 'linked-list.pp.bc' source_filename = "linked-list.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !17 { call void @llvm.dbg.value(metadata i32 %0, metadata !23, metadata !DIExpression()), !dbg !24 call void @llvm.dbg.value(metadata i8** %1, metadata !25, metadata !DIExpression()), !dbg !24 ret i32 0, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!12, !13, !14, !15} !llvm.ident = !{!16} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "linked-list.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "head", scope: !0, file: !1, line: 6, type: !6, isLocal: false, isDefinition: true) !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "node", file: !1, line: 1, size: 128, elements: !7) !7 = !{!8, !10} !8 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !6, file: !1, line: 2, baseType: !9, size: 32) !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !10 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !6, file: !1, line: 3, baseType: !11, size: 64, offset: 64) !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) !12 = !{i32 2, !"Dwarf Version", i32 4} !13 = !{i32 2, !"Debug Info Version", i32 3} !14 = !{i32 1, !"wchar_size", i32 4} !15 = !{i32 7, !"PIC Level", i32 2} !16 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !17 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !18, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !18 = !DISubroutineType(types: !19) !19 = !{!9, !9, !20} !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !23 = !DILocalVariable(name: "argc", arg: 1, scope: !17, file: !1, line: 8, type: !9) !24 = !DILocation(line: 0, scope: !17) !25 = !DILocalVariable(name: "argv", arg: 2, scope: !17, file: !1, line: 8, type: !20) !26 = !DILocation(line: 9, column: 3, scope: !17) local-array-1.c000066400000000000000000000002771473507761200334640ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization// SAFE #include // To test loops int main(int argc, char** argv) { int i; int a[10]; for (i = 0; i < 10; i++) { a[i] = i; } printf("%d\n", a[i - 1]); return 0; } local-array-1.ll000066400000000000000000000132001473507761200336370ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'local-array-1.pp.bc' source_filename = "local-array-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !8 { %3 = alloca [10 x i32], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata [10 x i32]* %3, metadata !18, metadata !DIExpression()), !dbg !22 call void @llvm.dbg.value(metadata i32 0, metadata !23, metadata !DIExpression()), !dbg !16 br label %4, !dbg !24 4: ; preds = %6, %2 %.0 = phi i32 [ 0, %2 ], [ %9, %6 ], !dbg !26 call void @llvm.dbg.value(metadata i32 %.0, metadata !23, metadata !DIExpression()), !dbg !16 %5 = icmp ult i32 %.0, 10, !dbg !27 br i1 %5, label %6, label %10, !dbg !29 6: ; preds = %4 %7 = zext i32 %.0 to i64, !dbg !30 %8 = getelementptr inbounds [10 x i32], [10 x i32]* %3, i64 0, i64 %7, !dbg !30 store i32 %.0, i32* %8, align 4, !dbg !32 %9 = add nuw nsw i32 %.0, 1, !dbg !33 call void @llvm.dbg.value(metadata i32 %9, metadata !23, metadata !DIExpression()), !dbg !16 br label %4, !dbg !34, !llvm.loop !35 10: ; preds = %4 call void @llvm.dbg.value(metadata !2, metadata !23, metadata !DIExpression()), !dbg !16 ret i32 0, !dbg !37 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: [10 x si32]* $3 = allocate [10 x si32], 1, align 16 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: ui32 %4 = bitcast %.0 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %4 uilt 10 ; CHECK: ui32 %5 = bitcast %.0 ; CHECK: ui64 %6 = zext %5 ; CHECK: si32* %7 = ptrshift $3, 40 * 0, 4 * %6 ; CHECK: store %7, %.0, align 4 ; CHECK: si32 %8 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %8 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %4 uige 10 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "local-array-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 6, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 6, type: !12) !18 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 8, type: !19) !19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !20) !20 = !{!21} !21 = !DISubrange(count: 10) !22 = !DILocation(line: 8, column: 7, scope: !8) !23 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 7, type: !11) !24 = !DILocation(line: 9, column: 8, scope: !25) !25 = distinct !DILexicalBlock(scope: !8, file: !1, line: 9, column: 3) !26 = !DILocation(line: 0, scope: !25) !27 = !DILocation(line: 9, column: 17, scope: !28) !28 = distinct !DILexicalBlock(scope: !25, file: !1, line: 9, column: 3) !29 = !DILocation(line: 9, column: 3, scope: !25) !30 = !DILocation(line: 10, column: 5, scope: !31) !31 = distinct !DILexicalBlock(scope: !28, file: !1, line: 9, column: 28) !32 = !DILocation(line: 10, column: 10, scope: !31) !33 = !DILocation(line: 9, column: 24, scope: !28) !34 = !DILocation(line: 9, column: 3, scope: !28) !35 = distinct !{!35, !29, !36} !36 = !DILocation(line: 11, column: 3, scope: !25) !37 = !DILocation(line: 13, column: 3, scope: !8) local-array-2.c000066400000000000000000000006571473507761200334670ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include #include char* foo(char* a, int n) { int i; for (i = 0; i < n; i++) a[i] = 'A'; return a; } int main() { char str[50]; strcpy(str, "This is string.h library function"); puts(str); memset(str, '$', 50); // SAFE char* A = foo(str, 10); // char * B; <- B will be undefined char B[10]; memcpy(B, A, 10); // SAFE char* C = foo(B, 10); // SAFE puts(C); return (0); } local-array-2.ll000066400000000000000000000213711473507761200336500ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'local-array-2.pp.bc' source_filename = "local-array-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [34 x i8] c"This is string.h library function\00", align 1 ; CHECK: define [34 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [84, 104, 105, 115, 32, 105, 115, 32, 115, 116, 114, 105, 110, 103, 46, 104, 32, 108, 105, 98, 114, 97, 114, 121, 32, 102, 117, 110, 99, 116, 105, 111, 110, 0], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #2 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc i8* @foo(i8*, i32) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i8* %0, metadata !14, metadata !DIExpression()), !dbg !15 call void @llvm.dbg.value(metadata i32 %1, metadata !16, metadata !DIExpression()), !dbg !15 call void @llvm.dbg.value(metadata i32 0, metadata !17, metadata !DIExpression()), !dbg !15 br label %3, !dbg !18 3: ; preds = %5, %2 %.0 = phi i32 [ 0, %2 ], [ %8, %5 ], !dbg !20 call void @llvm.dbg.value(metadata i32 %.0, metadata !17, metadata !DIExpression()), !dbg !15 %4 = icmp slt i32 %.0, %1, !dbg !21 br i1 %4, label %5, label %9, !dbg !23 5: ; preds = %3 %6 = zext i32 %.0 to i64, !dbg !24 %7 = getelementptr inbounds i8, i8* %0, i64 %6, !dbg !24 store i8 65, i8* %7, align 1, !dbg !25 %8 = add nuw nsw i32 %.0, 1, !dbg !26 call void @llvm.dbg.value(metadata i32 %8, metadata !17, metadata !DIExpression()), !dbg !15 br label %3, !dbg !27, !llvm.loop !28 9: ; preds = %3 ret i8* %0, !dbg !30 } ; CHECK: define si8* @foo(si8* %1, si32 %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %.0 silt %2 ; CHECK: ui32 %3 = bitcast %.0 ; CHECK: ui64 %4 = zext %3 ; CHECK: si8* %5 = ptrshift %1, 1 * %4 ; CHECK: store %5, 65, align 1 ; CHECK: si32 %6 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %6 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %.0 sige %2 ; CHECK: return %1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !31 { %1 = alloca [50 x i8], align 16 %2 = alloca [10 x i8], align 1 call void @llvm.dbg.declare(metadata [50 x i8]* %1, metadata !34, metadata !DIExpression()), !dbg !38 %3 = getelementptr inbounds [50 x i8], [50 x i8]* %1, i64 0, i64 0, !dbg !39 %4 = getelementptr inbounds [34 x i8], [34 x i8]* @.str, i64 0, i64 0, !dbg !40 call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 16 %3, i8* align 1 %4, i64 34, i1 false), !dbg !40 call void @llvm.memset.p0i8.i64(i8* nonnull align 16 %3, i8 36, i64 50, i1 false), !dbg !41 %5 = call fastcc i8* @foo(i8* nonnull %3, i32 10), !dbg !42 call void @llvm.dbg.value(metadata i8* %5, metadata !43, metadata !DIExpression()), !dbg !44 call void @llvm.dbg.declare(metadata [10 x i8]* %2, metadata !45, metadata !DIExpression()), !dbg !49 %6 = getelementptr inbounds [10 x i8], [10 x i8]* %2, i64 0, i64 0, !dbg !50 call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 1 %6, i8* align 1 %5, i64 10, i1 false), !dbg !50 %7 = call fastcc i8* @foo(i8* nonnull %6, i32 10), !dbg !51 call void @llvm.dbg.value(metadata i8* %7, metadata !52, metadata !DIExpression()), !dbg !44 ret i32 0, !dbg !53 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: [50 x si8]* $1 = allocate [50 x si8], 1, align 16 ; CHECK: [10 x si8]* $2 = allocate [10 x si8], 1, align 1 ; CHECK: si8* %3 = ptrshift $1, 50 * 0, 1 * 0 ; CHECK: si8* %4 = ptrshift @.str, 34 * 0, 1 * 0 ; CHECK: call @ar.memcpy(%3, %4, 34, 16, 1, 0) ; CHECK: call @ar.memset(%3, 36, 50, 16, 0) ; CHECK: si8* %5 = call @foo(%3, 10) ; CHECK: si8* %6 = ptrshift $2, 10 * 0, 1 * 0 ; CHECK: call @ar.memcpy(%6, %5, 10, 1, 1, 0) ; CHECK: si8* %7 = call @foo(%6, 10) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "local-array-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !13} !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) !12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11) !15 = !DILocation(line: 0, scope: !8) !16 = !DILocalVariable(name: "n", arg: 2, scope: !8, file: !1, line: 4, type: !13) !17 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 5, type: !13) !18 = !DILocation(line: 6, column: 8, scope: !19) !19 = distinct !DILexicalBlock(scope: !8, file: !1, line: 6, column: 3) !20 = !DILocation(line: 0, scope: !19) !21 = !DILocation(line: 6, column: 17, scope: !22) !22 = distinct !DILexicalBlock(scope: !19, file: !1, line: 6, column: 3) !23 = !DILocation(line: 6, column: 3, scope: !19) !24 = !DILocation(line: 7, column: 5, scope: !22) !25 = !DILocation(line: 7, column: 10, scope: !22) !26 = !DILocation(line: 6, column: 23, scope: !22) !27 = !DILocation(line: 6, column: 3, scope: !22) !28 = distinct !{!28, !23, !29} !29 = !DILocation(line: 7, column: 12, scope: !19) !30 = !DILocation(line: 8, column: 3, scope: !8) !31 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 11, type: !32, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !32 = !DISubroutineType(types: !33) !33 = !{!13} !34 = !DILocalVariable(name: "str", scope: !31, file: !1, line: 12, type: !35) !35 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 400, elements: !36) !36 = !{!37} !37 = !DISubrange(count: 50) !38 = !DILocation(line: 12, column: 8, scope: !31) !39 = !DILocation(line: 14, column: 10, scope: !31) !40 = !DILocation(line: 14, column: 3, scope: !31) !41 = !DILocation(line: 17, column: 3, scope: !31) !42 = !DILocation(line: 18, column: 13, scope: !31) !43 = !DILocalVariable(name: "A", scope: !31, file: !1, line: 18, type: !11) !44 = !DILocation(line: 0, scope: !31) !45 = !DILocalVariable(name: "B", scope: !31, file: !1, line: 20, type: !46) !46 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 80, elements: !47) !47 = !{!48} !48 = !DISubrange(count: 10) !49 = !DILocation(line: 20, column: 8, scope: !31) !50 = !DILocation(line: 21, column: 3, scope: !31) !51 = !DILocation(line: 22, column: 13, scope: !31) !52 = !DILocalVariable(name: "C", scope: !31, file: !1, line: 22, type: !11) !53 = !DILocation(line: 24, column: 3, scope: !31) mem-intrinsics.c000066400000000000000000000003231473507761200340510ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include int cst() { int G = 0 ? 0 : (((1 + 1) + 3) * 2); return G; } int main() { int *p, *q, *r; r = (int*)memcpy(p, q, 10); r = (int*)memmove(p, q, 50); r = (int*)memset(p, 1, 50); } mem-intrinsics.ll000066400000000000000000000062061473507761200342440ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'mem-intrinsics.pp.bc' source_filename = "mem-intrinsics.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #1 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !11 { call void @llvm.dbg.value(metadata i8* undef, metadata !14, metadata !DIExpression()), !dbg !15 call void @llvm.dbg.value(metadata i8* undef, metadata !14, metadata !DIExpression()), !dbg !15 call void @llvm.memset.p0i8.i64(i8* align 4 undef, i8 1, i64 50, i1 false), !dbg !16 call void @llvm.dbg.value(metadata i8* undef, metadata !14, metadata !DIExpression()), !dbg !15 ret i32 0, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: call @ar.memset(undef, 1, 50, 4, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { argmemonly nounwind } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!6, !7, !8, !9} !llvm.ident = !{!10} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "mem-intrinsics.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) !5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} !8 = !{i32 1, !"wchar_size", i32 4} !9 = !{i32 7, !"PIC Level", i32 2} !10 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !11 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !12, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !12 = !DISubroutineType(types: !13) !13 = !{!5} !14 = !DILocalVariable(name: "r", scope: !11, file: !1, line: 9, type: !4) !15 = !DILocation(line: 0, scope: !11) !16 = !DILocation(line: 12, column: 13, scope: !11) !17 = !DILocation(line: 13, column: 1, scope: !11) multiple-inheritance.cpp000066400000000000000000000003641473507761200355770ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationclass Base { private: int x; int y; }; struct Mixin { private: unsigned z; }; struct Empty { void f() {} }; class Child : public Base, public Mixin, public Empty { private: int tab[10]; }; Child c; int main(void) { return 0; } multiple-inheritance.ll000066400000000000000000000106751473507761200354320ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'multiple-inheritance.pp.bc' source_filename = "multiple-inheritance.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !35 { ret i32 0, !dbg !38 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!30, !31, !32, !33} !llvm.ident = !{!34} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "multiple-inheritance.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 21, type: !6, isLocal: false, isDefinition: true) !6 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Child", file: !1, line: 16, size: 416, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS5Child") !7 = !{!8, !14, !19, !26} !8 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !9, flags: DIFlagPublic, extraData: i32 0) !9 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Base", file: !1, line: 1, size: 64, flags: DIFlagTypePassByValue, elements: !10, identifier: "_ZTS4Base") !10 = !{!11, !13} !11 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !9, file: !1, line: 3, baseType: !12, size: 32) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !9, file: !1, line: 4, baseType: !12, size: 32, offset: 32) !14 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !15, offset: 64, flags: DIFlagPublic, extraData: i32 0) !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Mixin", file: !1, line: 7, size: 32, flags: DIFlagTypePassByValue, elements: !16, identifier: "_ZTS5Mixin") !16 = !{!17} !17 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !15, file: !1, line: 9, baseType: !18, size: 32, flags: DIFlagPrivate) !18 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !19 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !20, flags: DIFlagPublic, extraData: i32 0) !20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Empty", file: !1, line: 12, size: 8, flags: DIFlagTypePassByValue, elements: !21, identifier: "_ZTS5Empty") !21 = !{!22} !22 = !DISubprogram(name: "f", linkageName: "_ZN5Empty1fEv", scope: !20, file: !1, line: 13, type: !23, scopeLine: 13, flags: DIFlagPrototyped, spFlags: 0) !23 = !DISubroutineType(types: !24) !24 = !{null, !25} !25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !26 = !DIDerivedType(tag: DW_TAG_member, name: "tab", scope: !6, file: !1, line: 18, baseType: !27, size: 320, offset: 96) !27 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 320, elements: !28) !28 = !{!29} !29 = !DISubrange(count: 10) !30 = !{i32 2, !"Dwarf Version", i32 4} !31 = !{i32 2, !"Debug Info Version", i32 3} !32 = !{i32 1, !"wchar_size", i32 4} !33 = !{i32 7, !"PIC Level", i32 2} !34 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !35 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 23, type: !36, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !36 = !DISubroutineType(types: !37) !37 = !{!12} !38 = !DILocation(line: 24, column: 3, scope: !35) nested-struct.c000066400000000000000000000002411473507761200337130ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include struct Node { struct Node* next; }; int main(int argc, char* argv[]) { struct Node* node = malloc(sizeof(struct Node*)); return 0; } nested-struct.ll000066400000000000000000000056161473507761200341130ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'nested-struct.pp.bc' source_filename = "nested-struct.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 ret i32 0, !dbg !18 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "nested-struct.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !9, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 7, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 7, type: !12) !18 = !DILocation(line: 9, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/noexcept.cpp000066400000000000000000000000641473507761200333560ustar00rootroot00000000000000extern int f(); int g() noexcept { return f(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/noexcept.ll000066400000000000000000000017411473507761200332060ustar00rootroot00000000000000; ModuleID = 'noexcept.pp.bc' source_filename = "noexcept.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "noexcept.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/non-term-1.c000066400000000000000000000001741473507761200330700ustar00rootroot00000000000000#include int main(int argc, char** argv) { int i; while (1) { if (i == 0) exit(1); i++; } } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/non-term-1.ll000066400000000000000000000076421473507761200332640ustar00rootroot00000000000000; ModuleID = 'non-term-1.pp.bc' source_filename = "non-term-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noreturn declare void @exit(i32) local_unnamed_addr #1 ; CHECK: declare void @ar.libc.exit(si32) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 undef, metadata !18, metadata !DIExpression()), !dbg !16 call void @exit(i32 1) #3, !dbg !19 unreachable, !dbg !19 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: call @ar.libc.exit(1) ; CHECK: unreachable ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noreturn "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } attributes #3 = { noreturn nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "non-term-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 3, type: !12) !18 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 4, type: !11) !19 = !DILocation(line: 7, column: 7, scope: !20) !20 = distinct !DILexicalBlock(scope: !21, file: !1, line: 6, column: 9) !21 = distinct !DILexicalBlock(scope: !8, file: !1, line: 5, column: 13) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/non-term-2.c000066400000000000000000000001371473507761200330700ustar00rootroot00000000000000#include int main() { while (1) { printf("hello world\n"); } return 42; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/non-term-2.ll000066400000000000000000000044601473507761200332600ustar00rootroot00000000000000; ModuleID = 'non-term-2.pp.bc' source_filename = "non-term-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { br label %1, !dbg !12 1: ; preds = %0, %1 br label %1, !dbg !12, !llvm.loop !13 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2} { ; CHECK: } ; CHECK: #2 predecessors={#1, #2} successors={#2} { ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "non-term-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 4, column: 3, scope: !8) !13 = distinct !{!13, !12, !14} !14 = !DILocation(line: 6, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/nullptr.cpp000066400000000000000000000001201473507761200332220ustar00rootroot00000000000000int f(decltype(nullptr) x) { return 1; } int main() { return f(nullptr); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/nullptr.ll000066400000000000000000000074571473507761200330730ustar00rootroot00000000000000; ModuleID = 'nullptr.pp.bc' source_filename = "nullptr.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc i32 @_Z1fDn(i8*) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i8* %0, metadata !13, metadata !DIExpression()), !dbg !14 ret i32 1, !dbg !15 } ; CHECK: define si32 @_Z1fDn(si8* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #1 !dbg !16 { %1 = call fastcc i32 @_Z1fDn(i8* null), !dbg !19 ret i32 %1, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32 %1 = call @_Z1fDn(null) ; CHECK: return %1 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "nullptr.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fDn", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "decltype(nullptr)") !13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !12) !14 = !DILocation(line: 0, scope: !8) !15 = !DILocation(line: 2, column: 3, scope: !8) !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!11} !19 = !DILocation(line: 6, column: 10, scope: !16) !20 = !DILocation(line: 6, column: 3, scope: !16) opaque-struct.c000066400000000000000000000002011473507761200337170ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include struct X; typedef struct { int* a; struct X* b; } my_struct; my_struct s; int main() { return 0; } opaque-struct.ll000066400000000000000000000057241473507761200341230ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'opaque-struct.pp.bc' source_filename = "opaque-struct.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !20 { ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "opaque-struct.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "s", scope: !0, file: !1, line: 10, type: !6, isLocal: false, isDefinition: true) !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "my_struct", file: !1, line: 8, baseType: !7) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 5, size: 128, elements: !8) !8 = !{!9, !12} !9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !1, line: 6, baseType: !10, size: 64) !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !1, line: 7, baseType: !13, size: 64, offset: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !1, line: 3, flags: DIFlagFwdDecl) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 12, type: !21, scopeLine: 12, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !21 = !DISubroutineType(types: !22) !22 = !{!11} !23 = !DILocation(line: 13, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-1.c000066400000000000000000000001761473507761200321130ustar00rootroot00000000000000double a[10]; int main(int argc, char** argv) { int i; for (i = 0; i < 10; i++) { a[i] = i * 0.88; } a[i] = i; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-1.ll000066400000000000000000000070441473507761200323010ustar00rootroot00000000000000; ModuleID = 'phi-1.pp.bc' source_filename = "phi-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !15 { call void @llvm.dbg.value(metadata i32 %0, metadata !22, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i8** %1, metadata !24, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i32 0, metadata !25, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i32 undef, metadata !25, metadata !DIExpression()), !dbg !23 ret i32 0, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!10, !11, !12, !13} !llvm.ident = !{!14} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "phi-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true) !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 640, elements: !8) !7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 10) !10 = !{i32 2, !"Dwarf Version", i32 4} !11 = !{i32 2, !"Debug Info Version", i32 3} !12 = !{i32 1, !"wchar_size", i32 4} !13 = !{i32 7, !"PIC Level", i32 2} !14 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !15 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !16 = !DISubroutineType(types: !17) !17 = !{!18, !18, !19} !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !15, file: !1, line: 3, type: !18) !23 = !DILocation(line: 0, scope: !15) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !15, file: !1, line: 3, type: !19) !25 = !DILocalVariable(name: "i", scope: !15, file: !1, line: 4, type: !18) !26 = !DILocation(line: 9, column: 1, scope: !15) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-2.c000066400000000000000000000010751473507761200321130ustar00rootroot00000000000000// SAFE #include #define MAX_ARRAY 10 struct bar { int x; float y; }; struct foo { int x; struct bar y; int a[MAX_ARRAY][MAX_ARRAY][MAX_ARRAY - 1]; }; // To test loops int main(int argc, char** argv) { int i, j, k; struct foo x; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) { for (k = 0; k < MAX_ARRAY - 1; k++) { x.a[i][j][k] = argc; // some unknown value here x.y.x = x.a[i][j][k]; } } } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", x.a[i][i][i - 1]); } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-2.ll000066400000000000000000000252101473507761200322750ustar00rootroot00000000000000; ModuleID = 'phi-2.pp.bc' source_filename = "phi-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.foo = type { i32, %struct.bar, [10 x [10 x [9 x i32]]] } %struct.bar = type { i32, float } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !8 { %3 = alloca %struct.foo, align 4 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 0, metadata !18, metadata !DIExpression()), !dbg !16 %4 = getelementptr inbounds %struct.foo, %struct.foo* %3, i64 0, i32 1, i32 0, !dbg !19 store i32 %0, i32* %4, align 4, !dbg !19 br label %5, !dbg !29 5: ; preds = %17, %2 %.02 = phi i32 [ 0, %2 ], [ %18, %17 ], !dbg !30 call void @llvm.dbg.value(metadata i32 %.02, metadata !18, metadata !DIExpression()), !dbg !16 %6 = icmp ult i32 %.02, 10, !dbg !31 br i1 %6, label %.preheader4.preheader, label %.preheader, !dbg !32 .preheader4.preheader: ; preds = %5 %7 = zext i32 %.02 to i64, !dbg !19 br label %.preheader4, !dbg !33 .preheader4: ; preds = %.preheader4.preheader, %15 %.01 = phi i32 [ %16, %15 ], [ 0, %.preheader4.preheader ], !dbg !34 call void @llvm.dbg.value(metadata i32 %.01, metadata !35, metadata !DIExpression()), !dbg !16 %8 = icmp ult i32 %.01, 10, !dbg !36 br i1 %8, label %.preheader3.preheader, label %17, !dbg !33 .preheader3.preheader: ; preds = %.preheader4 %9 = zext i32 %.01 to i64, !dbg !19 br label %.preheader3, !dbg !37 .preheader3: ; preds = %.preheader3.preheader, %11 %.0 = phi i32 [ %14, %11 ], [ 0, %.preheader3.preheader ], !dbg !38 call void @llvm.dbg.value(metadata i32 %.0, metadata !39, metadata !DIExpression()), !dbg !16 %10 = icmp ult i32 %.0, 9, !dbg !40 br i1 %10, label %11, label %15, !dbg !37 11: ; preds = %.preheader3 %12 = zext i32 %.0 to i64, !dbg !41 %13 = getelementptr inbounds %struct.foo, %struct.foo* %3, i64 0, i32 2, i64 %7, i64 %9, i64 %12, !dbg !41 store i32 %0, i32* %13, align 4, !dbg !42 %14 = add nuw nsw i32 %.0, 1, !dbg !43 call void @llvm.dbg.value(metadata i32 %14, metadata !39, metadata !DIExpression()), !dbg !16 br label %.preheader3, !dbg !44, !llvm.loop !45 15: ; preds = %.preheader3 %16 = add nuw nsw i32 %.01, 1, !dbg !47 call void @llvm.dbg.value(metadata i32 %16, metadata !35, metadata !DIExpression()), !dbg !16 br label %.preheader4, !dbg !48, !llvm.loop !49 17: ; preds = %.preheader4 %18 = add nuw nsw i32 %.02, 1, !dbg !51 call void @llvm.dbg.value(metadata i32 %18, metadata !18, metadata !DIExpression()), !dbg !16 br label %5, !dbg !52, !llvm.loop !53 .preheader: ; preds = %5, %20 %.1 = phi i32 [ %21, %20 ], [ 0, %5 ], !dbg !55 call void @llvm.dbg.value(metadata i32 %.1, metadata !18, metadata !DIExpression()), !dbg !16 %19 = icmp ult i32 %.1, 10, !dbg !57 br i1 %19, label %20, label %22, !dbg !59 20: ; preds = %.preheader %21 = add nuw nsw i32 %.1, 1, !dbg !60 call void @llvm.dbg.value(metadata i32 %21, metadata !18, metadata !DIExpression()), !dbg !16 br label %.preheader, !dbg !61, !llvm.loop !62 22: ; preds = %.preheader ret i32 0, !dbg !64 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: {0: si32, 4: {0: si32, 4: float}, 12: [10 x [10 x [9 x si32]]]}* $3 = allocate {0: si32, 4: {0: si32, 4: float}, 12: [10 x [10 x [9 x si32]]]}, 1, align 4 ; CHECK: si32* %4 = ptrshift $3, 3612 * 0, 1 * 4, 1 * 0 ; CHECK: store %4, %1, align 4 ; CHECK: si32 %.02 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #6} successors={#3, #4} { ; CHECK: ui32 %5 = bitcast %.02 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#.preheader4} { ; CHECK: %5 uilt 10 ; CHECK: ui32 %6 = bitcast %.02 ; CHECK: ui64 %7 = zext %6 ; CHECK: si32 %.01 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#.preheader} { ; CHECK: %5 uige 10 ; CHECK: si32 %.1 = 0 ; CHECK: } ; CHECK: #.preheader predecessors={#4, #7} successors={#7, #8} { ; CHECK: ui32 %9 = bitcast %.1 ; CHECK: } ; CHECK: #7 predecessors={#.preheader} successors={#.preheader} { ; CHECK: %9 uilt 10 ; CHECK: si32 %13 = %.1 sadd.nw 1 ; CHECK: si32 %.1 = %13 ; CHECK: } ; CHECK: #8 !exit predecessors={#.preheader} { ; CHECK: %9 uige 10 ; CHECK: return 0 ; CHECK: } ; CHECK: #.preheader4 predecessors={#3, #10} successors={#5, #6} { ; CHECK: ui32 %8 = bitcast %.01 ; CHECK: } ; CHECK: #5 predecessors={#.preheader4} successors={#.preheader3} { ; CHECK: %8 uilt 10 ; CHECK: ui32 %10 = bitcast %.01 ; CHECK: ui64 %11 = zext %10 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #6 predecessors={#.preheader4} successors={#2} { ; CHECK: %8 uige 10 ; CHECK: si32 %12 = %.02 sadd.nw 1 ; CHECK: si32 %.02 = %12 ; CHECK: } ; CHECK: #.preheader3 predecessors={#5, #9} successors={#9, #10} { ; CHECK: ui32 %14 = bitcast %.0 ; CHECK: } ; CHECK: #9 predecessors={#.preheader3} successors={#.preheader3} { ; CHECK: %14 uilt 9 ; CHECK: ui32 %15 = bitcast %.0 ; CHECK: ui64 %16 = zext %15 ; CHECK: si32* %17 = ptrshift $3, 3612 * 0, 1 * 12, 360 * %7, 36 * %11, 4 * %16 ; CHECK: store %17, %1, align 4 ; CHECK: si32 %18 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %18 ; CHECK: } ; CHECK: #10 predecessors={#.preheader3} successors={#.preheader4} { ; CHECK: %14 uige 9 ; CHECK: si32 %19 = %.01 sadd.nw 1 ; CHECK: si32 %.01 = %19 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 18, type: !9, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 18, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 18, type: !12) !18 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 19, type: !11) !19 = !DILocation(line: 0, scope: !20) !20 = distinct !DILexicalBlock(scope: !21, file: !1, line: 23, column: 43) !21 = distinct !DILexicalBlock(scope: !22, file: !1, line: 23, column: 7) !22 = distinct !DILexicalBlock(scope: !23, file: !1, line: 23, column: 7) !23 = distinct !DILexicalBlock(scope: !24, file: !1, line: 22, column: 37) !24 = distinct !DILexicalBlock(scope: !25, file: !1, line: 22, column: 5) !25 = distinct !DILexicalBlock(scope: !26, file: !1, line: 22, column: 5) !26 = distinct !DILexicalBlock(scope: !27, file: !1, line: 21, column: 35) !27 = distinct !DILexicalBlock(scope: !28, file: !1, line: 21, column: 3) !28 = distinct !DILexicalBlock(scope: !8, file: !1, line: 21, column: 3) !29 = !DILocation(line: 21, column: 8, scope: !28) !30 = !DILocation(line: 0, scope: !28) !31 = !DILocation(line: 21, column: 17, scope: !27) !32 = !DILocation(line: 21, column: 3, scope: !28) !33 = !DILocation(line: 22, column: 5, scope: !25) !34 = !DILocation(line: 0, scope: !25) !35 = !DILocalVariable(name: "j", scope: !8, file: !1, line: 19, type: !11) !36 = !DILocation(line: 22, column: 19, scope: !24) !37 = !DILocation(line: 23, column: 7, scope: !22) !38 = !DILocation(line: 0, scope: !22) !39 = !DILocalVariable(name: "k", scope: !8, file: !1, line: 19, type: !11) !40 = !DILocation(line: 23, column: 21, scope: !21) !41 = !DILocation(line: 24, column: 9, scope: !20) !42 = !DILocation(line: 24, column: 22, scope: !20) !43 = !DILocation(line: 23, column: 39, scope: !21) !44 = !DILocation(line: 23, column: 7, scope: !21) !45 = distinct !{!45, !37, !46} !46 = !DILocation(line: 26, column: 7, scope: !22) !47 = !DILocation(line: 22, column: 33, scope: !24) !48 = !DILocation(line: 22, column: 5, scope: !24) !49 = distinct !{!49, !33, !50} !50 = !DILocation(line: 27, column: 5, scope: !25) !51 = !DILocation(line: 21, column: 31, scope: !27) !52 = !DILocation(line: 21, column: 3, scope: !27) !53 = distinct !{!53, !32, !54} !54 = !DILocation(line: 28, column: 3, scope: !28) !55 = !DILocation(line: 0, scope: !56) !56 = distinct !DILexicalBlock(scope: !8, file: !1, line: 30, column: 3) !57 = !DILocation(line: 30, column: 17, scope: !58) !58 = distinct !DILexicalBlock(scope: !56, file: !1, line: 30, column: 3) !59 = !DILocation(line: 30, column: 3, scope: !56) !60 = !DILocation(line: 30, column: 31, scope: !58) !61 = !DILocation(line: 30, column: 3, scope: !58) !62 = distinct !{!62, !59, !63} !63 = !DILocation(line: 32, column: 3, scope: !56) !64 = !DILocation(line: 34, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-3.c000066400000000000000000000010271473507761200321110ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); int foo(int* a, int* b, int* c) { int* p; int* q; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } __ikos_assert(*p == 3); __ikos_assert(*q == 6); int res = c[*p + *q]; c[*p + *q] = 555; return res; } int main(int argc, char** argv) { int a[2]; int b[3]; int c[10]; c[9] = 666; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 5; b[2] = 6; int x = foo(a, b, c); __ikos_assert(x == 666); __ikos_assert(c[9] == 555); return x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-3.ll000066400000000000000000000355761473507761200323160ustar00rootroot00000000000000; ModuleID = 'phi-3.pp.bc' source_filename = "phi-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 declare void @__ikos_assert(i32) local_unnamed_addr #2 ; CHECK: declare void @ar.ikos.assert(ui32) ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc i32 @foo(i32*, i32*, i32*) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32* %0, metadata !13, metadata !DIExpression()), !dbg !14 call void @llvm.dbg.value(metadata i32* %1, metadata !15, metadata !DIExpression()), !dbg !14 call void @llvm.dbg.value(metadata i32* %2, metadata !16, metadata !DIExpression()), !dbg !14 %4 = getelementptr inbounds i32, i32* %0, i64 1, !dbg !17 call void @llvm.dbg.value(metadata i32* %4, metadata !18, metadata !DIExpression()), !dbg !14 %5 = getelementptr inbounds i32, i32* %1, i64 2, !dbg !19 call void @llvm.dbg.value(metadata i32* %5, metadata !20, metadata !DIExpression()), !dbg !14 %6 = icmp eq i32* %4, %5, !dbg !21 %7 = getelementptr inbounds i32, i32* %1, i64 -8, !dbg !23 %8 = getelementptr inbounds i32, i32* %0, i64 43, !dbg !23 br i1 %6, label %9, label %10, !dbg !23 9: ; preds = %3 br label %11, !dbg !23 10: ; preds = %3 br label %11, !dbg !23 11: ; preds = %10, %9 %.01.phi = phi i32* [ %8, %9 ], [ %4, %10 ], !dbg !23 br i1 %6, label %12, label %13, !dbg !23 12: ; preds = %11 br label %14, !dbg !23 13: ; preds = %11 br label %14, !dbg !23 14: ; preds = %13, %12 %.0.phi = phi i32* [ %7, %12 ], [ %5, %13 ], !dbg !23 call void @llvm.dbg.value(metadata i32* %.0.phi, metadata !20, metadata !DIExpression()), !dbg !14 call void @llvm.dbg.value(metadata i32* %.01.phi, metadata !18, metadata !DIExpression()), !dbg !14 %15 = load i32, i32* %.01.phi, align 4, !dbg !24 %16 = icmp eq i32 %15, 3, !dbg !25 %17 = zext i1 %16 to i32, !dbg !25 call void @__ikos_assert(i32 %17) #3, !dbg !26 %18 = load i32, i32* %.0.phi, align 4, !dbg !27 %19 = icmp eq i32 %18, 6, !dbg !28 %20 = zext i1 %19 to i32, !dbg !28 call void @__ikos_assert(i32 %20) #3, !dbg !29 %21 = load i32, i32* %.01.phi, align 4, !dbg !30 %22 = load i32, i32* %.0.phi, align 4, !dbg !31 %23 = add nsw i32 %21, %22, !dbg !32 %24 = sext i32 %23 to i64, !dbg !33 %25 = getelementptr inbounds i32, i32* %2, i64 %24, !dbg !33 %26 = load i32, i32* %25, align 4, !dbg !33 call void @llvm.dbg.value(metadata i32 %26, metadata !34, metadata !DIExpression()), !dbg !14 store i32 555, i32* %25, align 4, !dbg !35 ret i32 %26, !dbg !36 } ; CHECK: define si32 @foo(si32* %1, si32* %2, si32* %3) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* %4 = ptrshift %1, 4 * 1 ; CHECK: si32* %5 = ptrshift %2, 4 * 2 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %4 peq %5 ; CHECK: ui1 %6 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %4 pne %5 ; CHECK: ui1 %6 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5, #6} { ; CHECK: si32* %7 = ptrshift %2, 4 * -8 ; CHECK: si32* %8 = ptrshift %1, 4 * 43 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %6 uieq 1 ; CHECK: si32* %.01.phi = %8 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %6 uieq 0 ; CHECK: si32* %.01.phi = %4 ; CHECK: } ; CHECK: #7 predecessors={#5, #6} successors={#8, #9} { ; CHECK: } ; CHECK: #8 predecessors={#7} successors={#10} { ; CHECK: %6 uieq 1 ; CHECK: si32* %.0.phi = %7 ; CHECK: } ; CHECK: #9 predecessors={#7} successors={#10} { ; CHECK: %6 uieq 0 ; CHECK: si32* %.0.phi = %5 ; CHECK: } ; CHECK: #10 predecessors={#8, #9} successors={#11, #12} { ; CHECK: si32 %9 = load %.01.phi, align 4 ; CHECK: } ; CHECK: #11 predecessors={#10} successors={#13} { ; CHECK: %9 sieq 3 ; CHECK: ui1 %10 = 1 ; CHECK: } ; CHECK: #12 predecessors={#10} successors={#13} { ; CHECK: %9 sine 3 ; CHECK: ui1 %10 = 0 ; CHECK: } ; CHECK: #13 predecessors={#11, #12} successors={#14, #15} { ; CHECK: ui32 %11 = zext %10 ; CHECK: call @ar.ikos.assert(%11) ; CHECK: si32 %12 = load %.0.phi, align 4 ; CHECK: } ; CHECK: #14 predecessors={#13} successors={#16} { ; CHECK: %12 sieq 6 ; CHECK: ui1 %13 = 1 ; CHECK: } ; CHECK: #15 predecessors={#13} successors={#16} { ; CHECK: %12 sine 6 ; CHECK: ui1 %13 = 0 ; CHECK: } ; CHECK: #16 !exit predecessors={#14, #15} { ; CHECK: ui32 %14 = zext %13 ; CHECK: call @ar.ikos.assert(%14) ; CHECK: si32 %15 = load %.01.phi, align 4 ; CHECK: si32 %16 = load %.0.phi, align 4 ; CHECK: si32 %17 = %15 sadd.nw %16 ; CHECK: si64 %18 = sext %17 ; CHECK: si32* %19 = ptrshift %3, 4 * %18 ; CHECK: si32 %20 = load %19, align 4 ; CHECK: store %19, 555, align 4 ; CHECK: return %20 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !37 { %3 = alloca [2 x i32], align 4 %4 = alloca [3 x i32], align 4 %5 = alloca [10 x i32], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !43, metadata !DIExpression()), !dbg !44 call void @llvm.dbg.value(metadata i8** %1, metadata !45, metadata !DIExpression()), !dbg !44 call void @llvm.dbg.declare(metadata [2 x i32]* %3, metadata !46, metadata !DIExpression()), !dbg !50 call void @llvm.dbg.declare(metadata [3 x i32]* %4, metadata !51, metadata !DIExpression()), !dbg !55 call void @llvm.dbg.declare(metadata [10 x i32]* %5, metadata !56, metadata !DIExpression()), !dbg !60 %6 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i64 0, i64 9, !dbg !61 store i32 666, i32* %6, align 4, !dbg !62 %7 = getelementptr inbounds [2 x i32], [2 x i32]* %3, i64 0, i64 0, !dbg !63 store i32 1, i32* %7, align 4, !dbg !64 %8 = getelementptr inbounds [2 x i32], [2 x i32]* %3, i64 0, i64 1, !dbg !65 store i32 3, i32* %8, align 4, !dbg !66 %9 = getelementptr inbounds [3 x i32], [3 x i32]* %4, i64 0, i64 0, !dbg !67 store i32 4, i32* %9, align 4, !dbg !68 %10 = getelementptr inbounds [3 x i32], [3 x i32]* %4, i64 0, i64 1, !dbg !69 store i32 5, i32* %10, align 4, !dbg !70 %11 = getelementptr inbounds [3 x i32], [3 x i32]* %4, i64 0, i64 2, !dbg !71 store i32 6, i32* %11, align 4, !dbg !72 %12 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i64 0, i64 0, !dbg !73 %13 = call fastcc i32 @foo(i32* nonnull %7, i32* nonnull %9, i32* nonnull %12), !dbg !74 call void @llvm.dbg.value(metadata i32 %13, metadata !75, metadata !DIExpression()), !dbg !44 %14 = icmp eq i32 %13, 666, !dbg !76 %15 = zext i1 %14 to i32, !dbg !76 call void @__ikos_assert(i32 %15) #3, !dbg !77 %16 = load i32, i32* %6, align 4, !dbg !78 %17 = icmp eq i32 %16, 555, !dbg !79 %18 = zext i1 %17 to i32, !dbg !79 call void @__ikos_assert(i32 %18) #3, !dbg !80 ret i32 %13, !dbg !81 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: [2 x si32]* $3 = allocate [2 x si32], 1, align 4 ; CHECK: [3 x si32]* $4 = allocate [3 x si32], 1, align 4 ; CHECK: [10 x si32]* $5 = allocate [10 x si32], 1, align 16 ; CHECK: si32* %6 = ptrshift $5, 40 * 0, 4 * 9 ; CHECK: store %6, 666, align 4 ; CHECK: si32* %7 = ptrshift $3, 8 * 0, 4 * 0 ; CHECK: store %7, 1, align 4 ; CHECK: si32* %8 = ptrshift $3, 8 * 0, 4 * 1 ; CHECK: store %8, 3, align 4 ; CHECK: si32* %9 = ptrshift $4, 12 * 0, 4 * 0 ; CHECK: store %9, 4, align 4 ; CHECK: si32* %10 = ptrshift $4, 12 * 0, 4 * 1 ; CHECK: store %10, 5, align 4 ; CHECK: si32* %11 = ptrshift $4, 12 * 0, 4 * 2 ; CHECK: store %11, 6, align 4 ; CHECK: si32* %12 = ptrshift $5, 40 * 0, 4 * 0 ; CHECK: si32 %13 = call @foo(%7, %9, %12) ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %13 sieq 666 ; CHECK: ui1 %14 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %13 sine 666 ; CHECK: ui1 %14 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5, #6} { ; CHECK: ui32 %15 = zext %14 ; CHECK: call @ar.ikos.assert(%15) ; CHECK: si32 %16 = load %6, align 4 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %16 sieq 555 ; CHECK: ui1 %17 = 1 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %16 sine 555 ; CHECK: ui1 %17 = 0 ; CHECK: } ; CHECK: #7 !exit predecessors={#5, #6} { ; CHECK: ui32 %18 = zext %17 ; CHECK: call @ar.ikos.assert(%18) ; CHECK: return %13 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, type: !9, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12, !12, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 5, type: !12) !14 = !DILocation(line: 0, scope: !8) !15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 5, type: !12) !16 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 5, type: !12) !17 = !DILocation(line: 9, column: 9, scope: !8) !18 = !DILocalVariable(name: "p", scope: !8, file: !1, line: 6, type: !12) !19 = !DILocation(line: 10, column: 9, scope: !8) !20 = !DILocalVariable(name: "q", scope: !8, file: !1, line: 7, type: !12) !21 = !DILocation(line: 12, column: 9, scope: !22) !22 = distinct !DILexicalBlock(scope: !8, file: !1, line: 12, column: 7) !23 = !DILocation(line: 12, column: 7, scope: !8) !24 = !DILocation(line: 16, column: 17, scope: !8) !25 = !DILocation(line: 16, column: 20, scope: !8) !26 = !DILocation(line: 16, column: 3, scope: !8) !27 = !DILocation(line: 17, column: 17, scope: !8) !28 = !DILocation(line: 17, column: 20, scope: !8) !29 = !DILocation(line: 17, column: 3, scope: !8) !30 = !DILocation(line: 19, column: 15, scope: !8) !31 = !DILocation(line: 19, column: 20, scope: !8) !32 = !DILocation(line: 19, column: 18, scope: !8) !33 = !DILocation(line: 19, column: 13, scope: !8) !34 = !DILocalVariable(name: "res", scope: !8, file: !1, line: 19, type: !11) !35 = !DILocation(line: 20, column: 14, scope: !8) !36 = !DILocation(line: 21, column: 3, scope: !8) !37 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 24, type: !38, scopeLine: 24, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !38 = !DISubroutineType(types: !39) !39 = !{!11, !11, !40} !40 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !41, size: 64) !41 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !42, size: 64) !42 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !43 = !DILocalVariable(name: "argc", arg: 1, scope: !37, file: !1, line: 24, type: !11) !44 = !DILocation(line: 0, scope: !37) !45 = !DILocalVariable(name: "argv", arg: 2, scope: !37, file: !1, line: 24, type: !40) !46 = !DILocalVariable(name: "a", scope: !37, file: !1, line: 25, type: !47) !47 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 64, elements: !48) !48 = !{!49} !49 = !DISubrange(count: 2) !50 = !DILocation(line: 25, column: 7, scope: !37) !51 = !DILocalVariable(name: "b", scope: !37, file: !1, line: 26, type: !52) !52 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 96, elements: !53) !53 = !{!54} !54 = !DISubrange(count: 3) !55 = !DILocation(line: 26, column: 7, scope: !37) !56 = !DILocalVariable(name: "c", scope: !37, file: !1, line: 27, type: !57) !57 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !58) !58 = !{!59} !59 = !DISubrange(count: 10) !60 = !DILocation(line: 27, column: 7, scope: !37) !61 = !DILocation(line: 29, column: 3, scope: !37) !62 = !DILocation(line: 29, column: 8, scope: !37) !63 = !DILocation(line: 31, column: 3, scope: !37) !64 = !DILocation(line: 31, column: 8, scope: !37) !65 = !DILocation(line: 32, column: 3, scope: !37) !66 = !DILocation(line: 32, column: 8, scope: !37) !67 = !DILocation(line: 34, column: 3, scope: !37) !68 = !DILocation(line: 34, column: 8, scope: !37) !69 = !DILocation(line: 35, column: 3, scope: !37) !70 = !DILocation(line: 35, column: 8, scope: !37) !71 = !DILocation(line: 36, column: 3, scope: !37) !72 = !DILocation(line: 36, column: 8, scope: !37) !73 = !DILocation(line: 38, column: 21, scope: !37) !74 = !DILocation(line: 38, column: 11, scope: !37) !75 = !DILocalVariable(name: "x", scope: !37, file: !1, line: 38, type: !11) !76 = !DILocation(line: 40, column: 19, scope: !37) !77 = !DILocation(line: 40, column: 3, scope: !37) !78 = !DILocation(line: 41, column: 17, scope: !37) !79 = !DILocation(line: 41, column: 22, scope: !37) !80 = !DILocation(line: 41, column: 3, scope: !37) !81 = !DILocation(line: 42, column: 3, scope: !37) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-4.cpp000066400000000000000000000002741473507761200324550ustar00rootroot00000000000000int main(int argc, char** argv) { int i = 0, a[10]; bool flag = argc % 5 == 0; for (; i < 10; i++) { if (flag) a[i] = i ^ 2; else a[i] = i * 2; } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/phi-4.ll000066400000000000000000000062421473507761200323030ustar00rootroot00000000000000; ModuleID = 'phi-4.pp.bc' source_filename = "phi-4.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 0, metadata !18, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 undef, metadata !18, metadata !DIExpression()), !dbg !16 ret i32 0, !dbg !19 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-4.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 1, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 1, type: !12) !18 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 2, type: !11) !19 = !DILocation(line: 10, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/pod-types.c000066400000000000000000000003001473507761200331060ustar00rootroot00000000000000unsigned int i; float f; double d; void* p; int* q; unsigned char b; short tab[10][12]; void fun() {} int main(int argc, char** argv) { int xxx[10] = {1, -1, 255, 42}; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/pod-types.ll000066400000000000000000000140171473507761200333050ustar00rootroot00000000000000; ModuleID = 'pod-types.pp.bc' source_filename = "pod-types.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !35 { call void @llvm.dbg.value(metadata i32 %0, metadata !41, metadata !DIExpression()), !dbg !42 call void @llvm.dbg.value(metadata i8** %1, metadata !43, metadata !DIExpression()), !dbg !42 call void @llvm.dbg.value(metadata i32 0, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !42 call void @llvm.dbg.value(metadata i32 0, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !42 call void @llvm.dbg.value(metadata i32 0, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32)), !dbg !42 call void @llvm.dbg.value(metadata i32 0, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 96, 32)), !dbg !42 call void @llvm.dbg.value(metadata i32 1, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !42 call void @llvm.dbg.value(metadata i32 -1, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !42 call void @llvm.dbg.value(metadata i32 255, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32)), !dbg !42 call void @llvm.dbg.value(metadata i32 42, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 96, 32)), !dbg !42 ret i32 0, !dbg !47 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!30, !31, !32, !33} !llvm.ident = !{!34} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "pod-types.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4, !7, !10, !13, !16, !20, !23} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "i", scope: !0, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true) !6 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression()) !8 = distinct !DIGlobalVariable(name: "f", scope: !0, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true) !9 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) !11 = distinct !DIGlobalVariable(name: "d", scope: !0, file: !1, line: 5, type: !12, isLocal: false, isDefinition: true) !12 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "p", scope: !0, file: !1, line: 7, type: !15, isLocal: false, isDefinition: true) !15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !16 = !DIGlobalVariableExpression(var: !17, expr: !DIExpression()) !17 = distinct !DIGlobalVariable(name: "q", scope: !0, file: !1, line: 9, type: !18, isLocal: false, isDefinition: true) !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !20 = !DIGlobalVariableExpression(var: !21, expr: !DIExpression()) !21 = distinct !DIGlobalVariable(name: "b", scope: !0, file: !1, line: 11, type: !22, isLocal: false, isDefinition: true) !22 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !23 = !DIGlobalVariableExpression(var: !24, expr: !DIExpression()) !24 = distinct !DIGlobalVariable(name: "tab", scope: !0, file: !1, line: 13, type: !25, isLocal: false, isDefinition: true) !25 = !DICompositeType(tag: DW_TAG_array_type, baseType: !26, size: 1920, elements: !27) !26 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) !27 = !{!28, !29} !28 = !DISubrange(count: 10) !29 = !DISubrange(count: 12) !30 = !{i32 2, !"Dwarf Version", i32 4} !31 = !{i32 2, !"Debug Info Version", i32 3} !32 = !{i32 1, !"wchar_size", i32 4} !33 = !{i32 7, !"PIC Level", i32 2} !34 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !35 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 17, type: !36, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !36 = !DISubroutineType(types: !37) !37 = !{!19, !19, !38} !38 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !39, size: 64) !39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64) !40 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !41 = !DILocalVariable(name: "argc", arg: 1, scope: !35, file: !1, line: 17, type: !19) !42 = !DILocation(line: 0, scope: !35) !43 = !DILocalVariable(name: "argv", arg: 2, scope: !35, file: !1, line: 17, type: !38) !44 = !DILocalVariable(name: "xxx", scope: !35, file: !1, line: 18, type: !45) !45 = !DICompositeType(tag: DW_TAG_array_type, baseType: !19, size: 320, elements: !46) !46 = !{!28} !47 = !DILocation(line: 19, column: 3, scope: !35) pointer-arithmetic.cpp000066400000000000000000000004561473507761200352660ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include int f() { return 6; } unsigned char* ptr_fun = (unsigned char*)&f + 1; const char* string_map[] = {"aaa", "bbb"}; struct vector { int x; int y; int z; }; struct vector v[] = {{1, 2, 3}, {4, 5, 6}}; int* ptr = &(v[1].z); int main() { return printf("%d\n", v[1].z); } pointer-arithmetic.ll000066400000000000000000000122711473507761200351110ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'pointer-arithmetic.pp.bc' source_filename = "pointer-arithmetic.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str.2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str.2, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.2, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) local_unnamed_addr #1 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !33 { %1 = getelementptr inbounds [4 x i8], [4 x i8]* @.str.2, i64 0, i64 0, !dbg !36 %2 = call i32 (i8*, ...) @printf(i8* %1, i32 6), !dbg !36 ret i32 %2, !dbg !37 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = ptrshift @.str.2, 4 * 0, 1 * 0 ; CHECK: si32 %2 = call @ar.libc.printf(%1, 6) ; CHECK: return %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!28, !29, !30, !31} !llvm.ident = !{!32} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "pointer-arithmetic.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4, !8, !16, !25} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "ptr_fun", scope: !0, file: !1, line: 7, type: !6, isLocal: false, isDefinition: true) !6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) !7 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !8 = !DIGlobalVariableExpression(var: !9, expr: !DIExpression()) !9 = distinct !DIGlobalVariable(name: "string_map", scope: !0, file: !1, line: 9, type: !10, isLocal: false, isDefinition: true) !10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 128, elements: !14) !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) !12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) !13 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !14 = !{!15} !15 = !DISubrange(count: 2) !16 = !DIGlobalVariableExpression(var: !17, expr: !DIExpression()) !17 = distinct !DIGlobalVariable(name: "v", scope: !0, file: !1, line: 17, type: !18, isLocal: false, isDefinition: true) !18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !19, size: 192, elements: !14) !19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "vector", file: !1, line: 11, size: 96, flags: DIFlagTypePassByValue, elements: !20, identifier: "_ZTS6vector") !20 = !{!21, !23, !24} !21 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !19, file: !1, line: 12, baseType: !22, size: 32) !22 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !23 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !19, file: !1, line: 13, baseType: !22, size: 32, offset: 32) !24 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !19, file: !1, line: 14, baseType: !22, size: 32, offset: 64) !25 = !DIGlobalVariableExpression(var: !26, expr: !DIExpression()) !26 = distinct !DIGlobalVariable(name: "ptr", scope: !0, file: !1, line: 19, type: !27, isLocal: false, isDefinition: true) !27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !28 = !{i32 2, !"Dwarf Version", i32 4} !29 = !{i32 2, !"Debug Info Version", i32 3} !30 = !{i32 1, !"wchar_size", i32 4} !31 = !{i32 7, !"PIC Level", i32 2} !32 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !33 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 21, type: !34, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !34 = !DISubroutineType(types: !35) !35 = !{!22} !36 = !DILocation(line: 22, column: 10, scope: !33) !37 = !DILocation(line: 22, column: 3, scope: !33) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/ptr-to-int.c000066400000000000000000000001121473507761200332000ustar00rootroot00000000000000#include int f() { return 0; } uintptr_t x = (intptr_t)&f; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/ptr-to-int.ll000066400000000000000000000027441473507761200334020ustar00rootroot00000000000000; ModuleID = 'ptr-to-int.pp.bc' source_filename = "ptr-to-int.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!9, !10, !11, !12} !llvm.ident = !{!13} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "ptr-to-int.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "x", scope: !0, file: !1, line: 7, type: !6, isLocal: false, isDefinition: true) !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "uintptr_t", file: !7, line: 30, baseType: !8) !7 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_uintptr_t.h", directory: "") !8 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) !9 = !{i32 2, !"Dwarf Version", i32 4} !10 = !{i32 2, !"Debug Info Version", i32 3} !11 = !{i32 1, !"wchar_size", i32 4} !12 = !{i32 7, !"PIC Level", i32 2} !13 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/reference.cpp000066400000000000000000000001151473507761200334640ustar00rootroot00000000000000void f(int& x) { x = 1; } int main() { int y = 0; f(y); return y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/reference.ll000066400000000000000000000112631473507761200333170ustar00rootroot00000000000000; ModuleID = 'reference.pp.bc' source_filename = "reference.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_Z1fRi(i32* dereferenceable(4)) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32* %0, metadata !13, metadata !DIExpression()), !dbg !14 store i32 1, i32* %0, align 4, !dbg !15 ret void, !dbg !16 } ; CHECK: define void @_Z1fRi(si32* %1) { ; CHECK: #1 !entry !exit { ; CHECK: store %1, 1, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #1 !dbg !17 { %1 = alloca i32, align 4 call void @llvm.dbg.value(metadata i32 0, metadata !20, metadata !DIExpression()), !dbg !21 store i32 0, i32* %1, align 4, !dbg !22 call void @llvm.dbg.value(metadata i32* %1, metadata !20, metadata !DIExpression(DW_OP_deref)), !dbg !21 call fastcc void @_Z1fRi(i32* nonnull dereferenceable(4) %1), !dbg !23 %2 = load i32, i32* %1, align 4, !dbg !24 call void @llvm.dbg.value(metadata i32 %2, metadata !20, metadata !DIExpression()), !dbg !21 ret i32 %2, !dbg !25 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: call @_Z1fRi($1) ; CHECK: si32 %2 = load $1, align 4 ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "reference.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fRi", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null, !11} !11 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !12, size: 64) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11) !14 = !DILocation(line: 0, scope: !8) !15 = !DILocation(line: 2, column: 5, scope: !8) !16 = !DILocation(line: 3, column: 1, scope: !8) !17 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !18, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !18 = !DISubroutineType(types: !19) !19 = !{!12} !20 = !DILocalVariable(name: "y", scope: !17, file: !1, line: 6, type: !12) !21 = !DILocation(line: 0, scope: !17) !22 = !DILocation(line: 6, column: 7, scope: !17) !23 = !DILocation(line: 7, column: 3, scope: !17) !24 = !DILocation(line: 8, column: 10, scope: !17) !25 = !DILocation(line: 8, column: 3, scope: !17) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/regenerate-ll000077500000000000000000000027061473507761200335060ustar00rootroot00000000000000#!/bin/bash # Use this script to regenerate all the .ll files from the .c and .cpp files clang="clang" ikos_pp="ikos-pp" opt="opt" opt_level="aggressive" cflags="-c -emit-llvm -Wall -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone" cxxflags="$cflags -std=c++17" ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" set -e function run { echo "#" "$@" "$@" } for filename in *.c do echo "[*] $filename ..." filename="${filename%.c}" if [[ -f "$filename.ll" ]]; then echo "$filename.ll already exists, skipping" continue fi run "$clang" $cflags "$filename.c" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.ll" "$ikos_import" $ikos_import_opts "$filename.ll" | sed 's/^/; CHECK: /' >> "$filename.ll" rm -f "$filename.bc" "$filename.pp.bc" done for filename in *.cpp do echo "[*] $filename ..." filename="${filename%.cpp}" if [[ -f "$filename.ll" ]]; then echo "$filename.ll already exists, skipping" continue fi run "$clang" $cxxflags "$filename.cpp" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.ll" "$ikos_import" $ikos_import_opts "$filename.ll" | sed 's/^/; CHECK: /' >> "$filename.ll" rm -f "$filename.bc" "$filename.pp.bc" done NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/runtest000077500000000000000000000066751473507761200324750ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing ikos-import with aggressive optimizations # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" file_check="FileCheck" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h]" echo " [--ikos-import IKOS-IMPORT]" echo " [--file-check FILE-CHECK]" echo "" echo "Run regression tests for llvm-to-ar" exit 1 elif [[ "$1" = "--ikos-import" ]]; then shift ikos_import=$1 elif [[ "$1" = "--file-check" ]]; then shift file_check=$1 else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-import if ! command -v "$ikos_import" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_import" >&2 exit 2 fi # Check FileCheck if ! command -v "$file_check" >/dev/null 2>&1; then echo "error: $progname: could not find $file_check" >&2 exit 2 fi # Run the tests echo "# Running regression tests for ikos-import" for filename in *.ll do echo -en "$filename ... \r" "$ikos_import" $ikos_import_opts "$filename" \ | "$file_check" "$filename" \ || { echo "Test Failed"; exit 1; } echo "$filename ... Passed" rm -f "$filename_pp" done echo "All tests passed successfully." exit 0 NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/select.cpp000066400000000000000000000003461473507761200330130ustar00rootroot00000000000000/** * To generate LLVM select instruction, we need to compile * the code with optimization enabled (at least -O1) * * > clang++ -O1 -emit-llvm -o test.bc -g -c test.cpp */ int a; int main() { return a > 0 ? 123 : 321; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/select.ll000066400000000000000000000045071473507761200326430ustar00rootroot00000000000000; ModuleID = 'select.pp.bc' source_filename = "select.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !12 { ret i32 321, !dbg !15 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 321 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "select.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 8, type: !6, isLocal: false, isDefinition: true) !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 10, type: !13, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 11, column: 3, scope: !12) shufflevector.c000066400000000000000000000002551473507761200337730ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include extern void printv(__m128); int main(int argc, char** argv) { __m128 m = _mm_set_ps(4, 3, 2, 1); m = _mm_shuffle_ps(m, m, 0x1B); printv(m); } shufflevector.ll000066400000000000000000000113271473507761200341620ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'shufflevector.pp.bc' source_filename = "shufflevector.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !16 { call void @llvm.dbg.value(metadata i32 %0, metadata !23, metadata !DIExpression()), !dbg !24 call void @llvm.dbg.value(metadata i8** %1, metadata !25, metadata !DIExpression()), !dbg !24 call void @llvm.dbg.value(metadata <4 x float> , metadata !26, metadata !DIExpression()), !dbg !24 call void @llvm.dbg.value(metadata <4 x float> , metadata !26, metadata !DIExpression()), !dbg !24 call void @printv(<4 x float> ) #3, !dbg !27 ret i32 0, !dbg !28 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: call @printv(<4.0E+0, 3.0E+0, 2.0E+0, 1.0E+0>) ; CHECK: return 0 ; CHECK: } ; CHECK: } declare void @printv(<4 x float>) local_unnamed_addr #1 ; CHECK: declare void @printv(<4 x float>) ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="128" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!11, !12, !13, !14} !llvm.ident = !{!15} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "shufflevector.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4, !10} !4 = !DIDerivedType(tag: DW_TAG_typedef, name: "__m128", file: !5, line: 17, baseType: !6) !5 = !DIFile(filename: "Homebrew/Cellar/llvm/9.0.0_1/lib/clang/9.0.0/include/xmmintrin.h", directory: "/Users/marthaud") !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 128, flags: DIFlagVector, elements: !8) !7 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 4) !10 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v4sf", file: !5, line: 16, baseType: !6) !11 = !{i32 2, !"Dwarf Version", i32 4} !12 = !{i32 2, !"Debug Info Version", i32 3} !13 = !{i32 1, !"wchar_size", i32 4} !14 = !{i32 7, !"PIC Level", i32 2} !15 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!19, !19, !20} !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !23 = !DILocalVariable(name: "argc", arg: 1, scope: !16, file: !1, line: 5, type: !19) !24 = !DILocation(line: 0, scope: !16) !25 = !DILocalVariable(name: "argv", arg: 2, scope: !16, file: !1, line: 5, type: !20) !26 = !DILocalVariable(name: "m", scope: !16, file: !1, line: 6, type: !4) !27 = !DILocation(line: 8, column: 3, scope: !16) !28 = !DILocation(line: 9, column: 1, scope: !16) struct-parameters.c000066400000000000000000000003271473507761200346010ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization#include typedef struct { char buf[10]; char buf1[10]; char buf2[10]; } my_struct; my_struct f(my_struct* s) { return *s; } my_struct g(my_struct s) { return s; } int main() { return 0; } struct-parameters.ll000066400000000000000000000041241473507761200347650ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'struct-parameters.pp.bc' source_filename = "struct-parameters.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { ret i32 0, !dbg !12 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "struct-parameters.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 17, type: !9, scopeLine: 17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 18, column: 3, scope: !8) thread-local.cpp000066400000000000000000000000671473507761200340140ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationstatic thread_local int x; int main() { return x; } thread-local.ll000066400000000000000000000070121473507761200336360ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'thread-local.pp.bc' source_filename = "thread-local.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @_ZL1x = internal thread_local global i32 0, align 4, !dbg !0 ; CHECK: define si32* @_ZL1x, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZL1x, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal cxx_fast_tlscc i32* @_ZTWL1x() unnamed_addr #1 { ret i32* @_ZL1x } ; CHECK: define si32* @_ZTWL1x() { ; CHECK: #1 !entry !exit { ; CHECK: return @_ZL1x ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !12 { %1 = call cxx_fast_tlscc i32* @_ZTWL1x(), !dbg !15 %2 = load i32, i32* %1, align 4, !dbg !15 ret i32 %2, !dbg !16 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* %1 = call @_ZTWL1x() ; CHECK: si32 %2 = load %1, align 4 ; CHECK: return %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", linkageName: "_ZL1x", scope: !2, file: !3, line: 1, type: !6, isLocal: true, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "thread-local.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 4, column: 10, scope: !12) !16 = !DILocation(line: 4, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/try-catch.cpp000066400000000000000000000010071473507761200334250ustar00rootroot00000000000000int G; class A { public: virtual void f(int x) {} virtual int g() { return 0; } }; class B : public A { public: virtual void f(int x) { G = x; } virtual int g() { return 0; } }; class C : public B { public: virtual void f(int x) { G = -x; } virtual int g() { return 1; } }; void h(int x) {} int hh(int x) { return x * x; } void run(A* p) { int x; p->f(12); x = p->g(); h(14); x = hh(15); } int main() { B b; C c; try { run(&b); run(&c); } catch (A& e) { } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/try-catch.ll000066400000000000000000000724701473507761200332660ustar00rootroot00000000000000; ModuleID = 'try-catch.pp.bc' source_filename = "try-catch.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.A = type { i32 (...)** } %class.B = type { %class.A } %class.C = type { %class.B } @_ZTI1A = internal constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1A, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1A, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1A, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1B = internal constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0), i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*) }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si8*}* @_ZTI1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv120__si_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1B, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1B, {0: %4, 8: %3, 16: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1C = internal constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1B to i8*) }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si8*}* @_ZTI1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv120__si_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1B ; CHECK: si8* %3 = ptrshift @_ZTS1C, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1C, {0: %4, 8: %3, 16: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTS1A = internal constant [3 x i8] c"1A\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1A, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1A, [49, 65, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1B = internal constant [3 x i8] c"1B\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1B, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1B, [49, 66, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1C = internal constant [3 x i8] c"1C\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1C, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1C, [49, 67, 0], align 1 ; CHECK: } ; CHECK: } @_ZTV1A = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast (void (%class.A*, i32)* @_ZN1A1fEi to i8*), i8* bitcast (i32 (%class.A*)* @_ZN1A1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1A1gEv ; CHECK: si8* %2 = bitcast @_ZN1A1fEi ; CHECK: si8* %3 = bitcast @_ZTI1A ; CHECK: store @_ZTV1A, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1B = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1B to i8*), i8* bitcast (void (%class.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%class.B*)* @_ZN1B1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1B1gEv ; CHECK: si8* %2 = bitcast @_ZN1B1fEi ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: store @_ZTV1B, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1C = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1C to i8*), i8* bitcast (void (%class.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%class.C*)* @_ZN1C1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1C1gEv ; CHECK: si8* %2 = bitcast @_ZN1C1fEi ; CHECK: si8* %3 = bitcast @_ZTI1C ; CHECK: store @_ZTV1C, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTVN10__cxxabiv117__class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv117__class_type_infoE @_ZTVN10__cxxabiv120__si_class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv120__si_class_type_infoE ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_Z1hi(i32) unnamed_addr #0 !dbg !12 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 ret void, !dbg !17 } ; CHECK: define void @_Z1hi(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc i32 @_Z2hhi(i32) unnamed_addr #0 !dbg !18 { call void @llvm.dbg.value(metadata i32 %0, metadata !21, metadata !DIExpression()), !dbg !22 %2 = mul nsw i32 %0, %0, !dbg !23 ret i32 %2, !dbg !24 } ; CHECK: define si32 @_Z2hhi(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %2 = %1 smul.nw %1 ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define internal fastcc void @_Z3runP1A(%class.A*) unnamed_addr #1 !dbg !25 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !43, metadata !DIExpression()), !dbg !44 %2 = bitcast %class.A* %0 to void (%class.A*, i32)***, !dbg !45 %3 = load void (%class.A*, i32)**, void (%class.A*, i32)*** %2, align 8, !dbg !45 %4 = load void (%class.A*, i32)*, void (%class.A*, i32)** %3, align 8, !dbg !45 call void %4(%class.A* %0, i32 12), !dbg !45 %5 = bitcast %class.A* %0 to i32 (%class.A*)***, !dbg !46 %6 = load i32 (%class.A*)**, i32 (%class.A*)*** %5, align 8, !dbg !46 %7 = getelementptr inbounds i32 (%class.A*)*, i32 (%class.A*)** %6, i64 1, !dbg !46 %8 = load i32 (%class.A*)*, i32 (%class.A*)** %7, align 8, !dbg !46 %9 = call i32 %8(%class.A* %0), !dbg !46 call void @llvm.dbg.value(metadata i32 %9, metadata !47, metadata !DIExpression()), !dbg !44 call fastcc void @_Z1hi(i32 14), !dbg !48 %10 = call fastcc i32 @_Z2hhi(i32 15), !dbg !49 call void @llvm.dbg.value(metadata i32 %10, metadata !47, metadata !DIExpression()), !dbg !44 ret void, !dbg !50 } ; CHECK: define void @_Z3runP1A({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: void ({0: si32 (...)**}*, si32)*** %2 = bitcast %1 ; CHECK: void ({0: si32 (...)**}*, si32)** %3 = load %2, align 8 ; CHECK: void ({0: si32 (...)**}*, si32)* %4 = load %3, align 8 ; CHECK: call %4(%1, 12) ; CHECK: si32 ({0: si32 (...)**}*)*** %5 = bitcast %1 ; CHECK: si32 ({0: si32 (...)**}*)** %6 = load %5, align 8 ; CHECK: si32 ({0: si32 (...)**}*)** %7 = ptrshift %6, 8 * 1 ; CHECK: si32 ({0: si32 (...)**}*)* %8 = load %7, align 8 ; CHECK: si32 %9 = call %8(%1) ; CHECK: call @_Z1hi(14) ; CHECK: si32 %10 = call @_Z2hhi(15) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal void @_ZN1A1fEi(%class.A*, i32) unnamed_addr #0 align 2 !dbg !119 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !120, metadata !DIExpression()), !dbg !121 call void @llvm.dbg.value(metadata i32 %1, metadata !122, metadata !DIExpression()), !dbg !121 ret void, !dbg !123 } ; CHECK: define void @_ZN1A1fEi({0: si32 (...)**}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal i32 @_ZN1A1gEv(%class.A*) unnamed_addr #0 align 2 !dbg !124 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !125, metadata !DIExpression()), !dbg !126 ret i32 0, !dbg !127 } ; CHECK: define si32 @_ZN1A1gEv({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1AC2Ev(%class.A*) unnamed_addr #0 align 2 !dbg !103 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !107, metadata !DIExpression()), !dbg !108 %2 = getelementptr inbounds %class.A, %class.A* %0, i64 0, i32 0, !dbg !109 %3 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i64 0, i32 0, i64 2, !dbg !109 %4 = bitcast i8** %3 to i32 (...)**, !dbg !109 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !109 ret void, !dbg !109 } ; CHECK: define void @_ZN1AC2Ev({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = ptrshift %1, 8 * 0, 1 * 0 ; CHECK: si8** %3 = ptrshift @_ZTV1A, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal void @_ZN1B1fEi(%class.B*, i32) unnamed_addr #0 align 2 !dbg !110 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !111, metadata !DIExpression()), !dbg !112 call void @llvm.dbg.value(metadata i32 %1, metadata !113, metadata !DIExpression()), !dbg !112 ret void, !dbg !114 } ; CHECK: define void @_ZN1B1fEi({0: {0: si32 (...)**}}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal i32 @_ZN1B1gEv(%class.B*) unnamed_addr #0 align 2 !dbg !115 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !116, metadata !DIExpression()), !dbg !117 ret i32 0, !dbg !118 } ; CHECK: define si32 @_ZN1B1gEv({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1BC1Ev(%class.B*) unnamed_addr #0 align 2 !dbg !83 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !87, metadata !DIExpression()), !dbg !89 call fastcc void @_ZN1BC2Ev(%class.B* %0) #4, !dbg !90 ret void, !dbg !90 } ; CHECK: define void @_ZN1BC1Ev({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN1BC2Ev(%1) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1BC2Ev(%class.B*) unnamed_addr #0 align 2 !dbg !99 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !100, metadata !DIExpression()), !dbg !101 %2 = getelementptr inbounds %class.B, %class.B* %0, i64 0, i32 0, !dbg !102 call fastcc void @_ZN1AC2Ev(%class.A* %2) #4, !dbg !102 %3 = getelementptr inbounds %class.B, %class.B* %0, i64 0, i32 0, i32 0, !dbg !102 %4 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1B, i64 0, i32 0, i64 2, !dbg !102 %5 = bitcast i8** %4 to i32 (...)**, !dbg !102 store i32 (...)** %5, i32 (...)*** %3, align 8, !dbg !102 ret void, !dbg !102 } ; CHECK: define void @_ZN1BC2Ev({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**}* %2 = ptrshift %1, 8 * 0, 1 * 0 ; CHECK: call @_ZN1AC2Ev(%2) ; CHECK: si32 (...)*** %3 = ptrshift %1, 8 * 0, 1 * 0, 1 * 0 ; CHECK: si8** %4 = ptrshift @_ZTV1B, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %5 = bitcast %4 ; CHECK: store %3, %5, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal void @_ZN1C1fEi(%class.C*, i32) unnamed_addr #0 align 2 !dbg !132 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !133, metadata !DIExpression()), !dbg !134 call void @llvm.dbg.value(metadata i32 %1, metadata !135, metadata !DIExpression()), !dbg !134 ret void, !dbg !136 } ; CHECK: define void @_ZN1C1fEi({0: {0: {0: si32 (...)**}}}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal i32 @_ZN1C1gEv(%class.C*) unnamed_addr #0 align 2 !dbg !137 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !138, metadata !DIExpression()), !dbg !139 ret i32 1, !dbg !140 } ; CHECK: define si32 @_ZN1C1gEv({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1CC1Ev(%class.C*) unnamed_addr #0 align 2 !dbg !91 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !95, metadata !DIExpression()), !dbg !97 call fastcc void @_ZN1CC2Ev(%class.C* %0) #4, !dbg !98 ret void, !dbg !98 } ; CHECK: define void @_ZN1CC1Ev({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN1CC2Ev(%1) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1CC2Ev(%class.C*) unnamed_addr #0 align 2 !dbg !128 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !129, metadata !DIExpression()), !dbg !130 %2 = getelementptr inbounds %class.C, %class.C* %0, i64 0, i32 0, !dbg !131 call fastcc void @_ZN1BC2Ev(%class.B* %2) #4, !dbg !131 %3 = getelementptr inbounds %class.C, %class.C* %0, i64 0, i32 0, i32 0, i32 0, !dbg !131 %4 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1C, i64 0, i32 0, i64 2, !dbg !131 %5 = bitcast i8** %4 to i32 (...)**, !dbg !131 store i32 (...)** %5, i32 (...)*** %3, align 8, !dbg !131 ret void, !dbg !131 } ; CHECK: define void @_ZN1CC2Ev({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32 (...)**}}* %2 = ptrshift %1, 8 * 0, 1 * 0 ; CHECK: call @_ZN1BC2Ev(%2) ; CHECK: si32 (...)*** %3 = ptrshift %1, 8 * 0, 1 * 0, 1 * 0, 1 * 0 ; CHECK: si8** %4 = ptrshift @_ZTV1C, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %5 = bitcast %4 ; CHECK: store %3, %5, align 8 ; CHECK: return ; CHECK: } ; CHECK: } declare i32 @__gxx_personality_v0(...) ; CHECK: declare si32 @__gxx_personality_v0(...) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() local_unnamed_addr #2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !51 { %1 = alloca %class.B, align 8 %2 = alloca %class.C, align 8 call void @llvm.dbg.value(metadata %class.B* %1, metadata !52, metadata !DIExpression(DW_OP_deref)), !dbg !63 call fastcc void @_ZN1BC1Ev(%class.B* nonnull %1) #4, !dbg !64 call void @llvm.dbg.value(metadata %class.C* %2, metadata !65, metadata !DIExpression(DW_OP_deref)), !dbg !63 call fastcc void @_ZN1CC1Ev(%class.C* nonnull %2) #4, !dbg !76 %3 = getelementptr inbounds %class.B, %class.B* %1, i64 0, i32 0, !dbg !77 call fastcc void @_Z3runP1A(%class.A* nonnull %3), !dbg !79 %4 = getelementptr inbounds %class.C, %class.C* %2, i64 0, i32 0, i32 0, !dbg !80 call fastcc void @_Z3runP1A(%class.A* nonnull %4), !dbg !81 ret i32 0, !dbg !82 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32 (...)**}}* $1 = allocate {0: {0: si32 (...)**}}, 1, align 8 ; CHECK: {0: {0: {0: si32 (...)**}}}* $2 = allocate {0: {0: {0: si32 (...)**}}}, 1, align 8 ; CHECK: call @_ZN1BC1Ev($1) ; CHECK: call @_ZN1CC1Ev($2) ; CHECK: {0: si32 (...)**}* %3 = ptrshift $1, 8 * 0, 1 * 0 ; CHECK: call @_Z3runP1A(%3) ; CHECK: {0: si32 (...)**}* %4 = ptrshift $2, 8 * 0, 1 * 0, 1 * 0 ; CHECK: call @_Z3runP1A(%4) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #3 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind readnone speculatable } attributes #4 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "try-catch.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "G", scope: !0, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true) !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "h", linkageName: "_Z1hi", scope: !1, file: !1, line: 21, type: !13, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !13 = !DISubroutineType(types: !14) !14 = !{null, !6} !15 = !DILocalVariable(name: "x", arg: 1, scope: !12, file: !1, line: 21, type: !6) !16 = !DILocation(line: 0, scope: !12) !17 = !DILocation(line: 21, column: 16, scope: !12) !18 = distinct !DISubprogram(name: "hh", linkageName: "_Z2hhi", scope: !1, file: !1, line: 23, type: !19, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !19 = !DISubroutineType(types: !20) !20 = !{!6, !6} !21 = !DILocalVariable(name: "x", arg: 1, scope: !18, file: !1, line: 23, type: !6) !22 = !DILocation(line: 0, scope: !18) !23 = !DILocation(line: 24, column: 12, scope: !18) !24 = !DILocation(line: 24, column: 3, scope: !18) !25 = distinct !DISubprogram(name: "run", linkageName: "_Z3runP1A", scope: !1, file: !1, line: 27, type: !26, scopeLine: 27, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !26 = !DISubroutineType(types: !27) !27 = !{null, !28} !28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64) !29 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A", file: !1, line: 3, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !30, vtableHolder: !29, identifier: "_ZTS1A") !30 = !{!31, !36, !40} !31 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$A", scope: !1, file: !1, baseType: !32, size: 64, flags: DIFlagArtificial) !32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64) !33 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: !34, size: 64) !34 = !DISubroutineType(types: !35) !35 = !{!6} !36 = !DISubprogram(name: "f", linkageName: "_ZN1A1fEi", scope: !29, file: !1, line: 5, type: !37, scopeLine: 5, containingType: !29, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !37 = !DISubroutineType(types: !38) !38 = !{null, !39, !6} !39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !40 = !DISubprogram(name: "g", linkageName: "_ZN1A1gEv", scope: !29, file: !1, line: 6, type: !41, scopeLine: 6, containingType: !29, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !41 = !DISubroutineType(types: !42) !42 = !{!6, !39} !43 = !DILocalVariable(name: "p", arg: 1, scope: !25, file: !1, line: 27, type: !28) !44 = !DILocation(line: 0, scope: !25) !45 = !DILocation(line: 29, column: 6, scope: !25) !46 = !DILocation(line: 30, column: 10, scope: !25) !47 = !DILocalVariable(name: "x", scope: !25, file: !1, line: 28, type: !6) !48 = !DILocation(line: 31, column: 3, scope: !25) !49 = !DILocation(line: 32, column: 7, scope: !25) !50 = !DILocation(line: 33, column: 1, scope: !25) !51 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 35, type: !34, scopeLine: 35, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !52 = !DILocalVariable(name: "b", scope: !51, file: !1, line: 36, type: !53) !53 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "B", file: !1, line: 9, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !54, vtableHolder: !29, identifier: "_ZTS1B") !54 = !{!55, !56, !60} !55 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !53, baseType: !29, flags: DIFlagPublic, extraData: i32 0) !56 = !DISubprogram(name: "f", linkageName: "_ZN1B1fEi", scope: !53, file: !1, line: 11, type: !57, scopeLine: 11, containingType: !53, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !57 = !DISubroutineType(types: !58) !58 = !{null, !59, !6} !59 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !53, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !60 = !DISubprogram(name: "g", linkageName: "_ZN1B1gEv", scope: !53, file: !1, line: 12, type: !61, scopeLine: 12, containingType: !53, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !61 = !DISubroutineType(types: !62) !62 = !{!6, !59} !63 = !DILocation(line: 0, scope: !51) !64 = !DILocation(line: 36, column: 5, scope: !51) !65 = !DILocalVariable(name: "c", scope: !51, file: !1, line: 37, type: !66) !66 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C", file: !1, line: 15, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !67, vtableHolder: !29, identifier: "_ZTS1C") !67 = !{!68, !69, !73} !68 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !66, baseType: !53, flags: DIFlagPublic, extraData: i32 0) !69 = !DISubprogram(name: "f", linkageName: "_ZN1C1fEi", scope: !66, file: !1, line: 17, type: !70, scopeLine: 17, containingType: !66, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !70 = !DISubroutineType(types: !71) !71 = !{null, !72, !6} !72 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !66, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !73 = !DISubprogram(name: "g", linkageName: "_ZN1C1gEv", scope: !66, file: !1, line: 18, type: !74, scopeLine: 18, containingType: !66, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !74 = !DISubroutineType(types: !75) !75 = !{!6, !72} !76 = !DILocation(line: 37, column: 5, scope: !51) !77 = !DILocation(line: 39, column: 9, scope: !78) !78 = distinct !DILexicalBlock(scope: !51, file: !1, line: 38, column: 7) !79 = !DILocation(line: 39, column: 5, scope: !78) !80 = !DILocation(line: 40, column: 9, scope: !78) !81 = !DILocation(line: 40, column: 5, scope: !78) !82 = !DILocation(line: 43, column: 3, scope: !51) !83 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC1Ev", scope: !53, file: !1, line: 9, type: !84, scopeLine: 9, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !86, retainedNodes: !2) !84 = !DISubroutineType(types: !85) !85 = !{null, !59} !86 = !DISubprogram(name: "B", scope: !53, type: !84, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !87 = !DILocalVariable(name: "this", arg: 1, scope: !83, type: !88, flags: DIFlagArtificial | DIFlagObjectPointer) !88 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !53, size: 64) !89 = !DILocation(line: 0, scope: !83) !90 = !DILocation(line: 9, column: 7, scope: !83) !91 = distinct !DISubprogram(name: "C", linkageName: "_ZN1CC1Ev", scope: !66, file: !1, line: 15, type: !92, scopeLine: 15, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !94, retainedNodes: !2) !92 = !DISubroutineType(types: !93) !93 = !{null, !72} !94 = !DISubprogram(name: "C", scope: !66, type: !92, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !95 = !DILocalVariable(name: "this", arg: 1, scope: !91, type: !96, flags: DIFlagArtificial | DIFlagObjectPointer) !96 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !66, size: 64) !97 = !DILocation(line: 0, scope: !91) !98 = !DILocation(line: 15, column: 7, scope: !91) !99 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC2Ev", scope: !53, file: !1, line: 9, type: !84, scopeLine: 9, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !86, retainedNodes: !2) !100 = !DILocalVariable(name: "this", arg: 1, scope: !99, type: !88, flags: DIFlagArtificial | DIFlagObjectPointer) !101 = !DILocation(line: 0, scope: !99) !102 = !DILocation(line: 9, column: 7, scope: !99) !103 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AC2Ev", scope: !29, file: !1, line: 3, type: !104, scopeLine: 3, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !106, retainedNodes: !2) !104 = !DISubroutineType(types: !105) !105 = !{null, !39} !106 = !DISubprogram(name: "A", scope: !29, type: !104, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !107 = !DILocalVariable(name: "this", arg: 1, scope: !103, type: !28, flags: DIFlagArtificial | DIFlagObjectPointer) !108 = !DILocation(line: 0, scope: !103) !109 = !DILocation(line: 3, column: 7, scope: !103) !110 = distinct !DISubprogram(name: "f", linkageName: "_ZN1B1fEi", scope: !53, file: !1, line: 11, type: !57, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !56, retainedNodes: !2) !111 = !DILocalVariable(name: "this", arg: 1, scope: !110, type: !88, flags: DIFlagArtificial | DIFlagObjectPointer) !112 = !DILocation(line: 0, scope: !110) !113 = !DILocalVariable(name: "x", arg: 2, scope: !110, file: !1, line: 11, type: !6) !114 = !DILocation(line: 11, column: 34, scope: !110) !115 = distinct !DISubprogram(name: "g", linkageName: "_ZN1B1gEv", scope: !53, file: !1, line: 12, type: !61, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !60, retainedNodes: !2) !116 = !DILocalVariable(name: "this", arg: 1, scope: !115, type: !88, flags: DIFlagArtificial | DIFlagObjectPointer) !117 = !DILocation(line: 0, scope: !115) !118 = !DILocation(line: 12, column: 21, scope: !115) !119 = distinct !DISubprogram(name: "f", linkageName: "_ZN1A1fEi", scope: !29, file: !1, line: 5, type: !37, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !36, retainedNodes: !2) !120 = !DILocalVariable(name: "this", arg: 1, scope: !119, type: !28, flags: DIFlagArtificial | DIFlagObjectPointer) !121 = !DILocation(line: 0, scope: !119) !122 = !DILocalVariable(name: "x", arg: 2, scope: !119, file: !1, line: 5, type: !6) !123 = !DILocation(line: 5, column: 26, scope: !119) !124 = distinct !DISubprogram(name: "g", linkageName: "_ZN1A1gEv", scope: !29, file: !1, line: 6, type: !41, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !40, retainedNodes: !2) !125 = !DILocalVariable(name: "this", arg: 1, scope: !124, type: !28, flags: DIFlagArtificial | DIFlagObjectPointer) !126 = !DILocation(line: 0, scope: !124) !127 = !DILocation(line: 6, column: 21, scope: !124) !128 = distinct !DISubprogram(name: "C", linkageName: "_ZN1CC2Ev", scope: !66, file: !1, line: 15, type: !92, scopeLine: 15, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !94, retainedNodes: !2) !129 = !DILocalVariable(name: "this", arg: 1, scope: !128, type: !96, flags: DIFlagArtificial | DIFlagObjectPointer) !130 = !DILocation(line: 0, scope: !128) !131 = !DILocation(line: 15, column: 7, scope: !128) !132 = distinct !DISubprogram(name: "f", linkageName: "_ZN1C1fEi", scope: !66, file: !1, line: 17, type: !70, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !69, retainedNodes: !2) !133 = !DILocalVariable(name: "this", arg: 1, scope: !132, type: !96, flags: DIFlagArtificial | DIFlagObjectPointer) !134 = !DILocation(line: 0, scope: !132) !135 = !DILocalVariable(name: "x", arg: 2, scope: !132, file: !1, line: 17, type: !6) !136 = !DILocation(line: 17, column: 35, scope: !132) !137 = distinct !DISubprogram(name: "g", linkageName: "_ZN1C1gEv", scope: !66, file: !1, line: 18, type: !74, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !73, retainedNodes: !2) !138 = !DILocalVariable(name: "this", arg: 1, scope: !137, type: !96, flags: DIFlagArtificial | DIFlagObjectPointer) !139 = !DILocation(line: 0, scope: !137) !140 = !DILocation(line: 18, column: 21, scope: !137) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/undef.c000066400000000000000000000001241473507761200322670ustar00rootroot00000000000000extern int flag; int main(int argc, char** argv) { int* v; return flag + *v; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/undef.ll000066400000000000000000000061151473507761200324620ustar00rootroot00000000000000; ModuleID = 'undef.pp.bc' source_filename = "undef.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: cold noreturn nounwind declare void @llvm.trap() #2 ; CHECK: declare void @ar.trap() ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.trap(), !dbg !18 unreachable, !dbg !18 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: call @ar.trap() ; CHECK: unreachable ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { cold noreturn nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "undef.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 3, type: !12) !18 = !DILocation(line: 5, column: 17, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/union.c000066400000000000000000000001431473507761200323170ustar00rootroot00000000000000union my_union { int m_int; char* m_ptr; }; int main() { union my_union x = {.m_int = 1}; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/union.ll000066400000000000000000000040551473507761200325120ustar00rootroot00000000000000; ModuleID = 'union.pp.bc' source_filename = "union.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { ret i32 0, !dbg !12 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "union.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, scopeLine: 6, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 8, column: 1, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/update-ll000077500000000000000000000022541473507761200326450ustar00rootroot00000000000000#!/bin/bash # Use this script to update all the .ll files from the .c and .cpp files clang="clang" ikos_pp="ikos-pp" opt="opt" opt_level="aggressive" cflags="-c -emit-llvm -Wall -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone" cxxflags="$cflags -std=c++17" ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" set -e function run { echo "#" "$@" "$@" } for filename in *.c do echo "[*] $filename ..." filename="${filename%.c}" run "$clang" $cflags "$filename.c" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.new.ll" vimdiff "$filename.ll" "$filename.new.ll" rm -f "$filename.bc" "$filename.pp.bc" "$filename.new.ll" done for filename in *.cpp do echo "[*] $filename ..." filename="${filename%.cpp}" run "$clang" $cxxflags "$filename.cpp" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.new.ll" vimdiff "$filename.ll" "$filename.new.ll" rm -f "$filename.bc" "$filename.pp.bc" "$filename.new.ll" done NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/var-args.c000066400000000000000000000016441473507761200327200ustar00rootroot00000000000000/* va_copy example */ #include /* va_list, va_start, va_copy, va_arg, va_end */ #include /* printf, vprintf*/ #include /* malloc */ #include /* strlen, strcat */ /* print ints until a zero is found: */ void PrintInts(int first, ...) { char* buffer; const char* format = "[%d] "; int count = 0; int val = first; va_list vl, vl_count; va_start(vl, first); /* count number of arguments: */ va_copy(vl_count, vl); while (val != 0) { val = va_arg(vl_count, int); ++count; } va_end(vl_count); /* allocate storage for format string: */ buffer = (char*)malloc(strlen(format) * count + 1); buffer[0] = '\0'; /* generate format string: */ for (; count > 0; --count) { strcat(buffer, format); } /* print integers: */ printf(format, first); vprintf(buffer, vl); va_end(vl); } int main() { PrintInts(10, 20, 30, 40, 50, 0); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/var-args.ll000066400000000000000000000423071473507761200331060ustar00rootroot00000000000000; ModuleID = 'var-args.pp.bc' source_filename = "var-args.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.__va_list_tag = type { i32, i32, i8*, i8* } @.str = private unnamed_addr constant [6 x i8] c"[%d] \00", align 1 ; CHECK: define [6 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [91, 37, 100, 93, 32, 0], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal void @PrintInts(i32, ...) unnamed_addr #0 !dbg !11 { %2 = alloca [1 x %struct.__va_list_tag], align 16 %3 = alloca [1 x %struct.__va_list_tag], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata !2, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 0, metadata !20, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 %0, metadata !21, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata [1 x %struct.__va_list_tag]* %2, metadata !22, metadata !DIExpression()), !dbg !39 call void @llvm.dbg.declare(metadata [1 x %struct.__va_list_tag]* %3, metadata !40, metadata !DIExpression()), !dbg !41 %4 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %2, i64 0, i64 0, !dbg !42 %5 = bitcast [1 x %struct.__va_list_tag]* %2 to i8*, !dbg !42 call void @llvm.va_start(i8* %5), !dbg !42 %6 = bitcast [1 x %struct.__va_list_tag]* %3 to i8*, !dbg !43 call void @llvm.va_copy(i8* %6, i8* %5), !dbg !43 %7 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %3, i64 0, i64 0, i32 0, !dbg !44 %8 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %3, i64 0, i64 0, i32 2, !dbg !44 %9 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %3, i64 0, i64 0, i32 3, !dbg !44 br label %10, !dbg !46 10: ; preds = %23, %1 %.01 = phi i32 [ 0, %1 ], [ %26, %23 ], !dbg !16 %.0 = phi i32 [ %0, %1 ], [ %25, %23 ], !dbg !16 call void @llvm.dbg.value(metadata i32 %.0, metadata !21, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 %.01, metadata !20, metadata !DIExpression()), !dbg !16 %11 = icmp eq i32 %.0, 0, !dbg !47 br i1 %11, label %27, label %12, !dbg !46 12: ; preds = %10 %13 = load i32, i32* %7, align 16, !dbg !48 %14 = icmp ult i32 %13, 41, !dbg !48 br i1 %14, label %15, label %20, !dbg !48 15: ; preds = %12 %16 = load i8*, i8** %9, align 16, !dbg !48 %17 = sext i32 %13 to i64, !dbg !48 %18 = getelementptr i8, i8* %16, i64 %17, !dbg !48 %19 = add i32 %13, 8, !dbg !48 store i32 %19, i32* %7, align 16, !dbg !48 br label %23, !dbg !48 20: ; preds = %12 %21 = load i8*, i8** %8, align 8, !dbg !48 %22 = getelementptr i8, i8* %21, i64 8, !dbg !48 store i8* %22, i8** %8, align 8, !dbg !48 br label %23, !dbg !48 23: ; preds = %20, %15 %.in = phi i8* [ %18, %15 ], [ %21, %20 ] %24 = bitcast i8* %.in to i32*, !dbg !48 %25 = load i32, i32* %24, align 4, !dbg !48 call void @llvm.dbg.value(metadata i32 %25, metadata !21, metadata !DIExpression()), !dbg !16 %26 = add nuw nsw i32 %.01, 1, !dbg !49 call void @llvm.dbg.value(metadata i32 %26, metadata !20, metadata !DIExpression()), !dbg !16 br label %10, !dbg !46, !llvm.loop !50 27: ; preds = %10 %.01.lcssa = phi i32 [ %.01, %10 ], !dbg !16 call void @llvm.dbg.value(metadata i32 %.01.lcssa, metadata !20, metadata !DIExpression()), !dbg !16 call void @llvm.va_end(i8* nonnull %6), !dbg !52 %28 = zext i32 %.01.lcssa to i64, !dbg !53 %29 = mul nuw nsw i64 %28, 5, !dbg !54 %30 = add nuw nsw i64 %29, 1, !dbg !55 %31 = call i8* @malloc(i64 %30) #7, !dbg !56 call void @llvm.dbg.value(metadata i8* %31, metadata !57, metadata !DIExpression()), !dbg !16 store i8 0, i8* %31, align 1, !dbg !58 br label %32, !dbg !59 32: ; preds = %34, %27 %.1 = phi i32 [ %.01.lcssa, %27 ], [ %36, %34 ], !dbg !16 call void @llvm.dbg.value(metadata i32 %.1, metadata !20, metadata !DIExpression()), !dbg !16 %33 = icmp sgt i32 %.1, 0, !dbg !60 br i1 %33, label %34, label %37, !dbg !63 34: ; preds = %32 %strlen = call i64 @strlen(i8* %31), !dbg !64 %endptr = getelementptr i8, i8* %31, i64 %strlen, !dbg !64 %35 = getelementptr inbounds [6 x i8], [6 x i8]* @.str, i64 0, i64 0, !dbg !64 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %endptr, i8* align 1 %35, i64 6, i1 false), !dbg !64 %36 = add nsw i32 %.1, -1, !dbg !66 call void @llvm.dbg.value(metadata i32 %36, metadata !20, metadata !DIExpression()), !dbg !16 br label %32, !dbg !67, !llvm.loop !68 37: ; preds = %32 %38 = call i32 @vprintf(i8* %31, %struct.__va_list_tag* nonnull %4) #2, !dbg !70 call void @llvm.va_end(i8* nonnull %5), !dbg !71 ret void, !dbg !72 } ; CHECK: define void @PrintInts(si32 %1, ...) { ; CHECK: #1 !entry successors={#2} { ; CHECK: [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}]* $2 = allocate [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}], 1, align 16 ; CHECK: [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}]* $3 = allocate [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}], 1, align 16 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %4 = ptrshift $2, 24 * 0, 24 * 0 ; CHECK: si8* %5 = bitcast $2 ; CHECK: call @ar.va_start(%5) ; CHECK: si8* %6 = bitcast $3 ; CHECK: call @ar.va_copy(%6, %5) ; CHECK: si32* %7 = ptrshift $3, 24 * 0, 24 * 0, 1 * 0 ; CHECK: si8** %8 = ptrshift $3, 24 * 0, 24 * 0, 1 * 8 ; CHECK: si8** %9 = ptrshift $3, 24 * 0, 24 * 0, 1 * 16 ; CHECK: si32 %.01 = 0 ; CHECK: si32 %.0 = %1 ; CHECK: } ; CHECK: #2 predecessors={#1, #10} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#5} { ; CHECK: %.0 sieq 0 ; CHECK: si32 %.01.lcssa = %.01 ; CHECK: call @ar.va_end(%6) ; CHECK: ui32 %10 = bitcast %.01.lcssa ; CHECK: ui64 %11 = zext %10 ; CHECK: si64 %12 = bitcast %11 ; CHECK: si64 %13 = %12 smul.nw 5 ; CHECK: si64 %14 = %13 sadd.nw 1 ; CHECK: ui64 %15 = bitcast %14 ; CHECK: si8* %16 = call @ar.libc.malloc(%15) ; CHECK: store %16, 0, align 1 ; CHECK: si32 %.1 = %.01.lcssa ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#6, #7} { ; CHECK: %.0 sine 0 ; CHECK: ui32* %17 = bitcast %7 ; CHECK: ui32 %18 = load %17, align 16 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#10} { ; CHECK: %18 uilt 41 ; CHECK: si8* %19 = load %9, align 16 ; CHECK: si32 %20 = bitcast %18 ; CHECK: si64 %21 = sext %20 ; CHECK: si8* %22 = ptrshift %19, 1 * %21 ; CHECK: ui32 %23 = %18 uadd 8 ; CHECK: si32 %24 = bitcast %23 ; CHECK: store %7, %24, align 16 ; CHECK: si8* %.in = %22 ; CHECK: } ; CHECK: #7 predecessors={#4} successors={#10} { ; CHECK: %18 uige 41 ; CHECK: si8* %25 = load %8, align 8 ; CHECK: si8* %26 = ptrshift %25, 1 * 8 ; CHECK: store %8, %26, align 8 ; CHECK: si8* %.in = %25 ; CHECK: } ; CHECK: #5 predecessors={#3, #8} successors={#8, #9} { ; CHECK: } ; CHECK: #8 predecessors={#5} successors={#5} { ; CHECK: %.1 sigt 0 ; CHECK: ui64 %strlen = call @ar.libc.strlen(%16) ; CHECK: si8* %endptr = ptrshift %16, 1 * %strlen ; CHECK: si8* %27 = ptrshift @.str, 6 * 0, 1 * 0 ; CHECK: call @ar.memcpy(%endptr, %27, 6, 1, 1, 0) ; CHECK: si32 %28 = %.1 sadd.nw -1 ; CHECK: si32 %.1 = %28 ; CHECK: } ; CHECK: #9 !exit predecessors={#5} { ; CHECK: %.1 sile 0 ; CHECK: si32 %29 = call @vprintf(%16, %4) ; CHECK: call @ar.va_end(%5) ; CHECK: return ; CHECK: } ; CHECK: #10 predecessors={#6, #7} successors={#2} { ; CHECK: si32* %30 = bitcast %.in ; CHECK: si32 %31 = load %30, align 4 ; CHECK: si32 %32 = %.01 sadd.nw 1 ; CHECK: si32 %.01 = %32 ; CHECK: si32 %.0 = %31 ; CHECK: } ; CHECK: } ; Function Attrs: allocsize(0) declare i8* @malloc(i64) local_unnamed_addr #3 ; CHECK: declare si8* @ar.libc.malloc(ui64) ; Function Attrs: argmemonly nofree nounwind readonly declare i64 @strlen(i8* nocapture) local_unnamed_addr #4 ; CHECK: declare ui64 @ar.libc.strlen(si8*) ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #6 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: nounwind declare void @llvm.va_copy(i8*, i8*) #2 ; CHECK: declare void @ar.va_copy(si8*, si8*) ; Function Attrs: nounwind declare void @llvm.va_end(i8*) #2 ; CHECK: declare void @ar.va_end(si8*) ; Function Attrs: nounwind declare void @llvm.va_start(i8*) #2 ; CHECK: declare void @ar.va_start(si8*) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !73 { call void (i32, ...) @PrintInts(i32 10, i32 20, i32 30, i32 40, i32 50, i32 0), !dbg !76 ret i32 0, !dbg !77 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: call @PrintInts(10, 20, 30, 40, 50, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } declare i32 @vprintf(i8*, %struct.__va_list_tag*) local_unnamed_addr #5 ; CHECK: declare si32 @vprintf(si8*, {0: si32, 4: si32, 8: si8*, 16: si8*}*) ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { nounwind } attributes #3 = { allocsize(0) "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { argmemonly nofree nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #6 = { argmemonly nounwind } attributes #7 = { nounwind allocsize(0) } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!6, !7, !8, !9} !llvm.ident = !{!10} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "var-args.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4} !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) !5 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} !8 = !{i32 1, !"wchar_size", i32 4} !9 = !{i32 7, !"PIC Level", i32 2} !10 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !11 = distinct !DISubprogram(name: "PrintInts", scope: !1, file: !1, line: 8, type: !12, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !12 = !DISubroutineType(types: !13) !13 = !{null, !14, null} !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !15 = !DILocalVariable(name: "first", arg: 1, scope: !11, file: !1, line: 8, type: !14) !16 = !DILocation(line: 0, scope: !11) !17 = !DILocalVariable(name: "format", scope: !11, file: !1, line: 10, type: !18) !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) !19 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !5) !20 = !DILocalVariable(name: "count", scope: !11, file: !1, line: 11, type: !14) !21 = !DILocalVariable(name: "val", scope: !11, file: !1, line: 12, type: !14) !22 = !DILocalVariable(name: "vl", scope: !11, file: !1, line: 13, type: !23) !23 = !DIDerivedType(tag: DW_TAG_typedef, name: "va_list", file: !24, line: 32, baseType: !25) !24 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_va_list.h", directory: "") !25 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_va_list", file: !26, line: 98, baseType: !27) !26 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/i386/_types.h", directory: "") !27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__builtin_va_list", file: !1, line: 13, baseType: !28) !28 = !DICompositeType(tag: DW_TAG_array_type, baseType: !29, size: 192, elements: !37) !29 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", file: !1, line: 13, size: 192, elements: !30) !30 = !{!31, !33, !34, !36} !31 = !DIDerivedType(tag: DW_TAG_member, name: "gp_offset", scope: !29, file: !1, line: 13, baseType: !32, size: 32) !32 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !33 = !DIDerivedType(tag: DW_TAG_member, name: "fp_offset", scope: !29, file: !1, line: 13, baseType: !32, size: 32, offset: 32) !34 = !DIDerivedType(tag: DW_TAG_member, name: "overflow_arg_area", scope: !29, file: !1, line: 13, baseType: !35, size: 64, offset: 64) !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !36 = !DIDerivedType(tag: DW_TAG_member, name: "reg_save_area", scope: !29, file: !1, line: 13, baseType: !35, size: 64, offset: 128) !37 = !{!38} !38 = !DISubrange(count: 1) !39 = !DILocation(line: 13, column: 11, scope: !11) !40 = !DILocalVariable(name: "vl_count", scope: !11, file: !1, line: 13, type: !23) !41 = !DILocation(line: 13, column: 15, scope: !11) !42 = !DILocation(line: 14, column: 3, scope: !11) !43 = !DILocation(line: 17, column: 3, scope: !11) !44 = !DILocation(line: 0, scope: !45) !45 = distinct !DILexicalBlock(scope: !11, file: !1, line: 18, column: 20) !46 = !DILocation(line: 18, column: 3, scope: !11) !47 = !DILocation(line: 18, column: 14, scope: !11) !48 = !DILocation(line: 19, column: 11, scope: !45) !49 = !DILocation(line: 20, column: 5, scope: !45) !50 = distinct !{!50, !46, !51} !51 = !DILocation(line: 21, column: 3, scope: !11) !52 = !DILocation(line: 22, column: 3, scope: !11) !53 = !DILocation(line: 25, column: 43, scope: !11) !54 = !DILocation(line: 25, column: 41, scope: !11) !55 = !DILocation(line: 25, column: 49, scope: !11) !56 = !DILocation(line: 25, column: 19, scope: !11) !57 = !DILocalVariable(name: "buffer", scope: !11, file: !1, line: 9, type: !4) !58 = !DILocation(line: 26, column: 13, scope: !11) !59 = !DILocation(line: 29, column: 3, scope: !11) !60 = !DILocation(line: 29, column: 16, scope: !61) !61 = distinct !DILexicalBlock(scope: !62, file: !1, line: 29, column: 3) !62 = distinct !DILexicalBlock(scope: !11, file: !1, line: 29, column: 3) !63 = !DILocation(line: 29, column: 3, scope: !62) !64 = !DILocation(line: 30, column: 5, scope: !65) !65 = distinct !DILexicalBlock(scope: !61, file: !1, line: 29, column: 30) !66 = !DILocation(line: 29, column: 21, scope: !61) !67 = !DILocation(line: 29, column: 3, scope: !61) !68 = distinct !{!68, !63, !69} !69 = !DILocation(line: 31, column: 3, scope: !62) !70 = !DILocation(line: 35, column: 3, scope: !11) !71 = !DILocation(line: 37, column: 3, scope: !11) !72 = !DILocation(line: 38, column: 1, scope: !11) !73 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 40, type: !74, scopeLine: 40, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !74 = !DISubroutineType(types: !75) !75 = !{!14} !76 = !DILocation(line: 41, column: 3, scope: !73) !77 = !DILocation(line: 42, column: 3, scope: !73) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-1.c000066400000000000000000000001711473507761200326300ustar00rootroot00000000000000typedef float vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a + b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-1.ll000066400000000000000000000057061473507761200330260ustar00rootroot00000000000000; ModuleID = 'vector-1.pp.bc' source_filename = "vector-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !20 { ret i32 0, !dbg !24 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "vector-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4, !11, !13} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !1, line: 1, baseType: !7) !7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 128, flags: DIFlagVector, elements: !9) !8 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !9 = !{!10} !10 = !DISubrange(count: 4) !11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression()) !12 = distinct !DIGlobalVariable(name: "b", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !21 = !DISubroutineType(types: !22) !22 = !{!23} !23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !24 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-2.c000066400000000000000000000001721473507761200326320ustar00rootroot00000000000000typedef double vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a * b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-2.ll000066400000000000000000000057071473507761200330300ustar00rootroot00000000000000; ModuleID = 'vector-2.pp.bc' source_filename = "vector-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !20 { ret i32 0, !dbg !24 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "vector-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4, !11, !13} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !1, line: 1, baseType: !7) !7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 128, flags: DIFlagVector, elements: !9) !8 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !9 = !{!10} !10 = !DISubrange(count: 2) !11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression()) !12 = distinct !DIGlobalVariable(name: "b", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !21 = !DISubroutineType(types: !22) !22 = !{!23} !23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !24 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-3.c000066400000000000000000000001671473507761200326370ustar00rootroot00000000000000typedef int vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a + b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-3.ll000066400000000000000000000056011473507761200330220ustar00rootroot00000000000000; ModuleID = 'vector-3.pp.bc' source_filename = "vector-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !20 { ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: GNU) !1 = !DIFile(filename: "vector-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{!4, !11, !13} !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) !5 = distinct !DIGlobalVariable(name: "a", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !1, line: 1, baseType: !7) !7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 128, flags: DIFlagVector, elements: !9) !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !9 = !{!10} !10 = !DISubrange(count: 4) !11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression()) !12 = distinct !DIGlobalVariable(name: "b", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !21 = !DISubroutineType(types: !22) !22 = !{!8} !23 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-4.c000066400000000000000000000001761473507761200326400ustar00rootroot00000000000000typedef long vector_t __attribute__((__vector_size__(16))); vector_t f(vector_t x) { return __builtin_ia32_pshufd(x, 0); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vector-4.ll000066400000000000000000000017251473507761200330260ustar00rootroot00000000000000; ModuleID = 'vector-4.pp.bc' source_filename = "vector-4.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "vector-4.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} virtual-inheritance.cpp000066400000000000000000000006431473507761200354320ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimizationstruct A { int x; }; struct B { char* y; }; struct C { bool a; }; struct E : public virtual A, public B, public C { int x; virtual void f() {} }; struct D : public virtual A, public virtual B, public C { float z; }; struct F : public virtual A { int y; }; struct G : public virtual A { char* z; }; struct H : public F, public G {}; int main() { E e; D d; F f; G g; H h; return 0; } virtual-inheritance.ll000066400000000000000000001111411473507761200352530ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization; ModuleID = 'virtual-inheritance.pp.bc' source_filename = "virtual-inheritance.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.E = type { i32 (...)**, %struct.B, %struct.C, i32, %struct.A } %struct.B = type { i8* } %struct.C = type { i8 } %struct.A = type { i32 } %struct.D = type { i32 (...)**, %struct.C, float, %struct.A, %struct.B } %struct.F = type <{ i32 (...)**, i32, %struct.A }> %struct.G = type { i32 (...)**, i8*, %struct.A } %struct.H = type { %struct.F.base, %struct.G.base, %struct.A } %struct.F.base = type <{ i32 (...)**, i32 }> %struct.G.base = type { i32 (...)**, i8* } @_ZTC1H0_1F = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTC1H0_1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1F ; CHECK: si8* %2 = sitoptr 32 ; CHECK: store @_ZTC1H0_1F, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTC1H16_1G = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTC1H16_1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1G ; CHECK: si8* %2 = sitoptr 16 ; CHECK: store @_ZTC1H16_1G, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTI1A = internal constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1A, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1A, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1A, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1B = internal constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1B, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1B, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1C = internal constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1C, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1C, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1D = internal constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1D, i32 0, i32 0), i32 0, i32 3, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141, i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i64 -8189, i8* bitcast ({ i8*, i8* }* @_ZTI1C to i8*), i64 2050 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64, 56: si8*, 64: si64}* @_ZTI1D, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1C ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: si8* %4 = bitcast @_ZTI1A ; CHECK: si8* %5 = ptrshift @_ZTS1D, 3 * 0, 1 * 0 ; CHECK: si8* %6 = bitcast %1 ; CHECK: store @_ZTI1D, {0: %6, 8: %5, 16: 0, 20: 3, 24: %4, 32: -6141, 40: %3, 48: -8189, 56: %2, 64: 2050}, align 1 ; CHECK: } ; CHECK: } @_ZTI1E = internal constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1E, i32 0, i32 0), i32 0, i32 3, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141, i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i64 2050, i8* bitcast ({ i8*, i8* }* @_ZTI1C to i8*), i64 4098 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64, 56: si8*, 64: si64}* @_ZTI1E, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1C ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: si8* %4 = bitcast @_ZTI1A ; CHECK: si8* %5 = ptrshift @_ZTS1E, 3 * 0, 1 * 0 ; CHECK: si8* %6 = bitcast %1 ; CHECK: store @_ZTI1E, {0: %6, 8: %5, 16: 0, 20: 3, 24: %4, 32: -6141, 40: %3, 48: 2050, 56: %2, 64: 4098}, align 1 ; CHECK: } ; CHECK: } @_ZTI1F = internal constant { i8*, i8*, i32, i32, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1F, i32 0, i32 0), i32 0, i32 1, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64}* @_ZTI1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1F, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1F, {0: %4, 8: %3, 16: 0, 20: 1, 24: %2, 32: -6141}, align 1 ; CHECK: } ; CHECK: } @_ZTI1G = internal constant { i8*, i8*, i32, i32, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1G, i32 0, i32 0), i32 0, i32 1, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64}* @_ZTI1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1G, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1G, {0: %4, 8: %3, 16: 0, 20: 1, 24: %2, 32: -6141}, align 1 ; CHECK: } ; CHECK: } @_ZTI1H = internal constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1H, i32 0, i32 0), i32 2, i32 2, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*), i64 2, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*), i64 4098 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64}* @_ZTI1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1G ; CHECK: si8* %3 = bitcast @_ZTI1F ; CHECK: si8* %4 = ptrshift @_ZTS1H, 3 * 0, 1 * 0 ; CHECK: si8* %5 = bitcast %1 ; CHECK: store @_ZTI1H, {0: %5, 8: %4, 16: 2, 20: 2, 24: %3, 32: 2, 40: %2, 48: 4098}, align 1 ; CHECK: } ; CHECK: } @_ZTS1A = internal constant [3 x i8] c"1A\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1A, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1A, [49, 65, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1B = internal constant [3 x i8] c"1B\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1B, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1B, [49, 66, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1C = internal constant [3 x i8] c"1C\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1C, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1C, [49, 67, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1D = internal constant [3 x i8] c"1D\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1D, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1D, [49, 68, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1E = internal constant [3 x i8] c"1E\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1E, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1E, [49, 69, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1F = internal constant [3 x i8] c"1F\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1F, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1F, [49, 70, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1G = internal constant [3 x i8] c"1G\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1G, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1G, [49, 71, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1H = internal constant [3 x i8] c"1H\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1H, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1H, [49, 72, 0], align 1 ; CHECK: } ; CHECK: } @_ZTT1H = internal unnamed_addr constant [4 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTC1H0_1F, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTC1H16_1G, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, inrange i32 1, i32 3) to i8*)], align 8 ; CHECK: define [4 x si8*]* @_ZTT1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTV1H, 48 * 0, 1 * 24, 8 * 3 ; CHECK: si8** %2 = ptrshift @_ZTC1H16_1G, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8** %3 = ptrshift @_ZTC1H0_1F, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8** %4 = ptrshift @_ZTV1H, 48 * 0, 1 * 0, 8 * 3 ; CHECK: si8* %5 = bitcast %1 ; CHECK: si8* %6 = bitcast %2 ; CHECK: si8* %7 = bitcast %3 ; CHECK: si8* %8 = bitcast %4 ; CHECK: store @_ZTT1H, [%8, %7, %6, %5], align 1 ; CHECK: } ; CHECK: } @_ZTV1D = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1D to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1D, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1D ; CHECK: si8* %2 = sitoptr 16 ; CHECK: si8* %3 = sitoptr 24 ; CHECK: store @_ZTV1D, {0: [%3, %2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1E = internal unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* inttoptr (i64 24 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1E to i8*), i8* bitcast (void (%struct.E*)* @_ZN1E1fEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1E, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1E1fEv ; CHECK: si8* %2 = bitcast @_ZTI1E ; CHECK: si8* %3 = sitoptr 24 ; CHECK: store @_ZTV1E, {0: [%3, null, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1F = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 12 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTV1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1F ; CHECK: si8* %2 = sitoptr 12 ; CHECK: store @_ZTV1F, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1G = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTV1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1G ; CHECK: si8* %2 = sitoptr 16 ; CHECK: store @_ZTV1G, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1H = internal unnamed_addr constant { [3 x i8*], [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1H to i8*)], [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1H to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*], 24: [3 x si8*]}* @_ZTV1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1H ; CHECK: si8* %2 = sitoptr -16 ; CHECK: si8* %3 = sitoptr 16 ; CHECK: si8* %4 = bitcast @_ZTI1H ; CHECK: si8* %5 = sitoptr 32 ; CHECK: store @_ZTV1H, {0: [%5, null, %4], 24: [%3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTVN10__cxxabiv117__class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv117__class_type_infoE @_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1DC1Ev(%struct.D*) unnamed_addr #1 align 2 !dbg !77 { call void @llvm.dbg.value(metadata %struct.D* %0, metadata !82, metadata !DIExpression()), !dbg !84 %2 = getelementptr inbounds %struct.D, %struct.D* %0, i64 0, i32 0, !dbg !85 %3 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1D, i64 0, i32 0, i64 4, !dbg !85 %4 = bitcast i8** %3 to i32 (...)**, !dbg !85 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !85 ret void, !dbg !85 } ; CHECK: define void @_ZN1DC1Ev({0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = ptrshift %1, 32 * 0, 1 * 0 ; CHECK: si8** %3 = ptrshift @_ZTV1D, 32 * 0, 1 * 0, 8 * 4 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal void @_ZN1E1fEv(%struct.E*) unnamed_addr #1 align 2 !dbg !113 { call void @llvm.dbg.value(metadata %struct.E* %0, metadata !114, metadata !DIExpression()), !dbg !115 ret void, !dbg !116 } ; CHECK: define void @_ZN1E1fEv({0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1EC1Ev(%struct.E*) unnamed_addr #1 align 2 !dbg !71 { call void @llvm.dbg.value(metadata %struct.E* %0, metadata !73, metadata !DIExpression()), !dbg !75 %2 = getelementptr inbounds %struct.E, %struct.E* %0, i64 0, i32 0, !dbg !76 %3 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1E, i64 0, i32 0, i64 3, !dbg !76 %4 = bitcast i8** %3 to i32 (...)**, !dbg !76 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !76 ret void, !dbg !76 } ; CHECK: define void @_ZN1EC1Ev({0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = ptrshift %1, 32 * 0, 1 * 0 ; CHECK: si8** %3 = ptrshift @_ZTV1E, 32 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1FC1Ev(%struct.F*) unnamed_addr #1 align 2 !dbg !86 { call void @llvm.dbg.value(metadata %struct.F* %0, metadata !91, metadata !DIExpression()), !dbg !93 %2 = getelementptr inbounds %struct.F, %struct.F* %0, i64 0, i32 0, !dbg !94 %3 = getelementptr inbounds { [3 x i8*] }, { [3 x i8*] }* @_ZTV1F, i64 0, i32 0, i64 3, !dbg !94 %4 = bitcast i8** %3 to i32 (...)**, !dbg !94 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !94 ret void, !dbg !94 } ; CHECK: define void @_ZN1FC1Ev(<{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = ptrshift %1, 16 * 0, 1 * 0 ; CHECK: si8** %3 = ptrshift @_ZTV1F, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1FC2Ev(%struct.F*, i8**) unnamed_addr #1 align 2 !dbg !117 { call void @llvm.dbg.value(metadata %struct.F* %0, metadata !118, metadata !DIExpression()), !dbg !119 call void @llvm.dbg.value(metadata i8** %1, metadata !120, metadata !DIExpression()), !dbg !119 %3 = bitcast i8** %1 to i64*, !dbg !123 %4 = load i64, i64* %3, align 8, !dbg !123 %5 = bitcast %struct.F* %0 to i64*, !dbg !123 store i64 %4, i64* %5, align 8, !dbg !123 ret void, !dbg !123 } ; CHECK: define void @_ZN1FC2Ev(<{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si64* %3 = bitcast %2 ; CHECK: si64 %4 = load %3, align 8 ; CHECK: si64* %5 = bitcast %1 ; CHECK: store %5, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1GC1Ev(%struct.G*) unnamed_addr #1 align 2 !dbg !95 { call void @llvm.dbg.value(metadata %struct.G* %0, metadata !100, metadata !DIExpression()), !dbg !102 %2 = getelementptr inbounds %struct.G, %struct.G* %0, i64 0, i32 0, !dbg !103 %3 = getelementptr inbounds { [3 x i8*] }, { [3 x i8*] }* @_ZTV1G, i64 0, i32 0, i64 3, !dbg !103 %4 = bitcast i8** %3 to i32 (...)**, !dbg !103 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !103 ret void, !dbg !103 } ; CHECK: define void @_ZN1GC1Ev({0: si32 (...)**, 8: si8*, 16: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = ptrshift %1, 24 * 0, 1 * 0 ; CHECK: si8** %3 = ptrshift @_ZTV1G, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1GC2Ev(%struct.G*, i8**) unnamed_addr #1 align 2 !dbg !124 { call void @llvm.dbg.value(metadata %struct.G* %0, metadata !125, metadata !DIExpression()), !dbg !126 call void @llvm.dbg.value(metadata i8** %1, metadata !127, metadata !DIExpression()), !dbg !126 %3 = bitcast i8** %1 to i64*, !dbg !128 %4 = load i64, i64* %3, align 8, !dbg !128 %5 = bitcast %struct.G* %0 to i64*, !dbg !128 store i64 %4, i64* %5, align 8, !dbg !128 ret void, !dbg !128 } ; CHECK: define void @_ZN1GC2Ev({0: si32 (...)**, 8: si8*, 16: {0: si32}}* %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si64* %3 = bitcast %2 ; CHECK: si64 %4 = load %3, align 8 ; CHECK: si64* %5 = bitcast %1 ; CHECK: store %5, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @_ZN1HC1Ev(%struct.H*) unnamed_addr #1 align 2 !dbg !104 { call void @llvm.dbg.value(metadata %struct.H* %0, metadata !109, metadata !DIExpression()), !dbg !111 %2 = bitcast %struct.H* %0 to %struct.F*, !dbg !112 %3 = getelementptr inbounds [4 x i8*], [4 x i8*]* @_ZTT1H, i64 0, i64 1, !dbg !112 call fastcc void @_ZN1FC2Ev(%struct.F* %2, i8** %3) #3, !dbg !112 %4 = getelementptr inbounds %struct.H, %struct.H* %0, i64 0, i32 1, !dbg !112 %5 = bitcast %struct.G.base* %4 to %struct.G*, !dbg !112 %6 = getelementptr inbounds [4 x i8*], [4 x i8*]* @_ZTT1H, i64 0, i64 2, !dbg !112 call fastcc void @_ZN1GC2Ev(%struct.G* nonnull %5, i8** %6) #3, !dbg !112 %7 = getelementptr inbounds %struct.H, %struct.H* %0, i64 0, i32 0, i32 0, !dbg !112 %8 = getelementptr inbounds { [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i64 0, i32 0, i64 3, !dbg !112 %9 = bitcast i8** %8 to i32 (...)**, !dbg !112 store i32 (...)** %9, i32 (...)*** %7, align 8, !dbg !112 %10 = getelementptr inbounds %struct.G.base, %struct.G.base* %4, i64 0, i32 0, !dbg !112 %11 = getelementptr inbounds { [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i64 0, i32 1, i64 3, !dbg !112 %12 = bitcast i8** %11 to i32 (...)**, !dbg !112 store i32 (...)** %12, i32 (...)*** %10, align 8, !dbg !112 ret void, !dbg !112 } ; CHECK: define void @_ZN1HC1Ev({0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %2 = bitcast %1 ; CHECK: si8** %3 = ptrshift @_ZTT1H, 32 * 0, 8 * 1 ; CHECK: call @_ZN1FC2Ev(%2, %3) ; CHECK: {0: si32 (...)**, 8: si8*}* %4 = ptrshift %1, 40 * 0, 1 * 16 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* %5 = bitcast %4 ; CHECK: si8** %6 = ptrshift @_ZTT1H, 32 * 0, 8 * 2 ; CHECK: call @_ZN1GC2Ev(%5, %6) ; CHECK: si32 (...)*** %7 = ptrshift %1, 40 * 0, 1 * 0, 1 * 0 ; CHECK: si8** %8 = ptrshift @_ZTV1H, 48 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %9 = bitcast %8 ; CHECK: store %7, %9, align 8 ; CHECK: si32 (...)*** %10 = ptrshift %4, 16 * 0, 1 * 0 ; CHECK: si8** %11 = ptrshift @_ZTV1H, 48 * 0, 1 * 24, 8 * 3 ; CHECK: si32 (...)** %12 = bitcast %11 ; CHECK: store %10, %12, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() local_unnamed_addr #0 !dbg !8 { %1 = alloca %struct.E, align 8 %2 = alloca %struct.D, align 8 %3 = alloca %struct.F, align 8 %4 = alloca %struct.G, align 8 %5 = alloca %struct.H, align 8 call void @llvm.dbg.value(metadata %struct.E* %1, metadata !12, metadata !DIExpression(DW_OP_deref)), !dbg !38 call fastcc void @_ZN1EC1Ev(%struct.E* nonnull %1) #3, !dbg !39 call void @llvm.dbg.value(metadata %struct.D* %2, metadata !40, metadata !DIExpression(DW_OP_deref)), !dbg !38 call fastcc void @_ZN1DC1Ev(%struct.D* nonnull %2) #3, !dbg !49 call void @llvm.dbg.value(metadata %struct.F* %3, metadata !50, metadata !DIExpression(DW_OP_deref)), !dbg !38 call fastcc void @_ZN1FC1Ev(%struct.F* nonnull %3) #3, !dbg !56 call void @llvm.dbg.value(metadata %struct.G* %4, metadata !57, metadata !DIExpression(DW_OP_deref)), !dbg !38 call fastcc void @_ZN1GC1Ev(%struct.G* nonnull %4) #3, !dbg !63 call void @llvm.dbg.value(metadata %struct.H* %5, metadata !64, metadata !DIExpression(DW_OP_deref)), !dbg !38 call fastcc void @_ZN1HC1Ev(%struct.H* nonnull %5) #3, !dbg !69 ret i32 0, !dbg !70 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* $1 = allocate {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}, 1, align 8 ; CHECK: {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}* $2 = allocate {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}, 1, align 8 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* $3 = allocate <{0: si32 (...)**, 8: si32, 12: {0: si32}}>, 1, align 8 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* $4 = allocate {0: si32 (...)**, 8: si8*, 16: {0: si32}}, 1, align 8 ; CHECK: {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}* $5 = allocate {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}, 1, align 8 ; CHECK: call @_ZN1EC1Ev($1) ; CHECK: call @_ZN1DC1Ev($2) ; CHECK: call @_ZN1FC1Ev($3) ; CHECK: call @_ZN1GC1Ev($4) ; CHECK: call @_ZN1HC1Ev($5) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "virtual-inheritance.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 33, type: !9, scopeLine: 33, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "e", scope: !8, file: !1, line: 34, type: !13) !13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "E", file: !1, line: 13, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !14, vtableHolder: !13, identifier: "_ZTS1E") !14 = !{!15, !19, !25, !30, !33, !34} !15 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !1, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !17, identifier: "_ZTS1A") !17 = !{!18} !18 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !16, file: !1, line: 2, baseType: !11, size: 32) !19 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !20, offset: 64, extraData: i32 0) !20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "B", file: !1, line: 5, size: 64, flags: DIFlagTypePassByValue, elements: !21, identifier: "_ZTS1B") !21 = !{!22} !22 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !20, file: !1, line: 6, baseType: !23, size: 64) !23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) !24 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !25 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !26, offset: 128, extraData: i32 0) !26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C", file: !1, line: 9, size: 8, flags: DIFlagTypePassByValue, elements: !27, identifier: "_ZTS1C") !27 = !{!28} !28 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !26, file: !1, line: 10, baseType: !29, size: 8) !29 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !30 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$E", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64) !32 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: !9, size: 64) !33 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !13, file: !1, line: 14, baseType: !11, size: 32, offset: 160) !34 = !DISubprogram(name: "f", linkageName: "_ZN1E1fEv", scope: !13, file: !1, line: 16, type: !35, scopeLine: 16, containingType: !13, virtualIndex: 0, flags: DIFlagPrototyped, spFlags: DISPFlagVirtual) !35 = !DISubroutineType(types: !36) !36 = !{null, !37} !37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !38 = !DILocation(line: 0, scope: !8) !39 = !DILocation(line: 34, column: 5, scope: !8) !40 = !DILocalVariable(name: "d", scope: !8, file: !1, line: 35, type: !41) !41 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "D", file: !1, line: 19, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !42, vtableHolder: !41, identifier: "_ZTS1D") !42 = !{!43, !44, !45, !46, !47} !43 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !41, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !44 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !41, baseType: !20, offset: 32, flags: DIFlagVirtual, extraData: i32 0) !45 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !41, baseType: !26, offset: 64, extraData: i32 0) !46 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$D", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !47 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !41, file: !1, line: 20, baseType: !48, size: 32, offset: 96) !48 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !49 = !DILocation(line: 35, column: 5, scope: !8) !50 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 36, type: !51) !51 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "F", file: !1, line: 23, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !52, vtableHolder: !51, identifier: "_ZTS1F") !52 = !{!53, !54, !55} !53 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !51, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !54 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$F", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !55 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !51, file: !1, line: 24, baseType: !11, size: 32, offset: 64) !56 = !DILocation(line: 36, column: 5, scope: !8) !57 = !DILocalVariable(name: "g", scope: !8, file: !1, line: 37, type: !58) !58 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "G", file: !1, line: 27, size: 192, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !59, vtableHolder: !58, identifier: "_ZTS1G") !59 = !{!60, !61, !62} !60 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !58, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !61 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$G", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !62 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !58, file: !1, line: 28, baseType: !23, size: 64, offset: 64) !63 = !DILocation(line: 37, column: 5, scope: !8) !64 = !DILocalVariable(name: "h", scope: !8, file: !1, line: 38, type: !65) !65 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "H", file: !1, line: 31, size: 320, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !66, vtableHolder: !51, identifier: "_ZTS1H") !66 = !{!67, !68} !67 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !65, baseType: !51, extraData: i32 0) !68 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !65, baseType: !58, offset: 128, extraData: i32 0) !69 = !DILocation(line: 38, column: 5, scope: !8) !70 = !DILocation(line: 39, column: 3, scope: !8) !71 = distinct !DISubprogram(name: "E", linkageName: "_ZN1EC1Ev", scope: !13, file: !1, line: 13, type: !35, scopeLine: 13, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !72, retainedNodes: !2) !72 = !DISubprogram(name: "E", scope: !13, type: !35, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !73 = !DILocalVariable(name: "this", arg: 1, scope: !71, type: !74, flags: DIFlagArtificial | DIFlagObjectPointer) !74 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !75 = !DILocation(line: 0, scope: !71) !76 = !DILocation(line: 13, column: 8, scope: !71) !77 = distinct !DISubprogram(name: "D", linkageName: "_ZN1DC1Ev", scope: !41, file: !1, line: 19, type: !78, scopeLine: 19, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !81, retainedNodes: !2) !78 = !DISubroutineType(types: !79) !79 = !{null, !80} !80 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !41, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !81 = !DISubprogram(name: "D", scope: !41, type: !78, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !82 = !DILocalVariable(name: "this", arg: 1, scope: !77, type: !83, flags: DIFlagArtificial | DIFlagObjectPointer) !83 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !41, size: 64) !84 = !DILocation(line: 0, scope: !77) !85 = !DILocation(line: 19, column: 8, scope: !77) !86 = distinct !DISubprogram(name: "F", linkageName: "_ZN1FC1Ev", scope: !51, file: !1, line: 23, type: !87, scopeLine: 23, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !90, retainedNodes: !2) !87 = !DISubroutineType(types: !88) !88 = !{null, !89} !89 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !51, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !90 = !DISubprogram(name: "F", scope: !51, type: !87, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !91 = !DILocalVariable(name: "this", arg: 1, scope: !86, type: !92, flags: DIFlagArtificial | DIFlagObjectPointer) !92 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !51, size: 64) !93 = !DILocation(line: 0, scope: !86) !94 = !DILocation(line: 23, column: 8, scope: !86) !95 = distinct !DISubprogram(name: "G", linkageName: "_ZN1GC1Ev", scope: !58, file: !1, line: 27, type: !96, scopeLine: 27, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !99, retainedNodes: !2) !96 = !DISubroutineType(types: !97) !97 = !{null, !98} !98 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !58, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !99 = !DISubprogram(name: "G", scope: !58, type: !96, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !100 = !DILocalVariable(name: "this", arg: 1, scope: !95, type: !101, flags: DIFlagArtificial | DIFlagObjectPointer) !101 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !58, size: 64) !102 = !DILocation(line: 0, scope: !95) !103 = !DILocation(line: 27, column: 8, scope: !95) !104 = distinct !DISubprogram(name: "H", linkageName: "_ZN1HC1Ev", scope: !65, file: !1, line: 31, type: !105, scopeLine: 31, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !108, retainedNodes: !2) !105 = !DISubroutineType(types: !106) !106 = !{null, !107} !107 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !65, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !108 = !DISubprogram(name: "H", scope: !65, type: !105, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !109 = !DILocalVariable(name: "this", arg: 1, scope: !104, type: !110, flags: DIFlagArtificial | DIFlagObjectPointer) !110 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !65, size: 64) !111 = !DILocation(line: 0, scope: !104) !112 = !DILocation(line: 31, column: 8, scope: !104) !113 = distinct !DISubprogram(name: "f", linkageName: "_ZN1E1fEv", scope: !13, file: !1, line: 16, type: !35, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !34, retainedNodes: !2) !114 = !DILocalVariable(name: "this", arg: 1, scope: !113, type: !74, flags: DIFlagArtificial | DIFlagObjectPointer) !115 = !DILocation(line: 0, scope: !113) !116 = !DILocation(line: 16, column: 21, scope: !113) !117 = distinct !DISubprogram(name: "F", linkageName: "_ZN1FC2Ev", scope: !51, file: !1, line: 23, type: !87, scopeLine: 23, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !90, retainedNodes: !2) !118 = !DILocalVariable(name: "this", arg: 1, scope: !117, type: !92, flags: DIFlagArtificial | DIFlagObjectPointer) !119 = !DILocation(line: 0, scope: !117) !120 = !DILocalVariable(name: "vtt", arg: 2, scope: !117, type: !121, flags: DIFlagArtificial) !121 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !122, size: 64) !122 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !123 = !DILocation(line: 23, column: 8, scope: !117) !124 = distinct !DISubprogram(name: "G", linkageName: "_ZN1GC2Ev", scope: !58, file: !1, line: 27, type: !96, scopeLine: 27, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !99, retainedNodes: !2) !125 = !DILocalVariable(name: "this", arg: 1, scope: !124, type: !101, flags: DIFlagArtificial | DIFlagObjectPointer) !126 = !DILocation(line: 0, scope: !124) !127 = !DILocalVariable(name: "vtt", arg: 2, scope: !124, type: !121, flags: DIFlagArtificial) !128 = !DILocation(line: 27, column: 8, scope: !124) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vla.c000066400000000000000000000003171473507761200317540ustar00rootroot00000000000000#include void foo(int n) { int a[n], i; for (i = 0; i < n; i++) { a[i] = i * i; } a[n] = n * n; } int main(int argc, char** argv) { int v; scanf("%d", &v); foo(v); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/aggressive_optimization/vla.ll000066400000000000000000000141501473507761200321410ustar00rootroot00000000000000; ModuleID = 'vla.pp.bc' source_filename = "vla.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 ; CHECK: define [3 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @scanf(i8*, ...) local_unnamed_addr #1 ; CHECK: declare si32 @ar.libc.scanf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define internal fastcc void @foo(i32) unnamed_addr #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 %0, metadata !14, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 0, metadata !16, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 undef, metadata !16, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 undef, metadata !17, metadata !DIExpression()), !dbg !13 ret void, !dbg !21 } ; CHECK: define void @foo(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) local_unnamed_addr #0 !dbg !22 { %3 = alloca i32, align 4 call void @llvm.dbg.value(metadata i32 %0, metadata !28, metadata !DIExpression()), !dbg !29 call void @llvm.dbg.value(metadata i8** %1, metadata !30, metadata !DIExpression()), !dbg !29 call void @llvm.dbg.value(metadata i32* %3, metadata !31, metadata !DIExpression(DW_OP_deref)), !dbg !29 %4 = getelementptr inbounds [3 x i8], [3 x i8]* @.str, i64 0, i64 0, !dbg !32 %5 = call i32 (i8*, ...) @scanf(i8* %4, i32* nonnull %3) #3, !dbg !32 %6 = load i32, i32* %3, align 4, !dbg !33 call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !29 call fastcc void @foo(i32 %6), !dbg !34 ret i32 0, !dbg !35 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si8* %4 = ptrshift @.str, 3 * 0, 1 * 0 ; CHECK: si32 %5 = call @ar.libc.scanf(%4, $3) ; CHECK: si32 %6 = load $3, align 4 ; CHECK: call @foo(%6) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "vla.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/aggressive_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "n", arg: 1, scope: !8, file: !1, line: 2, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocalVariable(name: "__vla_expr0", scope: !8, type: !15, flags: DIFlagArtificial) !15 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) !16 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 3, type: !11) !17 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 3, type: !18) !18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, elements: !19) !19 = !{!20} !20 = !DISubrange(count: !14) !21 = !DILocation(line: 8, column: 1, scope: !8) !22 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 10, type: !23, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !23 = !DISubroutineType(types: !24) !24 = !{!11, !11, !25} !25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64) !26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !27, size: 64) !27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !28 = !DILocalVariable(name: "argc", arg: 1, scope: !22, file: !1, line: 10, type: !11) !29 = !DILocation(line: 0, scope: !22) !30 = !DILocalVariable(name: "argv", arg: 2, scope: !22, file: !1, line: 10, type: !25) !31 = !DILocalVariable(name: "v", scope: !22, file: !1, line: 11, type: !11) !32 = !DILocation(line: 12, column: 3, scope: !22) !33 = !DILocation(line: 13, column: 7, scope: !22) !34 = !DILocation(line: 13, column: 3, scope: !22) !35 = !DILocation(line: 14, column: 3, scope: !22) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/000077500000000000000000000000001473507761200277475ustar00rootroot00000000000000aggregate-in-reg-1.cpp000066400000000000000000000006461473507761200336450ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimizationtemplate < typename T > class Vector3 { private: T _x, _y, _z; public: Vector3< T >(T x, T y, T z) : _x(x), _y(y), _z(z) {} }; class Foo { private: Vector3< float > coord; public: Foo(float x, float y, float z) : coord(Vector3< float >(x, y, z)) {} Vector3< float > get_coord() { return coord; } }; int main(int argc, char* argv[]) { Foo f(1, 2, 3); Vector3< float > coord = f.get_coord(); return 0; } aggregate-in-reg-1.ll000066400000000000000000000430371473507761200334730ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'aggregate-in-reg-1.pp.bc' source_filename = "aggregate-in-reg-1.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Foo = type { %class.Vector3 } %class.Vector3 = type { float, float, float } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr { <2 x float>, float } @_ZN3Foo9get_coordEv(%class.Foo*) #3 align 2 !dbg !55 { %2 = alloca %class.Vector3, align 4 %3 = alloca { <2 x float>, float }, align 8 call void @llvm.dbg.value(metadata %class.Foo* %0, metadata !56, metadata !DIExpression()), !dbg !57 %4 = getelementptr inbounds %class.Foo, %class.Foo* %0, i32 0, i32 0, !dbg !58 %5 = bitcast %class.Vector3* %2 to i8*, !dbg !58 %6 = bitcast %class.Vector3* %4 to i8*, !dbg !58 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %5, i8* align 4 %6, i64 12, i1 false), !dbg !58 %7 = bitcast { <2 x float>, float }* %3 to i8*, !dbg !59 %8 = bitcast %class.Vector3* %2 to i8*, !dbg !59 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %7, i8* align 4 %8, i64 12, i1 false), !dbg !59 %9 = load { <2 x float>, float }, { <2 x float>, float }* %3, align 8, !dbg !59 ret { <2 x float>, float } %9, !dbg !59 } ; CHECK: define {0: <2 x float>, 8: float} @_ZN3Foo9get_coordEv({0: {0: float, 4: float, 8: float}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: float, 4: float, 8: float}* $2 = allocate {0: float, 4: float, 8: float}, 1, align 4 ; CHECK: {0: <2 x float>, 8: float}* $3 = allocate {0: <2 x float>, 8: float}, 1, align 8 ; CHECK: {0: float, 4: float, 8: float}* %4 = ptrshift %1, 12 * 0, 1 * 0 ; CHECK: si8* %5 = bitcast $2 ; CHECK: si8* %6 = bitcast %4 ; CHECK: call @ar.memcpy(%5, %6, 12, 4, 4, 0) ; CHECK: si8* %7 = bitcast $3 ; CHECK: si8* %8 = bitcast $2 ; CHECK: call @ar.memcpy(%7, %8, 12, 8, 4, 0) ; CHECK: {0: <2 x float>, 8: float} %9 = load $3, align 8 ; CHECK: return %9 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN3FooC1Efff(%class.Foo*, float, float, float) unnamed_addr #2 align 2 !dbg !46 { call void @llvm.dbg.value(metadata %class.Foo* %0, metadata !47, metadata !DIExpression()), !dbg !49 call void @llvm.dbg.value(metadata float %1, metadata !50, metadata !DIExpression()), !dbg !49 call void @llvm.dbg.value(metadata float %2, metadata !51, metadata !DIExpression()), !dbg !49 call void @llvm.dbg.value(metadata float %3, metadata !52, metadata !DIExpression()), !dbg !49 call void @_ZN3FooC2Efff(%class.Foo* %0, float %1, float %2, float %3), !dbg !53 ret void, !dbg !54 } ; CHECK: define void @_ZN3FooC1Efff({0: {0: float, 4: float, 8: float}}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN3FooC2Efff(%1, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN3FooC2Efff(%class.Foo*, float, float, float) unnamed_addr #2 align 2 !dbg !60 { call void @llvm.dbg.value(metadata %class.Foo* %0, metadata !61, metadata !DIExpression()), !dbg !62 call void @llvm.dbg.value(metadata float %1, metadata !63, metadata !DIExpression()), !dbg !62 call void @llvm.dbg.value(metadata float %2, metadata !64, metadata !DIExpression()), !dbg !62 call void @llvm.dbg.value(metadata float %3, metadata !65, metadata !DIExpression()), !dbg !62 %5 = getelementptr inbounds %class.Foo, %class.Foo* %0, i32 0, i32 0, !dbg !66 call void @_ZN7Vector3IfEC1Efff(%class.Vector3* %5, float %1, float %2, float %3), !dbg !67 ret void, !dbg !68 } ; CHECK: define void @_ZN3FooC2Efff({0: {0: float, 4: float, 8: float}}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: float, 4: float, 8: float}* %5 = ptrshift %1, 12 * 0, 1 * 0 ; CHECK: call @_ZN7Vector3IfEC1Efff(%5, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN7Vector3IfEC1Efff(%class.Vector3*, float, float, float) unnamed_addr #2 align 2 !dbg !69 { call void @llvm.dbg.value(metadata %class.Vector3* %0, metadata !70, metadata !DIExpression()), !dbg !72 call void @llvm.dbg.value(metadata float %1, metadata !73, metadata !DIExpression()), !dbg !72 call void @llvm.dbg.value(metadata float %2, metadata !74, metadata !DIExpression()), !dbg !72 call void @llvm.dbg.value(metadata float %3, metadata !75, metadata !DIExpression()), !dbg !72 call void @_ZN7Vector3IfEC2Efff(%class.Vector3* %0, float %1, float %2, float %3), !dbg !76 ret void, !dbg !77 } ; CHECK: define void @_ZN7Vector3IfEC1Efff({0: float, 4: float, 8: float}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN7Vector3IfEC2Efff(%1, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN7Vector3IfEC2Efff(%class.Vector3*, float, float, float) unnamed_addr #3 align 2 !dbg !78 { call void @llvm.dbg.value(metadata %class.Vector3* %0, metadata !79, metadata !DIExpression()), !dbg !80 call void @llvm.dbg.value(metadata float %1, metadata !81, metadata !DIExpression()), !dbg !80 call void @llvm.dbg.value(metadata float %2, metadata !82, metadata !DIExpression()), !dbg !80 call void @llvm.dbg.value(metadata float %3, metadata !83, metadata !DIExpression()), !dbg !80 %5 = getelementptr inbounds %class.Vector3, %class.Vector3* %0, i32 0, i32 0, !dbg !84 store float %1, float* %5, align 4, !dbg !84 %6 = getelementptr inbounds %class.Vector3, %class.Vector3* %0, i32 0, i32 1, !dbg !85 store float %2, float* %6, align 4, !dbg !85 %7 = getelementptr inbounds %class.Vector3, %class.Vector3* %0, i32 0, i32 2, !dbg !86 store float %3, float* %7, align 4, !dbg !86 ret void, !dbg !87 } ; CHECK: define void @_ZN7Vector3IfEC2Efff({0: float, 4: float, 8: float}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: float* %5 = ptrshift %1, 12 * 0, 1 * 0 ; CHECK: store %5, %2, align 4 ; CHECK: float* %6 = ptrshift %1, 12 * 0, 1 * 4 ; CHECK: store %6, %3, align 4 ; CHECK: float* %7 = ptrshift %1, 12 * 0, 1 * 8 ; CHECK: store %7, %4, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #4 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca %class.Foo, align 4 %4 = alloca %class.Vector3, align 4 %5 = alloca { <2 x float>, float }, align 8 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata %class.Foo* %3, metadata !18, metadata !DIExpression()), !dbg !41 call void @_ZN3FooC1Efff(%class.Foo* %3, float 1.000000e+00, float 2.000000e+00, float 3.000000e+00), !dbg !41 call void @llvm.dbg.declare(metadata %class.Vector3* %4, metadata !42, metadata !DIExpression()), !dbg !43 %6 = call { <2 x float>, float } @_ZN3Foo9get_coordEv(%class.Foo* %3), !dbg !44 store { <2 x float>, float } %6, { <2 x float>, float }* %5, align 8, !dbg !44 %7 = bitcast { <2 x float>, float }* %5 to i8*, !dbg !44 %8 = bitcast %class.Vector3* %4 to i8*, !dbg !44 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %8, i8* align 8 %7, i64 12, i1 false), !dbg !44 ret i32 0, !dbg !45 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: float, 4: float, 8: float}}* $3 = allocate {0: {0: float, 4: float, 8: float}}, 1, align 4 ; CHECK: {0: float, 4: float, 8: float}* $4 = allocate {0: float, 4: float, 8: float}, 1, align 4 ; CHECK: {0: <2 x float>, 8: float}* $5 = allocate {0: <2 x float>, 8: float}, 1, align 8 ; CHECK: call @_ZN3FooC1Efff($3, 1.0E+0, 2.0E+0, 3.0E+0) ; CHECK: {0: <2 x float>, 8: float} %6 = call @_ZN3Foo9get_coordEv($3) ; CHECK: store $5, %6, align 8 ; CHECK: si8* %7 = bitcast $5 ; CHECK: si8* %8 = bitcast $4 ; CHECK: call @ar.memcpy(%8, %7, 12, 4, 8, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "aggregate-in-reg-1.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 19, type: !9, scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 19, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 19, type: !12) !18 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 20, type: !19) !19 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Foo", file: !1, line: 10, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !20, identifier: "_ZTS3Foo") !20 = !{!21, !34, !38} !21 = !DIDerivedType(tag: DW_TAG_member, name: "coord", scope: !19, file: !1, line: 12, baseType: !22, size: 96) !22 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Vector3", file: !1, line: 2, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !23, templateParams: !32, identifier: "_ZTS7Vector3IfE") !23 = !{!24, !26, !27, !28} !24 = !DIDerivedType(tag: DW_TAG_member, name: "_x", scope: !22, file: !1, line: 4, baseType: !25, size: 32) !25 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !26 = !DIDerivedType(tag: DW_TAG_member, name: "_y", scope: !22, file: !1, line: 4, baseType: !25, size: 32, offset: 32) !27 = !DIDerivedType(tag: DW_TAG_member, name: "_z", scope: !22, file: !1, line: 4, baseType: !25, size: 32, offset: 64) !28 = !DISubprogram(name: "Vector3", scope: !22, file: !1, line: 7, type: !29, scopeLine: 7, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !29 = !DISubroutineType(types: !30) !30 = !{null, !31, !25, !25, !25} !31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !32 = !{!33} !33 = !DITemplateTypeParameter(name: "T", type: !25) !34 = !DISubprogram(name: "Foo", scope: !19, file: !1, line: 15, type: !35, scopeLine: 15, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !35 = !DISubroutineType(types: !36) !36 = !{null, !37, !25, !25, !25} !37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !38 = !DISubprogram(name: "get_coord", linkageName: "_ZN3Foo9get_coordEv", scope: !19, file: !1, line: 16, type: !39, scopeLine: 16, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !39 = !DISubroutineType(types: !40) !40 = !{!22, !37} !41 = !DILocation(line: 20, column: 7, scope: !8) !42 = !DILocalVariable(name: "coord", scope: !8, file: !1, line: 21, type: !22) !43 = !DILocation(line: 21, column: 20, scope: !8) !44 = !DILocation(line: 21, column: 30, scope: !8) !45 = !DILocation(line: 22, column: 3, scope: !8) !46 = distinct !DISubprogram(name: "Foo", linkageName: "_ZN3FooC1Efff", scope: !19, file: !1, line: 15, type: !35, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !34, retainedNodes: !2) !47 = !DILocalVariable(name: "this", arg: 1, scope: !46, type: !48, flags: DIFlagArtificial | DIFlagObjectPointer) !48 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) !49 = !DILocation(line: 0, scope: !46) !50 = !DILocalVariable(name: "x", arg: 2, scope: !46, file: !1, line: 15, type: !25) !51 = !DILocalVariable(name: "y", arg: 3, scope: !46, file: !1, line: 15, type: !25) !52 = !DILocalVariable(name: "z", arg: 4, scope: !46, file: !1, line: 15, type: !25) !53 = !DILocation(line: 15, column: 69, scope: !46) !54 = !DILocation(line: 15, column: 70, scope: !46) !55 = distinct !DISubprogram(name: "get_coord", linkageName: "_ZN3Foo9get_coordEv", scope: !19, file: !1, line: 16, type: !39, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !38, retainedNodes: !2) !56 = !DILocalVariable(name: "this", arg: 1, scope: !55, type: !48, flags: DIFlagArtificial | DIFlagObjectPointer) !57 = !DILocation(line: 0, scope: !55) !58 = !DILocation(line: 16, column: 41, scope: !55) !59 = !DILocation(line: 16, column: 34, scope: !55) !60 = distinct !DISubprogram(name: "Foo", linkageName: "_ZN3FooC2Efff", scope: !19, file: !1, line: 15, type: !35, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !34, retainedNodes: !2) !61 = !DILocalVariable(name: "this", arg: 1, scope: !60, type: !48, flags: DIFlagArtificial | DIFlagObjectPointer) !62 = !DILocation(line: 0, scope: !60) !63 = !DILocalVariable(name: "x", arg: 2, scope: !60, file: !1, line: 15, type: !25) !64 = !DILocalVariable(name: "y", arg: 3, scope: !60, file: !1, line: 15, type: !25) !65 = !DILocalVariable(name: "z", arg: 4, scope: !60, file: !1, line: 15, type: !25) !66 = !DILocation(line: 15, column: 36, scope: !60) !67 = !DILocation(line: 15, column: 42, scope: !60) !68 = !DILocation(line: 15, column: 70, scope: !60) !69 = distinct !DISubprogram(name: "Vector3", linkageName: "_ZN7Vector3IfEC1Efff", scope: !22, file: !1, line: 7, type: !29, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !28, retainedNodes: !2) !70 = !DILocalVariable(name: "this", arg: 1, scope: !69, type: !71, flags: DIFlagArtificial | DIFlagObjectPointer) !71 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !72 = !DILocation(line: 0, scope: !69) !73 = !DILocalVariable(name: "x", arg: 2, scope: !69, file: !1, line: 7, type: !25) !74 = !DILocalVariable(name: "y", arg: 3, scope: !69, file: !1, line: 7, type: !25) !75 = !DILocalVariable(name: "z", arg: 4, scope: !69, file: !1, line: 7, type: !25) !76 = !DILocation(line: 7, column: 53, scope: !69) !77 = !DILocation(line: 7, column: 54, scope: !69) !78 = distinct !DISubprogram(name: "Vector3", linkageName: "_ZN7Vector3IfEC2Efff", scope: !22, file: !1, line: 7, type: !29, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !28, retainedNodes: !2) !79 = !DILocalVariable(name: "this", arg: 1, scope: !78, type: !71, flags: DIFlagArtificial | DIFlagObjectPointer) !80 = !DILocation(line: 0, scope: !78) !81 = !DILocalVariable(name: "x", arg: 2, scope: !78, file: !1, line: 7, type: !25) !82 = !DILocalVariable(name: "y", arg: 3, scope: !78, file: !1, line: 7, type: !25) !83 = !DILocalVariable(name: "z", arg: 4, scope: !78, file: !1, line: 7, type: !25) !84 = !DILocation(line: 7, column: 33, scope: !78) !85 = !DILocation(line: 7, column: 40, scope: !78) !86 = !DILocation(line: 7, column: 47, scope: !78) !87 = !DILocation(line: 7, column: 54, scope: !78) aggregate-in-reg-2.cpp000066400000000000000000000003501473507761200336360ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization#include typedef struct { float x; float y; } pos_t; typedef struct { pos_t begin, end; } line_t; line_t f(float y) { return {{0.0, y}, {2.0, 0}}; } int main() { printf("%f\n", f(2.0).begin.y); return 0; } aggregate-in-reg-2.ll000066400000000000000000000226771473507761200335030ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'aggregate-in-reg-2.pp.bc' source_filename = "aggregate-in-reg-2.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.line_t = type { %struct.pos_t, %struct.pos_t } %struct.pos_t = type { float, float } @.str = private unnamed_addr constant [4 x i8] c"%f\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 102, 10, 0], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define { <2 x float>, <2 x float> } @_Z1ff(float) #0 !dbg !8 { %2 = alloca %struct.line_t, align 4 call void @llvm.dbg.value(metadata float %0, metadata !22, metadata !DIExpression()), !dbg !23 %3 = getelementptr inbounds %struct.line_t, %struct.line_t* %2, i32 0, i32 0, !dbg !24 %4 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %3, i32 0, i32 0, !dbg !25 store float 0.000000e+00, float* %4, align 4, !dbg !25 %5 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %3, i32 0, i32 1, !dbg !25 store float %0, float* %5, align 4, !dbg !25 %6 = getelementptr inbounds %struct.line_t, %struct.line_t* %2, i32 0, i32 1, !dbg !24 %7 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %6, i32 0, i32 0, !dbg !26 store float 2.000000e+00, float* %7, align 4, !dbg !26 %8 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %6, i32 0, i32 1, !dbg !26 store float 0.000000e+00, float* %8, align 4, !dbg !26 %9 = bitcast %struct.line_t* %2 to { <2 x float>, <2 x float> }*, !dbg !27 %10 = load { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %9, align 4, !dbg !27 ret { <2 x float>, <2 x float> } %10, !dbg !27 } ; CHECK: define {0: <2 x float>, 8: <2 x float>} @_Z1ff(float %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: float, 4: float}, 8: {0: float, 4: float}}* $2 = allocate {0: {0: float, 4: float}, 8: {0: float, 4: float}}, 1, align 4 ; CHECK: {0: float, 4: float}* %3 = ptrshift $2, 16 * 0, 1 * 0 ; CHECK: float* %4 = ptrshift %3, 8 * 0, 1 * 0 ; CHECK: store %4, 0.0E+0, align 4 ; CHECK: float* %5 = ptrshift %3, 8 * 0, 1 * 4 ; CHECK: store %5, %1, align 4 ; CHECK: {0: float, 4: float}* %6 = ptrshift $2, 16 * 0, 1 * 8 ; CHECK: float* %7 = ptrshift %6, 8 * 0, 1 * 0 ; CHECK: store %7, 2.0E+0, align 4 ; CHECK: float* %8 = ptrshift %6, 8 * 0, 1 * 4 ; CHECK: store %8, 0.0E+0, align 4 ; CHECK: {0: <2 x float>, 8: <2 x float>}* %9 = bitcast $2 ; CHECK: {0: <2 x float>, 8: <2 x float>} %10 = load %9, align 4 ; CHECK: return %10 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #1 !dbg !28 { %1 = alloca %struct.line_t, align 4 %2 = call { <2 x float>, <2 x float> } @_Z1ff(float 2.000000e+00), !dbg !32 %3 = bitcast %struct.line_t* %1 to { <2 x float>, <2 x float> }*, !dbg !32 %4 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %3, i32 0, i32 0, !dbg !32 %5 = extractvalue { <2 x float>, <2 x float> } %2, 0, !dbg !32 store <2 x float> %5, <2 x float>* %4, align 4, !dbg !32 %6 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %3, i32 0, i32 1, !dbg !32 %7 = extractvalue { <2 x float>, <2 x float> } %2, 1, !dbg !32 store <2 x float> %7, <2 x float>* %6, align 4, !dbg !32 %8 = getelementptr inbounds %struct.line_t, %struct.line_t* %1, i32 0, i32 0, !dbg !33 %9 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %8, i32 0, i32 1, !dbg !34 %10 = load float, float* %9, align 4, !dbg !34 %11 = fpext float %10 to double, !dbg !32 %12 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !35 %13 = call i32 (i8*, ...) @printf(i8* %12, double %11), !dbg !35 ret i32 0, !dbg !36 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: float, 4: float}, 8: {0: float, 4: float}}* $1 = allocate {0: {0: float, 4: float}, 8: {0: float, 4: float}}, 1, align 4 ; CHECK: {0: <2 x float>, 8: <2 x float>} %2 = call @_Z1ff(2.0E+0) ; CHECK: {0: <2 x float>, 8: <2 x float>}* %3 = bitcast $1 ; CHECK: <2 x float>* %4 = ptrshift %3, 16 * 0, 1 * 0 ; CHECK: <2 x float> %5 = extractelement %2, 0 ; CHECK: store %4, %5, align 4 ; CHECK: <2 x float>* %6 = ptrshift %3, 16 * 0, 1 * 8 ; CHECK: <2 x float> %7 = extractelement %2, 8 ; CHECK: store %6, %7, align 4 ; CHECK: {0: float, 4: float}* %8 = ptrshift $1, 16 * 0, 1 * 0 ; CHECK: float* %9 = ptrshift %8, 8 * 0, 1 * 4 ; CHECK: float %10 = load %9, align 4 ; CHECK: double %11 = fpext %10 ; CHECK: si8* %12 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %13 = call @ar.libc.printf(%12, %11) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #3 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "aggregate-in-reg-2.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1ff", scope: !1, file: !1, line: 12, type: !9, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !19} !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "line_t", file: !1, line: 10, baseType: !12) !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 8, size: 128, flags: DIFlagTypePassByValue, elements: !13, identifier: "_ZTS6line_t") !13 = !{!14, !21} !14 = !DIDerivedType(tag: DW_TAG_member, name: "begin", scope: !12, file: !1, line: 9, baseType: !15, size: 64) !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "pos_t", file: !1, line: 6, baseType: !16) !16 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 3, size: 64, flags: DIFlagTypePassByValue, elements: !17, identifier: "_ZTS5pos_t") !17 = !{!18, !20} !18 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !16, file: !1, line: 4, baseType: !19, size: 32) !19 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !20 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !16, file: !1, line: 5, baseType: !19, size: 32, offset: 32) !21 = !DIDerivedType(tag: DW_TAG_member, name: "end", scope: !12, file: !1, line: 9, baseType: !15, size: 64, offset: 64) !22 = !DILocalVariable(name: "y", arg: 1, scope: !8, file: !1, line: 12, type: !19) !23 = !DILocation(line: 0, scope: !8) !24 = !DILocation(line: 13, column: 10, scope: !8) !25 = !DILocation(line: 13, column: 11, scope: !8) !26 = !DILocation(line: 13, column: 21, scope: !8) !27 = !DILocation(line: 13, column: 3, scope: !8) !28 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 16, type: !29, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !29 = !DISubroutineType(types: !30) !30 = !{!31} !31 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !32 = !DILocation(line: 17, column: 18, scope: !28) !33 = !DILocation(line: 17, column: 25, scope: !28) !34 = !DILocation(line: 17, column: 31, scope: !28) !35 = !DILocation(line: 17, column: 3, scope: !28) !36 = !DILocation(line: 18, column: 3, scope: !28) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/array-init.cpp000066400000000000000000000000551473507761200325320ustar00rootroot00000000000000struct i { unsigned j[16]; } k[]{{}, {2}}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/array-init.ll000066400000000000000000000043741473507761200323670ustar00rootroot00000000000000; ModuleID = 'array-init.pp.bc' source_filename = "array-init.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.i = type { [16 x i32] } @k = global <{ %struct.i, { <{ i32, [15 x i32] }> } }> <{ %struct.i zeroinitializer, { <{ i32, [15 x i32] }> } { <{ i32, [15 x i32] }> <{ i32 2, [15 x i32] zeroinitializer }> } }>, align 16, !dbg !0 ; CHECK: define <{0: {0: [16 x si32]}, 64: {0: <{0: si32, 4: [15 x si32]}>}}>* @k, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @k, {0: aggregate_zero, 64: {0: {0: 2, 4: aggregate_zero}}}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!16, !17, !18, !19} !llvm.ident = !{!20} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "k", scope: !2, file: !3, line: 3, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "array-init.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1024, elements: !14) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "i", file: !3, line: 1, size: 512, flags: DIFlagTypePassByValue, elements: !8, identifier: "_ZTS1i") !8 = !{!9} !9 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !7, file: !3, line: 2, baseType: !10, size: 512) !10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 512, elements: !12) !11 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !12 = !{!13} !13 = !DISubrange(count: 16) !14 = !{!15} !15 = !DISubrange(count: 2) !16 = !{i32 2, !"Dwarf Version", i32 4} !17 = !{i32 2, !"Debug Info Version", i32 3} !18 = !{i32 1, !"wchar_size", i32 4} !19 = !{i32 7, !"PIC Level", i32 2} !20 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/asm.c000066400000000000000000000002631473507761200306740ustar00rootroot00000000000000#include int main() { int src = 1; int dst; asm("mov %1, %0\n\t" "add $1, %0" : "=r"(dst) : "r"(src)); printf("%d\n", dst); return dst; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/asm.ll000066400000000000000000000076321473507761200310700ustar00rootroot00000000000000; ModuleID = 'asm.pp.bc' source_filename = "asm.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #1 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 1, metadata !12, metadata !DIExpression()), !dbg !13 %1 = call i32 asm "mov $1, $0\0A\09add $$1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 1) #3, !dbg !14, !srcloc !15 call void @llvm.dbg.value(metadata i32 %1, metadata !16, metadata !DIExpression()), !dbg !13 %2 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !17 %3 = call i32 (i8*, ...) @printf(i8* %2, i32 %1), !dbg !17 ret i32 %1, !dbg !18 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32 %1 = call asm "mov $1, $0 ; CHECK: add $$1, $0"(1) ; CHECK: si8* %2 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %3 = call @ar.libc.printf(%2, %1) ; CHECK: return %1 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } attributes #3 = { nounwind readnone } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "asm.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "src", scope: !8, file: !1, line: 4, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocation(line: 7, column: 3, scope: !8) !15 = !{i32 68, i32 81} !16 = !DILocalVariable(name: "dst", scope: !8, file: !1, line: 5, type: !11) !17 = !DILocation(line: 12, column: 3, scope: !8) !18 = !DILocation(line: 13, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/atomic.c000066400000000000000000000001101473507761200313570ustar00rootroot00000000000000_Atomic volatile unsigned x; int main() { x = 42; return (int)x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/atomic.ll000066400000000000000000000056761473507761200315720ustar00rootroot00000000000000; ModuleID = 'atomic.pp.bc' source_filename = "atomic.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @x = common global i32 0, align 4, !dbg !0 ; CHECK: define ui32* @x, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @x, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !16 { store volatile i32 42, i32* @x, align 4, !dbg !18 %1 = load volatile i32, i32* @x, align 4, !dbg !19 ret i32 %1, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: store volatile @x, 42, align 4 ; CHECK: si32* %1 = bitcast @x ; CHECK: si32 %2 = load volatile %1, align 4 ; CHECK: return %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!11, !12, !13, !14} !llvm.ident = !{!15} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !7, nameTableKind: GNU) !3 = !DIFile(filename: "atomic.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!6} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{!0} !8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !9) !9 = !DIDerivedType(tag: DW_TAG_atomic_type, baseType: !10) !10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !11 = !{i32 2, !"Dwarf Version", i32 4} !12 = !{i32 2, !"Debug Info Version", i32 3} !13 = !{i32 1, !"wchar_size", i32 4} !14 = !{i32 7, !"PIC Level", i32 2} !15 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !16 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !17 = !DISubroutineType(types: !5) !18 = !DILocation(line: 4, column: 5, scope: !16) !19 = !DILocation(line: 5, column: 15, scope: !16) !20 = !DILocation(line: 5, column: 3, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/basic-loop.c000066400000000000000000000001761473507761200321470ustar00rootroot00000000000000double a[10]; int main(int argc, char** argv) { int i; for (i = 0; i < 10; i++) { a[i] = i * 0.88; } a[i] = i; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/basic-loop.ll000066400000000000000000000146531473507761200323410ustar00rootroot00000000000000; ModuleID = 'basic-loop.pp.bc' source_filename = "basic-loop.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global [10 x double] zeroinitializer, align 16, !dbg !0 ; CHECK: define [10 x double]* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !15 { call void @llvm.dbg.value(metadata i32 %0, metadata !22, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i8** %1, metadata !24, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i32 0, metadata !25, metadata !DIExpression()), !dbg !23 br label %3, !dbg !26 3: ; preds = %10, %2 %.0 = phi i32 [ 0, %2 ], [ %11, %10 ], !dbg !28 call void @llvm.dbg.value(metadata i32 %.0, metadata !25, metadata !DIExpression()), !dbg !23 %4 = icmp slt i32 %.0, 10, !dbg !29 br i1 %4, label %5, label %12, !dbg !31 5: ; preds = %3 %6 = sitofp i32 %.0 to double, !dbg !32 %7 = fmul double %6, 8.800000e-01, !dbg !34 %8 = sext i32 %.0 to i64, !dbg !35 %9 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %8, !dbg !35 store double %7, double* %9, align 8, !dbg !36 br label %10, !dbg !37 10: ; preds = %5 %11 = add nsw i32 %.0, 1, !dbg !38 call void @llvm.dbg.value(metadata i32 %11, metadata !25, metadata !DIExpression()), !dbg !23 br label %3, !dbg !39, !llvm.loop !40 12: ; preds = %3 %13 = sitofp i32 %.0 to double, !dbg !42 %14 = sext i32 %.0 to i64, !dbg !43 %15 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %14, !dbg !43 store double %13, double* %15, align 8, !dbg !44 ret i32 0, !dbg !45 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %.0 silt 10 ; CHECK: double %3 = sitofp %.0 ; CHECK: double %4 = %3 fmul 8.8E-1 ; CHECK: si64 %5 = sext %.0 ; CHECK: double* %6 = ptrshift @a, 80 * 0, 8 * %5 ; CHECK: store %6, %4, align 8 ; CHECK: si32 %7 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %7 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %.0 sige 10 ; CHECK: double %8 = sitofp %.0 ; CHECK: si64 %9 = sext %.0 ; CHECK: double* %10 = ptrshift @a, 80 * 0, 8 * %9 ; CHECK: store %10, %8, align 8 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!10, !11, !12, !13} !llvm.ident = !{!14} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "basic-loop.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 640, elements: !8) !7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 10) !10 = !{i32 2, !"Dwarf Version", i32 4} !11 = !{i32 2, !"Debug Info Version", i32 3} !12 = !{i32 1, !"wchar_size", i32 4} !13 = !{i32 7, !"PIC Level", i32 2} !14 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !15 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !16 = !DISubroutineType(types: !17) !17 = !{!18, !18, !19} !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !15, file: !3, line: 3, type: !18) !23 = !DILocation(line: 0, scope: !15) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !15, file: !3, line: 3, type: !19) !25 = !DILocalVariable(name: "i", scope: !15, file: !3, line: 4, type: !18) !26 = !DILocation(line: 5, column: 8, scope: !27) !27 = distinct !DILexicalBlock(scope: !15, file: !3, line: 5, column: 3) !28 = !DILocation(line: 0, scope: !27) !29 = !DILocation(line: 5, column: 17, scope: !30) !30 = distinct !DILexicalBlock(scope: !27, file: !3, line: 5, column: 3) !31 = !DILocation(line: 5, column: 3, scope: !27) !32 = !DILocation(line: 6, column: 12, scope: !33) !33 = distinct !DILexicalBlock(scope: !30, file: !3, line: 5, column: 28) !34 = !DILocation(line: 6, column: 14, scope: !33) !35 = !DILocation(line: 6, column: 5, scope: !33) !36 = !DILocation(line: 6, column: 10, scope: !33) !37 = !DILocation(line: 7, column: 3, scope: !33) !38 = !DILocation(line: 5, column: 24, scope: !30) !39 = !DILocation(line: 5, column: 3, scope: !30) !40 = distinct !{!40, !31, !41} !41 = !DILocation(line: 7, column: 3, scope: !27) !42 = !DILocation(line: 8, column: 10, scope: !15) !43 = !DILocation(line: 8, column: 3, scope: !15) !44 = !DILocation(line: 8, column: 8, scope: !15) !45 = !DILocation(line: 9, column: 1, scope: !15) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bit-field-1.c000066400000000000000000000002141473507761200321050ustar00rootroot00000000000000struct info_t { char x : 1; char y : 1; int z : 10; int k : 1; }; int main() { struct info_t info = {0, 0, 42, 1}; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bit-field-1.ll000066400000000000000000000105771473507761200323070ustar00rootroot00000000000000; ModuleID = 'bit-field-1.pp.bc' source_filename = "bit-field-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.info_t = type { i16, [2 x i8] } @__const.main.info = private unnamed_addr constant { i8, i8, [2 x i8] } { i8 -88, i8 16, [2 x i8] undef }, align 4 ; CHECK: define {0: si8, 1: si8, 2: [2 x si8]}* @__const.main.info, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @__const.main.info, {0: -88, 1: 16, 2: undef}, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca %struct.info_t, align 4 call void @llvm.dbg.declare(metadata %struct.info_t* %1, metadata !12, metadata !DIExpression()), !dbg !20 %2 = bitcast %struct.info_t* %1 to i8*, !dbg !20 %3 = getelementptr inbounds { i8, i8, [2 x i8] }, { i8, i8, [2 x i8] }* @__const.main.info, i32 0, i32 0, !dbg !20 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 4, i1 false), !dbg !20 ret i32 0, !dbg !21 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: ui16, 2: [2 x si8]}* $1 = allocate {0: ui16, 2: [2 x si8]}, 1, align 4 ; CHECK: si8* %2 = bitcast $1 ; CHECK: si8* %3 = ptrshift @__const.main.info, 4 * 0, 1 * 0 ; CHECK: call @ar.memcpy(%2, %3, 4, 4, 4, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bit-field-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !9, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "info", scope: !8, file: !1, line: 9, type: !13) !13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "info_t", file: !1, line: 1, size: 32, elements: !14) !14 = !{!15, !17, !18, !19} !15 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !13, file: !1, line: 2, baseType: !16, size: 1, flags: DIFlagBitField, extraData: i64 0) !16 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !17 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !13, file: !1, line: 3, baseType: !16, size: 1, offset: 1, flags: DIFlagBitField, extraData: i64 0) !18 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !13, file: !1, line: 4, baseType: !11, size: 10, offset: 2, flags: DIFlagBitField, extraData: i64 0) !19 = !DIDerivedType(tag: DW_TAG_member, name: "k", scope: !13, file: !1, line: 5, baseType: !11, size: 1, offset: 12, flags: DIFlagBitField, extraData: i64 0) !20 = !DILocation(line: 9, column: 17, scope: !8) !21 = !DILocation(line: 10, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bit-field-2.c000066400000000000000000000000731473507761200321110ustar00rootroot00000000000000struct { unsigned : 7; unsigned a; } b[6][1] = {{{}}}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bit-field-2.ll000066400000000000000000000047601473507761200323050ustar00rootroot00000000000000; ModuleID = 'bit-field-2.pp.bc' source_filename = "bit-field-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.anon = type { i8, i32 } @b = global <{ [1 x { [4 x i8], i32 }], [1 x %struct.anon], [1 x %struct.anon], [1 x %struct.anon], [1 x %struct.anon], [1 x %struct.anon] }> <{ [1 x { [4 x i8], i32 }] [{ [4 x i8], i32 } { [4 x i8] undef, i32 0 }], [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer }>, align 16, !dbg !0 ; CHECK: define <{0: [1 x {0: [4 x si8], 4: si32}], 8: [1 x {0: si8, 4: si32}], 16: [1 x {0: si8, 4: si32}], 24: [1 x {0: si8, 4: si32}], 32: [1 x {0: si8, 4: si32}], 40: [1 x {0: si8, 4: si32}]}>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, {0: [{0: undef, 4: 0}], 8: aggregate_zero, 16: aggregate_zero, 24: aggregate_zero, 32: aggregate_zero, 40: aggregate_zero}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!14, !15, !16, !17} !llvm.ident = !{!18} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bit-field-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 384, elements: !11) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 64, elements: !8) !8 = !{!9} !9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 3, baseType: !10, size: 32, offset: 32) !10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !11 = !{!12, !13} !12 = !DISubrange(count: 6) !13 = !DISubrange(count: 1) !14 = !{i32 2, !"Dwarf Version", i32 4} !15 = !{i32 2, !"Debug Info Version", i32 3} !16 = !{i32 1, !"wchar_size", i32 4} !17 = !{i32 7, !"PIC Level", i32 2} !18 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bitwise-cond-1.c000066400000000000000000000001651473507761200326420ustar00rootroot00000000000000int foo(int x, int y, int z) { int a = x - y; int b = (z == 0 && a) ? x + y : y + z; return (a > b) ? x : y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bitwise-cond-1.ll000066400000000000000000000127401473507761200330310ustar00rootroot00000000000000; ModuleID = 'bitwise-cond-1.pp.bc' source_filename = "bitwise-cond-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32, i32, i32) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 %1, metadata !14, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 %2, metadata !15, metadata !DIExpression()), !dbg !13 %4 = sub nsw i32 %0, %1, !dbg !16 call void @llvm.dbg.value(metadata i32 %4, metadata !17, metadata !DIExpression()), !dbg !13 %5 = icmp eq i32 %2, 0, !dbg !18 br i1 %5, label %6, label %10, !dbg !19 6: ; preds = %3 %7 = icmp ne i32 %4, 0, !dbg !20 br i1 %7, label %8, label %10, !dbg !21 8: ; preds = %6 %9 = add nsw i32 %0, %1, !dbg !22 br label %12, !dbg !21 10: ; preds = %6, %3 %11 = add nsw i32 %1, %2, !dbg !23 br label %12, !dbg !21 12: ; preds = %10, %8 %13 = phi i32 [ %9, %8 ], [ %11, %10 ], !dbg !21 call void @llvm.dbg.value(metadata i32 %13, metadata !24, metadata !DIExpression()), !dbg !13 %14 = icmp sgt i32 %4, %13, !dbg !25 br i1 %14, label %15, label %16, !dbg !26 15: ; preds = %12 br label %17, !dbg !26 16: ; preds = %12 br label %17, !dbg !26 17: ; preds = %16, %15 %18 = phi i32 [ %0, %15 ], [ %1, %16 ], !dbg !26 ret i32 %18, !dbg !27 } ; CHECK: define si32 @foo(si32 %1, si32 %2, si32 %3) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32 %4 = %1 ssub.nw %2 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4, #5} { ; CHECK: %3 sieq 0 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#6} { ; CHECK: %3 sine 0 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: %4 sine 0 ; CHECK: si32 %5 = %1 sadd.nw %2 ; CHECK: si32 %6 = %5 ; CHECK: } ; CHECK: #5 predecessors={#2} successors={#6} { ; CHECK: %4 sieq 0 ; CHECK: } ; CHECK: #6 predecessors={#3, #5} successors={#7} { ; CHECK: si32 %7 = %2 sadd.nw %3 ; CHECK: si32 %6 = %7 ; CHECK: } ; CHECK: #7 predecessors={#4, #6} successors={#8, #9} { ; CHECK: } ; CHECK: #8 predecessors={#7} successors={#10} { ; CHECK: %4 sigt %6 ; CHECK: si32 %8 = %1 ; CHECK: } ; CHECK: #9 predecessors={#7} successors={#10} { ; CHECK: %4 sile %6 ; CHECK: si32 %8 = %2 ; CHECK: } ; CHECK: #10 !exit predecessors={#8, #9} { ; CHECK: return %8 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bitwise-cond-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !11, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocalVariable(name: "y", arg: 2, scope: !8, file: !1, line: 1, type: !11) !15 = !DILocalVariable(name: "z", arg: 3, scope: !8, file: !1, line: 1, type: !11) !16 = !DILocation(line: 2, column: 13, scope: !8) !17 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 2, type: !11) !18 = !DILocation(line: 3, column: 14, scope: !8) !19 = !DILocation(line: 3, column: 19, scope: !8) !20 = !DILocation(line: 3, column: 22, scope: !8) !21 = !DILocation(line: 3, column: 11, scope: !8) !22 = !DILocation(line: 3, column: 29, scope: !8) !23 = !DILocation(line: 3, column: 37, scope: !8) !24 = !DILocalVariable(name: "b", scope: !8, file: !1, line: 3, type: !11) !25 = !DILocation(line: 4, column: 13, scope: !8) !26 = !DILocation(line: 4, column: 10, scope: !8) !27 = !DILocation(line: 4, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bitwise-cond-2.c000066400000000000000000000002051473507761200326360ustar00rootroot00000000000000int g; int foo(int x, int y) { int z = x - y; int a; if (g == 0 && z) a = x + y; else a = x * y; return a * 42; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bitwise-cond-2.ll000066400000000000000000000127751473507761200330420ustar00rootroot00000000000000; ModuleID = 'bitwise-cond-2.pp.bc' source_filename = "bitwise-cond-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @g = common global i32 0, align 4, !dbg !0 ; CHECK: define si32* @g, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @g, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32, i32) #0 !dbg !12 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 %1, metadata !17, metadata !DIExpression()), !dbg !16 %3 = sub nsw i32 %0, %1, !dbg !18 call void @llvm.dbg.value(metadata i32 %3, metadata !19, metadata !DIExpression()), !dbg !16 %4 = load i32, i32* @g, align 4, !dbg !20 %5 = icmp eq i32 %4, 0, !dbg !22 br i1 %5, label %6, label %10, !dbg !23 6: ; preds = %2 %7 = icmp ne i32 %3, 0, !dbg !24 br i1 %7, label %8, label %10, !dbg !25 8: ; preds = %6 %9 = add nsw i32 %0, %1, !dbg !26 call void @llvm.dbg.value(metadata i32 %9, metadata !27, metadata !DIExpression()), !dbg !16 br label %12, !dbg !28 10: ; preds = %6, %2 %11 = mul nsw i32 %0, %1, !dbg !29 call void @llvm.dbg.value(metadata i32 %11, metadata !27, metadata !DIExpression()), !dbg !16 br label %12 12: ; preds = %10, %8 %.0 = phi i32 [ %9, %8 ], [ %11, %10 ], !dbg !30 call void @llvm.dbg.value(metadata i32 %.0, metadata !27, metadata !DIExpression()), !dbg !16 %13 = mul nsw i32 %.0, 42, !dbg !31 ret i32 %13, !dbg !32 } ; CHECK: define si32 @foo(si32 %1, si32 %2) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32 %3 = %1 ssub.nw %2 ; CHECK: si32 %4 = load @g, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4, #5} { ; CHECK: %4 sieq 0 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#6} { ; CHECK: %4 sine 0 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: %3 sine 0 ; CHECK: si32 %5 = %1 sadd.nw %2 ; CHECK: si32 %.0 = %5 ; CHECK: } ; CHECK: #5 predecessors={#2} successors={#6} { ; CHECK: %3 sieq 0 ; CHECK: } ; CHECK: #6 predecessors={#3, #5} successors={#7} { ; CHECK: si32 %6 = %1 smul.nw %2 ; CHECK: si32 %.0 = %6 ; CHECK: } ; CHECK: #7 !exit predecessors={#4, #6} { ; CHECK: si32 %7 = %.0 smul.nw 42 ; CHECK: return %7 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bitwise-cond-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6, !6, !6} !15 = !DILocalVariable(name: "x", arg: 1, scope: !12, file: !3, line: 3, type: !6) !16 = !DILocation(line: 0, scope: !12) !17 = !DILocalVariable(name: "y", arg: 2, scope: !12, file: !3, line: 3, type: !6) !18 = !DILocation(line: 4, column: 13, scope: !12) !19 = !DILocalVariable(name: "z", scope: !12, file: !3, line: 4, type: !6) !20 = !DILocation(line: 6, column: 7, scope: !21) !21 = distinct !DILexicalBlock(scope: !12, file: !3, line: 6, column: 7) !22 = !DILocation(line: 6, column: 9, scope: !21) !23 = !DILocation(line: 6, column: 14, scope: !21) !24 = !DILocation(line: 6, column: 17, scope: !21) !25 = !DILocation(line: 6, column: 7, scope: !12) !26 = !DILocation(line: 7, column: 11, scope: !21) !27 = !DILocalVariable(name: "a", scope: !12, file: !3, line: 5, type: !6) !28 = !DILocation(line: 7, column: 5, scope: !21) !29 = !DILocation(line: 9, column: 11, scope: !21) !30 = !DILocation(line: 0, scope: !21) !31 = !DILocation(line: 10, column: 12, scope: !12) !32 = !DILocation(line: 10, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bitwise-op.c000066400000000000000000000000641473507761200321750ustar00rootroot00000000000000int main() { int x = 3, y = 5; int z = x | y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bitwise-op.ll000066400000000000000000000054241473507761200323670ustar00rootroot00000000000000; ModuleID = 'bitwise-op.pp.bc' source_filename = "bitwise-op.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 3, metadata !12, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 5, metadata !14, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.value(metadata i32 3, metadata !15, metadata !DIExpression(DW_OP_constu, 5, DW_OP_or, DW_OP_stack_value)), !dbg !13 ret i32 0, !dbg !16 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bitwise-op.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocalVariable(name: "y", scope: !8, file: !1, line: 2, type: !11) !15 = !DILocalVariable(name: "z", scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 4, column: 1, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bool-op-select.cpp000066400000000000000000000003471473507761200333030ustar00rootroot00000000000000/** * To generate LLVM select instruction, we need to compile * the code with optimization enabled (at least -O1) * * > llvm-g++ -O1 -emit-llvm -o test.bc -g -c test.cpp */ int a; int main() { return a > 0 ? 123 : 321; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bool-op-select.ll000066400000000000000000000064471473507761200331370ustar00rootroot00000000000000; ModuleID = 'bool-op-select.pp.bc' source_filename = "bool-op-select.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = global i32 0, align 4, !dbg !0 ; CHECK: define si32* @a, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !12 { %1 = load i32, i32* @a, align 4, !dbg !15 %2 = icmp sgt i32 %1, 0, !dbg !16 br i1 %2, label %3, label %4, !dbg !15 3: ; preds = %0 br label %5, !dbg !15 4: ; preds = %0 br label %5, !dbg !15 5: ; preds = %4, %3 %6 = phi i32 [ 123, %3 ], [ 321, %4 ], !dbg !15 ret i32 %6, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32 %1 = load @a, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %1 sigt 0 ; CHECK: si32 %2 = 123 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %1 sile 0 ; CHECK: si32 %2 = 321 ; CHECK: } ; CHECK: #4 !exit predecessors={#2, #3} { ; CHECK: return %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 8, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bool-op-select.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 10, type: !13, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 11, column: 10, scope: !12) !16 = !DILocation(line: 11, column: 12, scope: !12) !17 = !DILocation(line: 11, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bool.cpp000066400000000000000000000000751473507761200314100ustar00rootroot00000000000000bool b = true; int f(bool i) {} int main() { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/bool.ll000066400000000000000000000102501473507761200312310ustar00rootroot00000000000000; ModuleID = 'bool.pp.bc' source_filename = "bool.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @b = global i8 1, align 1, !dbg !0 ; CHECK: define ui8* @b, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, 1, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fb(i1 zeroext) #0 !dbg !12 { call void @llvm.dbg.value(metadata i1 %0, metadata !16, metadata !DIExpression()), !dbg !17 call void @llvm.trap(), !dbg !18 unreachable, !dbg !18 } ; CHECK: define si32 @_Z1fb(ui1 %1) { ; CHECK: #1 !entry !exit { ; CHECK: call @ar.trap() ; CHECK: unreachable ; CHECK: } ; CHECK: } ; Function Attrs: cold noreturn nounwind declare void @llvm.trap() #1 ; CHECK: declare void @ar.trap() ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #2 !dbg !19 { ret i32 0, !dbg !22 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #3 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { cold noreturn nounwind } attributes #2 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bool.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "f", linkageName: "_Z1fb", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!15, !6} !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !16 = !DILocalVariable(name: "i", arg: 1, scope: !12, file: !3, line: 3, type: !6) !17 = !DILocation(line: 0, scope: !12) !18 = !DILocation(line: 3, column: 15, scope: !12) !19 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !20, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !20 = !DISubroutineType(types: !21) !21 = !{!15} !22 = !DILocation(line: 6, column: 3, scope: !19) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/branch-undef.c000066400000000000000000000000571473507761200324510ustar00rootroot00000000000000int main() { return main ? 0 % 0 ?: 1 : 2; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/branch-undef.ll000066400000000000000000000055751473507761200326500ustar00rootroot00000000000000; ModuleID = 'branch-undef.pp.bc' source_filename = "branch-undef.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { br label %1, !dbg !12 1: ; preds = %0 br i1 undef, label %2, label %3, !dbg !13 2: ; preds = %1 br label %4, !dbg !13 3: ; preds = %1 br label %4, !dbg !13 4: ; preds = %3, %2 %5 = phi i32 [ undef, %2 ], [ 1, %3 ], !dbg !13 br label %6, !dbg !12 6: ; preds = %4 ret i32 %5, !dbg !14 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: si32 %1 = undef ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: si32 %1 = 1 ; CHECK: } ; CHECK: #4 !exit predecessors={#2, #3} { ; CHECK: return %1 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "branch-undef.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 2, column: 10, scope: !8) !13 = !DILocation(line: 2, column: 17, scope: !8) !14 = !DILocation(line: 2, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/call-args.c000066400000000000000000000001341473507761200317560ustar00rootroot00000000000000int foo(int i) { return i + 1; } int main(int argc, char** argv) { return foo(argc); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/call-args.ll000066400000000000000000000074571473507761200321620ustar00rootroot00000000000000; ModuleID = 'call-args.pp.bc' source_filename = "call-args.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression()), !dbg !13 %2 = add nsw i32 %0, 1, !dbg !14 ret i32 %2, !dbg !15 } ; CHECK: define si32 @foo(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %2 = %1 sadd.nw 1 ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !16 { call void @llvm.dbg.value(metadata i32 %0, metadata !22, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i8** %1, metadata !24, metadata !DIExpression()), !dbg !23 %3 = call i32 @foo(i32 %0), !dbg !25 ret i32 %3, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %3 = call @foo(%1) ; CHECK: return %3 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "call-args.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "i", arg: 1, scope: !8, file: !1, line: 1, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocation(line: 2, column: 12, scope: !8) !15 = !DILocation(line: 2, column: 3, scope: !8) !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!11, !11, !19} !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !16, file: !1, line: 5, type: !11) !23 = !DILocation(line: 0, scope: !16) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !16, file: !1, line: 5, type: !19) !25 = !DILocation(line: 6, column: 10, scope: !16) !26 = !DILocation(line: 6, column: 3, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/complex.c000066400000000000000000000001341473507761200315600ustar00rootroot00000000000000#include int main() { double complex c = 1.0 + 2.0 * I; return creal(c); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/complex.ll000066400000000000000000000067771473507761200317700ustar00rootroot00000000000000; ModuleID = 'complex.pp.bc' source_filename = "complex.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca { double, double }, align 8 call void @llvm.dbg.declare(metadata { double, double }* %1, metadata !12, metadata !DIExpression()), !dbg !14 %2 = getelementptr inbounds { double, double }, { double, double }* %1, i32 0, i32 0, !dbg !14 %3 = getelementptr inbounds { double, double }, { double, double }* %1, i32 0, i32 1, !dbg !14 store double 1.000000e+00, double* %2, align 8, !dbg !14 store double 2.000000e+00, double* %3, align 8, !dbg !14 %4 = getelementptr inbounds { double, double }, { double, double }* %1, i32 0, i32 0, !dbg !15 %5 = load double, double* %4, align 8, !dbg !15 %6 = fptosi double %5 to i32, !dbg !16 ret i32 %6, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: double, 8: double}* $1 = allocate {0: double, 8: double}, 1, align 8 ; CHECK: double* %2 = ptrshift $1, 16 * 0, 1 * 0 ; CHECK: double* %3 = ptrshift $1, 16 * 0, 1 * 8 ; CHECK: store %2, 1.0E+0, align 8 ; CHECK: store %3, 2.0E+0, align 8 ; CHECK: double* %4 = ptrshift $1, 16 * 0, 1 * 0 ; CHECK: double %5 = load %4, align 8 ; CHECK: si32 %6 = fptosi %5 ; CHECK: return %6 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "complex.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "c", scope: !8, file: !1, line: 4, type: !13) !13 = !DIBasicType(name: "complex", size: 128, encoding: DW_ATE_complex_float) !14 = !DILocation(line: 4, column: 18, scope: !8) !15 = !DILocation(line: 5, column: 16, scope: !8) !16 = !DILocation(line: 5, column: 10, scope: !8) !17 = !DILocation(line: 5, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/constructors.cpp000066400000000000000000000006241473507761200332250ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int); } class Vector { public: int _x; int _y; int _z; Vector(int x, int y, int z) noexcept : _x(x), _y(y), _z(z) {} }; int f(Vector* v) { return v->_y; } class Master { public: Vector* _v; int* _p; Master() { _v = new Vector(1, 2, 3); _p = new int(4); __ikos_assert(f(_v) == 2); } }; int main() { Master master; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/constructors.ll000066400000000000000000000405711473507761200330570ustar00rootroot00000000000000; ModuleID = 'constructors.pp.bc' source_filename = "constructors.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Vector = type { i32, i32, i32 } %class.Master = type { %class.Vector*, i32* } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fP6Vector(%class.Vector*) #0 !dbg !8 { call void @llvm.dbg.value(metadata %class.Vector* %0, metadata !22, metadata !DIExpression()), !dbg !23 %2 = getelementptr inbounds %class.Vector, %class.Vector* %0, i32 0, i32 1, !dbg !24 %3 = load i32, i32* %2, align 4, !dbg !24 ret i32 %3, !dbg !25 } ; CHECK: define si32 @_Z1fP6Vector({0: si32, 4: si32, 8: si32}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32* %2 = ptrshift %1, 12 * 0, 1 * 4 ; CHECK: si32 %3 = load %2, align 4 ; CHECK: return %3 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN6MasterC1Ev(%class.Master*) unnamed_addr #3 align 2 !dbg !41 { call void @llvm.dbg.value(metadata %class.Master* %0, metadata !42, metadata !DIExpression()), !dbg !44 call void @_ZN6MasterC2Ev(%class.Master* %0), !dbg !45 ret void, !dbg !46 } ; CHECK: define void @_ZN6MasterC1Ev({0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN6MasterC2Ev(%1) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN6MasterC2Ev(%class.Master*) unnamed_addr #3 align 2 !dbg !47 { call void @llvm.dbg.value(metadata %class.Master* %0, metadata !48, metadata !DIExpression()), !dbg !49 %2 = call i8* @_Znwm(i64 12) #6, !dbg !50 %3 = bitcast i8* %2 to %class.Vector*, !dbg !50 call void @_ZN6VectorC1Eiii(%class.Vector* %3, i32 1, i32 2, i32 3) #7, !dbg !52 %4 = getelementptr inbounds %class.Master, %class.Master* %0, i32 0, i32 0, !dbg !53 store %class.Vector* %3, %class.Vector** %4, align 8, !dbg !54 %5 = call i8* @_Znwm(i64 4) #6, !dbg !55 %6 = bitcast i8* %5 to i32*, !dbg !55 store i32 4, i32* %6, align 4, !dbg !55 %7 = getelementptr inbounds %class.Master, %class.Master* %0, i32 0, i32 1, !dbg !56 store i32* %6, i32** %7, align 8, !dbg !57 %8 = getelementptr inbounds %class.Master, %class.Master* %0, i32 0, i32 0, !dbg !58 %9 = load %class.Vector*, %class.Vector** %8, align 8, !dbg !58 %10 = call i32 @_Z1fP6Vector(%class.Vector* %9), !dbg !59 %11 = icmp eq i32 %10, 2, !dbg !60 %12 = zext i1 %11 to i32, !dbg !59 call void @__ikos_assert(i32 %12), !dbg !61 ret void, !dbg !62 } ; CHECK: define void @_ZN6MasterC2Ev({0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %1) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si8* %2 = call @ar.libcpp.new(12) ; CHECK: {0: si32, 4: si32, 8: si32}* %3 = bitcast %2 ; CHECK: call @_ZN6VectorC1Eiii(%3, 1, 2, 3) ; CHECK: {0: si32, 4: si32, 8: si32}** %4 = ptrshift %1, 16 * 0, 1 * 0 ; CHECK: store %4, %3, align 8 ; CHECK: si8* %5 = call @ar.libcpp.new(4) ; CHECK: si32* %6 = bitcast %5 ; CHECK: store %6, 4, align 4 ; CHECK: si32** %7 = ptrshift %1, 16 * 0, 1 * 8 ; CHECK: store %7, %6, align 8 ; CHECK: {0: si32, 4: si32, 8: si32}** %8 = ptrshift %1, 16 * 0, 1 * 0 ; CHECK: {0: si32, 4: si32, 8: si32}** %9 = bitcast %8 ; CHECK: {0: si32, 4: si32, 8: si32}* %10 = load %9, align 8 ; CHECK: si32 %11 = call @_Z1fP6Vector(%10) ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %11 sieq 2 ; CHECK: ui1 %12 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %11 sine 2 ; CHECK: ui1 %12 = 0 ; CHECK: } ; CHECK: #4 !exit predecessors={#2, #3} { ; CHECK: ui32 %13 = zext %12 ; CHECK: call @ar.ikos.assert(%13) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN6VectorC1Eiii(%class.Vector*, i32, i32, i32) unnamed_addr #0 align 2 !dbg !63 { call void @llvm.dbg.value(metadata %class.Vector* %0, metadata !64, metadata !DIExpression()), !dbg !65 call void @llvm.dbg.value(metadata i32 %1, metadata !66, metadata !DIExpression()), !dbg !65 call void @llvm.dbg.value(metadata i32 %2, metadata !67, metadata !DIExpression()), !dbg !65 call void @llvm.dbg.value(metadata i32 %3, metadata !68, metadata !DIExpression()), !dbg !65 call void @_ZN6VectorC2Eiii(%class.Vector* %0, i32 %1, i32 %2, i32 %3) #7, !dbg !69 ret void, !dbg !70 } ; CHECK: define void @_ZN6VectorC1Eiii({0: si32, 4: si32, 8: si32}* %1, si32 %2, si32 %3, si32 %4) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN6VectorC2Eiii(%1, %2, %3, %4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN6VectorC2Eiii(%class.Vector*, i32, i32, i32) unnamed_addr #0 align 2 !dbg !71 { call void @llvm.dbg.value(metadata %class.Vector* %0, metadata !72, metadata !DIExpression()), !dbg !73 call void @llvm.dbg.value(metadata i32 %1, metadata !74, metadata !DIExpression()), !dbg !73 call void @llvm.dbg.value(metadata i32 %2, metadata !75, metadata !DIExpression()), !dbg !73 call void @llvm.dbg.value(metadata i32 %3, metadata !76, metadata !DIExpression()), !dbg !73 %5 = getelementptr inbounds %class.Vector, %class.Vector* %0, i32 0, i32 0, !dbg !77 store i32 %1, i32* %5, align 4, !dbg !77 %6 = getelementptr inbounds %class.Vector, %class.Vector* %0, i32 0, i32 1, !dbg !78 store i32 %2, i32* %6, align 4, !dbg !78 %7 = getelementptr inbounds %class.Vector, %class.Vector* %0, i32 0, i32 2, !dbg !79 store i32 %3, i32* %7, align 4, !dbg !79 ret void, !dbg !80 } ; CHECK: define void @_ZN6VectorC2Eiii({0: si32, 4: si32, 8: si32}* %1, si32 %2, si32 %3, si32 %4) { ; CHECK: #1 !entry !exit { ; CHECK: si32* %5 = ptrshift %1, 12 * 0, 1 * 0 ; CHECK: store %5, %2, align 4 ; CHECK: si32* %6 = ptrshift %1, 12 * 0, 1 * 4 ; CHECK: store %6, %3, align 4 ; CHECK: si32* %7 = ptrshift %1, 12 * 0, 1 * 8 ; CHECK: store %7, %4, align 4 ; CHECK: return ; CHECK: } ; CHECK: } declare void @__ikos_assert(i32) #5 ; CHECK: declare void @ar.ikos.assert(ui32) ; Function Attrs: nobuiltin declare noalias i8* @_Znwm(i64) #4 ; CHECK: declare si8* @ar.libcpp.new(ui64) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #2 !dbg !26 { %1 = alloca %class.Master, align 8 call void @llvm.dbg.declare(metadata %class.Master* %1, metadata !29, metadata !DIExpression()), !dbg !39 call void @_ZN6MasterC1Ev(%class.Master* %1), !dbg !39 ret i32 0, !dbg !40 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* $1 = allocate {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}, 1, align 8 ; CHECK: call @_ZN6MasterC1Ev($1) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { nobuiltin "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #6 = { builtin } attributes #7 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "constructors.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fP6Vector", scope: !1, file: !1, line: 14, type: !9, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Vector", file: !1, line: 5, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !14, identifier: "_ZTS6Vector") !14 = !{!15, !16, !17, !18} !15 = !DIDerivedType(tag: DW_TAG_member, name: "_x", scope: !13, file: !1, line: 7, baseType: !11, size: 32, flags: DIFlagPublic) !16 = !DIDerivedType(tag: DW_TAG_member, name: "_y", scope: !13, file: !1, line: 8, baseType: !11, size: 32, offset: 32, flags: DIFlagPublic) !17 = !DIDerivedType(tag: DW_TAG_member, name: "_z", scope: !13, file: !1, line: 9, baseType: !11, size: 32, offset: 64, flags: DIFlagPublic) !18 = !DISubprogram(name: "Vector", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !19 = !DISubroutineType(types: !20) !20 = !{null, !21, !11, !11, !11} !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !22 = !DILocalVariable(name: "v", arg: 1, scope: !8, file: !1, line: 14, type: !12) !23 = !DILocation(line: 0, scope: !8) !24 = !DILocation(line: 15, column: 13, scope: !8) !25 = !DILocation(line: 15, column: 3, scope: !8) !26 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 30, type: !27, scopeLine: 30, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !27 = !DISubroutineType(types: !28) !28 = !{!11} !29 = !DILocalVariable(name: "master", scope: !26, file: !1, line: 31, type: !30) !30 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Master", file: !1, line: 18, size: 128, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !31, identifier: "_ZTS6Master") !31 = !{!32, !33, !35} !32 = !DIDerivedType(tag: DW_TAG_member, name: "_v", scope: !30, file: !1, line: 20, baseType: !12, size: 64, flags: DIFlagPublic) !33 = !DIDerivedType(tag: DW_TAG_member, name: "_p", scope: !30, file: !1, line: 21, baseType: !34, size: 64, offset: 64, flags: DIFlagPublic) !34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !35 = !DISubprogram(name: "Master", scope: !30, file: !1, line: 23, type: !36, scopeLine: 23, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !36 = !DISubroutineType(types: !37) !37 = !{null, !38} !38 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !39 = !DILocation(line: 31, column: 10, scope: !26) !40 = !DILocation(line: 32, column: 3, scope: !26) !41 = distinct !DISubprogram(name: "Master", linkageName: "_ZN6MasterC1Ev", scope: !30, file: !1, line: 23, type: !36, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !35, retainedNodes: !2) !42 = !DILocalVariable(name: "this", arg: 1, scope: !41, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer) !43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) !44 = !DILocation(line: 0, scope: !41) !45 = !DILocation(line: 23, column: 12, scope: !41) !46 = !DILocation(line: 27, column: 3, scope: !41) !47 = distinct !DISubprogram(name: "Master", linkageName: "_ZN6MasterC2Ev", scope: !30, file: !1, line: 23, type: !36, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !35, retainedNodes: !2) !48 = !DILocalVariable(name: "this", arg: 1, scope: !47, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer) !49 = !DILocation(line: 0, scope: !47) !50 = !DILocation(line: 24, column: 10, scope: !51) !51 = distinct !DILexicalBlock(scope: !47, file: !1, line: 23, column: 12) !52 = !DILocation(line: 24, column: 14, scope: !51) !53 = !DILocation(line: 24, column: 5, scope: !51) !54 = !DILocation(line: 24, column: 8, scope: !51) !55 = !DILocation(line: 25, column: 10, scope: !51) !56 = !DILocation(line: 25, column: 5, scope: !51) !57 = !DILocation(line: 25, column: 8, scope: !51) !58 = !DILocation(line: 26, column: 21, scope: !51) !59 = !DILocation(line: 26, column: 19, scope: !51) !60 = !DILocation(line: 26, column: 25, scope: !51) !61 = !DILocation(line: 26, column: 5, scope: !51) !62 = !DILocation(line: 27, column: 3, scope: !47) !63 = distinct !DISubprogram(name: "Vector", linkageName: "_ZN6VectorC1Eiii", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !18, retainedNodes: !2) !64 = !DILocalVariable(name: "this", arg: 1, scope: !63, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) !65 = !DILocation(line: 0, scope: !63) !66 = !DILocalVariable(name: "x", arg: 2, scope: !63, file: !1, line: 11, type: !11) !67 = !DILocalVariable(name: "y", arg: 3, scope: !63, file: !1, line: 11, type: !11) !68 = !DILocalVariable(name: "z", arg: 4, scope: !63, file: !1, line: 11, type: !11) !69 = !DILocation(line: 11, column: 62, scope: !63) !70 = !DILocation(line: 11, column: 63, scope: !63) !71 = distinct !DISubprogram(name: "Vector", linkageName: "_ZN6VectorC2Eiii", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !18, retainedNodes: !2) !72 = !DILocalVariable(name: "this", arg: 1, scope: !71, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) !73 = !DILocation(line: 0, scope: !71) !74 = !DILocalVariable(name: "x", arg: 2, scope: !71, file: !1, line: 11, type: !11) !75 = !DILocalVariable(name: "y", arg: 3, scope: !71, file: !1, line: 11, type: !11) !76 = !DILocalVariable(name: "z", arg: 4, scope: !71, file: !1, line: 11, type: !11) !77 = !DILocation(line: 11, column: 42, scope: !71) !78 = !DILocation(line: 11, column: 49, scope: !71) !79 = !DILocation(line: 11, column: 56, scope: !71) !80 = !DILocation(line: 11, column: 63, scope: !71) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/empty-array-1.c000066400000000000000000000000731473507761200325230ustar00rootroot00000000000000struct { char a[0]; int* b; double c; } d = {{}, 1}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/empty-array-1.ll000066400000000000000000000046161473507761200327170ustar00rootroot00000000000000; ModuleID = 'empty-array-1.pp.bc' source_filename = "empty-array-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.anon = type { [0 x i8], i32*, double } @d = global %struct.anon { [0 x i8] zeroinitializer, i32* inttoptr (i64 1 to i32*), double 0.000000e+00 }, align 8, !dbg !0 ; CHECK: define {0: [0 x si8], 0: si32*, 8: double}* @d, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si32* %1 = sitoptr 1 ; CHECK: store @d, {0: aggregate_zero, 0: %1, 8: 0.0E+0}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!18, !19, !20, !21} !llvm.ident = !{!22} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 5, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "empty-array-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 128, elements: !7) !7 = !{!8, !13, !16} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !3, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !3, line: 3, baseType: !14, size: 64) !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !16 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !6, file: !3, line: 4, baseType: !17, size: 64, offset: 64) !17 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !18 = !{i32 2, !"Dwarf Version", i32 4} !19 = !{i32 2, !"Debug Info Version", i32 3} !20 = !{i32 1, !"wchar_size", i32 4} !21 = !{i32 7, !"PIC Level", i32 2} !22 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/empty-array-2.c000066400000000000000000000000771473507761200325300ustar00rootroot00000000000000struct { int a[0]; struct { int b; }; } c = {{}, 6}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/empty-array-2.ll000066400000000000000000000043661473507761200327220ustar00rootroot00000000000000; ModuleID = 'empty-array-2.pp.bc' source_filename = "empty-array-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.anon.0 = type { [0 x i32], %struct.anon } %struct.anon = type { i32 } @c = global %struct.anon.0 { [0 x i32] zeroinitializer, %struct.anon { i32 6 } }, align 4, !dbg !0 ; CHECK: define {0: [0 x si32], 0: {0: si32}}* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, {0: aggregate_zero, 0: {0: 6}}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!17, !18, !19, !20} !llvm.ident = !{!21} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 6, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "empty-array-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 32, elements: !7) !7 = !{!8, !13} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !3, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, scope: !6, file: !3, line: 3, baseType: !14, size: 32) !14 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !6, file: !3, line: 3, size: 32, elements: !15) !15 = !{!16} !16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !3, line: 4, baseType: !10, size: 32) !17 = !{i32 2, !"Dwarf Version", i32 4} !18 = !{i32 2, !"Debug Info Version", i32 3} !19 = !{i32 1, !"wchar_size", i32 4} !20 = !{i32 7, !"PIC Level", i32 2} !21 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/empty-array-3.c000066400000000000000000000000501473507761200325200ustar00rootroot00000000000000union { char a[0]; int b; } c = {}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/empty-array-3.ll000066400000000000000000000040071473507761200327130ustar00rootroot00000000000000; ModuleID = 'empty-array-3.pp.bc' source_filename = "empty-array-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @c = global { [0 x i8], [4 x i8] } { [0 x i8] zeroinitializer, [4 x i8] undef }, align 4, !dbg !0 ; CHECK: define {0: [0 x si8], 0: [4 x si8]}* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, {0: aggregate_zero, 0: undef}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "empty-array-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !3, line: 1, size: 32, elements: !7) !7 = !{!8, !13} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !3, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !3, line: 3, baseType: !14, size: 32) !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} empty-function-body.c000066400000000000000000000001131473507761200337430ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimizationvoid GEN2_w_test2_terminate(void) { /* (no terminate code required) */ } empty-function-body.ll000066400000000000000000000041121473507761200341330ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'empty-function-body.pp.bc' source_filename = "empty-function-body.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define void @GEN2_w_test2_terminate() #0 !dbg !8 { ret void, !dbg !11 } ; CHECK: define void @GEN2_w_test2_terminate() { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "empty-function-body.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "GEN2_w_test2_terminate", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null} !11 = !DILocation(line: 3, column: 1, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/file-intrinsics.c000066400000000000000000000003521473507761200332150ustar00rootroot00000000000000#include int main() { FILE* f = fopen("/tmp/test", "rw"); char buf[1025]; int x; fgets(buf, 1024, f); fgetc(f); fputs("hello world", f); fprintf(f, "%d", 1); fscanf(f, "%d", &x); fflush(f); fclose(f); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/file-intrinsics.ll000066400000000000000000000340611473507761200334060ustar00rootroot00000000000000; ModuleID = 'file-intrinsics.pp.bc' source_filename = "file-intrinsics.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 } %struct.__sFILEX = type opaque %struct.__sbuf = type { i8*, i32 } @.str = private unnamed_addr constant [10 x i8] c"/tmp/test\00", align 1 ; CHECK: define [10 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [47, 116, 109, 112, 47, 116, 101, 115, 116, 0], align 1 ; CHECK: } ; CHECK: } @.str.1 = private unnamed_addr constant [3 x i8] c"rw\00", align 1 ; CHECK: define [3 x si8]* @.str.1, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.1, [114, 119, 0], align 1 ; CHECK: } ; CHECK: } @.str.2 = private unnamed_addr constant [12 x i8] c"hello world\00", align 1 ; CHECK: define [12 x si8]* @.str.2, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.2, [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0], align 1 ; CHECK: } ; CHECK: } @.str.3 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 ; CHECK: define [3 x si8]* @.str.3, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.3, [37, 100, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @fclose(%struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fclose(opaque*) declare i32 @fflush(%struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fflush(opaque*) declare i32 @fgetc(%struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fgetc(opaque*) declare i8* @fgets(i8*, i32, %struct.__sFILE*) #2 ; CHECK: declare si8* @ar.libc.fgets(si8*, si32, opaque*) declare %struct.__sFILE* @"\01_fopen"(i8*, i8*) #2 ; CHECK: declare opaque* @ar.libc.fopen(si8*, si8*) declare i32 @fprintf(%struct.__sFILE*, i8*, ...) #2 ; CHECK: declare si32 @ar.libc.fprintf(opaque*, si8*, ...) declare i32 @"\01_fputs"(i8*, %struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fputs(si8*, opaque*) declare i32 @fscanf(%struct.__sFILE*, i8*, ...) #2 ; CHECK: declare si32 @ar.libc.fscanf(opaque*, si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca [1025 x i8], align 16 %2 = alloca i32, align 4 %3 = getelementptr inbounds [10 x i8], [10 x i8]* @.str, i64 0, i64 0, !dbg !12 %4 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.1, i64 0, i64 0, !dbg !12 %5 = call %struct.__sFILE* @"\01_fopen"(i8* %3, i8* %4), !dbg !12 call void @llvm.dbg.value(metadata %struct.__sFILE* %5, metadata !13, metadata !DIExpression()), !dbg !77 call void @llvm.dbg.declare(metadata [1025 x i8]* %1, metadata !78, metadata !DIExpression()), !dbg !82 call void @llvm.dbg.declare(metadata i32* %2, metadata !83, metadata !DIExpression()), !dbg !84 %6 = getelementptr inbounds [1025 x i8], [1025 x i8]* %1, i64 0, i64 0, !dbg !85 %7 = call i8* @fgets(i8* %6, i32 1024, %struct.__sFILE* %5), !dbg !86 %8 = call i32 @fgetc(%struct.__sFILE* %5), !dbg !87 %9 = getelementptr inbounds [12 x i8], [12 x i8]* @.str.2, i64 0, i64 0, !dbg !88 %10 = call i32 @"\01_fputs"(i8* %9, %struct.__sFILE* %5), !dbg !88 %11 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.3, i64 0, i64 0, !dbg !89 %12 = call i32 (%struct.__sFILE*, i8*, ...) @fprintf(%struct.__sFILE* %5, i8* %11, i32 1), !dbg !89 %13 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.3, i64 0, i64 0, !dbg !90 %14 = call i32 (%struct.__sFILE*, i8*, ...) @fscanf(%struct.__sFILE* %5, i8* %13, i32* %2), !dbg !90 %15 = call i32 @fflush(%struct.__sFILE* %5), !dbg !91 %16 = call i32 @fclose(%struct.__sFILE* %5), !dbg !92 ret i32 0, !dbg !93 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: [1025 x si8]* $1 = allocate [1025 x si8], 1, align 16 ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: si8* %3 = ptrshift @.str, 10 * 0, 1 * 0 ; CHECK: si8* %4 = ptrshift @.str.1, 3 * 0, 1 * 0 ; CHECK: opaque* %5 = call @ar.libc.fopen(%3, %4) ; CHECK: {0: ui8*, 8: si32, 12: si32, 16: si16, 18: si16, 24: {0: ui8*, 8: si32}, 40: si32, 48: si8*, 56: si32 (si8*)*, 64: si32 (si8*, si8*, si32)*, 72: si64 (si8*, si64, si32)*, 80: si32 (si8*, si8*, si32)*, 88: {0: ui8*, 8: si32}, 104: opaque*, 112: si32, 116: [3 x ui8], 119: [1 x ui8], 120: {0: ui8*, 8: si32}, 136: si32, 144: si64}* %6 = bitcast %5 ; CHECK: si8* %7 = ptrshift $1, 1025 * 0, 1 * 0 ; CHECK: opaque* %8 = bitcast %6 ; CHECK: si8* %9 = call @ar.libc.fgets(%7, 1024, %8) ; CHECK: opaque* %10 = bitcast %6 ; CHECK: si32 %11 = call @ar.libc.fgetc(%10) ; CHECK: si8* %12 = ptrshift @.str.2, 12 * 0, 1 * 0 ; CHECK: opaque* %13 = bitcast %6 ; CHECK: si32 %14 = call @ar.libc.fputs(%12, %13) ; CHECK: si8* %15 = ptrshift @.str.3, 3 * 0, 1 * 0 ; CHECK: opaque* %16 = bitcast %6 ; CHECK: si32 %17 = call @ar.libc.fprintf(%16, %15, 1) ; CHECK: si8* %18 = ptrshift @.str.3, 3 * 0, 1 * 0 ; CHECK: opaque* %19 = bitcast %6 ; CHECK: si32 %20 = call @ar.libc.fscanf(%19, %18, $2) ; CHECK: opaque* %21 = bitcast %6 ; CHECK: si32 %22 = call @ar.libc.fflush(%21) ; CHECK: opaque* %23 = bitcast %6 ; CHECK: si32 %24 = call @ar.libc.fclose(%23) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "file-intrinsics.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 4, column: 13, scope: !8) !13 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 4, type: !14) !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "FILE", file: !16, line: 157, baseType: !17) !16 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/_stdio.h", directory: "") !17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__sFILE", file: !16, line: 126, size: 1216, elements: !18) !18 = !{!19, !22, !23, !24, !26, !27, !32, !33, !35, !39, !45, !55, !61, !62, !65, !66, !70, !74, !75, !76} !19 = !DIDerivedType(tag: DW_TAG_member, name: "_p", scope: !17, file: !16, line: 127, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !22 = !DIDerivedType(tag: DW_TAG_member, name: "_r", scope: !17, file: !16, line: 128, baseType: !11, size: 32, offset: 64) !23 = !DIDerivedType(tag: DW_TAG_member, name: "_w", scope: !17, file: !16, line: 129, baseType: !11, size: 32, offset: 96) !24 = !DIDerivedType(tag: DW_TAG_member, name: "_flags", scope: !17, file: !16, line: 130, baseType: !25, size: 16, offset: 128) !25 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) !26 = !DIDerivedType(tag: DW_TAG_member, name: "_file", scope: !17, file: !16, line: 131, baseType: !25, size: 16, offset: 144) !27 = !DIDerivedType(tag: DW_TAG_member, name: "_bf", scope: !17, file: !16, line: 132, baseType: !28, size: 128, offset: 192) !28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__sbuf", file: !16, line: 92, size: 128, elements: !29) !29 = !{!30, !31} !30 = !DIDerivedType(tag: DW_TAG_member, name: "_base", scope: !28, file: !16, line: 93, baseType: !20, size: 64) !31 = !DIDerivedType(tag: DW_TAG_member, name: "_size", scope: !28, file: !16, line: 94, baseType: !11, size: 32, offset: 64) !32 = !DIDerivedType(tag: DW_TAG_member, name: "_lbfsize", scope: !17, file: !16, line: 133, baseType: !11, size: 32, offset: 320) !33 = !DIDerivedType(tag: DW_TAG_member, name: "_cookie", scope: !17, file: !16, line: 136, baseType: !34, size: 64, offset: 384) !34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !35 = !DIDerivedType(tag: DW_TAG_member, name: "_close", scope: !17, file: !16, line: 137, baseType: !36, size: 64, offset: 448) !36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !37, size: 64) !37 = !DISubroutineType(types: !38) !38 = !{!11, !34} !39 = !DIDerivedType(tag: DW_TAG_member, name: "_read", scope: !17, file: !16, line: 138, baseType: !40, size: 64, offset: 512) !40 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !41, size: 64) !41 = !DISubroutineType(types: !42) !42 = !{!11, !34, !43, !11} !43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !44, size: 64) !44 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !45 = !DIDerivedType(tag: DW_TAG_member, name: "_seek", scope: !17, file: !16, line: 139, baseType: !46, size: 64, offset: 576) !46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !47, size: 64) !47 = !DISubroutineType(types: !48) !48 = !{!49, !34, !49, !11} !49 = !DIDerivedType(tag: DW_TAG_typedef, name: "fpos_t", file: !16, line: 81, baseType: !50) !50 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_off_t", file: !51, line: 71, baseType: !52) !51 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h", directory: "") !52 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int64_t", file: !53, line: 46, baseType: !54) !53 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/i386/_types.h", directory: "") !54 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) !55 = !DIDerivedType(tag: DW_TAG_member, name: "_write", scope: !17, file: !16, line: 140, baseType: !56, size: 64, offset: 640) !56 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64) !57 = !DISubroutineType(types: !58) !58 = !{!11, !34, !59, !11} !59 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !60, size: 64) !60 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !44) !61 = !DIDerivedType(tag: DW_TAG_member, name: "_ub", scope: !17, file: !16, line: 143, baseType: !28, size: 128, offset: 704) !62 = !DIDerivedType(tag: DW_TAG_member, name: "_extra", scope: !17, file: !16, line: 144, baseType: !63, size: 64, offset: 832) !63 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !64, size: 64) !64 = !DICompositeType(tag: DW_TAG_structure_type, name: "__sFILEX", file: !16, line: 98, flags: DIFlagFwdDecl) !65 = !DIDerivedType(tag: DW_TAG_member, name: "_ur", scope: !17, file: !16, line: 145, baseType: !11, size: 32, offset: 896) !66 = !DIDerivedType(tag: DW_TAG_member, name: "_ubuf", scope: !17, file: !16, line: 148, baseType: !67, size: 24, offset: 928) !67 = !DICompositeType(tag: DW_TAG_array_type, baseType: !21, size: 24, elements: !68) !68 = !{!69} !69 = !DISubrange(count: 3) !70 = !DIDerivedType(tag: DW_TAG_member, name: "_nbuf", scope: !17, file: !16, line: 149, baseType: !71, size: 8, offset: 952) !71 = !DICompositeType(tag: DW_TAG_array_type, baseType: !21, size: 8, elements: !72) !72 = !{!73} !73 = !DISubrange(count: 1) !74 = !DIDerivedType(tag: DW_TAG_member, name: "_lb", scope: !17, file: !16, line: 152, baseType: !28, size: 128, offset: 960) !75 = !DIDerivedType(tag: DW_TAG_member, name: "_blksize", scope: !17, file: !16, line: 155, baseType: !11, size: 32, offset: 1088) !76 = !DIDerivedType(tag: DW_TAG_member, name: "_offset", scope: !17, file: !16, line: 156, baseType: !49, size: 64, offset: 1152) !77 = !DILocation(line: 0, scope: !8) !78 = !DILocalVariable(name: "buf", scope: !8, file: !1, line: 5, type: !79) !79 = !DICompositeType(tag: DW_TAG_array_type, baseType: !44, size: 8200, elements: !80) !80 = !{!81} !81 = !DISubrange(count: 1025) !82 = !DILocation(line: 5, column: 8, scope: !8) !83 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 6, type: !11) !84 = !DILocation(line: 6, column: 7, scope: !8) !85 = !DILocation(line: 7, column: 9, scope: !8) !86 = !DILocation(line: 7, column: 3, scope: !8) !87 = !DILocation(line: 8, column: 3, scope: !8) !88 = !DILocation(line: 9, column: 3, scope: !8) !89 = !DILocation(line: 10, column: 3, scope: !8) !90 = !DILocation(line: 11, column: 3, scope: !8) !91 = !DILocation(line: 12, column: 3, scope: !8) !92 = !DILocation(line: 13, column: 3, scope: !8) !93 = !DILocation(line: 14, column: 1, scope: !8) flexible-array-member.c000066400000000000000000000001361473507761200342070ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimizationstruct line { int length; char contents[]; }; struct line l; int main() { return 0; } flexible-array-member.ll000066400000000000000000000061141473507761200343760ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'flexible-array-member.pp.bc' source_filename = "flexible-array-member.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.line = type { i32, [0 x i8] } @l = common global %struct.line zeroinitializer, align 4, !dbg !0 ; CHECK: define {0: si32, 4: [0 x si8]}* @l, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @l, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "l", scope: !2, file: !3, line: 6, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "flexible-array-member.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "line", file: !3, line: 1, size: 32, elements: !7) !7 = !{!8, !10} !8 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !6, file: !3, line: 2, baseType: !9, size: 32) !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !10 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !6, file: !3, line: 3, baseType: !11, offset: 32) !11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, elements: !13) !12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !13 = !{!14} !14 = !DISubrange(count: -1) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !21, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!9} !23 = !DILocation(line: 9, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/gv-init.c000066400000000000000000000004321473507761200314670ustar00rootroot00000000000000int a[100][100]; int b[2] = {1, 2}; int c; int d = 5; extern int e; int main(int argc, char** argv) { int i = 0, j = 0; for (; i < 100; i++) for (; j < 100; j++) if (i % 2 == 0) a[i][j] = b[0] + c - e; else a[i][j] = b[1] + d - e; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/gv-init.ll000066400000000000000000000276041473507761200316660ustar00rootroot00000000000000; ModuleID = 'gv-init.pp.bc' source_filename = "gv-init.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global [100 x [100 x i32]] zeroinitializer, align 16, !dbg !9 ; CHECK: define [100 x [100 x si32]]* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = global [2 x i32] [i32 1, i32 2], align 4, !dbg !0 ; CHECK: define [2 x si32]* @b, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, [1, 2], align 1 ; CHECK: } ; CHECK: } @c = common global i32 0, align 4, !dbg !14 ; CHECK: define si32* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, 0, align 1 ; CHECK: } ; CHECK: } @d = global i32 5, align 4, !dbg !6 ; CHECK: define si32* @d, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @d, 5, align 1 ; CHECK: } ; CHECK: } @e = external global i32, align 4 ; CHECK: declare si32* @e, align 4 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !24 { call void @llvm.dbg.value(metadata i32 %0, metadata !30, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i8** %1, metadata !32, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i32 0, metadata !33, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i32 0, metadata !34, metadata !DIExpression()), !dbg !31 br label %3, !dbg !35 3: ; preds = %37, %2 %.01 = phi i32 [ 0, %2 ], [ %38, %37 ], !dbg !31 %.0 = phi i32 [ 0, %2 ], [ %.1, %37 ], !dbg !36 call void @llvm.dbg.value(metadata i32 %.0, metadata !34, metadata !DIExpression()), !dbg !31 call void @llvm.dbg.value(metadata i32 %.01, metadata !33, metadata !DIExpression()), !dbg !31 %4 = icmp slt i32 %.01, 100, !dbg !37 br i1 %4, label %5, label %39, !dbg !40 5: ; preds = %3 br label %6, !dbg !41 6: ; preds = %34, %5 %.1 = phi i32 [ %.0, %5 ], [ %35, %34 ], !dbg !31 call void @llvm.dbg.value(metadata i32 %.1, metadata !34, metadata !DIExpression()), !dbg !31 %7 = icmp slt i32 %.1, 100, !dbg !42 br i1 %7, label %8, label %36, !dbg !45 8: ; preds = %6 %9 = srem i32 %.01, 2, !dbg !46 %10 = icmp eq i32 %9, 0, !dbg !48 br i1 %10, label %11, label %22, !dbg !49 11: ; preds = %8 %12 = getelementptr inbounds [2 x i32], [2 x i32]* @b, i64 0, i64 0, !dbg !50 %13 = load i32, i32* %12, align 4, !dbg !50 %14 = load i32, i32* @c, align 4, !dbg !51 %15 = add nsw i32 %13, %14, !dbg !52 %16 = load i32, i32* @e, align 4, !dbg !53 %17 = sub nsw i32 %15, %16, !dbg !54 %18 = sext i32 %.01 to i64, !dbg !55 %19 = getelementptr inbounds [100 x [100 x i32]], [100 x [100 x i32]]* @a, i64 0, i64 %18, !dbg !55 %20 = sext i32 %.1 to i64, !dbg !55 %21 = getelementptr inbounds [100 x i32], [100 x i32]* %19, i64 0, i64 %20, !dbg !55 store i32 %17, i32* %21, align 4, !dbg !56 br label %33, !dbg !55 22: ; preds = %8 %23 = getelementptr inbounds [2 x i32], [2 x i32]* @b, i64 0, i64 1, !dbg !57 %24 = load i32, i32* %23, align 4, !dbg !57 %25 = load i32, i32* @d, align 4, !dbg !58 %26 = add nsw i32 %24, %25, !dbg !59 %27 = load i32, i32* @e, align 4, !dbg !60 %28 = sub nsw i32 %26, %27, !dbg !61 %29 = sext i32 %.01 to i64, !dbg !62 %30 = getelementptr inbounds [100 x [100 x i32]], [100 x [100 x i32]]* @a, i64 0, i64 %29, !dbg !62 %31 = sext i32 %.1 to i64, !dbg !62 %32 = getelementptr inbounds [100 x i32], [100 x i32]* %30, i64 0, i64 %31, !dbg !62 store i32 %28, i32* %32, align 4, !dbg !63 br label %33 33: ; preds = %22, %11 br label %34, !dbg !64 34: ; preds = %33 %35 = add nsw i32 %.1, 1, !dbg !65 call void @llvm.dbg.value(metadata i32 %35, metadata !34, metadata !DIExpression()), !dbg !31 br label %6, !dbg !66, !llvm.loop !67 36: ; preds = %6 br label %37, !dbg !68 37: ; preds = %36 %38 = add nsw i32 %.01, 1, !dbg !69 call void @llvm.dbg.value(metadata i32 %38, metadata !33, metadata !DIExpression()), !dbg !31 br label %3, !dbg !70, !llvm.loop !71 39: ; preds = %3 ret i32 0, !dbg !73 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32 %.01 = 0 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #7} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#5} { ; CHECK: %.01 silt 100 ; CHECK: si32 %.1 = %.0 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %.01 sige 100 ; CHECK: return 0 ; CHECK: } ; CHECK: #5 predecessors={#3, #10} successors={#6, #7} { ; CHECK: } ; CHECK: #6 predecessors={#5} successors={#8, #9} { ; CHECK: %.1 silt 100 ; CHECK: si32 %3 = %.01 srem 2 ; CHECK: } ; CHECK: #7 predecessors={#5} successors={#2} { ; CHECK: %.1 sige 100 ; CHECK: si32 %4 = %.01 sadd.nw 1 ; CHECK: si32 %.01 = %4 ; CHECK: si32 %.0 = %.1 ; CHECK: } ; CHECK: #8 predecessors={#6} successors={#10} { ; CHECK: %3 sieq 0 ; CHECK: si32* %5 = ptrshift @b, 8 * 0, 4 * 0 ; CHECK: si32 %6 = load %5, align 4 ; CHECK: si32 %7 = load @c, align 4 ; CHECK: si32 %8 = %6 sadd.nw %7 ; CHECK: si32 %9 = load @e, align 4 ; CHECK: si32 %10 = %8 ssub.nw %9 ; CHECK: si64 %11 = sext %.01 ; CHECK: [100 x si32]* %12 = ptrshift @a, 40000 * 0, 400 * %11 ; CHECK: si64 %13 = sext %.1 ; CHECK: si32* %14 = ptrshift %12, 400 * 0, 4 * %13 ; CHECK: store %14, %10, align 4 ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#10} { ; CHECK: %3 sine 0 ; CHECK: si32* %15 = ptrshift @b, 8 * 0, 4 * 1 ; CHECK: si32 %16 = load %15, align 4 ; CHECK: si32 %17 = load @d, align 4 ; CHECK: si32 %18 = %16 sadd.nw %17 ; CHECK: si32 %19 = load @e, align 4 ; CHECK: si32 %20 = %18 ssub.nw %19 ; CHECK: si64 %21 = sext %.01 ; CHECK: [100 x si32]* %22 = ptrshift @a, 40000 * 0, 400 * %21 ; CHECK: si64 %23 = sext %.1 ; CHECK: si32* %24 = ptrshift %22, 400 * 0, 4 * %23 ; CHECK: store %24, %20, align 4 ; CHECK: } ; CHECK: #10 predecessors={#8, #9} successors={#5} { ; CHECK: si32 %25 = %.1 sadd.nw 1 ; CHECK: si32 %.1 = %25 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!19, !20, !21, !22} !llvm.ident = !{!23} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 2, type: !16, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "gv-init.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0, !6, !9, !14} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 4, type: !8, isLocal: false, isDefinition: true) !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression()) !10 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !11, isLocal: false, isDefinition: true) !11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 320000, elements: !12) !12 = !{!13, !13} !13 = !DISubrange(count: 100) !14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression()) !15 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 64, elements: !17) !17 = !{!18} !18 = !DISubrange(count: 2) !19 = !{i32 2, !"Dwarf Version", i32 4} !20 = !{i32 2, !"Debug Info Version", i32 3} !21 = !{i32 1, !"wchar_size", i32 4} !22 = !{i32 7, !"PIC Level", i32 2} !23 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !24 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 7, type: !25, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !25 = !DISubroutineType(types: !26) !26 = !{!8, !8, !27} !27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64) !28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64) !29 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !30 = !DILocalVariable(name: "argc", arg: 1, scope: !24, file: !3, line: 7, type: !8) !31 = !DILocation(line: 0, scope: !24) !32 = !DILocalVariable(name: "argv", arg: 2, scope: !24, file: !3, line: 7, type: !27) !33 = !DILocalVariable(name: "i", scope: !24, file: !3, line: 8, type: !8) !34 = !DILocalVariable(name: "j", scope: !24, file: !3, line: 8, type: !8) !35 = !DILocation(line: 9, column: 3, scope: !24) !36 = !DILocation(line: 8, column: 14, scope: !24) !37 = !DILocation(line: 9, column: 12, scope: !38) !38 = distinct !DILexicalBlock(scope: !39, file: !3, line: 9, column: 3) !39 = distinct !DILexicalBlock(scope: !24, file: !3, line: 9, column: 3) !40 = !DILocation(line: 9, column: 3, scope: !39) !41 = !DILocation(line: 10, column: 5, scope: !38) !42 = !DILocation(line: 10, column: 14, scope: !43) !43 = distinct !DILexicalBlock(scope: !44, file: !3, line: 10, column: 5) !44 = distinct !DILexicalBlock(scope: !38, file: !3, line: 10, column: 5) !45 = !DILocation(line: 10, column: 5, scope: !44) !46 = !DILocation(line: 11, column: 13, scope: !47) !47 = distinct !DILexicalBlock(scope: !43, file: !3, line: 11, column: 11) !48 = !DILocation(line: 11, column: 17, scope: !47) !49 = !DILocation(line: 11, column: 11, scope: !43) !50 = !DILocation(line: 12, column: 19, scope: !47) !51 = !DILocation(line: 12, column: 26, scope: !47) !52 = !DILocation(line: 12, column: 24, scope: !47) !53 = !DILocation(line: 12, column: 30, scope: !47) !54 = !DILocation(line: 12, column: 28, scope: !47) !55 = !DILocation(line: 12, column: 9, scope: !47) !56 = !DILocation(line: 12, column: 17, scope: !47) !57 = !DILocation(line: 14, column: 19, scope: !47) !58 = !DILocation(line: 14, column: 26, scope: !47) !59 = !DILocation(line: 14, column: 24, scope: !47) !60 = !DILocation(line: 14, column: 30, scope: !47) !61 = !DILocation(line: 14, column: 28, scope: !47) !62 = !DILocation(line: 14, column: 9, scope: !47) !63 = !DILocation(line: 14, column: 17, scope: !47) !64 = !DILocation(line: 11, column: 20, scope: !47) !65 = !DILocation(line: 10, column: 22, scope: !43) !66 = !DILocation(line: 10, column: 5, scope: !43) !67 = distinct !{!67, !45, !68} !68 = !DILocation(line: 14, column: 30, scope: !44) !69 = !DILocation(line: 9, column: 20, scope: !38) !70 = !DILocation(line: 9, column: 3, scope: !38) !71 = distinct !{!71, !40, !72} !72 = !DILocation(line: 14, column: 30, scope: !39) !73 = !DILocation(line: 15, column: 3, scope: !24) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/linked-list.c000066400000000000000000000001671473507761200323360ustar00rootroot00000000000000struct node { int value; struct node* next; }; struct node head; int main(int argc, char** argv) { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/linked-list.ll000066400000000000000000000074241473507761200325260ustar00rootroot00000000000000; ModuleID = 'linked-list.pp.bc' source_filename = "linked-list.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.node = type { i32, %struct.node* } @head = common global %struct.node zeroinitializer, align 8, !dbg !0 ; CHECK: define {0: si32, 8: {...}*}* @head, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @head, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !17 { call void @llvm.dbg.value(metadata i32 %0, metadata !23, metadata !DIExpression()), !dbg !24 call void @llvm.dbg.value(metadata i8** %1, metadata !25, metadata !DIExpression()), !dbg !24 ret i32 0, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!12, !13, !14, !15} !llvm.ident = !{!16} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "head", scope: !2, file: !3, line: 6, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "linked-list.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "node", file: !3, line: 1, size: 128, elements: !7) !7 = !{!8, !10} !8 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !6, file: !3, line: 2, baseType: !9, size: 32) !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !10 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !6, file: !3, line: 3, baseType: !11, size: 64, offset: 64) !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) !12 = !{i32 2, !"Dwarf Version", i32 4} !13 = !{i32 2, !"Debug Info Version", i32 3} !14 = !{i32 1, !"wchar_size", i32 4} !15 = !{i32 7, !"PIC Level", i32 2} !16 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !17 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !18, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !18 = !DISubroutineType(types: !19) !19 = !{!9, !9, !20} !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !23 = !DILocalVariable(name: "argc", arg: 1, scope: !17, file: !3, line: 8, type: !9) !24 = !DILocation(line: 0, scope: !17) !25 = !DILocalVariable(name: "argv", arg: 2, scope: !17, file: !3, line: 8, type: !20) !26 = !DILocation(line: 9, column: 3, scope: !17) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/local-array-1.c000066400000000000000000000002771473507761200324650ustar00rootroot00000000000000// SAFE #include // To test loops int main(int argc, char** argv) { int i; int a[10]; for (i = 0; i < 10; i++) { a[i] = i; } printf("%d\n", a[i - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/local-array-1.ll000066400000000000000000000161521473507761200326510ustar00rootroot00000000000000; ModuleID = 'local-array-1.pp.bc' source_filename = "local-array-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca [10 x i32], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata [10 x i32]* %3, metadata !18, metadata !DIExpression()), !dbg !22 call void @llvm.dbg.value(metadata i32 0, metadata !23, metadata !DIExpression()), !dbg !16 br label %4, !dbg !24 4: ; preds = %9, %2 %.0 = phi i32 [ 0, %2 ], [ %10, %9 ], !dbg !26 call void @llvm.dbg.value(metadata i32 %.0, metadata !23, metadata !DIExpression()), !dbg !16 %5 = icmp slt i32 %.0, 10, !dbg !27 br i1 %5, label %6, label %11, !dbg !29 6: ; preds = %4 %7 = sext i32 %.0 to i64, !dbg !30 %8 = getelementptr inbounds [10 x i32], [10 x i32]* %3, i64 0, i64 %7, !dbg !30 store i32 %.0, i32* %8, align 4, !dbg !32 br label %9, !dbg !33 9: ; preds = %6 %10 = add nsw i32 %.0, 1, !dbg !34 call void @llvm.dbg.value(metadata i32 %10, metadata !23, metadata !DIExpression()), !dbg !16 br label %4, !dbg !35, !llvm.loop !36 11: ; preds = %4 %12 = sub nsw i32 %.0, 1, !dbg !38 %13 = sext i32 %12 to i64, !dbg !39 %14 = getelementptr inbounds [10 x i32], [10 x i32]* %3, i64 0, i64 %13, !dbg !39 %15 = load i32, i32* %14, align 4, !dbg !39 %16 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !40 %17 = call i32 (i8*, ...) @printf(i8* %16, i32 %15), !dbg !40 ret i32 0, !dbg !41 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: [10 x si32]* $3 = allocate [10 x si32], 1, align 16 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %.0 silt 10 ; CHECK: si64 %4 = sext %.0 ; CHECK: si32* %5 = ptrshift $3, 40 * 0, 4 * %4 ; CHECK: store %5, %.0, align 4 ; CHECK: si32 %6 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %6 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %.0 sige 10 ; CHECK: si32 %7 = %.0 ssub.nw 1 ; CHECK: si64 %8 = sext %7 ; CHECK: si32* %9 = ptrshift $3, 40 * 0, 4 * %8 ; CHECK: si32 %10 = load %9, align 4 ; CHECK: si8* %11 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %12 = call @ar.libc.printf(%11, %10) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "local-array-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 6, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 6, type: !12) !18 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 8, type: !19) !19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !20) !20 = !{!21} !21 = !DISubrange(count: 10) !22 = !DILocation(line: 8, column: 7, scope: !8) !23 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 7, type: !11) !24 = !DILocation(line: 9, column: 8, scope: !25) !25 = distinct !DILexicalBlock(scope: !8, file: !1, line: 9, column: 3) !26 = !DILocation(line: 0, scope: !25) !27 = !DILocation(line: 9, column: 17, scope: !28) !28 = distinct !DILexicalBlock(scope: !25, file: !1, line: 9, column: 3) !29 = !DILocation(line: 9, column: 3, scope: !25) !30 = !DILocation(line: 10, column: 5, scope: !31) !31 = distinct !DILexicalBlock(scope: !28, file: !1, line: 9, column: 28) !32 = !DILocation(line: 10, column: 10, scope: !31) !33 = !DILocation(line: 11, column: 3, scope: !31) !34 = !DILocation(line: 9, column: 24, scope: !28) !35 = !DILocation(line: 9, column: 3, scope: !28) !36 = distinct !{!36, !29, !37} !37 = !DILocation(line: 11, column: 3, scope: !25) !38 = !DILocation(line: 12, column: 22, scope: !8) !39 = !DILocation(line: 12, column: 18, scope: !8) !40 = !DILocation(line: 12, column: 3, scope: !8) !41 = !DILocation(line: 13, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/local-array-2.c000066400000000000000000000006571473507761200324700ustar00rootroot00000000000000#include #include char* foo(char* a, int n) { int i; for (i = 0; i < n; i++) a[i] = 'A'; return a; } int main() { char str[50]; strcpy(str, "This is string.h library function"); puts(str); memset(str, '$', 50); // SAFE char* A = foo(str, 10); // char * B; <- B will be undefined char B[10]; memcpy(B, A, 10); // SAFE char* C = foo(B, 10); // SAFE puts(C); return (0); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/local-array-2.ll000066400000000000000000000243221473507761200326500ustar00rootroot00000000000000; ModuleID = 'local-array-2.pp.bc' source_filename = "local-array-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [34 x i8] c"This is string.h library function\00", align 1 ; CHECK: define [34 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [84, 104, 105, 115, 32, 105, 115, 32, 115, 116, 114, 105, 110, 103, 46, 104, 32, 108, 105, 98, 114, 97, 114, 121, 32, 102, 117, 110, 99, 116, 105, 111, 110, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @puts(i8*) #2 ; CHECK: declare si32 @ar.libc.puts(si8*) declare i8* @strcpy(i8*, i8*) #2 ; CHECK: declare si8* @ar.libc.strcpy(si8*, si8*) ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #3 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #3 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i8* @foo(i8*, i32) #0 !dbg !8 { call void @llvm.dbg.value(metadata i8* %0, metadata !14, metadata !DIExpression()), !dbg !15 call void @llvm.dbg.value(metadata i32 %1, metadata !16, metadata !DIExpression()), !dbg !15 call void @llvm.dbg.value(metadata i32 0, metadata !17, metadata !DIExpression()), !dbg !15 br label %3, !dbg !18 3: ; preds = %8, %2 %.0 = phi i32 [ 0, %2 ], [ %9, %8 ], !dbg !20 call void @llvm.dbg.value(metadata i32 %.0, metadata !17, metadata !DIExpression()), !dbg !15 %4 = icmp slt i32 %.0, %1, !dbg !21 br i1 %4, label %5, label %10, !dbg !23 5: ; preds = %3 %6 = sext i32 %.0 to i64, !dbg !24 %7 = getelementptr inbounds i8, i8* %0, i64 %6, !dbg !24 store i8 65, i8* %7, align 1, !dbg !25 br label %8, !dbg !24 8: ; preds = %5 %9 = add nsw i32 %.0, 1, !dbg !26 call void @llvm.dbg.value(metadata i32 %9, metadata !17, metadata !DIExpression()), !dbg !15 br label %3, !dbg !27, !llvm.loop !28 10: ; preds = %3 ret i8* %0, !dbg !30 } ; CHECK: define si8* @foo(si8* %1, si32 %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %.0 silt %2 ; CHECK: si64 %3 = sext %.0 ; CHECK: si8* %4 = ptrshift %1, 1 * %3 ; CHECK: store %4, 65, align 1 ; CHECK: si32 %5 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %5 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %.0 sige %2 ; CHECK: return %1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !31 { %1 = alloca [50 x i8], align 16 %2 = alloca [10 x i8], align 1 call void @llvm.dbg.declare(metadata [50 x i8]* %1, metadata !34, metadata !DIExpression()), !dbg !38 %3 = getelementptr inbounds [50 x i8], [50 x i8]* %1, i64 0, i64 0, !dbg !39 %4 = getelementptr inbounds [34 x i8], [34 x i8]* @.str, i64 0, i64 0, !dbg !40 %5 = call i8* @strcpy(i8* %3, i8* %4), !dbg !40 %6 = getelementptr inbounds [50 x i8], [50 x i8]* %1, i64 0, i64 0, !dbg !41 %7 = call i32 @puts(i8* %6), !dbg !42 %8 = getelementptr inbounds [50 x i8], [50 x i8]* %1, i64 0, i64 0, !dbg !43 call void @llvm.memset.p0i8.i64(i8* align 16 %8, i8 36, i64 50, i1 false), !dbg !43 %9 = getelementptr inbounds [50 x i8], [50 x i8]* %1, i64 0, i64 0, !dbg !44 %10 = call i8* @foo(i8* %9, i32 10), !dbg !45 call void @llvm.dbg.value(metadata i8* %10, metadata !46, metadata !DIExpression()), !dbg !47 call void @llvm.dbg.declare(metadata [10 x i8]* %2, metadata !48, metadata !DIExpression()), !dbg !52 %11 = getelementptr inbounds [10 x i8], [10 x i8]* %2, i64 0, i64 0, !dbg !53 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %11, i8* align 1 %10, i64 10, i1 false), !dbg !53 %12 = getelementptr inbounds [10 x i8], [10 x i8]* %2, i64 0, i64 0, !dbg !54 %13 = call i8* @foo(i8* %12, i32 10), !dbg !55 call void @llvm.dbg.value(metadata i8* %13, metadata !56, metadata !DIExpression()), !dbg !47 %14 = call i32 @puts(i8* %13), !dbg !57 ret i32 0, !dbg !58 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: [50 x si8]* $1 = allocate [50 x si8], 1, align 16 ; CHECK: [10 x si8]* $2 = allocate [10 x si8], 1, align 1 ; CHECK: si8* %3 = ptrshift $1, 50 * 0, 1 * 0 ; CHECK: si8* %4 = ptrshift @.str, 34 * 0, 1 * 0 ; CHECK: si8* %5 = call @ar.libc.strcpy(%3, %4) ; CHECK: si8* %6 = ptrshift $1, 50 * 0, 1 * 0 ; CHECK: si32 %7 = call @ar.libc.puts(%6) ; CHECK: si8* %8 = ptrshift $1, 50 * 0, 1 * 0 ; CHECK: call @ar.memset(%8, 36, 50, 16, 0) ; CHECK: si8* %9 = ptrshift $1, 50 * 0, 1 * 0 ; CHECK: si8* %10 = call @foo(%9, 10) ; CHECK: si8* %11 = ptrshift $2, 10 * 0, 1 * 0 ; CHECK: call @ar.memcpy(%11, %10, 10, 1, 1, 0) ; CHECK: si8* %12 = ptrshift $2, 10 * 0, 1 * 0 ; CHECK: si8* %13 = call @foo(%12, 10) ; CHECK: si32 %14 = call @ar.libc.puts(%13) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "local-array-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !13} !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) !12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11) !15 = !DILocation(line: 0, scope: !8) !16 = !DILocalVariable(name: "n", arg: 2, scope: !8, file: !1, line: 4, type: !13) !17 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 5, type: !13) !18 = !DILocation(line: 6, column: 8, scope: !19) !19 = distinct !DILexicalBlock(scope: !8, file: !1, line: 6, column: 3) !20 = !DILocation(line: 0, scope: !19) !21 = !DILocation(line: 6, column: 17, scope: !22) !22 = distinct !DILexicalBlock(scope: !19, file: !1, line: 6, column: 3) !23 = !DILocation(line: 6, column: 3, scope: !19) !24 = !DILocation(line: 7, column: 5, scope: !22) !25 = !DILocation(line: 7, column: 10, scope: !22) !26 = !DILocation(line: 6, column: 23, scope: !22) !27 = !DILocation(line: 6, column: 3, scope: !22) !28 = distinct !{!28, !23, !29} !29 = !DILocation(line: 7, column: 12, scope: !19) !30 = !DILocation(line: 8, column: 3, scope: !8) !31 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 11, type: !32, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !32 = !DISubroutineType(types: !33) !33 = !{!13} !34 = !DILocalVariable(name: "str", scope: !31, file: !1, line: 12, type: !35) !35 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 400, elements: !36) !36 = !{!37} !37 = !DISubrange(count: 50) !38 = !DILocation(line: 12, column: 8, scope: !31) !39 = !DILocation(line: 14, column: 10, scope: !31) !40 = !DILocation(line: 14, column: 3, scope: !31) !41 = !DILocation(line: 15, column: 8, scope: !31) !42 = !DILocation(line: 15, column: 3, scope: !31) !43 = !DILocation(line: 17, column: 3, scope: !31) !44 = !DILocation(line: 18, column: 17, scope: !31) !45 = !DILocation(line: 18, column: 13, scope: !31) !46 = !DILocalVariable(name: "A", scope: !31, file: !1, line: 18, type: !11) !47 = !DILocation(line: 0, scope: !31) !48 = !DILocalVariable(name: "B", scope: !31, file: !1, line: 20, type: !49) !49 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 80, elements: !50) !50 = !{!51} !51 = !DISubrange(count: 10) !52 = !DILocation(line: 20, column: 8, scope: !31) !53 = !DILocation(line: 21, column: 3, scope: !31) !54 = !DILocation(line: 22, column: 17, scope: !31) !55 = !DILocation(line: 22, column: 13, scope: !31) !56 = !DILocalVariable(name: "C", scope: !31, file: !1, line: 22, type: !11) !57 = !DILocation(line: 23, column: 3, scope: !31) !58 = !DILocation(line: 24, column: 3, scope: !31) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/mem-intrinsics.c000066400000000000000000000003231473507761200330520ustar00rootroot00000000000000#include int cst() { int G = 0 ? 0 : (((1 + 1) + 3) * 2); return G; } int main() { int *p, *q, *r; r = (int*)memcpy(p, q, 10); r = (int*)memmove(p, q, 50); r = (int*)memset(p, 1, 50); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/mem-intrinsics.ll000066400000000000000000000116071473507761200332460ustar00rootroot00000000000000; ModuleID = 'mem-intrinsics.pp.bc' source_filename = "mem-intrinsics.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #1 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: argmemonly nounwind declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1 immarg) #1 ; CHECK: declare void @ar.memmove(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #1 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i32 @cst() #0 !dbg !11 { call void @llvm.dbg.value(metadata i32 10, metadata !14, metadata !DIExpression()), !dbg !15 ret i32 10, !dbg !16 } ; CHECK: define si32 @cst() { ; CHECK: #1 !entry !exit { ; CHECK: return 10 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !17 { %1 = bitcast i32* undef to i8*, !dbg !18 %2 = bitcast i32* undef to i8*, !dbg !18 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 %2, i64 10, i1 false), !dbg !18 call void @llvm.dbg.value(metadata i8* %1, metadata !19, metadata !DIExpression()), !dbg !20 %3 = bitcast i32* undef to i8*, !dbg !21 %4 = bitcast i32* undef to i8*, !dbg !21 call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 %3, i8* align 4 %4, i64 50, i1 false), !dbg !21 call void @llvm.dbg.value(metadata i8* %3, metadata !19, metadata !DIExpression()), !dbg !20 %5 = bitcast i32* undef to i8*, !dbg !22 call void @llvm.memset.p0i8.i64(i8* align 4 %5, i8 1, i64 50, i1 false), !dbg !22 call void @llvm.dbg.value(metadata i8* %5, metadata !19, metadata !DIExpression()), !dbg !20 ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast undef ; CHECK: si8* %2 = bitcast undef ; CHECK: call @ar.memcpy(%1, %2, 10, 4, 4, 0) ; CHECK: si8* %3 = bitcast undef ; CHECK: si8* %4 = bitcast undef ; CHECK: call @ar.memmove(%3, %4, 50, 4, 4, 0) ; CHECK: si8* %5 = bitcast undef ; CHECK: call @ar.memset(%5, 1, 50, 4, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { argmemonly nounwind } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!6, !7, !8, !9} !llvm.ident = !{!10} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "mem-intrinsics.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{!4} !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) !5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} !8 = !{i32 1, !"wchar_size", i32 4} !9 = !{i32 7, !"PIC Level", i32 2} !10 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !11 = distinct !DISubprogram(name: "cst", scope: !1, file: !1, line: 3, type: !12, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !12 = !DISubroutineType(types: !13) !13 = !{!5} !14 = !DILocalVariable(name: "G", scope: !11, file: !1, line: 4, type: !5) !15 = !DILocation(line: 0, scope: !11) !16 = !DILocation(line: 5, column: 3, scope: !11) !17 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !12, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !18 = !DILocation(line: 10, column: 13, scope: !17) !19 = !DILocalVariable(name: "r", scope: !17, file: !1, line: 9, type: !4) !20 = !DILocation(line: 0, scope: !17) !21 = !DILocation(line: 11, column: 13, scope: !17) !22 = !DILocation(line: 12, column: 13, scope: !17) !23 = !DILocation(line: 13, column: 1, scope: !17) multiple-inheritance.cpp000066400000000000000000000003641473507761200345210ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimizationclass Base { private: int x; int y; }; struct Mixin { private: unsigned z; }; struct Empty { void f() {} }; class Child : public Base, public Mixin, public Empty { private: int tab[10]; }; Child c; int main(void) { return 0; } multiple-inheritance.ll000066400000000000000000000114301473507761200343420ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'multiple-inheritance.pp.bc' source_filename = "multiple-inheritance.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Child = type { %class.Base, %struct.Mixin, [10 x i32] } %class.Base = type { i32, i32 } %struct.Mixin = type { i32 } @c = global %class.Child zeroinitializer, align 4, !dbg !0 ; CHECK: define {0: {0: si32, 4: si32}, 8: {0: ui32}, 12: [10 x si32]}* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !35 { ret i32 0, !dbg !38 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!30, !31, !32, !33} !llvm.ident = !{!34} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 21, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "multiple-inheritance.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Child", file: !3, line: 16, size: 416, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS5Child") !7 = !{!8, !14, !19, !26} !8 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !9, flags: DIFlagPublic, extraData: i32 0) !9 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Base", file: !3, line: 1, size: 64, flags: DIFlagTypePassByValue, elements: !10, identifier: "_ZTS4Base") !10 = !{!11, !13} !11 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !9, file: !3, line: 3, baseType: !12, size: 32) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !9, file: !3, line: 4, baseType: !12, size: 32, offset: 32) !14 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !15, offset: 64, flags: DIFlagPublic, extraData: i32 0) !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Mixin", file: !3, line: 7, size: 32, flags: DIFlagTypePassByValue, elements: !16, identifier: "_ZTS5Mixin") !16 = !{!17} !17 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !15, file: !3, line: 9, baseType: !18, size: 32, flags: DIFlagPrivate) !18 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !19 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !20, flags: DIFlagPublic, extraData: i32 0) !20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Empty", file: !3, line: 12, size: 8, flags: DIFlagTypePassByValue, elements: !21, identifier: "_ZTS5Empty") !21 = !{!22} !22 = !DISubprogram(name: "f", linkageName: "_ZN5Empty1fEv", scope: !20, file: !3, line: 13, type: !23, scopeLine: 13, flags: DIFlagPrototyped, spFlags: 0) !23 = !DISubroutineType(types: !24) !24 = !{null, !25} !25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !26 = !DIDerivedType(tag: DW_TAG_member, name: "tab", scope: !6, file: !3, line: 18, baseType: !27, size: 320, offset: 96) !27 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 320, elements: !28) !28 = !{!29} !29 = !DISubrange(count: 10) !30 = !{i32 2, !"Dwarf Version", i32 4} !31 = !{i32 2, !"Debug Info Version", i32 3} !32 = !{i32 1, !"wchar_size", i32 4} !33 = !{i32 7, !"PIC Level", i32 2} !34 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !35 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 23, type: !36, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !36 = !DISubroutineType(types: !37) !37 = !{!12} !38 = !DILocation(line: 24, column: 3, scope: !35) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/nested-struct.c000066400000000000000000000002411473507761200327140ustar00rootroot00000000000000#include struct Node { struct Node* next; }; int main(int argc, char* argv[]) { struct Node* node = malloc(sizeof(struct Node*)); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/nested-struct.ll000066400000000000000000000067311473507761200331130ustar00rootroot00000000000000; ModuleID = 'nested-struct.pp.bc' source_filename = "nested-struct.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: allocsize(0) declare i8* @malloc(i64) #1 ; CHECK: declare si8* @ar.libc.malloc(ui64) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 ret i32 0, !dbg !18 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { allocsize(0) "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "nested-struct.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !9, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 7, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 7, type: !12) !18 = !DILocation(line: 9, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/noexcept.cpp000066400000000000000000000000641473507761200323000ustar00rootroot00000000000000extern int f(); int g() noexcept { return f(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/noexcept.ll000066400000000000000000000105011473507761200321220ustar00rootroot00000000000000; ModuleID = 'noexcept.pp.bc' source_filename = "noexcept.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 declare i32 @_Z1fv() #1 ; CHECK: declare si32 @_Z1fv() ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1gv() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !8 { %1 = invoke i32 @_Z1fv() to label %2 unwind label %3, !dbg !12 2: ; preds = %0 ret i32 %1, !dbg !13 3: ; preds = %0 %4 = landingpad { i8*, i32 } catch i8* null, !dbg !12 %5 = extractvalue { i8*, i32 } %4, 0, !dbg !12 call void @__clang_call_terminate(i8* %5) #3, !dbg !12 unreachable, !dbg !12 } ; CHECK: define si32 @_Z1gv() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32 %1 = invoke @_Z1fv() normal=#2 exc=#3 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#unified-exit} { ; CHECK: return %1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#unified-exit} { ; CHECK: {0: si8*, 8: si32} %2 = landingpad ; CHECK: si8* %3 = extractelement %2, 0 ; CHECK: call @__clang_call_terminate(%3) ; CHECK: unreachable ; CHECK: } ; CHECK: #unified-exit !exit predecessors={#2, #3} { ; CHECK: } ; CHECK: } declare void @_ZSt9terminatev() ; CHECK: declare void @_ZSt9terminatev() ; Function Attrs: noinline noreturn nounwind define linkonce_odr hidden void @__clang_call_terminate(i8*) #2 { %2 = call i8* @__cxa_begin_catch(i8* %0) #4 call void @_ZSt9terminatev() #3 unreachable } ; CHECK: define void @__clang_call_terminate(si8* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si8* %2 = call @ar.libcpp.begincatch(%1) ; CHECK: call @_ZSt9terminatev() ; CHECK: unreachable ; CHECK: } ; CHECK: } declare i32 @__gxx_personality_v0(...) ; CHECK: declare si32 @__gxx_personality_v0(...) declare i8* @__cxa_begin_catch(i8*) ; CHECK: declare si8* @ar.libcpp.begincatch(si8*) attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { noinline noreturn nounwind } attributes #3 = { noreturn nounwind } attributes #4 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "noexcept.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "g", linkageName: "_Z1gv", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 4, column: 10, scope: !8) !13 = !DILocation(line: 4, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/non-term-1.c000066400000000000000000000001741473507761200320120ustar00rootroot00000000000000#include int main(int argc, char** argv) { int i; while (1) { if (i == 0) exit(1); i++; } } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/non-term-1.ll000066400000000000000000000117001473507761200321740ustar00rootroot00000000000000; ModuleID = 'non-term-1.pp.bc' source_filename = "non-term-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noreturn declare void @exit(i32) #1 ; CHECK: declare void @ar.libc.exit(si32) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 br label %3, !dbg !18 3: ; preds = %2, %6 %.0 = phi i32 [ undef, %2 ], [ %7, %6 ] call void @llvm.dbg.value(metadata i32 %.0, metadata !19, metadata !DIExpression()), !dbg !16 %4 = icmp eq i32 %.0, 0, !dbg !20 br i1 %4, label %5, label %6, !dbg !23 5: ; preds = %3 call void @exit(i32 1) #3, !dbg !24 unreachable, !dbg !24 6: ; preds = %3 %7 = add nsw i32 %.0, 1, !dbg !25 call void @llvm.dbg.value(metadata i32 %7, metadata !19, metadata !DIExpression()), !dbg !16 br label %3, !dbg !18, !llvm.loop !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32 %.0 = undef ; CHECK: } ; CHECK: #2 predecessors={#1, #4} successors={#3, #4} { ; CHECK: } ; CHECK: #3 !exit predecessors={#2} { ; CHECK: %.0 sieq 0 ; CHECK: call @ar.libc.exit(1) ; CHECK: unreachable ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#2} { ; CHECK: %.0 sine 0 ; CHECK: si32 %3 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %3 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noreturn "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } attributes #3 = { noreturn } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "non-term-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 3, type: !12) !18 = !DILocation(line: 5, column: 3, scope: !8) !19 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 4, type: !11) !20 = !DILocation(line: 6, column: 11, scope: !21) !21 = distinct !DILexicalBlock(scope: !22, file: !1, line: 6, column: 9) !22 = distinct !DILexicalBlock(scope: !8, file: !1, line: 5, column: 13) !23 = !DILocation(line: 6, column: 9, scope: !22) !24 = !DILocation(line: 7, column: 7, scope: !21) !25 = !DILocation(line: 8, column: 6, scope: !22) !26 = distinct !{!26, !18, !27} !27 = !DILocation(line: 9, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/non-term-2.c000066400000000000000000000001371473507761200320120ustar00rootroot00000000000000#include int main() { while (1) { printf("hello world\n"); } return 42; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/non-term-2.ll000066400000000000000000000067161473507761200322100ustar00rootroot00000000000000; ModuleID = 'non-term-2.pp.bc' source_filename = "non-term-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1 ; CHECK: define [13 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #1 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { br label %1, !dbg !12 1: ; preds = %0, %1 %2 = getelementptr inbounds [13 x i8], [13 x i8]* @.str, i64 0, i64 0, !dbg !13 %3 = call i32 (i8*, ...) @printf(i8* %2), !dbg !13 br label %1, !dbg !12, !llvm.loop !15 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2} { ; CHECK: } ; CHECK: #2 predecessors={#1, #2} successors={#2} { ; CHECK: si8* %1 = ptrshift @.str, 13 * 0, 1 * 0 ; CHECK: si32 %2 = call @ar.libc.printf(%1) ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "non-term-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 4, column: 3, scope: !8) !13 = !DILocation(line: 5, column: 5, scope: !14) !14 = distinct !DILexicalBlock(scope: !8, file: !1, line: 4, column: 13) !15 = distinct !{!15, !12, !16} !16 = !DILocation(line: 6, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/nullptr.cpp000066400000000000000000000001201473507761200321440ustar00rootroot00000000000000int f(decltype(nullptr) x) { return 1; } int main() { return f(nullptr); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/nullptr.ll000066400000000000000000000073631473507761200320110ustar00rootroot00000000000000; ModuleID = 'nullptr.pp.bc' source_filename = "nullptr.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fDn(i8*) #0 !dbg !8 { call void @llvm.dbg.value(metadata i8* %0, metadata !13, metadata !DIExpression()), !dbg !14 ret i32 1, !dbg !15 } ; CHECK: define si32 @_Z1fDn(si8* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #1 !dbg !16 { %1 = call i32 @_Z1fDn(i8* null), !dbg !19 ret i32 %1, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32 %1 = call @_Z1fDn(null) ; CHECK: return %1 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "nullptr.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fDn", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "decltype(nullptr)") !13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !12) !14 = !DILocation(line: 0, scope: !8) !15 = !DILocation(line: 2, column: 3, scope: !8) !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!11} !19 = !DILocation(line: 6, column: 10, scope: !16) !20 = !DILocation(line: 6, column: 3, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/opaque-struct.c000066400000000000000000000002011473507761200327200ustar00rootroot00000000000000#include struct X; typedef struct { int* a; struct X* b; } my_struct; my_struct s; int main() { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/opaque-struct.ll000066400000000000000000000063451473507761200331240ustar00rootroot00000000000000; ModuleID = 'opaque-struct.pp.bc' source_filename = "opaque-struct.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.my_struct = type { i32*, %struct.X* } %struct.X = type opaque @s = common global %struct.my_struct zeroinitializer, align 8, !dbg !0 ; CHECK: define {0: si32*, 8: opaque*}* @s, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @s, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "s", scope: !2, file: !3, line: 10, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "opaque-struct.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "my_struct", file: !3, line: 8, baseType: !7) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 5, size: 128, elements: !8) !8 = !{!9, !12} !9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 6, baseType: !10, size: 64) !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 7, baseType: !13, size: 64, offset: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !3, line: 3, flags: DIFlagFwdDecl) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 12, type: !21, scopeLine: 12, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!11} !23 = !DILocation(line: 13, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-1.c000066400000000000000000000001761473507761200310350ustar00rootroot00000000000000double a[10]; int main(int argc, char** argv) { int i; for (i = 0; i < 10; i++) { a[i] = i * 0.88; } a[i] = i; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-1.ll000066400000000000000000000146341473507761200312260ustar00rootroot00000000000000; ModuleID = 'phi-1.pp.bc' source_filename = "phi-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global [10 x double] zeroinitializer, align 16, !dbg !0 ; CHECK: define [10 x double]* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !15 { call void @llvm.dbg.value(metadata i32 %0, metadata !22, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i8** %1, metadata !24, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.value(metadata i32 0, metadata !25, metadata !DIExpression()), !dbg !23 br label %3, !dbg !26 3: ; preds = %10, %2 %.0 = phi i32 [ 0, %2 ], [ %11, %10 ], !dbg !28 call void @llvm.dbg.value(metadata i32 %.0, metadata !25, metadata !DIExpression()), !dbg !23 %4 = icmp slt i32 %.0, 10, !dbg !29 br i1 %4, label %5, label %12, !dbg !31 5: ; preds = %3 %6 = sitofp i32 %.0 to double, !dbg !32 %7 = fmul double %6, 8.800000e-01, !dbg !34 %8 = sext i32 %.0 to i64, !dbg !35 %9 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %8, !dbg !35 store double %7, double* %9, align 8, !dbg !36 br label %10, !dbg !37 10: ; preds = %5 %11 = add nsw i32 %.0, 1, !dbg !38 call void @llvm.dbg.value(metadata i32 %11, metadata !25, metadata !DIExpression()), !dbg !23 br label %3, !dbg !39, !llvm.loop !40 12: ; preds = %3 %13 = sitofp i32 %.0 to double, !dbg !42 %14 = sext i32 %.0 to i64, !dbg !43 %15 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %14, !dbg !43 store double %13, double* %15, align 8, !dbg !44 ret i32 0, !dbg !45 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %.0 silt 10 ; CHECK: double %3 = sitofp %.0 ; CHECK: double %4 = %3 fmul 8.8E-1 ; CHECK: si64 %5 = sext %.0 ; CHECK: double* %6 = ptrshift @a, 80 * 0, 8 * %5 ; CHECK: store %6, %4, align 8 ; CHECK: si32 %7 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %7 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %.0 sige 10 ; CHECK: double %8 = sitofp %.0 ; CHECK: si64 %9 = sext %.0 ; CHECK: double* %10 = ptrshift @a, 80 * 0, 8 * %9 ; CHECK: store %10, %8, align 8 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!10, !11, !12, !13} !llvm.ident = !{!14} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "phi-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 640, elements: !8) !7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 10) !10 = !{i32 2, !"Dwarf Version", i32 4} !11 = !{i32 2, !"Debug Info Version", i32 3} !12 = !{i32 1, !"wchar_size", i32 4} !13 = !{i32 7, !"PIC Level", i32 2} !14 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !15 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !16 = !DISubroutineType(types: !17) !17 = !{!18, !18, !19} !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !15, file: !3, line: 3, type: !18) !23 = !DILocation(line: 0, scope: !15) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !15, file: !3, line: 3, type: !19) !25 = !DILocalVariable(name: "i", scope: !15, file: !3, line: 4, type: !18) !26 = !DILocation(line: 5, column: 8, scope: !27) !27 = distinct !DILexicalBlock(scope: !15, file: !3, line: 5, column: 3) !28 = !DILocation(line: 0, scope: !27) !29 = !DILocation(line: 5, column: 17, scope: !30) !30 = distinct !DILexicalBlock(scope: !27, file: !3, line: 5, column: 3) !31 = !DILocation(line: 5, column: 3, scope: !27) !32 = !DILocation(line: 6, column: 12, scope: !33) !33 = distinct !DILexicalBlock(scope: !30, file: !3, line: 5, column: 28) !34 = !DILocation(line: 6, column: 14, scope: !33) !35 = !DILocation(line: 6, column: 5, scope: !33) !36 = !DILocation(line: 6, column: 10, scope: !33) !37 = !DILocation(line: 7, column: 3, scope: !33) !38 = !DILocation(line: 5, column: 24, scope: !30) !39 = !DILocation(line: 5, column: 3, scope: !30) !40 = distinct !{!40, !31, !41} !41 = !DILocation(line: 7, column: 3, scope: !27) !42 = !DILocation(line: 8, column: 10, scope: !15) !43 = !DILocation(line: 8, column: 3, scope: !15) !44 = !DILocation(line: 8, column: 8, scope: !15) !45 = !DILocation(line: 9, column: 1, scope: !15) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-2.c000066400000000000000000000010751473507761200310350ustar00rootroot00000000000000// SAFE #include #define MAX_ARRAY 10 struct bar { int x; float y; }; struct foo { int x; struct bar y; int a[MAX_ARRAY][MAX_ARRAY][MAX_ARRAY - 1]; }; // To test loops int main(int argc, char** argv) { int i, j, k; struct foo x; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) { for (k = 0; k < MAX_ARRAY - 1; k++) { x.a[i][j][k] = argc; // some unknown value here x.y.x = x.a[i][j][k]; } } } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", x.a[i][i][i - 1]); } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-2.ll000066400000000000000000000410021473507761200312140ustar00rootroot00000000000000; ModuleID = 'phi-2.pp.bc' source_filename = "phi-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.foo = type { i32, %struct.bar, [10 x [10 x [9 x i32]]] } %struct.bar = type { i32, float } @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca %struct.foo, align 4 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata %struct.foo* %3, metadata !18, metadata !DIExpression()), !dbg !33 call void @llvm.dbg.value(metadata i32 0, metadata !34, metadata !DIExpression()), !dbg !16 br label %4, !dbg !35 4: ; preds = %36, %2 %.02 = phi i32 [ 0, %2 ], [ %37, %36 ], !dbg !37 call void @llvm.dbg.value(metadata i32 %.02, metadata !34, metadata !DIExpression()), !dbg !16 %5 = icmp slt i32 %.02, 10, !dbg !38 br i1 %5, label %6, label %38, !dbg !40 6: ; preds = %4 call void @llvm.dbg.value(metadata i32 0, metadata !41, metadata !DIExpression()), !dbg !16 br label %7, !dbg !42 7: ; preds = %33, %6 %.01 = phi i32 [ 0, %6 ], [ %34, %33 ], !dbg !45 call void @llvm.dbg.value(metadata i32 %.01, metadata !41, metadata !DIExpression()), !dbg !16 %8 = icmp slt i32 %.01, 10, !dbg !46 br i1 %8, label %9, label %35, !dbg !48 9: ; preds = %7 call void @llvm.dbg.value(metadata i32 0, metadata !49, metadata !DIExpression()), !dbg !16 br label %10, !dbg !50 10: ; preds = %30, %9 %.0 = phi i32 [ 0, %9 ], [ %31, %30 ], !dbg !53 call void @llvm.dbg.value(metadata i32 %.0, metadata !49, metadata !DIExpression()), !dbg !16 %11 = icmp slt i32 %.0, 9, !dbg !54 br i1 %11, label %12, label %32, !dbg !56 12: ; preds = %10 %13 = getelementptr inbounds %struct.foo, %struct.foo* %3, i32 0, i32 2, !dbg !57 %14 = sext i32 %.02 to i64, !dbg !59 %15 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %13, i64 0, i64 %14, !dbg !59 %16 = sext i32 %.01 to i64, !dbg !59 %17 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %15, i64 0, i64 %16, !dbg !59 %18 = sext i32 %.0 to i64, !dbg !59 %19 = getelementptr inbounds [9 x i32], [9 x i32]* %17, i64 0, i64 %18, !dbg !59 store i32 %0, i32* %19, align 4, !dbg !60 %20 = getelementptr inbounds %struct.foo, %struct.foo* %3, i32 0, i32 2, !dbg !61 %21 = sext i32 %.02 to i64, !dbg !62 %22 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %20, i64 0, i64 %21, !dbg !62 %23 = sext i32 %.01 to i64, !dbg !62 %24 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %22, i64 0, i64 %23, !dbg !62 %25 = sext i32 %.0 to i64, !dbg !62 %26 = getelementptr inbounds [9 x i32], [9 x i32]* %24, i64 0, i64 %25, !dbg !62 %27 = load i32, i32* %26, align 4, !dbg !62 %28 = getelementptr inbounds %struct.foo, %struct.foo* %3, i32 0, i32 1, !dbg !63 %29 = getelementptr inbounds %struct.bar, %struct.bar* %28, i32 0, i32 0, !dbg !64 store i32 %27, i32* %29, align 4, !dbg !65 br label %30, !dbg !66 30: ; preds = %12 %31 = add nsw i32 %.0, 1, !dbg !67 call void @llvm.dbg.value(metadata i32 %31, metadata !49, metadata !DIExpression()), !dbg !16 br label %10, !dbg !68, !llvm.loop !69 32: ; preds = %10 br label %33, !dbg !71 33: ; preds = %32 %34 = add nsw i32 %.01, 1, !dbg !72 call void @llvm.dbg.value(metadata i32 %34, metadata !41, metadata !DIExpression()), !dbg !16 br label %7, !dbg !73, !llvm.loop !74 35: ; preds = %7 br label %36, !dbg !76 36: ; preds = %35 %37 = add nsw i32 %.02, 1, !dbg !77 call void @llvm.dbg.value(metadata i32 %37, metadata !34, metadata !DIExpression()), !dbg !16 br label %4, !dbg !78, !llvm.loop !79 38: ; preds = %4 call void @llvm.dbg.value(metadata i32 0, metadata !34, metadata !DIExpression()), !dbg !16 br label %39, !dbg !81 39: ; preds = %53, %38 %.1 = phi i32 [ 0, %38 ], [ %54, %53 ], !dbg !83 call void @llvm.dbg.value(metadata i32 %.1, metadata !34, metadata !DIExpression()), !dbg !16 %40 = icmp slt i32 %.1, 10, !dbg !84 br i1 %40, label %41, label %55, !dbg !86 41: ; preds = %39 %42 = getelementptr inbounds %struct.foo, %struct.foo* %3, i32 0, i32 2, !dbg !87 %43 = sext i32 %.1 to i64, !dbg !89 %44 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %42, i64 0, i64 %43, !dbg !89 %45 = sext i32 %.1 to i64, !dbg !89 %46 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %44, i64 0, i64 %45, !dbg !89 %47 = sub nsw i32 %.1, 1, !dbg !90 %48 = sext i32 %47 to i64, !dbg !89 %49 = getelementptr inbounds [9 x i32], [9 x i32]* %46, i64 0, i64 %48, !dbg !89 %50 = load i32, i32* %49, align 4, !dbg !89 %51 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !91 %52 = call i32 (i8*, ...) @printf(i8* %51, i32 %50), !dbg !91 br label %53, !dbg !92 53: ; preds = %41 %54 = add nsw i32 %.1, 1, !dbg !93 call void @llvm.dbg.value(metadata i32 %54, metadata !34, metadata !DIExpression()), !dbg !16 br label %39, !dbg !94, !llvm.loop !95 55: ; preds = %39 ret i32 0, !dbg !97 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: {0: si32, 4: {0: si32, 4: float}, 12: [10 x [10 x [9 x si32]]]}* $3 = allocate {0: si32, 4: {0: si32, 4: float}, 12: [10 x [10 x [9 x si32]]]}, 1, align 4 ; CHECK: si32 %.02 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #8} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#5} { ; CHECK: %.02 silt 10 ; CHECK: si32 %.01 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#6} { ; CHECK: %.02 sige 10 ; CHECK: si32 %.1 = 0 ; CHECK: } ; CHECK: #5 predecessors={#3, #13} successors={#7, #8} { ; CHECK: } ; CHECK: #7 predecessors={#5} successors={#11} { ; CHECK: %.01 silt 10 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #8 predecessors={#5} successors={#2} { ; CHECK: %.01 sige 10 ; CHECK: si32 %4 = %.02 sadd.nw 1 ; CHECK: si32 %.02 = %4 ; CHECK: } ; CHECK: #6 predecessors={#4, #9} successors={#9, #10} { ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#6} { ; CHECK: %.1 silt 10 ; CHECK: [10 x [10 x [9 x si32]]]* %5 = ptrshift $3, 3612 * 0, 1 * 12 ; CHECK: si64 %6 = sext %.1 ; CHECK: [10 x [9 x si32]]* %7 = ptrshift %5, 3600 * 0, 360 * %6 ; CHECK: si64 %8 = sext %.1 ; CHECK: [9 x si32]* %9 = ptrshift %7, 360 * 0, 36 * %8 ; CHECK: si32 %10 = %.1 ssub.nw 1 ; CHECK: si64 %11 = sext %10 ; CHECK: si32* %12 = ptrshift %9, 36 * 0, 4 * %11 ; CHECK: si32 %13 = load %12, align 4 ; CHECK: si8* %14 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %15 = call @ar.libc.printf(%14, %13) ; CHECK: si32 %16 = %.1 sadd.nw 1 ; CHECK: si32 %.1 = %16 ; CHECK: } ; CHECK: #10 !exit predecessors={#6} { ; CHECK: %.1 sige 10 ; CHECK: return 0 ; CHECK: } ; CHECK: #11 predecessors={#7, #12} successors={#12, #13} { ; CHECK: } ; CHECK: #12 predecessors={#11} successors={#11} { ; CHECK: %.0 silt 9 ; CHECK: [10 x [10 x [9 x si32]]]* %17 = ptrshift $3, 3612 * 0, 1 * 12 ; CHECK: si64 %18 = sext %.02 ; CHECK: [10 x [9 x si32]]* %19 = ptrshift %17, 3600 * 0, 360 * %18 ; CHECK: si64 %20 = sext %.01 ; CHECK: [9 x si32]* %21 = ptrshift %19, 360 * 0, 36 * %20 ; CHECK: si64 %22 = sext %.0 ; CHECK: si32* %23 = ptrshift %21, 36 * 0, 4 * %22 ; CHECK: store %23, %1, align 4 ; CHECK: [10 x [10 x [9 x si32]]]* %24 = ptrshift $3, 3612 * 0, 1 * 12 ; CHECK: si64 %25 = sext %.02 ; CHECK: [10 x [9 x si32]]* %26 = ptrshift %24, 3600 * 0, 360 * %25 ; CHECK: si64 %27 = sext %.01 ; CHECK: [9 x si32]* %28 = ptrshift %26, 360 * 0, 36 * %27 ; CHECK: si64 %29 = sext %.0 ; CHECK: si32* %30 = ptrshift %28, 36 * 0, 4 * %29 ; CHECK: si32 %31 = load %30, align 4 ; CHECK: {0: si32, 4: float}* %32 = ptrshift $3, 3612 * 0, 1 * 4 ; CHECK: si32* %33 = ptrshift %32, 8 * 0, 1 * 0 ; CHECK: store %33, %31, align 4 ; CHECK: si32 %34 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %34 ; CHECK: } ; CHECK: #13 predecessors={#11} successors={#5} { ; CHECK: %.0 sige 9 ; CHECK: si32 %35 = %.01 sadd.nw 1 ; CHECK: si32 %.01 = %35 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 18, type: !9, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 18, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 18, type: !12) !18 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 20, type: !19) !19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 11, size: 28896, elements: !20) !20 = !{!21, !22, !28} !21 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !19, file: !1, line: 12, baseType: !11, size: 32) !22 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !19, file: !1, line: 13, baseType: !23, size: 64, offset: 32) !23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !1, line: 6, size: 64, elements: !24) !24 = !{!25, !26} !25 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !23, file: !1, line: 7, baseType: !11, size: 32) !26 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !23, file: !1, line: 8, baseType: !27, size: 32, offset: 32) !27 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !28 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !19, file: !1, line: 14, baseType: !29, size: 28800, offset: 96) !29 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 28800, elements: !30) !30 = !{!31, !31, !32} !31 = !DISubrange(count: 10) !32 = !DISubrange(count: 9) !33 = !DILocation(line: 20, column: 14, scope: !8) !34 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 19, type: !11) !35 = !DILocation(line: 21, column: 8, scope: !36) !36 = distinct !DILexicalBlock(scope: !8, file: !1, line: 21, column: 3) !37 = !DILocation(line: 0, scope: !36) !38 = !DILocation(line: 21, column: 17, scope: !39) !39 = distinct !DILexicalBlock(scope: !36, file: !1, line: 21, column: 3) !40 = !DILocation(line: 21, column: 3, scope: !36) !41 = !DILocalVariable(name: "j", scope: !8, file: !1, line: 19, type: !11) !42 = !DILocation(line: 22, column: 10, scope: !43) !43 = distinct !DILexicalBlock(scope: !44, file: !1, line: 22, column: 5) !44 = distinct !DILexicalBlock(scope: !39, file: !1, line: 21, column: 35) !45 = !DILocation(line: 0, scope: !43) !46 = !DILocation(line: 22, column: 19, scope: !47) !47 = distinct !DILexicalBlock(scope: !43, file: !1, line: 22, column: 5) !48 = !DILocation(line: 22, column: 5, scope: !43) !49 = !DILocalVariable(name: "k", scope: !8, file: !1, line: 19, type: !11) !50 = !DILocation(line: 23, column: 12, scope: !51) !51 = distinct !DILexicalBlock(scope: !52, file: !1, line: 23, column: 7) !52 = distinct !DILexicalBlock(scope: !47, file: !1, line: 22, column: 37) !53 = !DILocation(line: 0, scope: !51) !54 = !DILocation(line: 23, column: 21, scope: !55) !55 = distinct !DILexicalBlock(scope: !51, file: !1, line: 23, column: 7) !56 = !DILocation(line: 23, column: 7, scope: !51) !57 = !DILocation(line: 24, column: 11, scope: !58) !58 = distinct !DILexicalBlock(scope: !55, file: !1, line: 23, column: 43) !59 = !DILocation(line: 24, column: 9, scope: !58) !60 = !DILocation(line: 24, column: 22, scope: !58) !61 = !DILocation(line: 25, column: 19, scope: !58) !62 = !DILocation(line: 25, column: 17, scope: !58) !63 = !DILocation(line: 25, column: 11, scope: !58) !64 = !DILocation(line: 25, column: 13, scope: !58) !65 = !DILocation(line: 25, column: 15, scope: !58) !66 = !DILocation(line: 26, column: 7, scope: !58) !67 = !DILocation(line: 23, column: 39, scope: !55) !68 = !DILocation(line: 23, column: 7, scope: !55) !69 = distinct !{!69, !56, !70} !70 = !DILocation(line: 26, column: 7, scope: !51) !71 = !DILocation(line: 27, column: 5, scope: !52) !72 = !DILocation(line: 22, column: 33, scope: !47) !73 = !DILocation(line: 22, column: 5, scope: !47) !74 = distinct !{!74, !48, !75} !75 = !DILocation(line: 27, column: 5, scope: !43) !76 = !DILocation(line: 28, column: 3, scope: !44) !77 = !DILocation(line: 21, column: 31, scope: !39) !78 = !DILocation(line: 21, column: 3, scope: !39) !79 = distinct !{!79, !40, !80} !80 = !DILocation(line: 28, column: 3, scope: !36) !81 = !DILocation(line: 30, column: 8, scope: !82) !82 = distinct !DILexicalBlock(scope: !8, file: !1, line: 30, column: 3) !83 = !DILocation(line: 0, scope: !82) !84 = !DILocation(line: 30, column: 17, scope: !85) !85 = distinct !DILexicalBlock(scope: !82, file: !1, line: 30, column: 3) !86 = !DILocation(line: 30, column: 3, scope: !82) !87 = !DILocation(line: 31, column: 22, scope: !88) !88 = distinct !DILexicalBlock(scope: !85, file: !1, line: 30, column: 35) !89 = !DILocation(line: 31, column: 20, scope: !88) !90 = !DILocation(line: 31, column: 32, scope: !88) !91 = !DILocation(line: 31, column: 5, scope: !88) !92 = !DILocation(line: 32, column: 3, scope: !88) !93 = !DILocation(line: 30, column: 31, scope: !85) !94 = !DILocation(line: 30, column: 3, scope: !85) !95 = distinct !{!95, !86, !96} !96 = !DILocation(line: 32, column: 3, scope: !82) !97 = !DILocation(line: 34, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-3.c000066400000000000000000000010271473507761200310330ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); int foo(int* a, int* b, int* c) { int* p; int* q; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } __ikos_assert(*p == 3); __ikos_assert(*q == 6); int res = c[*p + *q]; c[*p + *q] = 555; return res; } int main(int argc, char** argv) { int a[2]; int b[3]; int c[10]; c[9] = 666; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 5; b[2] = 6; int x = foo(a, b, c); __ikos_assert(x == 666); __ikos_assert(c[9] == 555); return x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-3.ll000066400000000000000000000364621473507761200312330ustar00rootroot00000000000000; ModuleID = 'phi-3.pp.bc' source_filename = "phi-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 declare void @__ikos_assert(i32) #2 ; CHECK: declare void @ar.ikos.assert(ui32) ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32*, i32*, i32*) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32* %0, metadata !13, metadata !DIExpression()), !dbg !14 call void @llvm.dbg.value(metadata i32* %1, metadata !15, metadata !DIExpression()), !dbg !14 call void @llvm.dbg.value(metadata i32* %2, metadata !16, metadata !DIExpression()), !dbg !14 %4 = getelementptr inbounds i32, i32* %0, i64 1, !dbg !17 call void @llvm.dbg.value(metadata i32* %4, metadata !18, metadata !DIExpression()), !dbg !14 %5 = getelementptr inbounds i32, i32* %1, i64 2, !dbg !19 call void @llvm.dbg.value(metadata i32* %5, metadata !20, metadata !DIExpression()), !dbg !14 %6 = icmp eq i32* %4, %5, !dbg !21 br i1 %6, label %7, label %10, !dbg !23 7: ; preds = %3 %8 = getelementptr inbounds i32, i32* %5, i64 -10, !dbg !24 call void @llvm.dbg.value(metadata i32* %8, metadata !20, metadata !DIExpression()), !dbg !14 %9 = getelementptr inbounds i32, i32* %4, i64 42, !dbg !26 call void @llvm.dbg.value(metadata i32* %9, metadata !18, metadata !DIExpression()), !dbg !14 br label %10, !dbg !27 10: ; preds = %7, %3 %.01 = phi i32* [ %9, %7 ], [ %4, %3 ], !dbg !14 %.0 = phi i32* [ %8, %7 ], [ %5, %3 ], !dbg !14 call void @llvm.dbg.value(metadata i32* %.0, metadata !20, metadata !DIExpression()), !dbg !14 call void @llvm.dbg.value(metadata i32* %.01, metadata !18, metadata !DIExpression()), !dbg !14 %11 = load i32, i32* %.01, align 4, !dbg !28 %12 = icmp eq i32 %11, 3, !dbg !29 %13 = zext i1 %12 to i32, !dbg !29 call void @__ikos_assert(i32 %13), !dbg !30 %14 = load i32, i32* %.0, align 4, !dbg !31 %15 = icmp eq i32 %14, 6, !dbg !32 %16 = zext i1 %15 to i32, !dbg !32 call void @__ikos_assert(i32 %16), !dbg !33 %17 = load i32, i32* %.01, align 4, !dbg !34 %18 = load i32, i32* %.0, align 4, !dbg !35 %19 = add nsw i32 %17, %18, !dbg !36 %20 = sext i32 %19 to i64, !dbg !37 %21 = getelementptr inbounds i32, i32* %2, i64 %20, !dbg !37 %22 = load i32, i32* %21, align 4, !dbg !37 call void @llvm.dbg.value(metadata i32 %22, metadata !38, metadata !DIExpression()), !dbg !14 %23 = load i32, i32* %.01, align 4, !dbg !39 %24 = load i32, i32* %.0, align 4, !dbg !40 %25 = add nsw i32 %23, %24, !dbg !41 %26 = sext i32 %25 to i64, !dbg !42 %27 = getelementptr inbounds i32, i32* %2, i64 %26, !dbg !42 store i32 555, i32* %27, align 4, !dbg !43 ret i32 %22, !dbg !44 } ; CHECK: define si32 @foo(si32* %1, si32* %2, si32* %3) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* %4 = ptrshift %1, 4 * 1 ; CHECK: si32* %5 = ptrshift %2, 4 * 2 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %4 peq %5 ; CHECK: si32* %6 = ptrshift %5, 4 * -10 ; CHECK: si32* %7 = ptrshift %4, 4 * 42 ; CHECK: si32* %.01 = %7 ; CHECK: si32* %.0 = %6 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %4 pne %5 ; CHECK: si32* %.01 = %4 ; CHECK: si32* %.0 = %5 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5, #6} { ; CHECK: si32 %8 = load %.01, align 4 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %8 sieq 3 ; CHECK: ui1 %9 = 1 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %8 sine 3 ; CHECK: ui1 %9 = 0 ; CHECK: } ; CHECK: #7 predecessors={#5, #6} successors={#8, #9} { ; CHECK: ui32 %10 = zext %9 ; CHECK: call @ar.ikos.assert(%10) ; CHECK: si32 %11 = load %.0, align 4 ; CHECK: } ; CHECK: #8 predecessors={#7} successors={#10} { ; CHECK: %11 sieq 6 ; CHECK: ui1 %12 = 1 ; CHECK: } ; CHECK: #9 predecessors={#7} successors={#10} { ; CHECK: %11 sine 6 ; CHECK: ui1 %12 = 0 ; CHECK: } ; CHECK: #10 !exit predecessors={#8, #9} { ; CHECK: ui32 %13 = zext %12 ; CHECK: call @ar.ikos.assert(%13) ; CHECK: si32 %14 = load %.01, align 4 ; CHECK: si32 %15 = load %.0, align 4 ; CHECK: si32 %16 = %14 sadd.nw %15 ; CHECK: si64 %17 = sext %16 ; CHECK: si32* %18 = ptrshift %3, 4 * %17 ; CHECK: si32 %19 = load %18, align 4 ; CHECK: si32 %20 = load %.01, align 4 ; CHECK: si32 %21 = load %.0, align 4 ; CHECK: si32 %22 = %20 sadd.nw %21 ; CHECK: si64 %23 = sext %22 ; CHECK: si32* %24 = ptrshift %3, 4 * %23 ; CHECK: store %24, 555, align 4 ; CHECK: return %19 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !45 { %3 = alloca [2 x i32], align 4 %4 = alloca [3 x i32], align 4 %5 = alloca [10 x i32], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !51, metadata !DIExpression()), !dbg !52 call void @llvm.dbg.value(metadata i8** %1, metadata !53, metadata !DIExpression()), !dbg !52 call void @llvm.dbg.declare(metadata [2 x i32]* %3, metadata !54, metadata !DIExpression()), !dbg !58 call void @llvm.dbg.declare(metadata [3 x i32]* %4, metadata !59, metadata !DIExpression()), !dbg !63 call void @llvm.dbg.declare(metadata [10 x i32]* %5, metadata !64, metadata !DIExpression()), !dbg !68 %6 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i64 0, i64 9, !dbg !69 store i32 666, i32* %6, align 4, !dbg !70 %7 = getelementptr inbounds [2 x i32], [2 x i32]* %3, i64 0, i64 0, !dbg !71 store i32 1, i32* %7, align 4, !dbg !72 %8 = getelementptr inbounds [2 x i32], [2 x i32]* %3, i64 0, i64 1, !dbg !73 store i32 3, i32* %8, align 4, !dbg !74 %9 = getelementptr inbounds [3 x i32], [3 x i32]* %4, i64 0, i64 0, !dbg !75 store i32 4, i32* %9, align 4, !dbg !76 %10 = getelementptr inbounds [3 x i32], [3 x i32]* %4, i64 0, i64 1, !dbg !77 store i32 5, i32* %10, align 4, !dbg !78 %11 = getelementptr inbounds [3 x i32], [3 x i32]* %4, i64 0, i64 2, !dbg !79 store i32 6, i32* %11, align 4, !dbg !80 %12 = getelementptr inbounds [2 x i32], [2 x i32]* %3, i64 0, i64 0, !dbg !81 %13 = getelementptr inbounds [3 x i32], [3 x i32]* %4, i64 0, i64 0, !dbg !82 %14 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i64 0, i64 0, !dbg !83 %15 = call i32 @foo(i32* %12, i32* %13, i32* %14), !dbg !84 call void @llvm.dbg.value(metadata i32 %15, metadata !85, metadata !DIExpression()), !dbg !52 %16 = icmp eq i32 %15, 666, !dbg !86 %17 = zext i1 %16 to i32, !dbg !86 call void @__ikos_assert(i32 %17), !dbg !87 %18 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i64 0, i64 9, !dbg !88 %19 = load i32, i32* %18, align 4, !dbg !88 %20 = icmp eq i32 %19, 555, !dbg !89 %21 = zext i1 %20 to i32, !dbg !89 call void @__ikos_assert(i32 %21), !dbg !90 ret i32 %15, !dbg !91 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: [2 x si32]* $3 = allocate [2 x si32], 1, align 4 ; CHECK: [3 x si32]* $4 = allocate [3 x si32], 1, align 4 ; CHECK: [10 x si32]* $5 = allocate [10 x si32], 1, align 16 ; CHECK: si32* %6 = ptrshift $5, 40 * 0, 4 * 9 ; CHECK: store %6, 666, align 4 ; CHECK: si32* %7 = ptrshift $3, 8 * 0, 4 * 0 ; CHECK: store %7, 1, align 4 ; CHECK: si32* %8 = ptrshift $3, 8 * 0, 4 * 1 ; CHECK: store %8, 3, align 4 ; CHECK: si32* %9 = ptrshift $4, 12 * 0, 4 * 0 ; CHECK: store %9, 4, align 4 ; CHECK: si32* %10 = ptrshift $4, 12 * 0, 4 * 1 ; CHECK: store %10, 5, align 4 ; CHECK: si32* %11 = ptrshift $4, 12 * 0, 4 * 2 ; CHECK: store %11, 6, align 4 ; CHECK: si32* %12 = ptrshift $3, 8 * 0, 4 * 0 ; CHECK: si32* %13 = ptrshift $4, 12 * 0, 4 * 0 ; CHECK: si32* %14 = ptrshift $5, 40 * 0, 4 * 0 ; CHECK: si32 %15 = call @foo(%12, %13, %14) ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %15 sieq 666 ; CHECK: ui1 %16 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %15 sine 666 ; CHECK: ui1 %16 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5, #6} { ; CHECK: ui32 %17 = zext %16 ; CHECK: call @ar.ikos.assert(%17) ; CHECK: si32* %18 = ptrshift $5, 40 * 0, 4 * 9 ; CHECK: si32 %19 = load %18, align 4 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %19 sieq 555 ; CHECK: ui1 %20 = 1 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %19 sine 555 ; CHECK: ui1 %20 = 0 ; CHECK: } ; CHECK: #7 !exit predecessors={#5, #6} { ; CHECK: ui32 %21 = zext %20 ; CHECK: call @ar.ikos.assert(%21) ; CHECK: return %15 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, type: !9, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12, !12, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 5, type: !12) !14 = !DILocation(line: 0, scope: !8) !15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 5, type: !12) !16 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 5, type: !12) !17 = !DILocation(line: 9, column: 9, scope: !8) !18 = !DILocalVariable(name: "p", scope: !8, file: !1, line: 6, type: !12) !19 = !DILocation(line: 10, column: 9, scope: !8) !20 = !DILocalVariable(name: "q", scope: !8, file: !1, line: 7, type: !12) !21 = !DILocation(line: 12, column: 9, scope: !22) !22 = distinct !DILexicalBlock(scope: !8, file: !1, line: 12, column: 7) !23 = !DILocation(line: 12, column: 7, scope: !8) !24 = !DILocation(line: 13, column: 11, scope: !25) !25 = distinct !DILexicalBlock(scope: !22, file: !1, line: 12, column: 15) !26 = !DILocation(line: 14, column: 11, scope: !25) !27 = !DILocation(line: 15, column: 3, scope: !25) !28 = !DILocation(line: 16, column: 17, scope: !8) !29 = !DILocation(line: 16, column: 20, scope: !8) !30 = !DILocation(line: 16, column: 3, scope: !8) !31 = !DILocation(line: 17, column: 17, scope: !8) !32 = !DILocation(line: 17, column: 20, scope: !8) !33 = !DILocation(line: 17, column: 3, scope: !8) !34 = !DILocation(line: 19, column: 15, scope: !8) !35 = !DILocation(line: 19, column: 20, scope: !8) !36 = !DILocation(line: 19, column: 18, scope: !8) !37 = !DILocation(line: 19, column: 13, scope: !8) !38 = !DILocalVariable(name: "res", scope: !8, file: !1, line: 19, type: !11) !39 = !DILocation(line: 20, column: 5, scope: !8) !40 = !DILocation(line: 20, column: 10, scope: !8) !41 = !DILocation(line: 20, column: 8, scope: !8) !42 = !DILocation(line: 20, column: 3, scope: !8) !43 = !DILocation(line: 20, column: 14, scope: !8) !44 = !DILocation(line: 21, column: 3, scope: !8) !45 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 24, type: !46, scopeLine: 24, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !46 = !DISubroutineType(types: !47) !47 = !{!11, !11, !48} !48 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !49, size: 64) !49 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !50, size: 64) !50 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !51 = !DILocalVariable(name: "argc", arg: 1, scope: !45, file: !1, line: 24, type: !11) !52 = !DILocation(line: 0, scope: !45) !53 = !DILocalVariable(name: "argv", arg: 2, scope: !45, file: !1, line: 24, type: !48) !54 = !DILocalVariable(name: "a", scope: !45, file: !1, line: 25, type: !55) !55 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 64, elements: !56) !56 = !{!57} !57 = !DISubrange(count: 2) !58 = !DILocation(line: 25, column: 7, scope: !45) !59 = !DILocalVariable(name: "b", scope: !45, file: !1, line: 26, type: !60) !60 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 96, elements: !61) !61 = !{!62} !62 = !DISubrange(count: 3) !63 = !DILocation(line: 26, column: 7, scope: !45) !64 = !DILocalVariable(name: "c", scope: !45, file: !1, line: 27, type: !65) !65 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !66) !66 = !{!67} !67 = !DISubrange(count: 10) !68 = !DILocation(line: 27, column: 7, scope: !45) !69 = !DILocation(line: 29, column: 3, scope: !45) !70 = !DILocation(line: 29, column: 8, scope: !45) !71 = !DILocation(line: 31, column: 3, scope: !45) !72 = !DILocation(line: 31, column: 8, scope: !45) !73 = !DILocation(line: 32, column: 3, scope: !45) !74 = !DILocation(line: 32, column: 8, scope: !45) !75 = !DILocation(line: 34, column: 3, scope: !45) !76 = !DILocation(line: 34, column: 8, scope: !45) !77 = !DILocation(line: 35, column: 3, scope: !45) !78 = !DILocation(line: 35, column: 8, scope: !45) !79 = !DILocation(line: 36, column: 3, scope: !45) !80 = !DILocation(line: 36, column: 8, scope: !45) !81 = !DILocation(line: 38, column: 15, scope: !45) !82 = !DILocation(line: 38, column: 18, scope: !45) !83 = !DILocation(line: 38, column: 21, scope: !45) !84 = !DILocation(line: 38, column: 11, scope: !45) !85 = !DILocalVariable(name: "x", scope: !45, file: !1, line: 38, type: !11) !86 = !DILocation(line: 40, column: 19, scope: !45) !87 = !DILocation(line: 40, column: 3, scope: !45) !88 = !DILocation(line: 41, column: 17, scope: !45) !89 = !DILocation(line: 41, column: 22, scope: !45) !90 = !DILocation(line: 41, column: 3, scope: !45) !91 = !DILocation(line: 42, column: 3, scope: !45) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-4.cpp000066400000000000000000000002741473507761200313770ustar00rootroot00000000000000int main(int argc, char** argv) { int i = 0, a[10]; bool flag = argc % 5 == 0; for (; i < 10; i++) { if (flag) a[i] = i ^ 2; else a[i] = i * 2; } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/phi-4.ll000066400000000000000000000172541473507761200312320ustar00rootroot00000000000000; ModuleID = 'phi-4.pp.bc' source_filename = "phi-4.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca [10 x i32], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 0, metadata !18, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata [10 x i32]* %3, metadata !19, metadata !DIExpression()), !dbg !23 %4 = srem i32 %0, 5, !dbg !24 %5 = icmp eq i32 %4, 0, !dbg !25 %6 = zext i1 %5 to i8, !dbg !26 call void @llvm.dbg.value(metadata i8 %6, metadata !27, metadata !DIExpression()), !dbg !16 br label %7, !dbg !29 7: ; preds = %20, %2 %.0 = phi i32 [ 0, %2 ], [ %21, %20 ], !dbg !16 call void @llvm.dbg.value(metadata i32 %.0, metadata !18, metadata !DIExpression()), !dbg !16 %8 = icmp slt i32 %.0, 10, !dbg !30 br i1 %8, label %9, label %22, !dbg !33 9: ; preds = %7 %10 = trunc i8 %6 to i1, !dbg !34 br i1 %10, label %11, label %15, !dbg !37 11: ; preds = %9 %12 = xor i32 %.0, 2, !dbg !38 %13 = sext i32 %.0 to i64, !dbg !39 %14 = getelementptr inbounds [10 x i32], [10 x i32]* %3, i64 0, i64 %13, !dbg !39 store i32 %12, i32* %14, align 4, !dbg !40 br label %19, !dbg !39 15: ; preds = %9 %16 = mul nsw i32 %.0, 2, !dbg !41 %17 = sext i32 %.0 to i64, !dbg !42 %18 = getelementptr inbounds [10 x i32], [10 x i32]* %3, i64 0, i64 %17, !dbg !42 store i32 %16, i32* %18, align 4, !dbg !43 br label %19 19: ; preds = %15, %11 br label %20, !dbg !44 20: ; preds = %19 %21 = add nsw i32 %.0, 1, !dbg !45 call void @llvm.dbg.value(metadata i32 %21, metadata !18, metadata !DIExpression()), !dbg !16 br label %7, !dbg !46, !llvm.loop !47 22: ; preds = %7 ret i32 0, !dbg !49 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: [10 x si32]* $3 = allocate [10 x si32], 1, align 16 ; CHECK: si32 %4 = %1 srem 5 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %4 sieq 0 ; CHECK: ui1 %5 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %4 sine 0 ; CHECK: ui1 %5 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5} { ; CHECK: ui8 %6 = zext %5 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #5 predecessors={#4, #10} successors={#6, #7} { ; CHECK: } ; CHECK: #6 predecessors={#5} successors={#8, #9} { ; CHECK: %.0 silt 10 ; CHECK: ui1 %7 = utrunc %6 ; CHECK: } ; CHECK: #7 !exit predecessors={#5} { ; CHECK: %.0 sige 10 ; CHECK: return 0 ; CHECK: } ; CHECK: #8 predecessors={#6} successors={#10} { ; CHECK: si32 %8 = %.0 sxor 2 ; CHECK: si64 %9 = sext %.0 ; CHECK: si32* %10 = ptrshift $3, 40 * 0, 4 * %9 ; CHECK: store %10, %8, align 4 ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#10} { ; CHECK: si32 %11 = %.0 smul.nw 2 ; CHECK: si64 %12 = sext %.0 ; CHECK: si32* %13 = ptrshift $3, 40 * 0, 4 * %12 ; CHECK: store %13, %11, align 4 ; CHECK: } ; CHECK: #10 predecessors={#8, #9} successors={#5} { ; CHECK: si32 %14 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %14 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-4.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 1, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 1, type: !12) !18 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 2, type: !11) !19 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 2, type: !20) !20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !21) !21 = !{!22} !22 = !DISubrange(count: 10) !23 = !DILocation(line: 2, column: 14, scope: !8) !24 = !DILocation(line: 3, column: 20, scope: !8) !25 = !DILocation(line: 3, column: 24, scope: !8) !26 = !DILocation(line: 3, column: 8, scope: !8) !27 = !DILocalVariable(name: "flag", scope: !8, file: !1, line: 3, type: !28) !28 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !29 = !DILocation(line: 4, column: 3, scope: !8) !30 = !DILocation(line: 4, column: 12, scope: !31) !31 = distinct !DILexicalBlock(scope: !32, file: !1, line: 4, column: 3) !32 = distinct !DILexicalBlock(scope: !8, file: !1, line: 4, column: 3) !33 = !DILocation(line: 4, column: 3, scope: !32) !34 = !DILocation(line: 5, column: 9, scope: !35) !35 = distinct !DILexicalBlock(scope: !36, file: !1, line: 5, column: 9) !36 = distinct !DILexicalBlock(scope: !31, file: !1, line: 4, column: 23) !37 = !DILocation(line: 5, column: 9, scope: !36) !38 = !DILocation(line: 6, column: 16, scope: !35) !39 = !DILocation(line: 6, column: 7, scope: !35) !40 = !DILocation(line: 6, column: 12, scope: !35) !41 = !DILocation(line: 8, column: 16, scope: !35) !42 = !DILocation(line: 8, column: 7, scope: !35) !43 = !DILocation(line: 8, column: 12, scope: !35) !44 = !DILocation(line: 9, column: 3, scope: !36) !45 = !DILocation(line: 4, column: 19, scope: !31) !46 = !DILocation(line: 4, column: 3, scope: !31) !47 = distinct !{!47, !33, !48} !48 = !DILocation(line: 9, column: 3, scope: !32) !49 = !DILocation(line: 10, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/pod-types.c000066400000000000000000000003001473507761200320300ustar00rootroot00000000000000unsigned int i; float f; double d; void* p; int* q; unsigned char b; short tab[10][12]; void fun() {} int main(int argc, char** argv) { int xxx[10] = {1, -1, 255, 42}; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/pod-types.ll000066400000000000000000000206631473507761200322330ustar00rootroot00000000000000; ModuleID = 'pod-types.pp.bc' source_filename = "pod-types.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @b = common global i8 0, align 1, !dbg !19 ; CHECK: define ui8* @b, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, 0, align 1 ; CHECK: } ; CHECK: } @d = common global double 0.000000e+00, align 8, !dbg !9 ; CHECK: define double* @d, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @d, 0.0E+0, align 1 ; CHECK: } ; CHECK: } @f = common global float 0.000000e+00, align 4, !dbg !6 ; CHECK: define float* @f, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @f, 0.0E+0, align 1 ; CHECK: } ; CHECK: } @i = common global i32 0, align 4, !dbg !0 ; CHECK: define ui32* @i, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @i, 0, align 1 ; CHECK: } ; CHECK: } @p = common global i8* null, align 8, !dbg !12 ; CHECK: define si8** @p, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @p, null, align 1 ; CHECK: } ; CHECK: } @q = common global i32* null, align 8, !dbg !15 ; CHECK: define si32** @q, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @q, null, align 1 ; CHECK: } ; CHECK: } @tab = common global [10 x [12 x i16]] zeroinitializer, align 16, !dbg !22 ; CHECK: define [10 x [12 x si16]]* @tab, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @tab, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #2 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define void @fun() #0 !dbg !35 { ret void, !dbg !38 } ; CHECK: define void @fun() { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !39 { %3 = alloca [10 x i32], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !45, metadata !DIExpression()), !dbg !46 call void @llvm.dbg.value(metadata i8** %1, metadata !47, metadata !DIExpression()), !dbg !46 call void @llvm.dbg.declare(metadata [10 x i32]* %3, metadata !48, metadata !DIExpression()), !dbg !51 %4 = bitcast [10 x i32]* %3 to i8*, !dbg !51 call void @llvm.memset.p0i8.i64(i8* align 16 %4, i8 0, i64 40, i1 false), !dbg !51 %5 = bitcast i8* %4 to [10 x i32]*, !dbg !51 %6 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i32 0, i32 0, !dbg !51 store i32 1, i32* %6, align 16, !dbg !51 %7 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i32 0, i32 1, !dbg !51 store i32 -1, i32* %7, align 4, !dbg !51 %8 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i32 0, i32 2, !dbg !51 store i32 255, i32* %8, align 8, !dbg !51 %9 = getelementptr inbounds [10 x i32], [10 x i32]* %5, i32 0, i32 3, !dbg !51 store i32 42, i32* %9, align 4, !dbg !51 ret i32 0, !dbg !52 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: [10 x si32]* $3 = allocate [10 x si32], 1, align 16 ; CHECK: si8* %4 = bitcast $3 ; CHECK: call @ar.memset(%4, 0, 40, 16, 0) ; CHECK: [10 x si32]* %5 = bitcast %4 ; CHECK: si32* %6 = ptrshift %5, 40 * 0, 4 * 0 ; CHECK: store %6, 1, align 16 ; CHECK: si32* %7 = ptrshift %5, 40 * 0, 4 * 1 ; CHECK: store %7, -1, align 4 ; CHECK: si32* %8 = ptrshift %5, 40 * 0, 4 * 2 ; CHECK: store %8, 255, align 8 ; CHECK: si32* %9 = ptrshift %5, 40 * 0, 4 * 3 ; CHECK: store %9, 42, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!30, !31, !32, !33} !llvm.ident = !{!34} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "i", scope: !2, file: !3, line: 1, type: !29, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "pod-types.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0, !6, !9, !12, !15, !19, !22} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "f", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression()) !10 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 5, type: !11, isLocal: false, isDefinition: true) !11 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression()) !13 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 7, type: !14, isLocal: false, isDefinition: true) !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !15 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression()) !16 = distinct !DIGlobalVariable(name: "q", scope: !2, file: !3, line: 9, type: !17, isLocal: false, isDefinition: true) !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression()) !20 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 11, type: !21, isLocal: false, isDefinition: true) !21 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !22 = !DIGlobalVariableExpression(var: !23, expr: !DIExpression()) !23 = distinct !DIGlobalVariable(name: "tab", scope: !2, file: !3, line: 13, type: !24, isLocal: false, isDefinition: true) !24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !25, size: 1920, elements: !26) !25 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) !26 = !{!27, !28} !27 = !DISubrange(count: 10) !28 = !DISubrange(count: 12) !29 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !30 = !{i32 2, !"Dwarf Version", i32 4} !31 = !{i32 2, !"Debug Info Version", i32 3} !32 = !{i32 1, !"wchar_size", i32 4} !33 = !{i32 7, !"PIC Level", i32 2} !34 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !35 = distinct !DISubprogram(name: "fun", scope: !3, file: !3, line: 15, type: !36, scopeLine: 15, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !36 = !DISubroutineType(types: !37) !37 = !{null} !38 = !DILocation(line: 15, column: 13, scope: !35) !39 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 17, type: !40, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !40 = !DISubroutineType(types: !41) !41 = !{!18, !18, !42} !42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !43, size: 64) !43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !44, size: 64) !44 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !45 = !DILocalVariable(name: "argc", arg: 1, scope: !39, file: !3, line: 17, type: !18) !46 = !DILocation(line: 0, scope: !39) !47 = !DILocalVariable(name: "argv", arg: 2, scope: !39, file: !3, line: 17, type: !42) !48 = !DILocalVariable(name: "xxx", scope: !39, file: !3, line: 18, type: !49) !49 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 320, elements: !50) !50 = !{!27} !51 = !DILocation(line: 18, column: 7, scope: !39) !52 = !DILocation(line: 19, column: 3, scope: !39) pointer-arithmetic.cpp000066400000000000000000000004561473507761200342100ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization#include int f() { return 6; } unsigned char* ptr_fun = (unsigned char*)&f + 1; const char* string_map[] = {"aaa", "bbb"}; struct vector { int x; int y; int z; }; struct vector v[] = {{1, 2, 3}, {4, 5, 6}}; int* ptr = &(v[1].z); int main() { return printf("%d\n", v[1].z); } pointer-arithmetic.ll000066400000000000000000000205341473507761200340340ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'pointer-arithmetic.pp.bc' source_filename = "pointer-arithmetic.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.vector = type { i32, i32, i32 } @.str = private unnamed_addr constant [4 x i8] c"aaa\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [97, 97, 97, 0], align 1 ; CHECK: } ; CHECK: } @.str.1 = private unnamed_addr constant [4 x i8] c"bbb\00", align 1 ; CHECK: define [4 x si8]* @.str.1, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.1, [98, 98, 98, 0], align 1 ; CHECK: } ; CHECK: } @.str.2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str.2, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.2, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } @ptr = global i32* bitcast (i8* getelementptr (i8, i8* bitcast ([2 x %struct.vector]* @v to i8*), i64 20) to i32*), align 8, !dbg !23 ; CHECK: define si32** @ptr, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @v ; CHECK: si8* %2 = ptrshift %1, 1 * 20 ; CHECK: si32* %3 = bitcast %2 ; CHECK: store @ptr, %3, align 1 ; CHECK: } ; CHECK: } @ptr_fun = global i8* getelementptr (i8, i8* bitcast (i32 ()* @_Z1fv to i8*), i64 1), align 8, !dbg !0 ; CHECK: define ui8** @ptr_fun, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_Z1fv ; CHECK: ui8* %2 = ptrshift %1, 1 * 1 ; CHECK: store @ptr_fun, %2, align 1 ; CHECK: } ; CHECK: } @string_map = global [2 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0)], align 16, !dbg !6 ; CHECK: define [2 x si8*]* @string_map, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = ptrshift @.str.1, 4 * 0, 1 * 0 ; CHECK: si8* %2 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: store @string_map, [%2, %1], align 1 ; CHECK: } ; CHECK: } @v = global [2 x %struct.vector] [%struct.vector { i32 1, i32 2, i32 3 }, %struct.vector { i32 4, i32 5, i32 6 }], align 16, !dbg !14 ; CHECK: define [2 x {0: si32, 4: si32, 8: si32}]* @v, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @v, [{0: 1, 4: 2, 8: 3}, {0: 4, 4: 5, 8: 6}], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fv() #0 !dbg !33 { ret i32 6, !dbg !36 } ; CHECK: define si32 @_Z1fv() { ; CHECK: #1 !entry !exit { ; CHECK: return 6 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #1 !dbg !37 { %1 = getelementptr inbounds [2 x %struct.vector], [2 x %struct.vector]* @v, i64 0, i64 1, i32 2, !dbg !38 %2 = load i32, i32* %1, align 4, !dbg !38 %3 = getelementptr inbounds [4 x i8], [4 x i8]* @.str.2, i64 0, i64 0, !dbg !39 %4 = call i32 (i8*, ...) @printf(i8* %3, i32 %2), !dbg !39 ret i32 %4, !dbg !40 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* %1 = ptrshift @v, 24 * 0, 12 * 1, 1 * 8 ; CHECK: si32 %2 = load %1, align 4 ; CHECK: si8* %3 = ptrshift @.str.2, 4 * 0, 1 * 0 ; CHECK: si32 %4 = call @ar.libc.printf(%3, %2) ; CHECK: return %4 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!28, !29, !30, !31} !llvm.ident = !{!32} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "ptr_fun", scope: !2, file: !3, line: 7, type: !26, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "pointer-arithmetic.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0, !6, !14, !23} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "string_map", scope: !2, file: !3, line: 9, type: !8, isLocal: false, isDefinition: true) !8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 128, elements: !12) !9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) !10 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !11) !11 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !12 = !{!13} !13 = !DISubrange(count: 2) !14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression()) !15 = distinct !DIGlobalVariable(name: "v", scope: !2, file: !3, line: 17, type: !16, isLocal: false, isDefinition: true) !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !17, size: 192, elements: !12) !17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "vector", file: !3, line: 11, size: 96, flags: DIFlagTypePassByValue, elements: !18, identifier: "_ZTS6vector") !18 = !{!19, !21, !22} !19 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !17, file: !3, line: 12, baseType: !20, size: 32) !20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !21 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !17, file: !3, line: 13, baseType: !20, size: 32, offset: 32) !22 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !17, file: !3, line: 14, baseType: !20, size: 32, offset: 64) !23 = !DIGlobalVariableExpression(var: !24, expr: !DIExpression()) !24 = distinct !DIGlobalVariable(name: "ptr", scope: !2, file: !3, line: 19, type: !25, isLocal: false, isDefinition: true) !25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !27, size: 64) !27 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !28 = !{i32 2, !"Dwarf Version", i32 4} !29 = !{i32 2, !"Debug Info Version", i32 3} !30 = !{i32 1, !"wchar_size", i32 4} !31 = !{i32 7, !"PIC Level", i32 2} !32 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !33 = distinct !DISubprogram(name: "f", linkageName: "_Z1fv", scope: !3, file: !3, line: 3, type: !34, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !34 = !DISubroutineType(types: !35) !35 = !{!20} !36 = !DILocation(line: 4, column: 3, scope: !33) !37 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 21, type: !34, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !38 = !DILocation(line: 22, column: 30, scope: !37) !39 = !DILocation(line: 22, column: 10, scope: !37) !40 = !DILocation(line: 22, column: 3, scope: !37) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/ptr-to-int.c000066400000000000000000000001121473507761200321220ustar00rootroot00000000000000#include int f() { return 0; } uintptr_t x = (intptr_t)&f; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/ptr-to-int.ll000066400000000000000000000054051473507761200323210ustar00rootroot00000000000000; ModuleID = 'ptr-to-int.pp.bc' source_filename = "ptr-to-int.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @x = global i64 ptrtoint (i32 ()* @f to i64), align 8, !dbg !0 ; CHECK: define ui64* @x, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: ui64 %1 = ptrtoui @f ; CHECK: store @x, %1, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @f() #0 !dbg !14 { ret i32 0, !dbg !18 } ; CHECK: define si32 @f() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!9, !10, !11, !12} !llvm.ident = !{!13} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "ptr-to-int.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "uintptr_t", file: !7, line: 30, baseType: !8) !7 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_uintptr_t.h", directory: "") !8 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) !9 = !{i32 2, !"Dwarf Version", i32 4} !10 = !{i32 2, !"Debug Info Version", i32 3} !11 = !{i32 1, !"wchar_size", i32 4} !12 = !{i32 7, !"PIC Level", i32 2} !13 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !14 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 3, type: !15, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !15 = !DISubroutineType(types: !16) !16 = !{!17} !17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !18 = !DILocation(line: 4, column: 3, scope: !14) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/reference.cpp000066400000000000000000000001151473507761200324060ustar00rootroot00000000000000void f(int& x) { x = 1; } int main() { int y = 0; f(y); return y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/reference.ll000066400000000000000000000107641473507761200322460ustar00rootroot00000000000000; ModuleID = 'reference.pp.bc' source_filename = "reference.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define void @_Z1fRi(i32* dereferenceable(4)) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32* %0, metadata !13, metadata !DIExpression()), !dbg !14 store i32 1, i32* %0, align 4, !dbg !15 ret void, !dbg !16 } ; CHECK: define void @_Z1fRi(si32* %1) { ; CHECK: #1 !entry !exit { ; CHECK: store %1, 1, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #2 !dbg !17 { %1 = alloca i32, align 4 call void @llvm.dbg.declare(metadata i32* %1, metadata !20, metadata !DIExpression()), !dbg !21 store i32 0, i32* %1, align 4, !dbg !21 call void @_Z1fRi(i32* dereferenceable(4) %1), !dbg !22 %2 = load i32, i32* %1, align 4, !dbg !23 ret i32 %2, !dbg !24 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: call @_Z1fRi($1) ; CHECK: si32 %2 = load $1, align 4 ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "reference.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fRi", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null, !11} !11 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !12, size: 64) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11) !14 = !DILocation(line: 0, scope: !8) !15 = !DILocation(line: 2, column: 5, scope: !8) !16 = !DILocation(line: 3, column: 1, scope: !8) !17 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !18, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !18 = !DISubroutineType(types: !19) !19 = !{!12} !20 = !DILocalVariable(name: "y", scope: !17, file: !1, line: 6, type: !12) !21 = !DILocation(line: 6, column: 7, scope: !17) !22 = !DILocation(line: 7, column: 3, scope: !17) !23 = !DILocation(line: 8, column: 10, scope: !17) !24 = !DILocation(line: 8, column: 3, scope: !17) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/regenerate-ll000077500000000000000000000027011473507761200324230ustar00rootroot00000000000000#!/bin/bash # Use this script to regenerate all the .ll files from the .c and .cpp files clang="clang" ikos_pp="ikos-pp" opt="opt" opt_level="basic" cflags="-c -emit-llvm -Wall -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone" cxxflags="$cflags -std=c++17" ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" set -e function run { echo "#" "$@" "$@" } for filename in *.c do echo "[*] $filename ..." filename="${filename%.c}" if [[ -f "$filename.ll" ]]; then echo "$filename.ll already exists, skipping" continue fi run "$clang" $cflags "$filename.c" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.ll" "$ikos_import" $ikos_import_opts "$filename.ll" | sed 's/^/; CHECK: /' >> "$filename.ll" rm -f "$filename.bc" "$filename.pp.bc" done for filename in *.cpp do echo "[*] $filename ..." filename="${filename%.cpp}" if [[ -f "$filename.ll" ]]; then echo "$filename.ll already exists, skipping" continue fi run "$clang" $cxxflags "$filename.cpp" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.ll" "$ikos_import" $ikos_import_opts "$filename.ll" | sed 's/^/; CHECK: /' >> "$filename.ll" rm -f "$filename.bc" "$filename.pp.bc" done NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/runtest000077500000000000000000000066701473507761200314120ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing ikos-import with basic optimizations # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" file_check="FileCheck" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h]" echo " [--ikos-import IKOS-IMPORT]" echo " [--file-check FILE-CHECK]" echo "" echo "Run regression tests for llvm-to-ar" exit 1 elif [[ "$1" = "--ikos-import" ]]; then shift ikos_import=$1 elif [[ "$1" = "--file-check" ]]; then shift file_check=$1 else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-import if ! command -v "$ikos_import" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_import" >&2 exit 2 fi # Check FileCheck if ! command -v "$file_check" >/dev/null 2>&1; then echo "error: $progname: could not find $file_check" >&2 exit 2 fi # Run the tests echo "# Running regression tests for ikos-import" for filename in *.ll do echo -en "$filename ... \r" "$ikos_import" $ikos_import_opts "$filename" \ | "$file_check" "$filename" \ || { echo "Test Failed"; exit 1; } echo "$filename ... Passed" rm -f "$filename_pp" done echo "All tests passed successfully." exit 0 NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/select.cpp000066400000000000000000000003461473507761200317350ustar00rootroot00000000000000/** * To generate LLVM select instruction, we need to compile * the code with optimization enabled (at least -O1) * * > clang++ -O1 -emit-llvm -o test.bc -g -c test.cpp */ int a; int main() { return a > 0 ? 123 : 321; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/select.ll000066400000000000000000000064171473507761200315670ustar00rootroot00000000000000; ModuleID = 'select.pp.bc' source_filename = "select.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = global i32 0, align 4, !dbg !0 ; CHECK: define si32* @a, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !12 { %1 = load i32, i32* @a, align 4, !dbg !15 %2 = icmp sgt i32 %1, 0, !dbg !16 br i1 %2, label %3, label %4, !dbg !15 3: ; preds = %0 br label %5, !dbg !15 4: ; preds = %0 br label %5, !dbg !15 5: ; preds = %4, %3 %6 = phi i32 [ 123, %3 ], [ 321, %4 ], !dbg !15 ret i32 %6, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32 %1 = load @a, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %1 sigt 0 ; CHECK: si32 %2 = 123 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %1 sile 0 ; CHECK: si32 %2 = 321 ; CHECK: } ; CHECK: #4 !exit predecessors={#2, #3} { ; CHECK: return %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 8, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "select.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 10, type: !13, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 11, column: 10, scope: !12) !16 = !DILocation(line: 11, column: 12, scope: !12) !17 = !DILocation(line: 11, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/shufflevector.c000066400000000000000000000002551473507761200327740ustar00rootroot00000000000000#include extern void printv(__m128); int main(int argc, char** argv) { __m128 m = _mm_set_ps(4, 3, 2, 1); m = _mm_shuffle_ps(m, m, 0x1B); printv(m); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/shufflevector.ll000066400000000000000000000122131473507761200331560ustar00rootroot00000000000000; ModuleID = 'shufflevector.pp.bc' source_filename = "shufflevector.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !16 { call void @llvm.dbg.value(metadata i32 %0, metadata !23, metadata !DIExpression()), !dbg !24 call void @llvm.dbg.value(metadata i8** %1, metadata !25, metadata !DIExpression()), !dbg !24 %3 = insertelement <4 x float> undef, float 1.000000e+00, i32 0, !dbg !26 %4 = insertelement <4 x float> %3, float 2.000000e+00, i32 1, !dbg !26 %5 = insertelement <4 x float> %4, float 3.000000e+00, i32 2, !dbg !26 %6 = insertelement <4 x float> %5, float 4.000000e+00, i32 3, !dbg !26 call void @llvm.dbg.value(metadata <4 x float> %6, metadata !27, metadata !DIExpression()), !dbg !24 %7 = shufflevector <4 x float> %6, <4 x float> %6, <4 x i32> , !dbg !28 call void @llvm.dbg.value(metadata <4 x float> %7, metadata !27, metadata !DIExpression()), !dbg !24 call void @printv(<4 x float> %7), !dbg !29 ret i32 0, !dbg !30 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: <4 x float> %3 = insertelement undef, 0, 1.0E+0 ; CHECK: <4 x float> %4 = insertelement %3, 4, 2.0E+0 ; CHECK: <4 x float> %5 = insertelement %4, 8, 3.0E+0 ; CHECK: <4 x float> %6 = insertelement %5, 12, 4.0E+0 ; CHECK: <4 x float> %7 = shufflevector %6, %6 ; CHECK: call @printv(%7) ; CHECK: return 0 ; CHECK: } ; CHECK: } declare void @printv(<4 x float>) #1 ; CHECK: declare void @printv(<4 x float>) ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #2 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="128" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!11, !12, !13, !14} !llvm.ident = !{!15} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "shufflevector.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{!4, !10} !4 = !DIDerivedType(tag: DW_TAG_typedef, name: "__m128", file: !5, line: 17, baseType: !6) !5 = !DIFile(filename: "Homebrew/Cellar/llvm/9.0.0_1/lib/clang/9.0.0/include/xmmintrin.h", directory: "/Users/marthaud") !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 128, flags: DIFlagVector, elements: !8) !7 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 4) !10 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v4sf", file: !5, line: 16, baseType: !6) !11 = !{i32 2, !"Dwarf Version", i32 4} !12 = !{i32 2, !"Debug Info Version", i32 3} !13 = !{i32 1, !"wchar_size", i32 4} !14 = !{i32 7, !"PIC Level", i32 2} !15 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!19, !19, !20} !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !23 = !DILocalVariable(name: "argc", arg: 1, scope: !16, file: !1, line: 5, type: !19) !24 = !DILocation(line: 0, scope: !16) !25 = !DILocalVariable(name: "argv", arg: 2, scope: !16, file: !1, line: 5, type: !20) !26 = !DILocation(line: 6, column: 14, scope: !16) !27 = !DILocalVariable(name: "m", scope: !16, file: !1, line: 6, type: !4) !28 = !DILocation(line: 7, column: 7, scope: !16) !29 = !DILocation(line: 8, column: 3, scope: !16) !30 = !DILocation(line: 9, column: 1, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/struct-parameters.c000066400000000000000000000003271473507761200336020ustar00rootroot00000000000000#include typedef struct { char buf[10]; char buf1[10]; char buf2[10]; } my_struct; my_struct f(my_struct* s) { return *s; } my_struct g(my_struct s) { return s; } int main() { return 0; } struct-parameters.ll000066400000000000000000000137511473507761200337150ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'struct-parameters.pp.bc' source_filename = "struct-parameters.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.my_struct = type { [10 x i8], [10 x i8], [10 x i8] } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define void @f(%struct.my_struct* noalias sret(%struct.my_struct), %struct.my_struct*) #0 !dbg !8 { call void @llvm.dbg.value(metadata %struct.my_struct* %1, metadata !22, metadata !DIExpression()), !dbg !23 %3 = bitcast %struct.my_struct* %0 to i8*, !dbg !24 %4 = bitcast %struct.my_struct* %1 to i8*, !dbg !24 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %3, i8* align 1 %4, i64 30, i1 false), !dbg !24 ret void, !dbg !25 } ; CHECK: define void @f({0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %1, {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %2) { ; CHECK: #1 !entry !exit { ; CHECK: si8* %3 = bitcast %1 ; CHECK: si8* %4 = bitcast %2 ; CHECK: call @ar.memcpy(%3, %4, 30, 1, 1, 0) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define void @g(%struct.my_struct* noalias sret(%struct.my_struct), %struct.my_struct* byval(%struct.my_struct) align 8) #0 !dbg !26 { call void @llvm.dbg.declare(metadata %struct.my_struct* %1, metadata !29, metadata !DIExpression()), !dbg !30 %3 = bitcast %struct.my_struct* %0 to i8*, !dbg !31 %4 = bitcast %struct.my_struct* %1 to i8*, !dbg !31 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %3, i8* align 8 %4, i64 30, i1 false), !dbg !31 ret void, !dbg !32 } ; CHECK: define void @g({0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %1, {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %2) { ; CHECK: #1 !entry !exit { ; CHECK: si8* %3 = bitcast %1 ; CHECK: si8* %4 = bitcast %2 ; CHECK: call @ar.memcpy(%3, %4, 30, 1, 8, 0) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !33 { ret i32 0, !dbg !37 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "struct-parameters.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 9, type: !9, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !21} !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "my_struct", file: !1, line: 7, baseType: !12) !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 3, size: 240, elements: !13) !13 = !{!14, !19, !20} !14 = !DIDerivedType(tag: DW_TAG_member, name: "buf", scope: !12, file: !1, line: 4, baseType: !15, size: 80) !15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !16, size: 80, elements: !17) !16 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !17 = !{!18} !18 = !DISubrange(count: 10) !19 = !DIDerivedType(tag: DW_TAG_member, name: "buf1", scope: !12, file: !1, line: 5, baseType: !15, size: 80, offset: 80) !20 = !DIDerivedType(tag: DW_TAG_member, name: "buf2", scope: !12, file: !1, line: 6, baseType: !15, size: 80, offset: 160) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !22 = !DILocalVariable(name: "s", arg: 1, scope: !8, file: !1, line: 9, type: !21) !23 = !DILocation(line: 0, scope: !8) !24 = !DILocation(line: 10, column: 10, scope: !8) !25 = !DILocation(line: 10, column: 3, scope: !8) !26 = distinct !DISubprogram(name: "g", scope: !1, file: !1, line: 13, type: !27, scopeLine: 13, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !27 = !DISubroutineType(types: !28) !28 = !{!11, !11} !29 = !DILocalVariable(name: "s", arg: 1, scope: !26, file: !1, line: 13, type: !11) !30 = !DILocation(line: 13, column: 23, scope: !26) !31 = !DILocation(line: 14, column: 10, scope: !26) !32 = !DILocation(line: 14, column: 3, scope: !26) !33 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 17, type: !34, scopeLine: 17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !34 = !DISubroutineType(types: !35) !35 = !{!36} !36 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !37 = !DILocation(line: 18, column: 3, scope: !33) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/thread-local.cpp000066400000000000000000000000671473507761200330150ustar00rootroot00000000000000static thread_local int x; int main() { return x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/thread-local.ll000066400000000000000000000067451473507761200326530ustar00rootroot00000000000000; ModuleID = 'thread-local.pp.bc' source_filename = "thread-local.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @_ZL1x = internal thread_local global i32 0, align 4, !dbg !0 ; CHECK: define si32* @_ZL1x, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZL1x, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal cxx_fast_tlscc i32* @_ZTWL1x() #1 { ret i32* @_ZL1x } ; CHECK: define si32* @_ZTWL1x() { ; CHECK: #1 !entry !exit { ; CHECK: return @_ZL1x ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !12 { %1 = call cxx_fast_tlscc i32* @_ZTWL1x(), !dbg !15 %2 = load i32, i32* %1, align 4, !dbg !15 ret i32 %2, !dbg !16 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* %1 = call @_ZTWL1x() ; CHECK: si32 %2 = load %1, align 4 ; CHECK: return %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", linkageName: "_ZL1x", scope: !2, file: !3, line: 1, type: !6, isLocal: true, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "thread-local.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 4, column: 10, scope: !12) !16 = !DILocation(line: 4, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/try-catch.cpp000066400000000000000000000010071473507761200323470ustar00rootroot00000000000000int G; class A { public: virtual void f(int x) {} virtual int g() { return 0; } }; class B : public A { public: virtual void f(int x) { G = x; } virtual int g() { return 0; } }; class C : public B { public: virtual void f(int x) { G = -x; } virtual int g() { return 1; } }; void h(int x) {} int hh(int x) { return x * x; } void run(A* p) { int x; p->f(12); x = p->g(); h(14); x = hh(15); } int main() { B b; C c; try { run(&b); run(&c); } catch (A& e) { } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/try-catch.ll000066400000000000000000001013631473507761200322020ustar00rootroot00000000000000; ModuleID = 'try-catch.pp.bc' source_filename = "try-catch.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.A = type { i32 (...)** } %class.B = type { %class.A } %class.C = type { %class.B } @G = global i32 0, align 4, !dbg !0 ; CHECK: define si32* @G, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @G, 0, align 1 ; CHECK: } ; CHECK: } @_ZTI1A = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1A, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1A, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1A, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1B = linkonce_odr constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0), i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*) }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si8*}* @_ZTI1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv120__si_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1B, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1B, {0: %4, 8: %3, 16: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1C = linkonce_odr constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1B to i8*) }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si8*}* @_ZTI1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv120__si_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1B ; CHECK: si8* %3 = ptrshift @_ZTS1C, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1C, {0: %4, 8: %3, 16: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1A, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1A, [49, 65, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1B = linkonce_odr constant [3 x i8] c"1B\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1B, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1B, [49, 66, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1C = linkonce_odr constant [3 x i8] c"1C\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1C, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1C, [49, 67, 0], align 1 ; CHECK: } ; CHECK: } @_ZTV1A = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast (void (%class.A*, i32)* @_ZN1A1fEi to i8*), i8* bitcast (i32 (%class.A*)* @_ZN1A1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1A1gEv ; CHECK: si8* %2 = bitcast @_ZN1A1fEi ; CHECK: si8* %3 = bitcast @_ZTI1A ; CHECK: store @_ZTV1A, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1B = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1B to i8*), i8* bitcast (void (%class.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%class.B*)* @_ZN1B1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1B1gEv ; CHECK: si8* %2 = bitcast @_ZN1B1fEi ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: store @_ZTV1B, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1C = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1C to i8*), i8* bitcast (void (%class.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%class.C*)* @_ZN1C1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1C1gEv ; CHECK: si8* %2 = bitcast @_ZN1C1fEi ; CHECK: si8* %3 = bitcast @_ZTI1C ; CHECK: store @_ZTV1C, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTVN10__cxxabiv117__class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv117__class_type_infoE @_ZTVN10__cxxabiv120__si_class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv120__si_class_type_infoE ; Function Attrs: noinline nounwind ssp uwtable define void @_Z1hi(i32) #0 !dbg !12 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 ret void, !dbg !17 } ; CHECK: define void @_Z1hi(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z2hhi(i32) #0 !dbg !18 { call void @llvm.dbg.value(metadata i32 %0, metadata !21, metadata !DIExpression()), !dbg !22 %2 = mul nsw i32 %0, %0, !dbg !23 ret i32 %2, !dbg !24 } ; CHECK: define si32 @_Z2hhi(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %2 = %1 smul.nw %1 ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define void @_Z3runP1A(%class.A*) #2 !dbg !25 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !43, metadata !DIExpression()), !dbg !44 %2 = bitcast %class.A* %0 to void (%class.A*, i32)***, !dbg !45 %3 = load void (%class.A*, i32)**, void (%class.A*, i32)*** %2, align 8, !dbg !45 %4 = getelementptr inbounds void (%class.A*, i32)*, void (%class.A*, i32)** %3, i64 0, !dbg !45 %5 = load void (%class.A*, i32)*, void (%class.A*, i32)** %4, align 8, !dbg !45 call void %5(%class.A* %0, i32 12), !dbg !45 %6 = bitcast %class.A* %0 to i32 (%class.A*)***, !dbg !46 %7 = load i32 (%class.A*)**, i32 (%class.A*)*** %6, align 8, !dbg !46 %8 = getelementptr inbounds i32 (%class.A*)*, i32 (%class.A*)** %7, i64 1, !dbg !46 %9 = load i32 (%class.A*)*, i32 (%class.A*)** %8, align 8, !dbg !46 %10 = call i32 %9(%class.A* %0), !dbg !46 call void @llvm.dbg.value(metadata i32 %10, metadata !47, metadata !DIExpression()), !dbg !44 call void @_Z1hi(i32 14), !dbg !48 %11 = call i32 @_Z2hhi(i32 15), !dbg !49 call void @llvm.dbg.value(metadata i32 %11, metadata !47, metadata !DIExpression()), !dbg !44 ret void, !dbg !50 } ; CHECK: define void @_Z3runP1A({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: void ({0: si32 (...)**}*, si32)*** %2 = bitcast %1 ; CHECK: void ({0: si32 (...)**}*, si32)** %3 = load %2, align 8 ; CHECK: void ({0: si32 (...)**}*, si32)** %4 = ptrshift %3, 8 * 0 ; CHECK: void ({0: si32 (...)**}*, si32)* %5 = load %4, align 8 ; CHECK: call %5(%1, 12) ; CHECK: si32 ({0: si32 (...)**}*)*** %6 = bitcast %1 ; CHECK: si32 ({0: si32 (...)**}*)** %7 = load %6, align 8 ; CHECK: si32 ({0: si32 (...)**}*)** %8 = ptrshift %7, 8 * 1 ; CHECK: si32 ({0: si32 (...)**}*)* %9 = load %8, align 8 ; CHECK: si32 %10 = call %9(%1) ; CHECK: call @_Z1hi(14) ; CHECK: si32 %11 = call @_Z2hhi(15) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1A1fEi(%class.A*, i32) unnamed_addr #0 align 2 !dbg !126 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !127, metadata !DIExpression()), !dbg !128 call void @llvm.dbg.value(metadata i32 %1, metadata !129, metadata !DIExpression()), !dbg !128 ret void, !dbg !130 } ; CHECK: define void @_ZN1A1fEi({0: si32 (...)**}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr i32 @_ZN1A1gEv(%class.A*) unnamed_addr #0 align 2 !dbg !131 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !132, metadata !DIExpression()), !dbg !133 ret i32 0, !dbg !134 } ; CHECK: define si32 @_ZN1A1gEv({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1AC2Ev(%class.A*) unnamed_addr #0 align 2 !dbg !109 { call void @llvm.dbg.value(metadata %class.A* %0, metadata !113, metadata !DIExpression()), !dbg !114 %2 = bitcast %class.A* %0 to i32 (...)***, !dbg !115 %3 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i32 0, i32 0, i32 2, !dbg !115 %4 = bitcast i8** %3 to i32 (...)**, !dbg !115 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !115 ret void, !dbg !115 } ; CHECK: define void @_ZN1AC2Ev({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = bitcast %1 ; CHECK: si8** %3 = ptrshift @_ZTV1A, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1B1fEi(%class.B*, i32) unnamed_addr #0 align 2 !dbg !116 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !117, metadata !DIExpression()), !dbg !118 call void @llvm.dbg.value(metadata i32 %1, metadata !119, metadata !DIExpression()), !dbg !118 store i32 %1, i32* @G, align 4, !dbg !120 ret void, !dbg !121 } ; CHECK: define void @_ZN1B1fEi({0: {0: si32 (...)**}}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: store @G, %2, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr i32 @_ZN1B1gEv(%class.B*) unnamed_addr #0 align 2 !dbg !122 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !123, metadata !DIExpression()), !dbg !124 ret i32 0, !dbg !125 } ; CHECK: define si32 @_ZN1B1gEv({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1BC1Ev(%class.B*) unnamed_addr #0 align 2 !dbg !89 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !93, metadata !DIExpression()), !dbg !95 call void @_ZN1BC2Ev(%class.B* %0) #5, !dbg !96 ret void, !dbg !96 } ; CHECK: define void @_ZN1BC1Ev({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN1BC2Ev(%1) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1BC2Ev(%class.B*) unnamed_addr #0 align 2 !dbg !105 { call void @llvm.dbg.value(metadata %class.B* %0, metadata !106, metadata !DIExpression()), !dbg !107 %2 = bitcast %class.B* %0 to %class.A*, !dbg !108 call void @_ZN1AC2Ev(%class.A* %2) #5, !dbg !108 %3 = bitcast %class.B* %0 to i32 (...)***, !dbg !108 %4 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1B, i32 0, i32 0, i32 2, !dbg !108 %5 = bitcast i8** %4 to i32 (...)**, !dbg !108 store i32 (...)** %5, i32 (...)*** %3, align 8, !dbg !108 ret void, !dbg !108 } ; CHECK: define void @_ZN1BC2Ev({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**}* %2 = bitcast %1 ; CHECK: call @_ZN1AC2Ev(%2) ; CHECK: si32 (...)*** %3 = bitcast %1 ; CHECK: si8** %4 = ptrshift @_ZTV1B, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %5 = bitcast %4 ; CHECK: store %3, %5, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1C1fEi(%class.C*, i32) unnamed_addr #0 align 2 !dbg !139 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !140, metadata !DIExpression()), !dbg !141 call void @llvm.dbg.value(metadata i32 %1, metadata !142, metadata !DIExpression()), !dbg !141 %3 = sub nsw i32 0, %1, !dbg !143 store i32 %3, i32* @G, align 4, !dbg !144 ret void, !dbg !145 } ; CHECK: define void @_ZN1C1fEi({0: {0: {0: si32 (...)**}}}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %3 = 0 ssub.nw %2 ; CHECK: store @G, %3, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr i32 @_ZN1C1gEv(%class.C*) unnamed_addr #0 align 2 !dbg !146 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !147, metadata !DIExpression()), !dbg !148 ret i32 1, !dbg !149 } ; CHECK: define si32 @_ZN1C1gEv({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1CC1Ev(%class.C*) unnamed_addr #0 align 2 !dbg !97 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !101, metadata !DIExpression()), !dbg !103 call void @_ZN1CC2Ev(%class.C* %0) #5, !dbg !104 ret void, !dbg !104 } ; CHECK: define void @_ZN1CC1Ev({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: call @_ZN1CC2Ev(%1) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1CC2Ev(%class.C*) unnamed_addr #0 align 2 !dbg !135 { call void @llvm.dbg.value(metadata %class.C* %0, metadata !136, metadata !DIExpression()), !dbg !137 %2 = bitcast %class.C* %0 to %class.B*, !dbg !138 call void @_ZN1BC2Ev(%class.B* %2) #5, !dbg !138 %3 = bitcast %class.C* %0 to i32 (...)***, !dbg !138 %4 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1C, i32 0, i32 0, i32 2, !dbg !138 %5 = bitcast i8** %4 to i32 (...)**, !dbg !138 store i32 (...)** %5, i32 (...)*** %3, align 8, !dbg !138 ret void, !dbg !138 } ; CHECK: define void @_ZN1CC2Ev({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32 (...)**}}* %2 = bitcast %1 ; CHECK: call @_ZN1BC2Ev(%2) ; CHECK: si32 (...)*** %3 = bitcast %1 ; CHECK: si8** %4 = ptrshift @_ZTV1C, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %5 = bitcast %4 ; CHECK: store %3, %5, align 8 ; CHECK: return ; CHECK: } ; CHECK: } declare i32 @__gxx_personality_v0(...) ; CHECK: declare si32 @__gxx_personality_v0(...) ; Function Attrs: nounwind readnone declare i32 @llvm.eh.typeid.for(i8*) #4 ; CHECK: declare si32 @ar.eh.typeid.for(si8*) declare i8* @__cxa_begin_catch(i8*) ; CHECK: declare si8* @ar.libcpp.begincatch(si8*) declare void @__cxa_end_catch() ; CHECK: declare void @ar.libcpp.endcatch() ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #3 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !51 { %1 = alloca %class.B, align 8 %2 = alloca %class.C, align 8 call void @llvm.dbg.declare(metadata %class.B* %1, metadata !52, metadata !DIExpression()), !dbg !63 call void @_ZN1BC1Ev(%class.B* %1) #5, !dbg !63 call void @llvm.dbg.declare(metadata %class.C* %2, metadata !64, metadata !DIExpression()), !dbg !75 call void @_ZN1CC1Ev(%class.C* %2) #5, !dbg !75 %3 = bitcast %class.B* %1 to %class.A*, !dbg !76 invoke void @_Z3runP1A(%class.A* %3) to label %4 unwind label %7, !dbg !78 4: ; preds = %0 %5 = bitcast %class.C* %2 to %class.A*, !dbg !79 invoke void @_Z3runP1A(%class.A* %5) to label %6 unwind label %7, !dbg !80 6: ; preds = %4 br label %17, !dbg !81 7: ; preds = %4, %0 %8 = landingpad { i8*, i32 } catch i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), !dbg !82 %9 = extractvalue { i8*, i32 } %8, 0, !dbg !82 %10 = extractvalue { i8*, i32 } %8, 1, !dbg !82 br label %11, !dbg !82 11: ; preds = %7 %12 = bitcast { i8*, i8* }* @_ZTI1A to i8*, !dbg !81 %13 = call i32 @llvm.eh.typeid.for(i8* %12) #5, !dbg !81 %14 = icmp eq i32 %10, %13, !dbg !81 br i1 %14, label %15, label %18, !dbg !81 15: ; preds = %11 %16 = call i8* @__cxa_begin_catch(i8* %9) #5, !dbg !81 call void @llvm.dbg.value(metadata i8* %16, metadata !83, metadata !DIExpression()), !dbg !85 call void @__cxa_end_catch(), !dbg !86 br label %17, !dbg !86 17: ; preds = %15, %6 ret i32 0, !dbg !88 18: ; preds = %11 %19 = insertvalue { i8*, i32 } undef, i8* %9, 0, !dbg !81 %20 = insertvalue { i8*, i32 } %19, i32 %10, 1, !dbg !81 resume { i8*, i32 } %20, !dbg !81 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: {0: {0: si32 (...)**}}* $1 = allocate {0: {0: si32 (...)**}}, 1, align 8 ; CHECK: {0: {0: {0: si32 (...)**}}}* $2 = allocate {0: {0: {0: si32 (...)**}}}, 1, align 8 ; CHECK: call @_ZN1BC1Ev($1) ; CHECK: call @_ZN1CC1Ev($2) ; CHECK: {0: si32 (...)**}* %3 = bitcast $1 ; CHECK: invoke @_Z3runP1A(%3) normal=#2 exc=#3 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4, #5} { ; CHECK: {0: si32 (...)**}* %4 = bitcast $2 ; CHECK: invoke @_Z3runP1A(%4) normal=#4 exc=#5 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#6} { ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: } ; CHECK: #5 predecessors={#2} successors={#6} { ; CHECK: } ; CHECK: #6 predecessors={#3, #5} successors={#8, #9} { ; CHECK: {0: si8*, 8: si32} %5 = landingpad ; CHECK: si8* %6 = extractelement %5, 0 ; CHECK: si32 %7 = extractelement %5, 8 ; CHECK: si8* %8 = bitcast @_ZTI1A ; CHECK: si32 %9 = call @ar.eh.typeid.for(%8) ; CHECK: } ; CHECK: #8 predecessors={#6} successors={#7} { ; CHECK: %7 sieq %9 ; CHECK: si8* %10 = call @ar.libcpp.begincatch(%6) ; CHECK: call @ar.libcpp.endcatch() ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#unified-exit} { ; CHECK: %7 sine %9 ; CHECK: {0: si8*, 8: si32} %11 = insertelement undef, 0, %6 ; CHECK: {0: si8*, 8: si32} %12 = insertelement %11, 8, %7 ; CHECK: resume %12 ; CHECK: } ; CHECK: #7 predecessors={#4, #8} successors={#unified-exit} { ; CHECK: return 0 ; CHECK: } ; CHECK: #unified-exit !exit predecessors={#7, #9} { ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { nounwind readnone } attributes #5 = { nounwind } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "G", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "try-catch.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "h", linkageName: "_Z1hi", scope: !3, file: !3, line: 21, type: !13, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{null, !6} !15 = !DILocalVariable(name: "x", arg: 1, scope: !12, file: !3, line: 21, type: !6) !16 = !DILocation(line: 0, scope: !12) !17 = !DILocation(line: 21, column: 16, scope: !12) !18 = distinct !DISubprogram(name: "hh", linkageName: "_Z2hhi", scope: !3, file: !3, line: 23, type: !19, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !19 = !DISubroutineType(types: !20) !20 = !{!6, !6} !21 = !DILocalVariable(name: "x", arg: 1, scope: !18, file: !3, line: 23, type: !6) !22 = !DILocation(line: 0, scope: !18) !23 = !DILocation(line: 24, column: 12, scope: !18) !24 = !DILocation(line: 24, column: 3, scope: !18) !25 = distinct !DISubprogram(name: "run", linkageName: "_Z3runP1A", scope: !3, file: !3, line: 27, type: !26, scopeLine: 27, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !26 = !DISubroutineType(types: !27) !27 = !{null, !28} !28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64) !29 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A", file: !3, line: 3, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !30, vtableHolder: !29, identifier: "_ZTS1A") !30 = !{!31, !36, !40} !31 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$A", scope: !3, file: !3, baseType: !32, size: 64, flags: DIFlagArtificial) !32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64) !33 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: !34, size: 64) !34 = !DISubroutineType(types: !35) !35 = !{!6} !36 = !DISubprogram(name: "f", linkageName: "_ZN1A1fEi", scope: !29, file: !3, line: 5, type: !37, scopeLine: 5, containingType: !29, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !37 = !DISubroutineType(types: !38) !38 = !{null, !39, !6} !39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !40 = !DISubprogram(name: "g", linkageName: "_ZN1A1gEv", scope: !29, file: !3, line: 6, type: !41, scopeLine: 6, containingType: !29, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !41 = !DISubroutineType(types: !42) !42 = !{!6, !39} !43 = !DILocalVariable(name: "p", arg: 1, scope: !25, file: !3, line: 27, type: !28) !44 = !DILocation(line: 0, scope: !25) !45 = !DILocation(line: 29, column: 6, scope: !25) !46 = !DILocation(line: 30, column: 10, scope: !25) !47 = !DILocalVariable(name: "x", scope: !25, file: !3, line: 28, type: !6) !48 = !DILocation(line: 31, column: 3, scope: !25) !49 = !DILocation(line: 32, column: 7, scope: !25) !50 = !DILocation(line: 33, column: 1, scope: !25) !51 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 35, type: !34, scopeLine: 35, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !52 = !DILocalVariable(name: "b", scope: !51, file: !3, line: 36, type: !53) !53 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "B", file: !3, line: 9, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !54, vtableHolder: !29, identifier: "_ZTS1B") !54 = !{!55, !56, !60} !55 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !53, baseType: !29, flags: DIFlagPublic, extraData: i32 0) !56 = !DISubprogram(name: "f", linkageName: "_ZN1B1fEi", scope: !53, file: !3, line: 11, type: !57, scopeLine: 11, containingType: !53, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !57 = !DISubroutineType(types: !58) !58 = !{null, !59, !6} !59 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !53, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !60 = !DISubprogram(name: "g", linkageName: "_ZN1B1gEv", scope: !53, file: !3, line: 12, type: !61, scopeLine: 12, containingType: !53, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !61 = !DISubroutineType(types: !62) !62 = !{!6, !59} !63 = !DILocation(line: 36, column: 5, scope: !51) !64 = !DILocalVariable(name: "c", scope: !51, file: !3, line: 37, type: !65) !65 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C", file: !3, line: 15, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !66, vtableHolder: !29, identifier: "_ZTS1C") !66 = !{!67, !68, !72} !67 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !65, baseType: !53, flags: DIFlagPublic, extraData: i32 0) !68 = !DISubprogram(name: "f", linkageName: "_ZN1C1fEi", scope: !65, file: !3, line: 17, type: !69, scopeLine: 17, containingType: !65, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !69 = !DISubroutineType(types: !70) !70 = !{null, !71, !6} !71 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !65, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !72 = !DISubprogram(name: "g", linkageName: "_ZN1C1gEv", scope: !65, file: !3, line: 18, type: !73, scopeLine: 18, containingType: !65, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !73 = !DISubroutineType(types: !74) !74 = !{!6, !71} !75 = !DILocation(line: 37, column: 5, scope: !51) !76 = !DILocation(line: 39, column: 9, scope: !77) !77 = distinct !DILexicalBlock(scope: !51, file: !3, line: 38, column: 7) !78 = !DILocation(line: 39, column: 5, scope: !77) !79 = !DILocation(line: 40, column: 9, scope: !77) !80 = !DILocation(line: 40, column: 5, scope: !77) !81 = !DILocation(line: 41, column: 3, scope: !77) !82 = !DILocation(line: 44, column: 1, scope: !77) !83 = !DILocalVariable(name: "e", scope: !51, file: !3, line: 41, type: !84) !84 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !29, size: 64) !85 = !DILocation(line: 0, scope: !51) !86 = !DILocation(line: 42, column: 3, scope: !87) !87 = distinct !DILexicalBlock(scope: !51, file: !3, line: 41, column: 18) !88 = !DILocation(line: 43, column: 3, scope: !51) !89 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC1Ev", scope: !53, file: !3, line: 9, type: !90, scopeLine: 9, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !92, retainedNodes: !4) !90 = !DISubroutineType(types: !91) !91 = !{null, !59} !92 = !DISubprogram(name: "B", scope: !53, type: !90, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !93 = !DILocalVariable(name: "this", arg: 1, scope: !89, type: !94, flags: DIFlagArtificial | DIFlagObjectPointer) !94 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !53, size: 64) !95 = !DILocation(line: 0, scope: !89) !96 = !DILocation(line: 9, column: 7, scope: !89) !97 = distinct !DISubprogram(name: "C", linkageName: "_ZN1CC1Ev", scope: !65, file: !3, line: 15, type: !98, scopeLine: 15, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !100, retainedNodes: !4) !98 = !DISubroutineType(types: !99) !99 = !{null, !71} !100 = !DISubprogram(name: "C", scope: !65, type: !98, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !101 = !DILocalVariable(name: "this", arg: 1, scope: !97, type: !102, flags: DIFlagArtificial | DIFlagObjectPointer) !102 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !65, size: 64) !103 = !DILocation(line: 0, scope: !97) !104 = !DILocation(line: 15, column: 7, scope: !97) !105 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC2Ev", scope: !53, file: !3, line: 9, type: !90, scopeLine: 9, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !92, retainedNodes: !4) !106 = !DILocalVariable(name: "this", arg: 1, scope: !105, type: !94, flags: DIFlagArtificial | DIFlagObjectPointer) !107 = !DILocation(line: 0, scope: !105) !108 = !DILocation(line: 9, column: 7, scope: !105) !109 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AC2Ev", scope: !29, file: !3, line: 3, type: !110, scopeLine: 3, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !112, retainedNodes: !4) !110 = !DISubroutineType(types: !111) !111 = !{null, !39} !112 = !DISubprogram(name: "A", scope: !29, type: !110, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !113 = !DILocalVariable(name: "this", arg: 1, scope: !109, type: !28, flags: DIFlagArtificial | DIFlagObjectPointer) !114 = !DILocation(line: 0, scope: !109) !115 = !DILocation(line: 3, column: 7, scope: !109) !116 = distinct !DISubprogram(name: "f", linkageName: "_ZN1B1fEi", scope: !53, file: !3, line: 11, type: !57, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !56, retainedNodes: !4) !117 = !DILocalVariable(name: "this", arg: 1, scope: !116, type: !94, flags: DIFlagArtificial | DIFlagObjectPointer) !118 = !DILocation(line: 0, scope: !116) !119 = !DILocalVariable(name: "x", arg: 2, scope: !116, file: !3, line: 11, type: !6) !120 = !DILocation(line: 11, column: 29, scope: !116) !121 = !DILocation(line: 11, column: 34, scope: !116) !122 = distinct !DISubprogram(name: "g", linkageName: "_ZN1B1gEv", scope: !53, file: !3, line: 12, type: !61, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !60, retainedNodes: !4) !123 = !DILocalVariable(name: "this", arg: 1, scope: !122, type: !94, flags: DIFlagArtificial | DIFlagObjectPointer) !124 = !DILocation(line: 0, scope: !122) !125 = !DILocation(line: 12, column: 21, scope: !122) !126 = distinct !DISubprogram(name: "f", linkageName: "_ZN1A1fEi", scope: !29, file: !3, line: 5, type: !37, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !36, retainedNodes: !4) !127 = !DILocalVariable(name: "this", arg: 1, scope: !126, type: !28, flags: DIFlagArtificial | DIFlagObjectPointer) !128 = !DILocation(line: 0, scope: !126) !129 = !DILocalVariable(name: "x", arg: 2, scope: !126, file: !3, line: 5, type: !6) !130 = !DILocation(line: 5, column: 26, scope: !126) !131 = distinct !DISubprogram(name: "g", linkageName: "_ZN1A1gEv", scope: !29, file: !3, line: 6, type: !41, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !40, retainedNodes: !4) !132 = !DILocalVariable(name: "this", arg: 1, scope: !131, type: !28, flags: DIFlagArtificial | DIFlagObjectPointer) !133 = !DILocation(line: 0, scope: !131) !134 = !DILocation(line: 6, column: 21, scope: !131) !135 = distinct !DISubprogram(name: "C", linkageName: "_ZN1CC2Ev", scope: !65, file: !3, line: 15, type: !98, scopeLine: 15, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !100, retainedNodes: !4) !136 = !DILocalVariable(name: "this", arg: 1, scope: !135, type: !102, flags: DIFlagArtificial | DIFlagObjectPointer) !137 = !DILocation(line: 0, scope: !135) !138 = !DILocation(line: 15, column: 7, scope: !135) !139 = distinct !DISubprogram(name: "f", linkageName: "_ZN1C1fEi", scope: !65, file: !3, line: 17, type: !69, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !68, retainedNodes: !4) !140 = !DILocalVariable(name: "this", arg: 1, scope: !139, type: !102, flags: DIFlagArtificial | DIFlagObjectPointer) !141 = !DILocation(line: 0, scope: !139) !142 = !DILocalVariable(name: "x", arg: 2, scope: !139, file: !3, line: 17, type: !6) !143 = !DILocation(line: 17, column: 31, scope: !139) !144 = !DILocation(line: 17, column: 29, scope: !139) !145 = !DILocation(line: 17, column: 35, scope: !139) !146 = distinct !DISubprogram(name: "g", linkageName: "_ZN1C1gEv", scope: !65, file: !3, line: 18, type: !73, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !72, retainedNodes: !4) !147 = !DILocalVariable(name: "this", arg: 1, scope: !146, type: !102, flags: DIFlagArtificial | DIFlagObjectPointer) !148 = !DILocation(line: 0, scope: !146) !149 = !DILocation(line: 18, column: 21, scope: !146) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/undef.c000066400000000000000000000001241473507761200312110ustar00rootroot00000000000000extern int flag; int main(int argc, char** argv) { int* v; return flag + *v; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/undef.ll000066400000000000000000000064711473507761200314110ustar00rootroot00000000000000; ModuleID = 'undef.pp.bc' source_filename = "undef.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @flag = external global i32, align 4 ; CHECK: declare si32* @flag, align 4 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8** %1, metadata !17, metadata !DIExpression()), !dbg !16 %3 = load i32, i32* @flag, align 4, !dbg !18 %4 = load i32, i32* undef, align 4, !dbg !19 %5 = add nsw i32 %3, %4, !dbg !20 ret i32 %5, !dbg !21 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32 %3 = load @flag, align 4 ; CHECK: si32 %4 = load undef, align 4 ; CHECK: si32 %5 = %3 sadd.nw %4 ; CHECK: return %5 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "undef.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 0, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 3, type: !12) !18 = !DILocation(line: 5, column: 10, scope: !8) !19 = !DILocation(line: 5, column: 17, scope: !8) !20 = !DILocation(line: 5, column: 15, scope: !8) !21 = !DILocation(line: 5, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/union.c000066400000000000000000000001431473507761200312410ustar00rootroot00000000000000union my_union { int m_int; char* m_ptr; }; int main() { union my_union x = {.m_int = 1}; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/union.ll000066400000000000000000000076171473507761200314430ustar00rootroot00000000000000; ModuleID = 'union.pp.bc' source_filename = "union.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %union.my_union = type { i8* } @__const.main.x = private unnamed_addr constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8 ; CHECK: define {0: si32, 4: [4 x si8]}* @__const.main.x, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @__const.main.x, {0: 1, 4: undef}, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1 immarg) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca %union.my_union, align 8 call void @llvm.dbg.declare(metadata %union.my_union* %1, metadata !12, metadata !DIExpression()), !dbg !19 %2 = bitcast %union.my_union* %1 to i8*, !dbg !19 %3 = bitcast { i32, [4 x i8] }* @__const.main.x to i8*, !dbg !19 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %2, i8* align 8 %3, i64 8, i1 false), !dbg !19 ret i32 0, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: si8*}* $1 = allocate {0: si8*}, 1, align 8 ; CHECK: si8* %2 = bitcast $1 ; CHECK: si8* %3 = bitcast @__const.main.x ; CHECK: call @ar.memcpy(%2, %3, 8, 8, 8, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "union.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, scopeLine: 6, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 7, type: !13) !13 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "my_union", file: !1, line: 1, size: 64, elements: !14) !14 = !{!15, !16} !15 = !DIDerivedType(tag: DW_TAG_member, name: "m_int", scope: !13, file: !1, line: 2, baseType: !11, size: 32) !16 = !DIDerivedType(tag: DW_TAG_member, name: "m_ptr", scope: !13, file: !1, line: 3, baseType: !17, size: 64) !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) !18 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !19 = !DILocation(line: 7, column: 18, scope: !8) !20 = !DILocation(line: 8, column: 1, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/update-ll000077500000000000000000000022471473507761200315710ustar00rootroot00000000000000#!/bin/bash # Use this script to update all the .ll files from the .c and .cpp files clang="clang" ikos_pp="ikos-pp" opt="opt" opt_level="basic" cflags="-c -emit-llvm -Wall -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone" cxxflags="$cflags -std=c++17" ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" set -e function run { echo "#" "$@" "$@" } for filename in *.c do echo "[*] $filename ..." filename="${filename%.c}" run "$clang" $cflags "$filename.c" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.new.ll" vimdiff "$filename.ll" "$filename.new.ll" rm -f "$filename.bc" "$filename.pp.bc" "$filename.new.ll" done for filename in *.cpp do echo "[*] $filename ..." filename="${filename%.cpp}" run "$clang" $cxxflags "$filename.cpp" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.new.ll" vimdiff "$filename.ll" "$filename.new.ll" rm -f "$filename.bc" "$filename.pp.bc" "$filename.new.ll" done NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/var-args.c000066400000000000000000000016441473507761200316420ustar00rootroot00000000000000/* va_copy example */ #include /* va_list, va_start, va_copy, va_arg, va_end */ #include /* printf, vprintf*/ #include /* malloc */ #include /* strlen, strcat */ /* print ints until a zero is found: */ void PrintInts(int first, ...) { char* buffer; const char* format = "[%d] "; int count = 0; int val = first; va_list vl, vl_count; va_start(vl, first); /* count number of arguments: */ va_copy(vl_count, vl); while (val != 0) { val = va_arg(vl_count, int); ++count; } va_end(vl_count); /* allocate storage for format string: */ buffer = (char*)malloc(strlen(format) * count + 1); buffer[0] = '\0'; /* generate format string: */ for (; count > 0; --count) { strcat(buffer, format); } /* print integers: */ printf(format, first); vprintf(buffer, vl); va_end(vl); } int main() { PrintInts(10, 20, 30, 40, 50, 0); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/var-args.ll000066400000000000000000000442001473507761200320220ustar00rootroot00000000000000; ModuleID = 'var-args.pp.bc' source_filename = "var-args.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.__va_list_tag = type { i32, i32, i8*, i8* } @.str = private unnamed_addr constant [6 x i8] c"[%d] \00", align 1 ; CHECK: define [6 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [91, 37, 100, 93, 32, 0], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define void @PrintInts(i32, ...) #0 !dbg !11 { %2 = alloca [1 x %struct.__va_list_tag], align 16 %3 = alloca [1 x %struct.__va_list_tag], align 16 call void @llvm.dbg.value(metadata i32 %0, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0), metadata !17, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 0, metadata !20, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 %0, metadata !21, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata [1 x %struct.__va_list_tag]* %2, metadata !22, metadata !DIExpression()), !dbg !39 call void @llvm.dbg.declare(metadata [1 x %struct.__va_list_tag]* %3, metadata !40, metadata !DIExpression()), !dbg !41 %4 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %2, i64 0, i64 0, !dbg !42 %5 = bitcast %struct.__va_list_tag* %4 to i8*, !dbg !42 call void @llvm.va_start(i8* %5), !dbg !42 %6 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %3, i64 0, i64 0, !dbg !43 %7 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %2, i64 0, i64 0, !dbg !43 %8 = bitcast %struct.__va_list_tag* %6 to i8*, !dbg !43 %9 = bitcast %struct.__va_list_tag* %7 to i8*, !dbg !43 call void @llvm.va_copy(i8* %8, i8* %9), !dbg !43 br label %10, !dbg !44 10: ; preds = %28, %1 %.01 = phi i32 [ 0, %1 ], [ %31, %28 ], !dbg !16 %.0 = phi i32 [ %0, %1 ], [ %30, %28 ], !dbg !16 call void @llvm.dbg.value(metadata i32 %.0, metadata !21, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.value(metadata i32 %.01, metadata !20, metadata !DIExpression()), !dbg !16 %11 = icmp ne i32 %.0, 0, !dbg !45 br i1 %11, label %12, label %32, !dbg !44 12: ; preds = %10 %13 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %3, i64 0, i64 0, !dbg !46 %14 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %13, i32 0, i32 0, !dbg !46 %15 = load i32, i32* %14, align 16, !dbg !46 %16 = icmp ule i32 %15, 40, !dbg !46 br i1 %16, label %17, label %23, !dbg !46 17: ; preds = %12 %18 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %13, i32 0, i32 3, !dbg !46 %19 = load i8*, i8** %18, align 16, !dbg !46 %20 = getelementptr i8, i8* %19, i32 %15, !dbg !46 %21 = bitcast i8* %20 to i32*, !dbg !46 %22 = add i32 %15, 8, !dbg !46 store i32 %22, i32* %14, align 16, !dbg !46 br label %28, !dbg !46 23: ; preds = %12 %24 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %13, i32 0, i32 2, !dbg !46 %25 = load i8*, i8** %24, align 8, !dbg !46 %26 = bitcast i8* %25 to i32*, !dbg !46 %27 = getelementptr i8, i8* %25, i32 8, !dbg !46 store i8* %27, i8** %24, align 8, !dbg !46 br label %28, !dbg !46 28: ; preds = %23, %17 %29 = phi i32* [ %21, %17 ], [ %26, %23 ], !dbg !46 %30 = load i32, i32* %29, align 4, !dbg !46 call void @llvm.dbg.value(metadata i32 %30, metadata !21, metadata !DIExpression()), !dbg !16 %31 = add nsw i32 %.01, 1, !dbg !48 call void @llvm.dbg.value(metadata i32 %31, metadata !20, metadata !DIExpression()), !dbg !16 br label %10, !dbg !44, !llvm.loop !49 32: ; preds = %10 %33 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %3, i64 0, i64 0, !dbg !51 %34 = bitcast %struct.__va_list_tag* %33 to i8*, !dbg !51 call void @llvm.va_end(i8* %34), !dbg !51 %35 = getelementptr inbounds [6 x i8], [6 x i8]* @.str, i64 0, i64 0, !dbg !52 %36 = call i64 @strlen(i8* %35), !dbg !52 %37 = sext i32 %.01 to i64, !dbg !53 %38 = mul i64 %36, %37, !dbg !54 %39 = add i64 %38, 1, !dbg !55 %40 = call i8* @malloc(i64 %39) #5, !dbg !56 call void @llvm.dbg.value(metadata i8* %40, metadata !57, metadata !DIExpression()), !dbg !16 %41 = getelementptr inbounds i8, i8* %40, i64 0, !dbg !58 store i8 0, i8* %41, align 1, !dbg !59 br label %42, !dbg !60 42: ; preds = %47, %32 %.1 = phi i32 [ %.01, %32 ], [ %48, %47 ], !dbg !16 call void @llvm.dbg.value(metadata i32 %.1, metadata !20, metadata !DIExpression()), !dbg !16 %43 = icmp sgt i32 %.1, 0, !dbg !61 br i1 %43, label %44, label %49, !dbg !64 44: ; preds = %42 %45 = getelementptr inbounds [6 x i8], [6 x i8]* @.str, i64 0, i64 0, !dbg !65 %46 = call i8* @strcat(i8* %40, i8* %45), !dbg !65 br label %47, !dbg !67 47: ; preds = %44 %48 = add nsw i32 %.1, -1, !dbg !68 call void @llvm.dbg.value(metadata i32 %48, metadata !20, metadata !DIExpression()), !dbg !16 br label %42, !dbg !69, !llvm.loop !70 49: ; preds = %42 %50 = getelementptr inbounds [6 x i8], [6 x i8]* @.str, i64 0, i64 0, !dbg !72 %51 = call i32 (i8*, ...) @printf(i8* %50, i32 %0), !dbg !72 %52 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %2, i64 0, i64 0, !dbg !73 %53 = call i32 @vprintf(i8* %40, %struct.__va_list_tag* %52), !dbg !74 %54 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %2, i64 0, i64 0, !dbg !75 %55 = bitcast %struct.__va_list_tag* %54 to i8*, !dbg !75 call void @llvm.va_end(i8* %55), !dbg !75 ret void, !dbg !76 } ; CHECK: define void @PrintInts(si32 %1, ...) { ; CHECK: #1 !entry successors={#2} { ; CHECK: [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}]* $2 = allocate [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}], 1, align 16 ; CHECK: [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}]* $3 = allocate [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}], 1, align 16 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %4 = ptrshift $2, 24 * 0, 24 * 0 ; CHECK: si8* %5 = bitcast %4 ; CHECK: call @ar.va_start(%5) ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %6 = ptrshift $3, 24 * 0, 24 * 0 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %7 = ptrshift $2, 24 * 0, 24 * 0 ; CHECK: si8* %8 = bitcast %6 ; CHECK: si8* %9 = bitcast %7 ; CHECK: call @ar.va_copy(%8, %9) ; CHECK: si32 %.01 = 0 ; CHECK: si32 %.0 = %1 ; CHECK: } ; CHECK: #2 predecessors={#1, #8} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#5, #6} { ; CHECK: %.0 sine 0 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %10 = ptrshift $3, 24 * 0, 24 * 0 ; CHECK: si32* %11 = ptrshift %10, 24 * 0, 1 * 0 ; CHECK: ui32* %12 = bitcast %11 ; CHECK: ui32 %13 = load %12, align 16 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: %.0 sieq 0 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %14 = ptrshift $3, 24 * 0, 24 * 0 ; CHECK: si8* %15 = bitcast %14 ; CHECK: call @ar.va_end(%15) ; CHECK: si8* %16 = ptrshift @.str, 6 * 0, 1 * 0 ; CHECK: ui64 %17 = call @ar.libc.strlen(%16) ; CHECK: si64 %18 = sext %.01 ; CHECK: ui64 %19 = bitcast %18 ; CHECK: ui64 %20 = %17 umul %19 ; CHECK: ui64 %21 = %20 uadd 1 ; CHECK: si8* %22 = call @ar.libc.malloc(%21) ; CHECK: si8* %23 = ptrshift %22, 1 * 0 ; CHECK: store %23, 0, align 1 ; CHECK: si32 %.1 = %.01 ; CHECK: } ; CHECK: #5 predecessors={#3} successors={#8} { ; CHECK: %13 uile 40 ; CHECK: si8** %24 = ptrshift %10, 24 * 0, 1 * 16 ; CHECK: si8* %25 = load %24, align 16 ; CHECK: si8* %26 = ptrshift %25, 1 * %13 ; CHECK: si32* %27 = bitcast %26 ; CHECK: ui32 %28 = %13 uadd 8 ; CHECK: si32 %29 = bitcast %28 ; CHECK: store %11, %29, align 16 ; CHECK: si32* %30 = %27 ; CHECK: } ; CHECK: #6 predecessors={#3} successors={#8} { ; CHECK: %13 uigt 40 ; CHECK: si8** %31 = ptrshift %10, 24 * 0, 1 * 8 ; CHECK: si8* %32 = load %31, align 8 ; CHECK: si32* %33 = bitcast %32 ; CHECK: si8* %34 = ptrshift %32, 1 * 8 ; CHECK: store %31, %34, align 8 ; CHECK: si32* %30 = %33 ; CHECK: } ; CHECK: #7 predecessors={#4, #9} successors={#9, #10} { ; CHECK: } ; CHECK: #9 predecessors={#7} successors={#7} { ; CHECK: %.1 sigt 0 ; CHECK: si8* %37 = ptrshift @.str, 6 * 0, 1 * 0 ; CHECK: si8* %38 = call @ar.libc.strcat(%22, %37) ; CHECK: si32 %39 = %.1 sadd.nw -1 ; CHECK: si32 %.1 = %39 ; CHECK: } ; CHECK: #10 !exit predecessors={#7} { ; CHECK: %.1 sile 0 ; CHECK: si8* %40 = ptrshift @.str, 6 * 0, 1 * 0 ; CHECK: si32 %41 = call @ar.libc.printf(%40, %1) ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %42 = ptrshift $2, 24 * 0, 24 * 0 ; CHECK: si32 %43 = call @vprintf(%22, %42) ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %44 = ptrshift $2, 24 * 0, 24 * 0 ; CHECK: si8* %45 = bitcast %44 ; CHECK: call @ar.va_end(%45) ; CHECK: return ; CHECK: } ; CHECK: #8 predecessors={#5, #6} successors={#2} { ; CHECK: si32 %35 = load %30, align 4 ; CHECK: si32 %36 = %.01 sadd.nw 1 ; CHECK: si32 %.01 = %36 ; CHECK: si32 %.0 = %35 ; CHECK: } ; CHECK: } ; Function Attrs: allocsize(0) declare i8* @malloc(i64) #3 ; CHECK: declare si8* @ar.libc.malloc(ui64) declare i32 @printf(i8*, ...) #4 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) declare i8* @strcat(i8*, i8*) #4 ; CHECK: declare si8* @ar.libc.strcat(si8*, si8*) declare i64 @strlen(i8*) #4 ; CHECK: declare ui64 @ar.libc.strlen(si8*) ; Function Attrs: nounwind declare void @llvm.va_copy(i8*, i8*) #2 ; CHECK: declare void @ar.va_copy(si8*, si8*) ; Function Attrs: nounwind declare void @llvm.va_end(i8*) #2 ; CHECK: declare void @ar.va_end(si8*) ; Function Attrs: nounwind declare void @llvm.va_start(i8*) #2 ; CHECK: declare void @ar.va_start(si8*) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !77 { call void (i32, ...) @PrintInts(i32 10, i32 20, i32 30, i32 40, i32 50, i32 0), !dbg !80 ret i32 0, !dbg !81 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: call @PrintInts(10, 20, 30, 40, 50, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } declare i32 @vprintf(i8*, %struct.__va_list_tag*) #4 ; CHECK: declare si32 @vprintf(si8*, {0: si32, 4: si32, 8: si8*, 16: si8*}*) ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { nounwind } attributes #3 = { allocsize(0) "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #5 = { allocsize(0) } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!6, !7, !8, !9} !llvm.ident = !{!10} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "var-args.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{!4} !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) !5 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} !8 = !{i32 1, !"wchar_size", i32 4} !9 = !{i32 7, !"PIC Level", i32 2} !10 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !11 = distinct !DISubprogram(name: "PrintInts", scope: !1, file: !1, line: 8, type: !12, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !12 = !DISubroutineType(types: !13) !13 = !{null, !14, null} !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !15 = !DILocalVariable(name: "first", arg: 1, scope: !11, file: !1, line: 8, type: !14) !16 = !DILocation(line: 0, scope: !11) !17 = !DILocalVariable(name: "format", scope: !11, file: !1, line: 10, type: !18) !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) !19 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !5) !20 = !DILocalVariable(name: "count", scope: !11, file: !1, line: 11, type: !14) !21 = !DILocalVariable(name: "val", scope: !11, file: !1, line: 12, type: !14) !22 = !DILocalVariable(name: "vl", scope: !11, file: !1, line: 13, type: !23) !23 = !DIDerivedType(tag: DW_TAG_typedef, name: "va_list", file: !24, line: 32, baseType: !25) !24 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_va_list.h", directory: "") !25 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_va_list", file: !26, line: 98, baseType: !27) !26 = !DIFile(filename: "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/i386/_types.h", directory: "") !27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__builtin_va_list", file: !1, line: 13, baseType: !28) !28 = !DICompositeType(tag: DW_TAG_array_type, baseType: !29, size: 192, elements: !37) !29 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", file: !1, line: 13, size: 192, elements: !30) !30 = !{!31, !33, !34, !36} !31 = !DIDerivedType(tag: DW_TAG_member, name: "gp_offset", scope: !29, file: !1, line: 13, baseType: !32, size: 32) !32 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !33 = !DIDerivedType(tag: DW_TAG_member, name: "fp_offset", scope: !29, file: !1, line: 13, baseType: !32, size: 32, offset: 32) !34 = !DIDerivedType(tag: DW_TAG_member, name: "overflow_arg_area", scope: !29, file: !1, line: 13, baseType: !35, size: 64, offset: 64) !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !36 = !DIDerivedType(tag: DW_TAG_member, name: "reg_save_area", scope: !29, file: !1, line: 13, baseType: !35, size: 64, offset: 128) !37 = !{!38} !38 = !DISubrange(count: 1) !39 = !DILocation(line: 13, column: 11, scope: !11) !40 = !DILocalVariable(name: "vl_count", scope: !11, file: !1, line: 13, type: !23) !41 = !DILocation(line: 13, column: 15, scope: !11) !42 = !DILocation(line: 14, column: 3, scope: !11) !43 = !DILocation(line: 17, column: 3, scope: !11) !44 = !DILocation(line: 18, column: 3, scope: !11) !45 = !DILocation(line: 18, column: 14, scope: !11) !46 = !DILocation(line: 19, column: 11, scope: !47) !47 = distinct !DILexicalBlock(scope: !11, file: !1, line: 18, column: 20) !48 = !DILocation(line: 20, column: 5, scope: !47) !49 = distinct !{!49, !44, !50} !50 = !DILocation(line: 21, column: 3, scope: !11) !51 = !DILocation(line: 22, column: 3, scope: !11) !52 = !DILocation(line: 25, column: 26, scope: !11) !53 = !DILocation(line: 25, column: 43, scope: !11) !54 = !DILocation(line: 25, column: 41, scope: !11) !55 = !DILocation(line: 25, column: 49, scope: !11) !56 = !DILocation(line: 25, column: 19, scope: !11) !57 = !DILocalVariable(name: "buffer", scope: !11, file: !1, line: 9, type: !4) !58 = !DILocation(line: 26, column: 3, scope: !11) !59 = !DILocation(line: 26, column: 13, scope: !11) !60 = !DILocation(line: 29, column: 3, scope: !11) !61 = !DILocation(line: 29, column: 16, scope: !62) !62 = distinct !DILexicalBlock(scope: !63, file: !1, line: 29, column: 3) !63 = distinct !DILexicalBlock(scope: !11, file: !1, line: 29, column: 3) !64 = !DILocation(line: 29, column: 3, scope: !63) !65 = !DILocation(line: 30, column: 5, scope: !66) !66 = distinct !DILexicalBlock(scope: !62, file: !1, line: 29, column: 30) !67 = !DILocation(line: 31, column: 3, scope: !66) !68 = !DILocation(line: 29, column: 21, scope: !62) !69 = !DILocation(line: 29, column: 3, scope: !62) !70 = distinct !{!70, !64, !71} !71 = !DILocation(line: 31, column: 3, scope: !63) !72 = !DILocation(line: 34, column: 3, scope: !11) !73 = !DILocation(line: 35, column: 19, scope: !11) !74 = !DILocation(line: 35, column: 3, scope: !11) !75 = !DILocation(line: 37, column: 3, scope: !11) !76 = !DILocation(line: 38, column: 1, scope: !11) !77 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 40, type: !78, scopeLine: 40, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !78 = !DISubroutineType(types: !79) !79 = !{!14} !80 = !DILocation(line: 41, column: 3, scope: !77) !81 = !DILocation(line: 42, column: 3, scope: !77) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-1.c000066400000000000000000000001711473507761200315520ustar00rootroot00000000000000typedef float vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a + b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-1.ll000066400000000000000000000101651473507761200317430ustar00rootroot00000000000000; ModuleID = 'vector-1.pp.bc' source_filename = "vector-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global <4 x float> zeroinitializer, align 16, !dbg !0 ; CHECK: define <4 x float>* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = common global <4 x float> zeroinitializer, align 16, !dbg !6 ; CHECK: define <4 x float>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @c = common global <4 x float> zeroinitializer, align 16, !dbg !13 ; CHECK: define <4 x float>* @c, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = load <4 x float>, <4 x float>* @a, align 16, !dbg !24 %2 = load <4 x float>, <4 x float>* @b, align 16, !dbg !25 %3 = fadd <4 x float> %1, %2, !dbg !26 store <4 x float> %3, <4 x float>* @c, align 16, !dbg !27 ret i32 0, !dbg !28 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: <4 x float> %1 = load @a, align 16 ; CHECK: <4 x float> %2 = load @b, align 16 ; CHECK: <4 x float> %3 = %1 fadd %2 ; CHECK: store @c, %3, align 16 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "vector-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0, !6, !13} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !3, line: 1, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 128, flags: DIFlagVector, elements: !11) !10 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !11 = !{!12} !12 = !DISubrange(count: 4) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!23} !23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !24 = !DILocation(line: 6, column: 7, scope: !20) !25 = !DILocation(line: 6, column: 11, scope: !20) !26 = !DILocation(line: 6, column: 9, scope: !20) !27 = !DILocation(line: 6, column: 5, scope: !20) !28 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-2.c000066400000000000000000000001721473507761200315540ustar00rootroot00000000000000typedef double vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a * b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-2.ll000066400000000000000000000102061473507761200317400ustar00rootroot00000000000000; ModuleID = 'vector-2.pp.bc' source_filename = "vector-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global <2 x double> zeroinitializer, align 16, !dbg !0 ; CHECK: define <2 x double>* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = common global <2 x double> zeroinitializer, align 16, !dbg !6 ; CHECK: define <2 x double>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @c = common global <2 x double> zeroinitializer, align 16, !dbg !13 ; CHECK: define <2 x double>* @c, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = load <2 x double>, <2 x double>* @a, align 16, !dbg !24 %2 = load <2 x double>, <2 x double>* @b, align 16, !dbg !25 %3 = fmul <2 x double> %1, %2, !dbg !26 store <2 x double> %3, <2 x double>* @c, align 16, !dbg !27 ret i32 0, !dbg !28 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: <2 x double> %1 = load @a, align 16 ; CHECK: <2 x double> %2 = load @b, align 16 ; CHECK: <2 x double> %3 = %1 fmul %2 ; CHECK: store @c, %3, align 16 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "vector-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0, !6, !13} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !3, line: 1, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 128, flags: DIFlagVector, elements: !11) !10 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !11 = !{!12} !12 = !DISubrange(count: 2) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!23} !23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !24 = !DILocation(line: 6, column: 7, scope: !20) !25 = !DILocation(line: 6, column: 11, scope: !20) !26 = !DILocation(line: 6, column: 9, scope: !20) !27 = !DILocation(line: 6, column: 5, scope: !20) !28 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-3.c000066400000000000000000000001671473507761200315610ustar00rootroot00000000000000typedef int vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a + b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-3.ll000066400000000000000000000102121473507761200317360ustar00rootroot00000000000000; ModuleID = 'vector-3.pp.bc' source_filename = "vector-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global <4 x i32> zeroinitializer, align 16, !dbg !0 ; CHECK: define <4 x si32>* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = common global <4 x i32> zeroinitializer, align 16, !dbg !6 ; CHECK: define <4 x si32>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @c = common global <4 x i32> zeroinitializer, align 16, !dbg !13 ; CHECK: define <4 x si32>* @c, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = load <4 x i32>, <4 x i32>* @a, align 16, !dbg !23 %2 = load <4 x i32>, <4 x i32>* @b, align 16, !dbg !24 %3 = add <4 x i32> %1, %2, !dbg !25 store <4 x i32> %3, <4 x i32>* @c, align 16, !dbg !26 ret i32 0, !dbg !27 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: <4 x ui32>* %1 = bitcast @a ; CHECK: <4 x ui32> %2 = load %1, align 16 ; CHECK: <4 x ui32>* %3 = bitcast @b ; CHECK: <4 x ui32> %4 = load %3, align 16 ; CHECK: <4 x ui32> %5 = %2 uadd %4 ; CHECK: <4 x si32> %6 = bitcast %5 ; CHECK: store @c, %6, align 16 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "vector-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !4 = !{} !5 = !{!0, !6, !13} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !3, line: 1, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 128, flags: DIFlagVector, elements: !11) !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !11 = !{!12} !12 = !DISubrange(count: 4) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!10} !23 = !DILocation(line: 6, column: 7, scope: !20) !24 = !DILocation(line: 6, column: 11, scope: !20) !25 = !DILocation(line: 6, column: 9, scope: !20) !26 = !DILocation(line: 6, column: 5, scope: !20) !27 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-4.c000066400000000000000000000001761473507761200315620ustar00rootroot00000000000000typedef long vector_t __attribute__((__vector_size__(16))); vector_t f(vector_t x) { return __builtin_ia32_pshufd(x, 0); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vector-4.ll000066400000000000000000000061721473507761200317510ustar00rootroot00000000000000; ModuleID = 'vector-4.pp.bc' source_filename = "vector-4.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define <2 x i64> @f(<2 x i64>) #0 !dbg !8 { call void @llvm.dbg.value(metadata <2 x i64> %0, metadata !16, metadata !DIExpression()), !dbg !17 %2 = bitcast <2 x i64> %0 to <4 x i32>, !dbg !18 %3 = shufflevector <4 x i32> %2, <4 x i32> undef, <4 x i32> zeroinitializer, !dbg !19 %4 = bitcast <4 x i32> %3 to <2 x i64>, !dbg !19 ret <2 x i64> %4, !dbg !20 } ; CHECK: define <2 x si64> @f(<2 x si64> %1) { ; CHECK: #1 !entry !exit { ; CHECK: <4 x si32> %2 = bitcast %1 ; CHECK: <4 x si32> %3 = shufflevector %2, undef ; CHECK: <2 x si64> %4 = bitcast %3 ; CHECK: return %4 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="128" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "vector-4.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11} !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !1, line: 1, baseType: !12) !12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 128, flags: DIFlagVector, elements: !14) !13 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) !14 = !{!15} !15 = !DISubrange(count: 2) !16 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type: !11) !17 = !DILocation(line: 0, scope: !8) !18 = !DILocation(line: 4, column: 32, scope: !8) !19 = !DILocation(line: 4, column: 10, scope: !8) !20 = !DILocation(line: 4, column: 3, scope: !8) virtual-inheritance.cpp000066400000000000000000000006431473507761200343540ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimizationstruct A { int x; }; struct B { char* y; }; struct C { bool a; }; struct E : public virtual A, public B, public C { int x; virtual void f() {} }; struct D : public virtual A, public virtual B, public C { float z; }; struct F : public virtual A { int y; }; struct G : public virtual A { char* z; }; struct H : public F, public G {}; int main() { E e; D d; F f; G g; H h; return 0; } virtual-inheritance.ll000066400000000000000000001111571473507761200342040ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization; ModuleID = 'virtual-inheritance.pp.bc' source_filename = "virtual-inheritance.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.E = type { i32 (...)**, %struct.B, %struct.C, i32, %struct.A } %struct.B = type { i8* } %struct.C = type { i8 } %struct.A = type { i32 } %struct.D = type { i32 (...)**, %struct.C, float, %struct.A, %struct.B } %struct.F = type <{ i32 (...)**, i32, %struct.A }> %struct.G = type { i32 (...)**, i8*, %struct.A } %struct.H = type { %struct.F.base, %struct.G.base, %struct.A } %struct.F.base = type <{ i32 (...)**, i32 }> %struct.G.base = type { i32 (...)**, i8* } @_ZTC1H0_1F = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTC1H0_1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1F ; CHECK: si8* %2 = sitoptr 32 ; CHECK: store @_ZTC1H0_1F, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTC1H16_1G = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTC1H16_1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1G ; CHECK: si8* %2 = sitoptr 16 ; CHECK: store @_ZTC1H16_1G, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTI1A = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1A, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1A, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1A, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1B = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1B, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1B, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1C = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1C, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1C, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1D = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1D, i32 0, i32 0), i32 0, i32 3, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141, i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i64 -8189, i8* bitcast ({ i8*, i8* }* @_ZTI1C to i8*), i64 2050 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64, 56: si8*, 64: si64}* @_ZTI1D, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1C ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: si8* %4 = bitcast @_ZTI1A ; CHECK: si8* %5 = ptrshift @_ZTS1D, 3 * 0, 1 * 0 ; CHECK: si8* %6 = bitcast %1 ; CHECK: store @_ZTI1D, {0: %6, 8: %5, 16: 0, 20: 3, 24: %4, 32: -6141, 40: %3, 48: -8189, 56: %2, 64: 2050}, align 1 ; CHECK: } ; CHECK: } @_ZTI1E = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1E, i32 0, i32 0), i32 0, i32 3, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141, i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i64 2050, i8* bitcast ({ i8*, i8* }* @_ZTI1C to i8*), i64 4098 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64, 56: si8*, 64: si64}* @_ZTI1E, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1C ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: si8* %4 = bitcast @_ZTI1A ; CHECK: si8* %5 = ptrshift @_ZTS1E, 3 * 0, 1 * 0 ; CHECK: si8* %6 = bitcast %1 ; CHECK: store @_ZTI1E, {0: %6, 8: %5, 16: 0, 20: 3, 24: %4, 32: -6141, 40: %3, 48: 2050, 56: %2, 64: 4098}, align 1 ; CHECK: } ; CHECK: } @_ZTI1F = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1F, i32 0, i32 0), i32 0, i32 1, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64}* @_ZTI1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1F, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1F, {0: %4, 8: %3, 16: 0, 20: 1, 24: %2, 32: -6141}, align 1 ; CHECK: } ; CHECK: } @_ZTI1G = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1G, i32 0, i32 0), i32 0, i32 1, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64}* @_ZTI1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1G, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1G, {0: %4, 8: %3, 16: 0, 20: 1, 24: %2, 32: -6141}, align 1 ; CHECK: } ; CHECK: } @_ZTI1H = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1H, i32 0, i32 0), i32 2, i32 2, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*), i64 2, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*), i64 4098 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64}* @_ZTI1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1G ; CHECK: si8* %3 = bitcast @_ZTI1F ; CHECK: si8* %4 = ptrshift @_ZTS1H, 3 * 0, 1 * 0 ; CHECK: si8* %5 = bitcast %1 ; CHECK: store @_ZTI1H, {0: %5, 8: %4, 16: 2, 20: 2, 24: %3, 32: 2, 40: %2, 48: 4098}, align 1 ; CHECK: } ; CHECK: } @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1A, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1A, [49, 65, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1B = linkonce_odr constant [3 x i8] c"1B\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1B, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1B, [49, 66, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1C = linkonce_odr constant [3 x i8] c"1C\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1C, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1C, [49, 67, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1D = linkonce_odr constant [3 x i8] c"1D\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1D, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1D, [49, 68, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1E = linkonce_odr constant [3 x i8] c"1E\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1E, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1E, [49, 69, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1F = linkonce_odr constant [3 x i8] c"1F\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1F, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1F, [49, 70, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1G = linkonce_odr constant [3 x i8] c"1G\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1G, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1G, [49, 71, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1H = linkonce_odr constant [3 x i8] c"1H\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1H, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1H, [49, 72, 0], align 1 ; CHECK: } ; CHECK: } @_ZTT1H = linkonce_odr unnamed_addr constant [4 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTC1H0_1F, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTC1H16_1G, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, inrange i32 1, i32 3) to i8*)], align 8 ; CHECK: define [4 x si8*]* @_ZTT1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTV1H, 48 * 0, 1 * 24, 8 * 3 ; CHECK: si8** %2 = ptrshift @_ZTC1H16_1G, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8** %3 = ptrshift @_ZTC1H0_1F, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8** %4 = ptrshift @_ZTV1H, 48 * 0, 1 * 0, 8 * 3 ; CHECK: si8* %5 = bitcast %1 ; CHECK: si8* %6 = bitcast %2 ; CHECK: si8* %7 = bitcast %3 ; CHECK: si8* %8 = bitcast %4 ; CHECK: store @_ZTT1H, [%8, %7, %6, %5], align 1 ; CHECK: } ; CHECK: } @_ZTV1D = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1D to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1D, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1D ; CHECK: si8* %2 = sitoptr 16 ; CHECK: si8* %3 = sitoptr 24 ; CHECK: store @_ZTV1D, {0: [%3, %2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1E = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* inttoptr (i64 24 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1E to i8*), i8* bitcast (void (%struct.E*)* @_ZN1E1fEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1E, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1E1fEv ; CHECK: si8* %2 = bitcast @_ZTI1E ; CHECK: si8* %3 = sitoptr 24 ; CHECK: store @_ZTV1E, {0: [%3, null, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1F = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 12 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTV1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1F ; CHECK: si8* %2 = sitoptr 12 ; CHECK: store @_ZTV1F, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1G = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTV1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1G ; CHECK: si8* %2 = sitoptr 16 ; CHECK: store @_ZTV1G, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1H = linkonce_odr unnamed_addr constant { [3 x i8*], [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1H to i8*)], [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1H to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*], 24: [3 x si8*]}* @_ZTV1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1H ; CHECK: si8* %2 = sitoptr -16 ; CHECK: si8* %3 = sitoptr 16 ; CHECK: si8* %4 = bitcast @_ZTI1H ; CHECK: si8* %5 = sitoptr 32 ; CHECK: store @_ZTV1H, {0: [%5, null, %4], 24: [%3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTVN10__cxxabiv117__class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv117__class_type_infoE @_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1DC1Ev(%struct.D*) unnamed_addr #2 align 2 !dbg !76 { call void @llvm.dbg.value(metadata %struct.D* %0, metadata !81, metadata !DIExpression()), !dbg !83 %2 = bitcast %struct.D* %0 to i32 (...)***, !dbg !84 %3 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1D, i32 0, i32 0, i32 4, !dbg !84 %4 = bitcast i8** %3 to i32 (...)**, !dbg !84 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !84 ret void, !dbg !84 } ; CHECK: define void @_ZN1DC1Ev({0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = bitcast %1 ; CHECK: si8** %3 = ptrshift @_ZTV1D, 32 * 0, 1 * 0, 8 * 4 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1E1fEv(%struct.E*) unnamed_addr #2 align 2 !dbg !112 { call void @llvm.dbg.value(metadata %struct.E* %0, metadata !113, metadata !DIExpression()), !dbg !114 ret void, !dbg !115 } ; CHECK: define void @_ZN1E1fEv({0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1EC1Ev(%struct.E*) unnamed_addr #2 align 2 !dbg !70 { call void @llvm.dbg.value(metadata %struct.E* %0, metadata !72, metadata !DIExpression()), !dbg !74 %2 = bitcast %struct.E* %0 to i32 (...)***, !dbg !75 %3 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1E, i32 0, i32 0, i32 3, !dbg !75 %4 = bitcast i8** %3 to i32 (...)**, !dbg !75 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !75 ret void, !dbg !75 } ; CHECK: define void @_ZN1EC1Ev({0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = bitcast %1 ; CHECK: si8** %3 = ptrshift @_ZTV1E, 32 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1FC1Ev(%struct.F*) unnamed_addr #2 align 2 !dbg !85 { call void @llvm.dbg.value(metadata %struct.F* %0, metadata !90, metadata !DIExpression()), !dbg !92 %2 = bitcast %struct.F* %0 to i32 (...)***, !dbg !93 %3 = getelementptr inbounds { [3 x i8*] }, { [3 x i8*] }* @_ZTV1F, i32 0, i32 0, i32 3, !dbg !93 %4 = bitcast i8** %3 to i32 (...)**, !dbg !93 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !93 ret void, !dbg !93 } ; CHECK: define void @_ZN1FC1Ev(<{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = bitcast %1 ; CHECK: si8** %3 = ptrshift @_ZTV1F, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1FC2Ev(%struct.F*, i8**) unnamed_addr #2 align 2 !dbg !116 { call void @llvm.dbg.value(metadata %struct.F* %0, metadata !117, metadata !DIExpression()), !dbg !118 call void @llvm.dbg.value(metadata i8** %1, metadata !119, metadata !DIExpression()), !dbg !118 %3 = load i8*, i8** %1, align 8, !dbg !122 %4 = bitcast %struct.F* %0 to i32 (...)***, !dbg !122 %5 = bitcast i8* %3 to i32 (...)**, !dbg !122 store i32 (...)** %5, i32 (...)*** %4, align 8, !dbg !122 ret void, !dbg !122 } ; CHECK: define void @_ZN1FC2Ev(<{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si8* %3 = load %2, align 8 ; CHECK: si32 (...)*** %4 = bitcast %1 ; CHECK: si32 (...)** %5 = bitcast %3 ; CHECK: store %4, %5, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1GC1Ev(%struct.G*) unnamed_addr #2 align 2 !dbg !94 { call void @llvm.dbg.value(metadata %struct.G* %0, metadata !99, metadata !DIExpression()), !dbg !101 %2 = bitcast %struct.G* %0 to i32 (...)***, !dbg !102 %3 = getelementptr inbounds { [3 x i8*] }, { [3 x i8*] }* @_ZTV1G, i32 0, i32 0, i32 3, !dbg !102 %4 = bitcast i8** %3 to i32 (...)**, !dbg !102 store i32 (...)** %4, i32 (...)*** %2, align 8, !dbg !102 ret void, !dbg !102 } ; CHECK: define void @_ZN1GC1Ev({0: si32 (...)**, 8: si8*, 16: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32 (...)*** %2 = bitcast %1 ; CHECK: si8** %3 = ptrshift @_ZTV1G, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %4 = bitcast %3 ; CHECK: store %2, %4, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1GC2Ev(%struct.G*, i8**) unnamed_addr #2 align 2 !dbg !123 { call void @llvm.dbg.value(metadata %struct.G* %0, metadata !124, metadata !DIExpression()), !dbg !125 call void @llvm.dbg.value(metadata i8** %1, metadata !126, metadata !DIExpression()), !dbg !125 %3 = load i8*, i8** %1, align 8, !dbg !127 %4 = bitcast %struct.G* %0 to i32 (...)***, !dbg !127 %5 = bitcast i8* %3 to i32 (...)**, !dbg !127 store i32 (...)** %5, i32 (...)*** %4, align 8, !dbg !127 ret void, !dbg !127 } ; CHECK: define void @_ZN1GC2Ev({0: si32 (...)**, 8: si8*, 16: {0: si32}}* %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si8* %3 = load %2, align 8 ; CHECK: si32 (...)*** %4 = bitcast %1 ; CHECK: si32 (...)** %5 = bitcast %3 ; CHECK: store %4, %5, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1HC1Ev(%struct.H*) unnamed_addr #2 align 2 !dbg !103 { call void @llvm.dbg.value(metadata %struct.H* %0, metadata !108, metadata !DIExpression()), !dbg !110 %2 = bitcast %struct.H* %0 to %struct.F*, !dbg !111 %3 = getelementptr inbounds [4 x i8*], [4 x i8*]* @_ZTT1H, i64 0, i64 1, !dbg !111 call void @_ZN1FC2Ev(%struct.F* %2, i8** %3) #3, !dbg !111 %4 = bitcast %struct.H* %0 to i8*, !dbg !111 %5 = getelementptr inbounds i8, i8* %4, i64 16, !dbg !111 %6 = bitcast i8* %5 to %struct.G*, !dbg !111 %7 = getelementptr inbounds [4 x i8*], [4 x i8*]* @_ZTT1H, i64 0, i64 2, !dbg !111 call void @_ZN1GC2Ev(%struct.G* %6, i8** %7) #3, !dbg !111 %8 = bitcast %struct.H* %0 to i32 (...)***, !dbg !111 %9 = getelementptr inbounds { [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, i32 0, i32 3, !dbg !111 %10 = bitcast i8** %9 to i32 (...)**, !dbg !111 store i32 (...)** %10, i32 (...)*** %8, align 8, !dbg !111 %11 = bitcast %struct.H* %0 to i8*, !dbg !111 %12 = getelementptr inbounds i8, i8* %11, i64 16, !dbg !111 %13 = bitcast i8* %12 to i32 (...)***, !dbg !111 %14 = getelementptr inbounds { [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, i32 1, i32 3, !dbg !111 %15 = bitcast i8** %14 to i32 (...)**, !dbg !111 store i32 (...)** %15, i32 (...)*** %13, align 8, !dbg !111 ret void, !dbg !111 } ; CHECK: define void @_ZN1HC1Ev({0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %2 = bitcast %1 ; CHECK: si8** %3 = ptrshift @_ZTT1H, 32 * 0, 8 * 1 ; CHECK: call @_ZN1FC2Ev(%2, %3) ; CHECK: si8* %4 = bitcast %1 ; CHECK: si8* %5 = ptrshift %4, 1 * 16 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* %6 = bitcast %5 ; CHECK: si8** %7 = ptrshift @_ZTT1H, 32 * 0, 8 * 2 ; CHECK: call @_ZN1GC2Ev(%6, %7) ; CHECK: si32 (...)*** %8 = bitcast %1 ; CHECK: si8** %9 = ptrshift @_ZTV1H, 48 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %10 = bitcast %9 ; CHECK: store %8, %10, align 8 ; CHECK: si8* %11 = bitcast %1 ; CHECK: si8* %12 = ptrshift %11, 1 * 16 ; CHECK: si32 (...)*** %13 = bitcast %12 ; CHECK: si8** %14 = ptrshift @_ZTV1H, 48 * 0, 1 * 24, 8 * 3 ; CHECK: si32 (...)** %15 = bitcast %14 ; CHECK: store %13, %15, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca %struct.E, align 8 %2 = alloca %struct.D, align 8 %3 = alloca %struct.F, align 8 %4 = alloca %struct.G, align 8 %5 = alloca %struct.H, align 8 call void @llvm.dbg.declare(metadata %struct.E* %1, metadata !12, metadata !DIExpression()), !dbg !38 call void @_ZN1EC1Ev(%struct.E* %1) #3, !dbg !38 call void @llvm.dbg.declare(metadata %struct.D* %2, metadata !39, metadata !DIExpression()), !dbg !48 call void @_ZN1DC1Ev(%struct.D* %2) #3, !dbg !48 call void @llvm.dbg.declare(metadata %struct.F* %3, metadata !49, metadata !DIExpression()), !dbg !55 call void @_ZN1FC1Ev(%struct.F* %3) #3, !dbg !55 call void @llvm.dbg.declare(metadata %struct.G* %4, metadata !56, metadata !DIExpression()), !dbg !62 call void @_ZN1GC1Ev(%struct.G* %4) #3, !dbg !62 call void @llvm.dbg.declare(metadata %struct.H* %5, metadata !63, metadata !DIExpression()), !dbg !68 call void @_ZN1HC1Ev(%struct.H* %5) #3, !dbg !68 ret i32 0, !dbg !69 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* $1 = allocate {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}, 1, align 8 ; CHECK: {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}* $2 = allocate {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}, 1, align 8 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* $3 = allocate <{0: si32 (...)**, 8: si32, 12: {0: si32}}>, 1, align 8 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* $4 = allocate {0: si32 (...)**, 8: si8*, 16: {0: si32}}, 1, align 8 ; CHECK: {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}* $5 = allocate {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}, 1, align 8 ; CHECK: call @_ZN1EC1Ev($1) ; CHECK: call @_ZN1DC1Ev($2) ; CHECK: call @_ZN1FC1Ev($3) ; CHECK: call @_ZN1GC1Ev($4) ; CHECK: call @_ZN1HC1Ev($5) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "virtual-inheritance.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 33, type: !9, scopeLine: 33, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "e", scope: !8, file: !1, line: 34, type: !13) !13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "E", file: !1, line: 13, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !14, vtableHolder: !13, identifier: "_ZTS1E") !14 = !{!15, !19, !25, !30, !33, !34} !15 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !1, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !17, identifier: "_ZTS1A") !17 = !{!18} !18 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !16, file: !1, line: 2, baseType: !11, size: 32) !19 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !20, offset: 64, extraData: i32 0) !20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "B", file: !1, line: 5, size: 64, flags: DIFlagTypePassByValue, elements: !21, identifier: "_ZTS1B") !21 = !{!22} !22 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !20, file: !1, line: 6, baseType: !23, size: 64) !23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) !24 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !25 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !26, offset: 128, extraData: i32 0) !26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C", file: !1, line: 9, size: 8, flags: DIFlagTypePassByValue, elements: !27, identifier: "_ZTS1C") !27 = !{!28} !28 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !26, file: !1, line: 10, baseType: !29, size: 8) !29 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !30 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$E", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64) !32 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: !9, size: 64) !33 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !13, file: !1, line: 14, baseType: !11, size: 32, offset: 160) !34 = !DISubprogram(name: "f", linkageName: "_ZN1E1fEv", scope: !13, file: !1, line: 16, type: !35, scopeLine: 16, containingType: !13, virtualIndex: 0, flags: DIFlagPrototyped, spFlags: DISPFlagVirtual) !35 = !DISubroutineType(types: !36) !36 = !{null, !37} !37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !38 = !DILocation(line: 34, column: 5, scope: !8) !39 = !DILocalVariable(name: "d", scope: !8, file: !1, line: 35, type: !40) !40 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "D", file: !1, line: 19, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !41, vtableHolder: !40, identifier: "_ZTS1D") !41 = !{!42, !43, !44, !45, !46} !42 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !40, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !43 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !40, baseType: !20, offset: 32, flags: DIFlagVirtual, extraData: i32 0) !44 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !40, baseType: !26, offset: 64, extraData: i32 0) !45 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$D", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !46 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !40, file: !1, line: 20, baseType: !47, size: 32, offset: 96) !47 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !48 = !DILocation(line: 35, column: 5, scope: !8) !49 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 36, type: !50) !50 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "F", file: !1, line: 23, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !51, vtableHolder: !50, identifier: "_ZTS1F") !51 = !{!52, !53, !54} !52 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !50, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !53 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$F", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !54 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !50, file: !1, line: 24, baseType: !11, size: 32, offset: 64) !55 = !DILocation(line: 36, column: 5, scope: !8) !56 = !DILocalVariable(name: "g", scope: !8, file: !1, line: 37, type: !57) !57 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "G", file: !1, line: 27, size: 192, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !58, vtableHolder: !57, identifier: "_ZTS1G") !58 = !{!59, !60, !61} !59 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !57, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !60 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$G", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !61 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !57, file: !1, line: 28, baseType: !23, size: 64, offset: 64) !62 = !DILocation(line: 37, column: 5, scope: !8) !63 = !DILocalVariable(name: "h", scope: !8, file: !1, line: 38, type: !64) !64 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "H", file: !1, line: 31, size: 320, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !65, vtableHolder: !50, identifier: "_ZTS1H") !65 = !{!66, !67} !66 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !64, baseType: !50, extraData: i32 0) !67 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !64, baseType: !57, offset: 128, extraData: i32 0) !68 = !DILocation(line: 38, column: 5, scope: !8) !69 = !DILocation(line: 39, column: 3, scope: !8) !70 = distinct !DISubprogram(name: "E", linkageName: "_ZN1EC1Ev", scope: !13, file: !1, line: 13, type: !35, scopeLine: 13, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !71, retainedNodes: !2) !71 = !DISubprogram(name: "E", scope: !13, type: !35, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !72 = !DILocalVariable(name: "this", arg: 1, scope: !70, type: !73, flags: DIFlagArtificial | DIFlagObjectPointer) !73 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !74 = !DILocation(line: 0, scope: !70) !75 = !DILocation(line: 13, column: 8, scope: !70) !76 = distinct !DISubprogram(name: "D", linkageName: "_ZN1DC1Ev", scope: !40, file: !1, line: 19, type: !77, scopeLine: 19, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !80, retainedNodes: !2) !77 = !DISubroutineType(types: !78) !78 = !{null, !79} !79 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !80 = !DISubprogram(name: "D", scope: !40, type: !77, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !81 = !DILocalVariable(name: "this", arg: 1, scope: !76, type: !82, flags: DIFlagArtificial | DIFlagObjectPointer) !82 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64) !83 = !DILocation(line: 0, scope: !76) !84 = !DILocation(line: 19, column: 8, scope: !76) !85 = distinct !DISubprogram(name: "F", linkageName: "_ZN1FC1Ev", scope: !50, file: !1, line: 23, type: !86, scopeLine: 23, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !89, retainedNodes: !2) !86 = !DISubroutineType(types: !87) !87 = !{null, !88} !88 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !50, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !89 = !DISubprogram(name: "F", scope: !50, type: !86, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !90 = !DILocalVariable(name: "this", arg: 1, scope: !85, type: !91, flags: DIFlagArtificial | DIFlagObjectPointer) !91 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !50, size: 64) !92 = !DILocation(line: 0, scope: !85) !93 = !DILocation(line: 23, column: 8, scope: !85) !94 = distinct !DISubprogram(name: "G", linkageName: "_ZN1GC1Ev", scope: !57, file: !1, line: 27, type: !95, scopeLine: 27, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !98, retainedNodes: !2) !95 = !DISubroutineType(types: !96) !96 = !{null, !97} !97 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !98 = !DISubprogram(name: "G", scope: !57, type: !95, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !99 = !DILocalVariable(name: "this", arg: 1, scope: !94, type: !100, flags: DIFlagArtificial | DIFlagObjectPointer) !100 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64) !101 = !DILocation(line: 0, scope: !94) !102 = !DILocation(line: 27, column: 8, scope: !94) !103 = distinct !DISubprogram(name: "H", linkageName: "_ZN1HC1Ev", scope: !64, file: !1, line: 31, type: !104, scopeLine: 31, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !107, retainedNodes: !2) !104 = !DISubroutineType(types: !105) !105 = !{null, !106} !106 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !64, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !107 = !DISubprogram(name: "H", scope: !64, type: !104, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !108 = !DILocalVariable(name: "this", arg: 1, scope: !103, type: !109, flags: DIFlagArtificial | DIFlagObjectPointer) !109 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !64, size: 64) !110 = !DILocation(line: 0, scope: !103) !111 = !DILocation(line: 31, column: 8, scope: !103) !112 = distinct !DISubprogram(name: "f", linkageName: "_ZN1E1fEv", scope: !13, file: !1, line: 16, type: !35, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !34, retainedNodes: !2) !113 = !DILocalVariable(name: "this", arg: 1, scope: !112, type: !73, flags: DIFlagArtificial | DIFlagObjectPointer) !114 = !DILocation(line: 0, scope: !112) !115 = !DILocation(line: 16, column: 21, scope: !112) !116 = distinct !DISubprogram(name: "F", linkageName: "_ZN1FC2Ev", scope: !50, file: !1, line: 23, type: !86, scopeLine: 23, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !89, retainedNodes: !2) !117 = !DILocalVariable(name: "this", arg: 1, scope: !116, type: !91, flags: DIFlagArtificial | DIFlagObjectPointer) !118 = !DILocation(line: 0, scope: !116) !119 = !DILocalVariable(name: "vtt", arg: 2, scope: !116, type: !120, flags: DIFlagArtificial) !120 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !121, size: 64) !121 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !122 = !DILocation(line: 23, column: 8, scope: !116) !123 = distinct !DISubprogram(name: "G", linkageName: "_ZN1GC2Ev", scope: !57, file: !1, line: 27, type: !95, scopeLine: 27, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !98, retainedNodes: !2) !124 = !DILocalVariable(name: "this", arg: 1, scope: !123, type: !100, flags: DIFlagArtificial | DIFlagObjectPointer) !125 = !DILocation(line: 0, scope: !123) !126 = !DILocalVariable(name: "vtt", arg: 2, scope: !123, type: !120, flags: DIFlagArtificial) !127 = !DILocation(line: 27, column: 8, scope: !123) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vla.c000066400000000000000000000003171473507761200306760ustar00rootroot00000000000000#include void foo(int n) { int a[n], i; for (i = 0; i < n; i++) { a[i] = i * i; } a[n] = n * n; } int main(int argc, char** argv) { int v; scanf("%d", &v); foo(v); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/basic_optimization/vla.ll000066400000000000000000000223041473507761200310630ustar00rootroot00000000000000; ModuleID = 'vla.pp.bc' source_filename = "vla.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 ; CHECK: define [3 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @scanf(i8*, ...) #3 ; CHECK: declare si32 @ar.libc.scanf(si8*, ...) ; Function Attrs: nounwind declare void @llvm.stackrestore(i8*) #2 ; CHECK: declare void @ar.stackrestore(si8*) ; Function Attrs: nounwind declare i8* @llvm.stacksave() #2 ; CHECK: declare si8* @ar.stacksave() ; Function Attrs: noinline nounwind ssp uwtable define void @foo(i32) #0 !dbg !8 { call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression()), !dbg !13 %2 = zext i32 %0 to i64, !dbg !14 %3 = call i8* @llvm.stacksave(), !dbg !14 %4 = alloca i32, i64 %2, align 16, !dbg !14 call void @llvm.dbg.value(metadata i64 %2, metadata !15, metadata !DIExpression()), !dbg !13 call void @llvm.dbg.declare(metadata i32* %4, metadata !17, metadata !DIExpression()), !dbg !21 call void @llvm.dbg.value(metadata i32 0, metadata !22, metadata !DIExpression()), !dbg !13 br label %5, !dbg !23 5: ; preds = %11, %1 %.0 = phi i32 [ 0, %1 ], [ %12, %11 ], !dbg !25 call void @llvm.dbg.value(metadata i32 %.0, metadata !22, metadata !DIExpression()), !dbg !13 %6 = icmp slt i32 %.0, %0, !dbg !26 br i1 %6, label %7, label %13, !dbg !28 7: ; preds = %5 %8 = mul nsw i32 %.0, %.0, !dbg !29 %9 = sext i32 %.0 to i64, !dbg !31 %10 = getelementptr inbounds i32, i32* %4, i64 %9, !dbg !31 store i32 %8, i32* %10, align 4, !dbg !32 br label %11, !dbg !33 11: ; preds = %7 %12 = add nsw i32 %.0, 1, !dbg !34 call void @llvm.dbg.value(metadata i32 %12, metadata !22, metadata !DIExpression()), !dbg !13 br label %5, !dbg !35, !llvm.loop !36 13: ; preds = %5 %14 = mul nsw i32 %0, %0, !dbg !38 %15 = sext i32 %0 to i64, !dbg !39 %16 = getelementptr inbounds i32, i32* %4, i64 %15, !dbg !39 store i32 %14, i32* %16, align 4, !dbg !40 call void @llvm.stackrestore(i8* %3), !dbg !41 ret void, !dbg !41 } ; CHECK: define void @foo(si32 %1) { ; CHECK: #1 !entry successors={#2} { ; CHECK: ui32 %2 = bitcast %1 ; CHECK: ui64 %3 = zext %2 ; CHECK: si8* %4 = call @ar.stacksave() ; CHECK: si32* $5 = allocate si32, %3, align 16 ; CHECK: si32 %.0 = 0 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %.0 silt %1 ; CHECK: si32 %6 = %.0 smul.nw %.0 ; CHECK: si64 %7 = sext %.0 ; CHECK: si32* %8 = ptrshift $5, 4 * %7 ; CHECK: store %8, %6, align 4 ; CHECK: si32 %9 = %.0 sadd.nw 1 ; CHECK: si32 %.0 = %9 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %.0 sige %1 ; CHECK: si32 %10 = %1 smul.nw %1 ; CHECK: si64 %11 = sext %1 ; CHECK: si32* %12 = ptrshift $5, 4 * %11 ; CHECK: store %12, %10, align 4 ; CHECK: call @ar.stackrestore(%4) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !42 { %3 = alloca i32, align 4 call void @llvm.dbg.value(metadata i32 %0, metadata !48, metadata !DIExpression()), !dbg !49 call void @llvm.dbg.value(metadata i8** %1, metadata !50, metadata !DIExpression()), !dbg !49 call void @llvm.dbg.declare(metadata i32* %3, metadata !51, metadata !DIExpression()), !dbg !52 %4 = getelementptr inbounds [3 x i8], [3 x i8]* @.str, i64 0, i64 0, !dbg !53 %5 = call i32 (i8*, ...) @scanf(i8* %4, i32* %3), !dbg !53 %6 = load i32, i32* %3, align 4, !dbg !54 call void @foo(i32 %6), !dbg !55 ret i32 0, !dbg !56 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si8* %4 = ptrshift @.str, 3 * 0, 1 * 0 ; CHECK: si32 %5 = call @ar.libc.scanf(%4, $3) ; CHECK: si32 %6 = load $3, align 4 ; CHECK: call @foo(%6) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { nounwind } attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "vla.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/basic_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "n", arg: 1, scope: !8, file: !1, line: 2, type: !11) !13 = !DILocation(line: 0, scope: !8) !14 = !DILocation(line: 3, column: 3, scope: !8) !15 = !DILocalVariable(name: "__vla_expr0", scope: !8, type: !16, flags: DIFlagArtificial) !16 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) !17 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 3, type: !18) !18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, elements: !19) !19 = !{!20} !20 = !DISubrange(count: !15) !21 = !DILocation(line: 3, column: 7, scope: !8) !22 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 3, type: !11) !23 = !DILocation(line: 4, column: 8, scope: !24) !24 = distinct !DILexicalBlock(scope: !8, file: !1, line: 4, column: 3) !25 = !DILocation(line: 0, scope: !24) !26 = !DILocation(line: 4, column: 17, scope: !27) !27 = distinct !DILexicalBlock(scope: !24, file: !1, line: 4, column: 3) !28 = !DILocation(line: 4, column: 3, scope: !24) !29 = !DILocation(line: 5, column: 14, scope: !30) !30 = distinct !DILexicalBlock(scope: !27, file: !1, line: 4, column: 27) !31 = !DILocation(line: 5, column: 5, scope: !30) !32 = !DILocation(line: 5, column: 10, scope: !30) !33 = !DILocation(line: 6, column: 3, scope: !30) !34 = !DILocation(line: 4, column: 23, scope: !27) !35 = !DILocation(line: 4, column: 3, scope: !27) !36 = distinct !{!36, !28, !37} !37 = !DILocation(line: 6, column: 3, scope: !24) !38 = !DILocation(line: 7, column: 12, scope: !8) !39 = !DILocation(line: 7, column: 3, scope: !8) !40 = !DILocation(line: 7, column: 8, scope: !8) !41 = !DILocation(line: 8, column: 1, scope: !8) !42 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 10, type: !43, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !43 = !DISubroutineType(types: !44) !44 = !{!11, !11, !45} !45 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !46, size: 64) !46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !47, size: 64) !47 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !48 = !DILocalVariable(name: "argc", arg: 1, scope: !42, file: !1, line: 10, type: !11) !49 = !DILocation(line: 0, scope: !42) !50 = !DILocalVariable(name: "argv", arg: 2, scope: !42, file: !1, line: 10, type: !45) !51 = !DILocalVariable(name: "v", scope: !42, file: !1, line: 11, type: !11) !52 = !DILocation(line: 11, column: 7, scope: !42) !53 = !DILocation(line: 12, column: 3, scope: !42) !54 = !DILocation(line: 13, column: 7, scope: !42) !55 = !DILocation(line: 13, column: 3, scope: !42) !56 = !DILocation(line: 14, column: 3, scope: !42) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/000077500000000000000000000000001473507761200273025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/aggregate-in-reg-1.cpp000066400000000000000000000006461473507761200332570ustar00rootroot00000000000000template < typename T > class Vector3 { private: T _x, _y, _z; public: Vector3< T >(T x, T y, T z) : _x(x), _y(y), _z(z) {} }; class Foo { private: Vector3< float > coord; public: Foo(float x, float y, float z) : coord(Vector3< float >(x, y, z)) {} Vector3< float > get_coord() { return coord; } }; int main(int argc, char* argv[]) { Foo f(1, 2, 3); Vector3< float > coord = f.get_coord(); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/aggregate-in-reg-1.ll000066400000000000000000000571711473507761200331110ustar00rootroot00000000000000; ModuleID = 'aggregate-in-reg-1.pp.bc' source_filename = "aggregate-in-reg-1.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Foo = type { %class.Vector3 } %class.Vector3 = type { float, float, float } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr { <2 x float>, float } @_ZN3Foo9get_coordEv(%class.Foo*) #3 align 2 !dbg !59 { %2 = alloca %class.Vector3, align 4 %3 = alloca %class.Foo*, align 8 %4 = alloca { <2 x float>, float }, align 8 store %class.Foo* %0, %class.Foo** %3, align 8 call void @llvm.dbg.declare(metadata %class.Foo** %3, metadata !60, metadata !DIExpression()), !dbg !61 %5 = load %class.Foo*, %class.Foo** %3, align 8 %6 = getelementptr inbounds %class.Foo, %class.Foo* %5, i32 0, i32 0, !dbg !62 %7 = bitcast %class.Vector3* %2 to i8*, !dbg !62 %8 = bitcast %class.Vector3* %6 to i8*, !dbg !62 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %8, i64 12, i1 false), !dbg !62 %9 = bitcast { <2 x float>, float }* %4 to i8*, !dbg !63 %10 = bitcast %class.Vector3* %2 to i8*, !dbg !63 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %9, i8* align 4 %10, i64 12, i1 false), !dbg !63 %11 = load { <2 x float>, float }, { <2 x float>, float }* %4, align 8, !dbg !63 ret { <2 x float>, float } %11, !dbg !63 } ; CHECK: define {0: <2 x float>, 8: float} @_ZN3Foo9get_coordEv({0: {0: float, 4: float, 8: float}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: float, 4: float, 8: float}* $2 = allocate {0: float, 4: float, 8: float}, 1, align 4 ; CHECK: {0: {0: float, 4: float, 8: float}}** $3 = allocate {0: {0: float, 4: float, 8: float}}*, 1, align 8 ; CHECK: {0: <2 x float>, 8: float}* $4 = allocate {0: <2 x float>, 8: float}, 1, align 8 ; CHECK: store $3, %1, align 8 ; CHECK: {0: {0: float, 4: float, 8: float}}** %5 = bitcast $3 ; CHECK: {0: {0: float, 4: float, 8: float}}* %6 = load %5, align 8 ; CHECK: {0: float, 4: float, 8: float}* %7 = ptrshift %6, 12 * 0, 1 * 0 ; CHECK: si8* %8 = bitcast $2 ; CHECK: si8* %9 = bitcast %7 ; CHECK: call @ar.memcpy(%8, %9, 12, 4, 4, 0) ; CHECK: si8* %10 = bitcast $4 ; CHECK: si8* %11 = bitcast $2 ; CHECK: call @ar.memcpy(%10, %11, 12, 8, 4, 0) ; CHECK: {0: <2 x float>, 8: float} %12 = load $4, align 8 ; CHECK: return %12 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN3FooC1Efff(%class.Foo*, float, float, float) unnamed_addr #2 align 2 !dbg !47 { %5 = alloca %class.Foo*, align 8 %6 = alloca float, align 4 %7 = alloca float, align 4 %8 = alloca float, align 4 store %class.Foo* %0, %class.Foo** %5, align 8 call void @llvm.dbg.declare(metadata %class.Foo** %5, metadata !48, metadata !DIExpression()), !dbg !50 store float %1, float* %6, align 4 call void @llvm.dbg.declare(metadata float* %6, metadata !51, metadata !DIExpression()), !dbg !52 store float %2, float* %7, align 4 call void @llvm.dbg.declare(metadata float* %7, metadata !53, metadata !DIExpression()), !dbg !54 store float %3, float* %8, align 4 call void @llvm.dbg.declare(metadata float* %8, metadata !55, metadata !DIExpression()), !dbg !56 %9 = load %class.Foo*, %class.Foo** %5, align 8 %10 = load float, float* %6, align 4, !dbg !57 %11 = load float, float* %7, align 4, !dbg !57 %12 = load float, float* %8, align 4, !dbg !57 call void @_ZN3FooC2Efff(%class.Foo* %9, float %10, float %11, float %12), !dbg !57 ret void, !dbg !58 } ; CHECK: define void @_ZN3FooC1Efff({0: {0: float, 4: float, 8: float}}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: float, 4: float, 8: float}}** $5 = allocate {0: {0: float, 4: float, 8: float}}*, 1, align 8 ; CHECK: float* $6 = allocate float, 1, align 4 ; CHECK: float* $7 = allocate float, 1, align 4 ; CHECK: float* $8 = allocate float, 1, align 4 ; CHECK: store $5, %1, align 8 ; CHECK: store $6, %2, align 4 ; CHECK: store $7, %3, align 4 ; CHECK: store $8, %4, align 4 ; CHECK: {0: {0: float, 4: float, 8: float}}* %9 = load $5, align 8 ; CHECK: float %10 = load $6, align 4 ; CHECK: float %11 = load $7, align 4 ; CHECK: float %12 = load $8, align 4 ; CHECK: call @_ZN3FooC2Efff(%9, %10, %11, %12) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN3FooC2Efff(%class.Foo*, float, float, float) unnamed_addr #2 align 2 !dbg !64 { %5 = alloca %class.Foo*, align 8 %6 = alloca float, align 4 %7 = alloca float, align 4 %8 = alloca float, align 4 store %class.Foo* %0, %class.Foo** %5, align 8 call void @llvm.dbg.declare(metadata %class.Foo** %5, metadata !65, metadata !DIExpression()), !dbg !66 store float %1, float* %6, align 4 call void @llvm.dbg.declare(metadata float* %6, metadata !67, metadata !DIExpression()), !dbg !68 store float %2, float* %7, align 4 call void @llvm.dbg.declare(metadata float* %7, metadata !69, metadata !DIExpression()), !dbg !70 store float %3, float* %8, align 4 call void @llvm.dbg.declare(metadata float* %8, metadata !71, metadata !DIExpression()), !dbg !72 %9 = load %class.Foo*, %class.Foo** %5, align 8 %10 = getelementptr inbounds %class.Foo, %class.Foo* %9, i32 0, i32 0, !dbg !73 %11 = load float, float* %6, align 4, !dbg !74 %12 = load float, float* %7, align 4, !dbg !75 %13 = load float, float* %8, align 4, !dbg !76 call void @_ZN7Vector3IfEC1Efff(%class.Vector3* %10, float %11, float %12, float %13), !dbg !77 ret void, !dbg !78 } ; CHECK: define void @_ZN3FooC2Efff({0: {0: float, 4: float, 8: float}}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: float, 4: float, 8: float}}** $5 = allocate {0: {0: float, 4: float, 8: float}}*, 1, align 8 ; CHECK: float* $6 = allocate float, 1, align 4 ; CHECK: float* $7 = allocate float, 1, align 4 ; CHECK: float* $8 = allocate float, 1, align 4 ; CHECK: store $5, %1, align 8 ; CHECK: store $6, %2, align 4 ; CHECK: store $7, %3, align 4 ; CHECK: store $8, %4, align 4 ; CHECK: {0: {0: float, 4: float, 8: float}}** %9 = bitcast $5 ; CHECK: {0: {0: float, 4: float, 8: float}}* %10 = load %9, align 8 ; CHECK: {0: float, 4: float, 8: float}* %11 = ptrshift %10, 12 * 0, 1 * 0 ; CHECK: float %12 = load $6, align 4 ; CHECK: float %13 = load $7, align 4 ; CHECK: float %14 = load $8, align 4 ; CHECK: call @_ZN7Vector3IfEC1Efff(%11, %12, %13, %14) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN7Vector3IfEC1Efff(%class.Vector3*, float, float, float) unnamed_addr #2 align 2 !dbg !79 { %5 = alloca %class.Vector3*, align 8 %6 = alloca float, align 4 %7 = alloca float, align 4 %8 = alloca float, align 4 store %class.Vector3* %0, %class.Vector3** %5, align 8 call void @llvm.dbg.declare(metadata %class.Vector3** %5, metadata !80, metadata !DIExpression()), !dbg !82 store float %1, float* %6, align 4 call void @llvm.dbg.declare(metadata float* %6, metadata !83, metadata !DIExpression()), !dbg !84 store float %2, float* %7, align 4 call void @llvm.dbg.declare(metadata float* %7, metadata !85, metadata !DIExpression()), !dbg !86 store float %3, float* %8, align 4 call void @llvm.dbg.declare(metadata float* %8, metadata !87, metadata !DIExpression()), !dbg !88 %9 = load %class.Vector3*, %class.Vector3** %5, align 8 %10 = load float, float* %6, align 4, !dbg !89 %11 = load float, float* %7, align 4, !dbg !89 %12 = load float, float* %8, align 4, !dbg !89 call void @_ZN7Vector3IfEC2Efff(%class.Vector3* %9, float %10, float %11, float %12), !dbg !89 ret void, !dbg !90 } ; CHECK: define void @_ZN7Vector3IfEC1Efff({0: float, 4: float, 8: float}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: float, 4: float, 8: float}** $5 = allocate {0: float, 4: float, 8: float}*, 1, align 8 ; CHECK: float* $6 = allocate float, 1, align 4 ; CHECK: float* $7 = allocate float, 1, align 4 ; CHECK: float* $8 = allocate float, 1, align 4 ; CHECK: store $5, %1, align 8 ; CHECK: store $6, %2, align 4 ; CHECK: store $7, %3, align 4 ; CHECK: store $8, %4, align 4 ; CHECK: {0: float, 4: float, 8: float}* %9 = load $5, align 8 ; CHECK: float %10 = load $6, align 4 ; CHECK: float %11 = load $7, align 4 ; CHECK: float %12 = load $8, align 4 ; CHECK: call @_ZN7Vector3IfEC2Efff(%9, %10, %11, %12) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN7Vector3IfEC2Efff(%class.Vector3*, float, float, float) unnamed_addr #3 align 2 !dbg !91 { %5 = alloca %class.Vector3*, align 8 %6 = alloca float, align 4 %7 = alloca float, align 4 %8 = alloca float, align 4 store %class.Vector3* %0, %class.Vector3** %5, align 8 call void @llvm.dbg.declare(metadata %class.Vector3** %5, metadata !92, metadata !DIExpression()), !dbg !93 store float %1, float* %6, align 4 call void @llvm.dbg.declare(metadata float* %6, metadata !94, metadata !DIExpression()), !dbg !95 store float %2, float* %7, align 4 call void @llvm.dbg.declare(metadata float* %7, metadata !96, metadata !DIExpression()), !dbg !97 store float %3, float* %8, align 4 call void @llvm.dbg.declare(metadata float* %8, metadata !98, metadata !DIExpression()), !dbg !99 %9 = load %class.Vector3*, %class.Vector3** %5, align 8 %10 = getelementptr inbounds %class.Vector3, %class.Vector3* %9, i32 0, i32 0, !dbg !100 %11 = load float, float* %6, align 4, !dbg !101 store float %11, float* %10, align 4, !dbg !100 %12 = getelementptr inbounds %class.Vector3, %class.Vector3* %9, i32 0, i32 1, !dbg !102 %13 = load float, float* %7, align 4, !dbg !103 store float %13, float* %12, align 4, !dbg !102 %14 = getelementptr inbounds %class.Vector3, %class.Vector3* %9, i32 0, i32 2, !dbg !104 %15 = load float, float* %8, align 4, !dbg !105 store float %15, float* %14, align 4, !dbg !104 ret void, !dbg !106 } ; CHECK: define void @_ZN7Vector3IfEC2Efff({0: float, 4: float, 8: float}* %1, float %2, float %3, float %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: float, 4: float, 8: float}** $5 = allocate {0: float, 4: float, 8: float}*, 1, align 8 ; CHECK: float* $6 = allocate float, 1, align 4 ; CHECK: float* $7 = allocate float, 1, align 4 ; CHECK: float* $8 = allocate float, 1, align 4 ; CHECK: store $5, %1, align 8 ; CHECK: store $6, %2, align 4 ; CHECK: store $7, %3, align 4 ; CHECK: store $8, %4, align 4 ; CHECK: {0: float, 4: float, 8: float}** %9 = bitcast $5 ; CHECK: {0: float, 4: float, 8: float}* %10 = load %9, align 8 ; CHECK: float* %11 = ptrshift %10, 12 * 0, 1 * 0 ; CHECK: float %12 = load $6, align 4 ; CHECK: store %11, %12, align 4 ; CHECK: float* %13 = ptrshift %10, 12 * 0, 1 * 4 ; CHECK: float %14 = load $7, align 4 ; CHECK: store %13, %14, align 4 ; CHECK: float* %15 = ptrshift %10, 12 * 0, 1 * 8 ; CHECK: float %16 = load $8, align 4 ; CHECK: store %15, %16, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #4 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca %class.Foo, align 4 %7 = alloca %class.Vector3, align 4 %8 = alloca { <2 x float>, float }, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !15, metadata !DIExpression()), !dbg !16 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata %class.Foo* %6, metadata !19, metadata !DIExpression()), !dbg !42 call void @_ZN3FooC1Efff(%class.Foo* %6, float 1.000000e+00, float 2.000000e+00, float 3.000000e+00), !dbg !42 call void @llvm.dbg.declare(metadata %class.Vector3* %7, metadata !43, metadata !DIExpression()), !dbg !44 %9 = call { <2 x float>, float } @_ZN3Foo9get_coordEv(%class.Foo* %6), !dbg !45 store { <2 x float>, float } %9, { <2 x float>, float }* %8, align 8, !dbg !45 %10 = bitcast { <2 x float>, float }* %8 to i8*, !dbg !45 %11 = bitcast %class.Vector3* %7 to i8*, !dbg !45 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %11, i8* align 8 %10, i64 12, i1 false), !dbg !45 ret i32 0, !dbg !46 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: {0: {0: float, 4: float, 8: float}}* $6 = allocate {0: {0: float, 4: float, 8: float}}, 1, align 4 ; CHECK: {0: float, 4: float, 8: float}* $7 = allocate {0: float, 4: float, 8: float}, 1, align 4 ; CHECK: {0: <2 x float>, 8: float}* $8 = allocate {0: <2 x float>, 8: float}, 1, align 8 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: call @_ZN3FooC1Efff($6, 1.0E+0, 2.0E+0, 3.0E+0) ; CHECK: {0: <2 x float>, 8: float} %9 = call @_ZN3Foo9get_coordEv($6) ; CHECK: store $8, %9, align 8 ; CHECK: si8* %10 = bitcast $8 ; CHECK: si8* %11 = bitcast $7 ; CHECK: call @ar.memcpy(%11, %10, 12, 4, 8, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "aggregate-in-reg-1.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 19, type: !9, scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 19, type: !11) !16 = !DILocation(line: 19, column: 14, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 19, type: !12) !18 = !DILocation(line: 19, column: 26, scope: !8) !19 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 20, type: !20) !20 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Foo", file: !1, line: 10, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !21, identifier: "_ZTS3Foo") !21 = !{!22, !35, !39} !22 = !DIDerivedType(tag: DW_TAG_member, name: "coord", scope: !20, file: !1, line: 12, baseType: !23, size: 96) !23 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Vector3", file: !1, line: 2, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !24, templateParams: !33, identifier: "_ZTS7Vector3IfE") !24 = !{!25, !27, !28, !29} !25 = !DIDerivedType(tag: DW_TAG_member, name: "_x", scope: !23, file: !1, line: 4, baseType: !26, size: 32) !26 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !27 = !DIDerivedType(tag: DW_TAG_member, name: "_y", scope: !23, file: !1, line: 4, baseType: !26, size: 32, offset: 32) !28 = !DIDerivedType(tag: DW_TAG_member, name: "_z", scope: !23, file: !1, line: 4, baseType: !26, size: 32, offset: 64) !29 = !DISubprogram(name: "Vector3", scope: !23, file: !1, line: 7, type: !30, scopeLine: 7, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !30 = !DISubroutineType(types: !31) !31 = !{null, !32, !26, !26, !26} !32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !33 = !{!34} !34 = !DITemplateTypeParameter(name: "T", type: !26) !35 = !DISubprogram(name: "Foo", scope: !20, file: !1, line: 15, type: !36, scopeLine: 15, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !36 = !DISubroutineType(types: !37) !37 = !{null, !38, !26, !26, !26} !38 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !39 = !DISubprogram(name: "get_coord", linkageName: "_ZN3Foo9get_coordEv", scope: !20, file: !1, line: 16, type: !40, scopeLine: 16, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !40 = !DISubroutineType(types: !41) !41 = !{!23, !38} !42 = !DILocation(line: 20, column: 7, scope: !8) !43 = !DILocalVariable(name: "coord", scope: !8, file: !1, line: 21, type: !23) !44 = !DILocation(line: 21, column: 20, scope: !8) !45 = !DILocation(line: 21, column: 30, scope: !8) !46 = !DILocation(line: 22, column: 3, scope: !8) !47 = distinct !DISubprogram(name: "Foo", linkageName: "_ZN3FooC1Efff", scope: !20, file: !1, line: 15, type: !36, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !35, retainedNodes: !2) !48 = !DILocalVariable(name: "this", arg: 1, scope: !47, type: !49, flags: DIFlagArtificial | DIFlagObjectPointer) !49 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !50 = !DILocation(line: 0, scope: !47) !51 = !DILocalVariable(name: "x", arg: 2, scope: !47, file: !1, line: 15, type: !26) !52 = !DILocation(line: 15, column: 13, scope: !47) !53 = !DILocalVariable(name: "y", arg: 3, scope: !47, file: !1, line: 15, type: !26) !54 = !DILocation(line: 15, column: 22, scope: !47) !55 = !DILocalVariable(name: "z", arg: 4, scope: !47, file: !1, line: 15, type: !26) !56 = !DILocation(line: 15, column: 31, scope: !47) !57 = !DILocation(line: 15, column: 69, scope: !47) !58 = !DILocation(line: 15, column: 70, scope: !47) !59 = distinct !DISubprogram(name: "get_coord", linkageName: "_ZN3Foo9get_coordEv", scope: !20, file: !1, line: 16, type: !40, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !39, retainedNodes: !2) !60 = !DILocalVariable(name: "this", arg: 1, scope: !59, type: !49, flags: DIFlagArtificial | DIFlagObjectPointer) !61 = !DILocation(line: 0, scope: !59) !62 = !DILocation(line: 16, column: 41, scope: !59) !63 = !DILocation(line: 16, column: 34, scope: !59) !64 = distinct !DISubprogram(name: "Foo", linkageName: "_ZN3FooC2Efff", scope: !20, file: !1, line: 15, type: !36, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !35, retainedNodes: !2) !65 = !DILocalVariable(name: "this", arg: 1, scope: !64, type: !49, flags: DIFlagArtificial | DIFlagObjectPointer) !66 = !DILocation(line: 0, scope: !64) !67 = !DILocalVariable(name: "x", arg: 2, scope: !64, file: !1, line: 15, type: !26) !68 = !DILocation(line: 15, column: 13, scope: !64) !69 = !DILocalVariable(name: "y", arg: 3, scope: !64, file: !1, line: 15, type: !26) !70 = !DILocation(line: 15, column: 22, scope: !64) !71 = !DILocalVariable(name: "z", arg: 4, scope: !64, file: !1, line: 15, type: !26) !72 = !DILocation(line: 15, column: 31, scope: !64) !73 = !DILocation(line: 15, column: 36, scope: !64) !74 = !DILocation(line: 15, column: 59, scope: !64) !75 = !DILocation(line: 15, column: 62, scope: !64) !76 = !DILocation(line: 15, column: 65, scope: !64) !77 = !DILocation(line: 15, column: 42, scope: !64) !78 = !DILocation(line: 15, column: 70, scope: !64) !79 = distinct !DISubprogram(name: "Vector3", linkageName: "_ZN7Vector3IfEC1Efff", scope: !23, file: !1, line: 7, type: !30, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !29, retainedNodes: !2) !80 = !DILocalVariable(name: "this", arg: 1, scope: !79, type: !81, flags: DIFlagArtificial | DIFlagObjectPointer) !81 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) !82 = !DILocation(line: 0, scope: !79) !83 = !DILocalVariable(name: "x", arg: 2, scope: !79, file: !1, line: 7, type: !26) !84 = !DILocation(line: 7, column: 18, scope: !79) !85 = !DILocalVariable(name: "y", arg: 3, scope: !79, file: !1, line: 7, type: !26) !86 = !DILocation(line: 7, column: 23, scope: !79) !87 = !DILocalVariable(name: "z", arg: 4, scope: !79, file: !1, line: 7, type: !26) !88 = !DILocation(line: 7, column: 28, scope: !79) !89 = !DILocation(line: 7, column: 53, scope: !79) !90 = !DILocation(line: 7, column: 54, scope: !79) !91 = distinct !DISubprogram(name: "Vector3", linkageName: "_ZN7Vector3IfEC2Efff", scope: !23, file: !1, line: 7, type: !30, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !29, retainedNodes: !2) !92 = !DILocalVariable(name: "this", arg: 1, scope: !91, type: !81, flags: DIFlagArtificial | DIFlagObjectPointer) !93 = !DILocation(line: 0, scope: !91) !94 = !DILocalVariable(name: "x", arg: 2, scope: !91, file: !1, line: 7, type: !26) !95 = !DILocation(line: 7, column: 18, scope: !91) !96 = !DILocalVariable(name: "y", arg: 3, scope: !91, file: !1, line: 7, type: !26) !97 = !DILocation(line: 7, column: 23, scope: !91) !98 = !DILocalVariable(name: "z", arg: 4, scope: !91, file: !1, line: 7, type: !26) !99 = !DILocation(line: 7, column: 28, scope: !91) !100 = !DILocation(line: 7, column: 33, scope: !91) !101 = !DILocation(line: 7, column: 36, scope: !91) !102 = !DILocation(line: 7, column: 40, scope: !91) !103 = !DILocation(line: 7, column: 43, scope: !91) !104 = !DILocation(line: 7, column: 47, scope: !91) !105 = !DILocation(line: 7, column: 50, scope: !91) !106 = !DILocation(line: 7, column: 54, scope: !91) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/aggregate-in-reg-2.cpp000066400000000000000000000003501473507761200332500ustar00rootroot00000000000000#include typedef struct { float x; float y; } pos_t; typedef struct { pos_t begin, end; } line_t; line_t f(float y) { return {{0.0, y}, {2.0, 0}}; } int main() { printf("%f\n", f(2.0).begin.y); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/aggregate-in-reg-2.ll000066400000000000000000000236041473507761200331040ustar00rootroot00000000000000; ModuleID = 'aggregate-in-reg-2.pp.bc' source_filename = "aggregate-in-reg-2.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.line_t = type { %struct.pos_t, %struct.pos_t } %struct.pos_t = type { float, float } @.str = private unnamed_addr constant [4 x i8] c"%f\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 102, 10, 0], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define { <2 x float>, <2 x float> } @_Z1ff(float) #0 !dbg !8 { %2 = alloca %struct.line_t, align 4 %3 = alloca float, align 4 store float %0, float* %3, align 4 call void @llvm.dbg.declare(metadata float* %3, metadata !22, metadata !DIExpression()), !dbg !23 %4 = getelementptr inbounds %struct.line_t, %struct.line_t* %2, i32 0, i32 0, !dbg !24 %5 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %4, i32 0, i32 0, !dbg !25 store float 0.000000e+00, float* %5, align 4, !dbg !25 %6 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %4, i32 0, i32 1, !dbg !25 %7 = load float, float* %3, align 4, !dbg !26 store float %7, float* %6, align 4, !dbg !25 %8 = getelementptr inbounds %struct.line_t, %struct.line_t* %2, i32 0, i32 1, !dbg !24 %9 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %8, i32 0, i32 0, !dbg !27 store float 2.000000e+00, float* %9, align 4, !dbg !27 %10 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %8, i32 0, i32 1, !dbg !27 store float 0.000000e+00, float* %10, align 4, !dbg !27 %11 = bitcast %struct.line_t* %2 to { <2 x float>, <2 x float> }*, !dbg !28 %12 = load { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %11, align 4, !dbg !28 ret { <2 x float>, <2 x float> } %12, !dbg !28 } ; CHECK: define {0: <2 x float>, 8: <2 x float>} @_Z1ff(float %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: float, 4: float}, 8: {0: float, 4: float}}* $2 = allocate {0: {0: float, 4: float}, 8: {0: float, 4: float}}, 1, align 4 ; CHECK: float* $3 = allocate float, 1, align 4 ; CHECK: store $3, %1, align 4 ; CHECK: {0: float, 4: float}* %4 = ptrshift $2, 16 * 0, 1 * 0 ; CHECK: float* %5 = ptrshift %4, 8 * 0, 1 * 0 ; CHECK: store %5, 0.0E+0, align 4 ; CHECK: float* %6 = ptrshift %4, 8 * 0, 1 * 4 ; CHECK: float %7 = load $3, align 4 ; CHECK: store %6, %7, align 4 ; CHECK: {0: float, 4: float}* %8 = ptrshift $2, 16 * 0, 1 * 8 ; CHECK: float* %9 = ptrshift %8, 8 * 0, 1 * 0 ; CHECK: store %9, 2.0E+0, align 4 ; CHECK: float* %10 = ptrshift %8, 8 * 0, 1 * 4 ; CHECK: store %10, 0.0E+0, align 4 ; CHECK: {0: <2 x float>, 8: <2 x float>}* %11 = bitcast $2 ; CHECK: {0: <2 x float>, 8: <2 x float>} %12 = load %11, align 4 ; CHECK: return %12 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #3 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #2 !dbg !29 { %1 = alloca i32, align 4 %2 = alloca %struct.line_t, align 4 store i32 0, i32* %1, align 4 %3 = call { <2 x float>, <2 x float> } @_Z1ff(float 2.000000e+00), !dbg !33 %4 = bitcast %struct.line_t* %2 to { <2 x float>, <2 x float> }*, !dbg !33 %5 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %4, i32 0, i32 0, !dbg !33 %6 = extractvalue { <2 x float>, <2 x float> } %3, 0, !dbg !33 store <2 x float> %6, <2 x float>* %5, align 4, !dbg !33 %7 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %4, i32 0, i32 1, !dbg !33 %8 = extractvalue { <2 x float>, <2 x float> } %3, 1, !dbg !33 store <2 x float> %8, <2 x float>* %7, align 4, !dbg !33 %9 = getelementptr inbounds %struct.line_t, %struct.line_t* %2, i32 0, i32 0, !dbg !34 %10 = getelementptr inbounds %struct.pos_t, %struct.pos_t* %9, i32 0, i32 1, !dbg !35 %11 = load float, float* %10, align 4, !dbg !35 %12 = fpext float %11 to double, !dbg !33 %13 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !36 %14 = call i32 (i8*, ...) @printf(i8* %13, double %12), !dbg !36 ret i32 0, !dbg !37 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: {0: {0: float, 4: float}, 8: {0: float, 4: float}}* $2 = allocate {0: {0: float, 4: float}, 8: {0: float, 4: float}}, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: {0: <2 x float>, 8: <2 x float>} %3 = call @_Z1ff(2.0E+0) ; CHECK: {0: <2 x float>, 8: <2 x float>}* %4 = bitcast $2 ; CHECK: <2 x float>* %5 = ptrshift %4, 16 * 0, 1 * 0 ; CHECK: <2 x float> %6 = extractelement %3, 0 ; CHECK: store %5, %6, align 4 ; CHECK: <2 x float>* %7 = ptrshift %4, 16 * 0, 1 * 8 ; CHECK: <2 x float> %8 = extractelement %3, 8 ; CHECK: store %7, %8, align 4 ; CHECK: {0: float, 4: float}* %9 = ptrshift $2, 16 * 0, 1 * 0 ; CHECK: float* %10 = ptrshift %9, 8 * 0, 1 * 4 ; CHECK: float %11 = load %10, align 4 ; CHECK: double %12 = fpext %11 ; CHECK: si8* %13 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %14 = call @ar.libc.printf(%13, %12) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "aggregate-in-reg-2.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1ff", scope: !1, file: !1, line: 12, type: !9, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !19} !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "line_t", file: !1, line: 10, baseType: !12) !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 8, size: 128, flags: DIFlagTypePassByValue, elements: !13, identifier: "_ZTS6line_t") !13 = !{!14, !21} !14 = !DIDerivedType(tag: DW_TAG_member, name: "begin", scope: !12, file: !1, line: 9, baseType: !15, size: 64) !15 = !DIDerivedType(tag: DW_TAG_typedef, name: "pos_t", file: !1, line: 6, baseType: !16) !16 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 3, size: 64, flags: DIFlagTypePassByValue, elements: !17, identifier: "_ZTS5pos_t") !17 = !{!18, !20} !18 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !16, file: !1, line: 4, baseType: !19, size: 32) !19 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !20 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !16, file: !1, line: 5, baseType: !19, size: 32, offset: 32) !21 = !DIDerivedType(tag: DW_TAG_member, name: "end", scope: !12, file: !1, line: 9, baseType: !15, size: 64, offset: 64) !22 = !DILocalVariable(name: "y", arg: 1, scope: !8, file: !1, line: 12, type: !19) !23 = !DILocation(line: 12, column: 16, scope: !8) !24 = !DILocation(line: 13, column: 10, scope: !8) !25 = !DILocation(line: 13, column: 11, scope: !8) !26 = !DILocation(line: 13, column: 17, scope: !8) !27 = !DILocation(line: 13, column: 21, scope: !8) !28 = !DILocation(line: 13, column: 3, scope: !8) !29 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 16, type: !30, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !30 = !DISubroutineType(types: !31) !31 = !{!32} !32 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !33 = !DILocation(line: 17, column: 18, scope: !29) !34 = !DILocation(line: 17, column: 25, scope: !29) !35 = !DILocation(line: 17, column: 31, scope: !29) !36 = !DILocation(line: 17, column: 3, scope: !29) !37 = !DILocation(line: 18, column: 3, scope: !29) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/array-init.cpp000066400000000000000000000000551473507761200320650ustar00rootroot00000000000000struct i { unsigned j[16]; } k[]{{}, {2}}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/array-init.ll000066400000000000000000000043711473507761200317170ustar00rootroot00000000000000; ModuleID = 'array-init.pp.bc' source_filename = "array-init.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.i = type { [16 x i32] } @k = global <{ %struct.i, { <{ i32, [15 x i32] }> } }> <{ %struct.i zeroinitializer, { <{ i32, [15 x i32] }> } { <{ i32, [15 x i32] }> <{ i32 2, [15 x i32] zeroinitializer }> } }>, align 16, !dbg !0 ; CHECK: define <{0: {0: [16 x si32]}, 64: {0: <{0: si32, 4: [15 x si32]}>}}>* @k, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @k, {0: aggregate_zero, 64: {0: {0: 2, 4: aggregate_zero}}}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!16, !17, !18, !19} !llvm.ident = !{!20} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "k", scope: !2, file: !3, line: 3, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "array-init.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1024, elements: !14) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "i", file: !3, line: 1, size: 512, flags: DIFlagTypePassByValue, elements: !8, identifier: "_ZTS1i") !8 = !{!9} !9 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !7, file: !3, line: 2, baseType: !10, size: 512) !10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 512, elements: !12) !11 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !12 = !{!13} !13 = !DISubrange(count: 16) !14 = !{!15} !15 = !DISubrange(count: 2) !16 = !{i32 2, !"Dwarf Version", i32 4} !17 = !{i32 2, !"Debug Info Version", i32 3} !18 = !{i32 1, !"wchar_size", i32 4} !19 = !{i32 7, !"PIC Level", i32 2} !20 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/asm.c000066400000000000000000000002631473507761200302270ustar00rootroot00000000000000#include int main() { int src = 1; int dst; asm("mov %1, %0\n\t" "add $1, %0" : "=r"(dst) : "r"(src)); printf("%d\n", dst); return dst; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/asm.ll000066400000000000000000000114441473507761200304170ustar00rootroot00000000000000; ModuleID = 'asm.pp.bc' source_filename = "asm.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca i32, align 4 %2 = alloca i32, align 4 %3 = alloca i32, align 4 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata i32* %2, metadata !12, metadata !DIExpression()), !dbg !13 store i32 1, i32* %2, align 4, !dbg !13 call void @llvm.dbg.declare(metadata i32* %3, metadata !14, metadata !DIExpression()), !dbg !15 %4 = load i32, i32* %2, align 4, !dbg !16 %5 = call i32 asm "mov $1, $0\0A\09add $$1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %4) #3, !dbg !17, !srcloc !18 store i32 %5, i32* %3, align 4, !dbg !17 %6 = load i32, i32* %3, align 4, !dbg !19 %7 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !20 %8 = call i32 (i8*, ...) @printf(i8* %7, i32 %6), !dbg !20 %9 = load i32, i32* %3, align 4, !dbg !21 ret i32 %9, !dbg !22 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: store $2, 1, align 4 ; CHECK: si32 %4 = load $2, align 4 ; CHECK: si32 %5 = call asm "mov $1, $0 ; CHECK: add $$1, $0"(%4) ; CHECK: store $3, %5, align 4 ; CHECK: si32 %6 = load $3, align 4 ; CHECK: si8* %7 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %8 = call @ar.libc.printf(%7, %6) ; CHECK: si32 %9 = load $3, align 4 ; CHECK: return %9 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind readnone } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "asm.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "src", scope: !8, file: !1, line: 4, type: !11) !13 = !DILocation(line: 4, column: 7, scope: !8) !14 = !DILocalVariable(name: "dst", scope: !8, file: !1, line: 5, type: !11) !15 = !DILocation(line: 5, column: 7, scope: !8) !16 = !DILocation(line: 10, column: 13, scope: !8) !17 = !DILocation(line: 7, column: 3, scope: !8) !18 = !{i32 68, i32 81} !19 = !DILocation(line: 12, column: 18, scope: !8) !20 = !DILocation(line: 12, column: 3, scope: !8) !21 = !DILocation(line: 13, column: 10, scope: !8) !22 = !DILocation(line: 13, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/atomic.c000066400000000000000000000001101473507761200307120ustar00rootroot00000000000000_Atomic volatile unsigned x; int main() { x = 42; return (int)x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/atomic.ll000066400000000000000000000061061473507761200311120ustar00rootroot00000000000000; ModuleID = 'atomic.pp.bc' source_filename = "atomic.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @x = common global i32 0, align 4, !dbg !0 ; CHECK: define ui32* @x, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @x, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !16 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 store volatile i32 42, i32* @x, align 4, !dbg !18 %2 = load volatile i32, i32* @x, align 4, !dbg !19 ret i32 %2, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: store volatile @x, 42, align 4 ; CHECK: si32* %2 = bitcast @x ; CHECK: si32 %3 = load volatile %2, align 4 ; CHECK: return %3 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!11, !12, !13, !14} !llvm.ident = !{!15} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !7, nameTableKind: GNU) !3 = !DIFile(filename: "atomic.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!6} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{!0} !8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !9) !9 = !DIDerivedType(tag: DW_TAG_atomic_type, baseType: !10) !10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !11 = !{i32 2, !"Dwarf Version", i32 4} !12 = !{i32 2, !"Debug Info Version", i32 3} !13 = !{i32 1, !"wchar_size", i32 4} !14 = !{i32 7, !"PIC Level", i32 2} !15 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !16 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !17 = !DISubroutineType(types: !5) !18 = !DILocation(line: 4, column: 5, scope: !16) !19 = !DILocation(line: 5, column: 15, scope: !16) !20 = !DILocation(line: 5, column: 3, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/basic-loop.c000066400000000000000000000001761473507761200315020ustar00rootroot00000000000000double a[10]; int main(int argc, char** argv) { int i; for (i = 0; i < 10; i++) { a[i] = i * 0.88; } a[i] = i; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/basic-loop.ll000066400000000000000000000172201473507761200316650ustar00rootroot00000000000000; ModuleID = 'basic-loop.pp.bc' source_filename = "basic-loop.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global [10 x double] zeroinitializer, align 16, !dbg !0 ; CHECK: define [10 x double]* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !15 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !22, metadata !DIExpression()), !dbg !23 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !24, metadata !DIExpression()), !dbg !25 call void @llvm.dbg.declare(metadata i32* %6, metadata !26, metadata !DIExpression()), !dbg !27 store i32 0, i32* %6, align 4, !dbg !28 br label %7, !dbg !30 7: ; preds = %17, %2 %8 = load i32, i32* %6, align 4, !dbg !31 %9 = icmp slt i32 %8, 10, !dbg !33 br i1 %9, label %10, label %20, !dbg !34 10: ; preds = %7 %11 = load i32, i32* %6, align 4, !dbg !35 %12 = sitofp i32 %11 to double, !dbg !35 %13 = fmul double %12, 8.800000e-01, !dbg !37 %14 = load i32, i32* %6, align 4, !dbg !38 %15 = sext i32 %14 to i64, !dbg !39 %16 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %15, !dbg !39 store double %13, double* %16, align 8, !dbg !40 br label %17, !dbg !41 17: ; preds = %10 %18 = load i32, i32* %6, align 4, !dbg !42 %19 = add nsw i32 %18, 1, !dbg !42 store i32 %19, i32* %6, align 4, !dbg !42 br label %7, !dbg !43, !llvm.loop !44 20: ; preds = %7 %21 = load i32, i32* %6, align 4, !dbg !46 %22 = sitofp i32 %21 to double, !dbg !46 %23 = load i32, i32* %6, align 4, !dbg !47 %24 = sext i32 %23 to i64, !dbg !48 %25 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %24, !dbg !48 store double %22, double* %25, align 8, !dbg !49 %26 = load i32, i32* %3, align 4, !dbg !50 ret i32 %26, !dbg !50 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: store $6, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: si32 %7 = load $6, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %7 silt 10 ; CHECK: si32 %8 = load $6, align 4 ; CHECK: double %9 = sitofp %8 ; CHECK: double %10 = %9 fmul 8.8E-1 ; CHECK: si32 %11 = load $6, align 4 ; CHECK: si64 %12 = sext %11 ; CHECK: double* %13 = ptrshift @a, 80 * 0, 8 * %12 ; CHECK: store %13, %10, align 8 ; CHECK: si32 %14 = load $6, align 4 ; CHECK: si32 %15 = %14 sadd.nw 1 ; CHECK: store $6, %15, align 4 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %7 sige 10 ; CHECK: si32 %16 = load $6, align 4 ; CHECK: double %17 = sitofp %16 ; CHECK: si32 %18 = load $6, align 4 ; CHECK: si64 %19 = sext %18 ; CHECK: double* %20 = ptrshift @a, 80 * 0, 8 * %19 ; CHECK: store %20, %17, align 8 ; CHECK: si32 %21 = load $3, align 4 ; CHECK: return %21 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!10, !11, !12, !13} !llvm.ident = !{!14} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "basic-loop.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 640, elements: !8) !7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 10) !10 = !{i32 2, !"Dwarf Version", i32 4} !11 = !{i32 2, !"Debug Info Version", i32 3} !12 = !{i32 1, !"wchar_size", i32 4} !13 = !{i32 7, !"PIC Level", i32 2} !14 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !15 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !16 = !DISubroutineType(types: !17) !17 = !{!18, !18, !19} !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !15, file: !3, line: 3, type: !18) !23 = !DILocation(line: 3, column: 14, scope: !15) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !15, file: !3, line: 3, type: !19) !25 = !DILocation(line: 3, column: 27, scope: !15) !26 = !DILocalVariable(name: "i", scope: !15, file: !3, line: 4, type: !18) !27 = !DILocation(line: 4, column: 7, scope: !15) !28 = !DILocation(line: 5, column: 10, scope: !29) !29 = distinct !DILexicalBlock(scope: !15, file: !3, line: 5, column: 3) !30 = !DILocation(line: 5, column: 8, scope: !29) !31 = !DILocation(line: 5, column: 15, scope: !32) !32 = distinct !DILexicalBlock(scope: !29, file: !3, line: 5, column: 3) !33 = !DILocation(line: 5, column: 17, scope: !32) !34 = !DILocation(line: 5, column: 3, scope: !29) !35 = !DILocation(line: 6, column: 12, scope: !36) !36 = distinct !DILexicalBlock(scope: !32, file: !3, line: 5, column: 28) !37 = !DILocation(line: 6, column: 14, scope: !36) !38 = !DILocation(line: 6, column: 7, scope: !36) !39 = !DILocation(line: 6, column: 5, scope: !36) !40 = !DILocation(line: 6, column: 10, scope: !36) !41 = !DILocation(line: 7, column: 3, scope: !36) !42 = !DILocation(line: 5, column: 24, scope: !32) !43 = !DILocation(line: 5, column: 3, scope: !32) !44 = distinct !{!44, !34, !45} !45 = !DILocation(line: 7, column: 3, scope: !29) !46 = !DILocation(line: 8, column: 10, scope: !15) !47 = !DILocation(line: 8, column: 5, scope: !15) !48 = !DILocation(line: 8, column: 3, scope: !15) !49 = !DILocation(line: 8, column: 8, scope: !15) !50 = !DILocation(line: 9, column: 1, scope: !15) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bit-field-1.c000066400000000000000000000002141473507761200314400ustar00rootroot00000000000000struct info_t { char x : 1; char y : 1; int z : 10; int k : 1; }; int main() { struct info_t info = {0, 0, 42, 1}; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bit-field-1.ll000066400000000000000000000110071473507761200316270ustar00rootroot00000000000000; ModuleID = 'bit-field-1.pp.bc' source_filename = "bit-field-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.info_t = type { i16, [2 x i8] } @__const.main.info = private unnamed_addr constant { i8, i8, [2 x i8] } { i8 -88, i8 16, [2 x i8] undef }, align 4 ; CHECK: define {0: si8, 1: si8, 2: [2 x si8]}* @__const.main.info, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @__const.main.info, {0: -88, 1: 16, 2: undef}, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca i32, align 4 %2 = alloca %struct.info_t, align 4 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata %struct.info_t* %2, metadata !12, metadata !DIExpression()), !dbg !20 %3 = bitcast %struct.info_t* %2 to i8*, !dbg !20 %4 = getelementptr inbounds { i8, i8, [2 x i8] }, { i8, i8, [2 x i8] }* @__const.main.info, i32 0, i32 0, !dbg !20 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %3, i8* align 4 %4, i64 4, i1 false), !dbg !20 ret i32 0, !dbg !21 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: {0: ui16, 2: [2 x si8]}* $2 = allocate {0: ui16, 2: [2 x si8]}, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: si8* %3 = bitcast $2 ; CHECK: si8* %4 = ptrshift @__const.main.info, 4 * 0, 1 * 0 ; CHECK: call @ar.memcpy(%3, %4, 4, 4, 4, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bit-field-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !9, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "info", scope: !8, file: !1, line: 9, type: !13) !13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "info_t", file: !1, line: 1, size: 32, elements: !14) !14 = !{!15, !17, !18, !19} !15 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !13, file: !1, line: 2, baseType: !16, size: 1, flags: DIFlagBitField, extraData: i64 0) !16 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !17 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !13, file: !1, line: 3, baseType: !16, size: 1, offset: 1, flags: DIFlagBitField, extraData: i64 0) !18 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !13, file: !1, line: 4, baseType: !11, size: 10, offset: 2, flags: DIFlagBitField, extraData: i64 0) !19 = !DIDerivedType(tag: DW_TAG_member, name: "k", scope: !13, file: !1, line: 5, baseType: !11, size: 1, offset: 12, flags: DIFlagBitField, extraData: i64 0) !20 = !DILocation(line: 9, column: 17, scope: !8) !21 = !DILocation(line: 10, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bit-field-2.c000066400000000000000000000000731473507761200314440ustar00rootroot00000000000000struct { unsigned : 7; unsigned a; } b[6][1] = {{{}}}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bit-field-2.ll000066400000000000000000000047551473507761200316440ustar00rootroot00000000000000; ModuleID = 'bit-field-2.pp.bc' source_filename = "bit-field-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.anon = type { i8, i32 } @b = global <{ [1 x { [4 x i8], i32 }], [1 x %struct.anon], [1 x %struct.anon], [1 x %struct.anon], [1 x %struct.anon], [1 x %struct.anon] }> <{ [1 x { [4 x i8], i32 }] [{ [4 x i8], i32 } { [4 x i8] undef, i32 0 }], [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer, [1 x %struct.anon] zeroinitializer }>, align 16, !dbg !0 ; CHECK: define <{0: [1 x {0: [4 x si8], 4: si32}], 8: [1 x {0: si8, 4: si32}], 16: [1 x {0: si8, 4: si32}], 24: [1 x {0: si8, 4: si32}], 32: [1 x {0: si8, 4: si32}], 40: [1 x {0: si8, 4: si32}]}>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, {0: [{0: undef, 4: 0}], 8: aggregate_zero, 16: aggregate_zero, 24: aggregate_zero, 32: aggregate_zero, 40: aggregate_zero}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!14, !15, !16, !17} !llvm.ident = !{!18} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bit-field-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 384, elements: !11) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 64, elements: !8) !8 = !{!9} !9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 3, baseType: !10, size: 32, offset: 32) !10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !11 = !{!12, !13} !12 = !DISubrange(count: 6) !13 = !DISubrange(count: 1) !14 = !{i32 2, !"Dwarf Version", i32 4} !15 = !{i32 2, !"Debug Info Version", i32 3} !16 = !{i32 1, !"wchar_size", i32 4} !17 = !{i32 7, !"PIC Level", i32 2} !18 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bitwise-cond-1.c000066400000000000000000000001651473507761200321750ustar00rootroot00000000000000int foo(int x, int y, int z) { int a = x - y; int b = (z == 0 && a) ? x + y : y + z; return (a > b) ? x : y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bitwise-cond-1.ll000066400000000000000000000177341473507761200323740ustar00rootroot00000000000000; ModuleID = 'bitwise-cond-1.pp.bc' source_filename = "bitwise-cond-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32, i32, i32) #0 !dbg !8 { %4 = alloca i32, align 4 %5 = alloca i32, align 4 %6 = alloca i32, align 4 %7 = alloca i32, align 4 %8 = alloca i32, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !12, metadata !DIExpression()), !dbg !13 store i32 %1, i32* %5, align 4 call void @llvm.dbg.declare(metadata i32* %5, metadata !14, metadata !DIExpression()), !dbg !15 store i32 %2, i32* %6, align 4 call void @llvm.dbg.declare(metadata i32* %6, metadata !16, metadata !DIExpression()), !dbg !17 call void @llvm.dbg.declare(metadata i32* %7, metadata !18, metadata !DIExpression()), !dbg !19 %9 = load i32, i32* %4, align 4, !dbg !20 %10 = load i32, i32* %5, align 4, !dbg !21 %11 = sub nsw i32 %9, %10, !dbg !22 store i32 %11, i32* %7, align 4, !dbg !19 call void @llvm.dbg.declare(metadata i32* %8, metadata !23, metadata !DIExpression()), !dbg !24 %12 = load i32, i32* %6, align 4, !dbg !25 %13 = icmp eq i32 %12, 0, !dbg !26 br i1 %13, label %14, label %21, !dbg !27 14: ; preds = %3 %15 = load i32, i32* %7, align 4, !dbg !28 %16 = icmp ne i32 %15, 0, !dbg !28 br i1 %16, label %17, label %21, !dbg !29 17: ; preds = %14 %18 = load i32, i32* %4, align 4, !dbg !30 %19 = load i32, i32* %5, align 4, !dbg !31 %20 = add nsw i32 %18, %19, !dbg !32 br label %25, !dbg !29 21: ; preds = %14, %3 %22 = load i32, i32* %5, align 4, !dbg !33 %23 = load i32, i32* %6, align 4, !dbg !34 %24 = add nsw i32 %22, %23, !dbg !35 br label %25, !dbg !29 25: ; preds = %21, %17 %26 = phi i32 [ %20, %17 ], [ %24, %21 ], !dbg !29 store i32 %26, i32* %8, align 4, !dbg !24 %27 = load i32, i32* %7, align 4, !dbg !36 %28 = load i32, i32* %8, align 4, !dbg !37 %29 = icmp sgt i32 %27, %28, !dbg !38 br i1 %29, label %30, label %32, !dbg !39 30: ; preds = %25 %31 = load i32, i32* %4, align 4, !dbg !40 br label %34, !dbg !39 32: ; preds = %25 %33 = load i32, i32* %5, align 4, !dbg !41 br label %34, !dbg !39 34: ; preds = %32, %30 %35 = phi i32 [ %31, %30 ], [ %33, %32 ], !dbg !39 ret i32 %35, !dbg !42 } ; CHECK: define si32 @foo(si32 %1, si32 %2, si32 %3) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si32* $5 = allocate si32, 1, align 4 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: si32* $7 = allocate si32, 1, align 4 ; CHECK: si32* $8 = allocate si32, 1, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 4 ; CHECK: store $6, %3, align 4 ; CHECK: si32 %9 = load $4, align 4 ; CHECK: si32 %10 = load $5, align 4 ; CHECK: si32 %11 = %9 ssub.nw %10 ; CHECK: store $7, %11, align 4 ; CHECK: si32 %12 = load $6, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4, #5} { ; CHECK: %12 sieq 0 ; CHECK: si32 %13 = load $7, align 4 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#6} { ; CHECK: %12 sine 0 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: %13 sine 0 ; CHECK: si32 %14 = load $4, align 4 ; CHECK: si32 %15 = load $5, align 4 ; CHECK: si32 %16 = %14 sadd.nw %15 ; CHECK: si32 %17 = %16 ; CHECK: } ; CHECK: #5 predecessors={#2} successors={#6} { ; CHECK: %13 sieq 0 ; CHECK: } ; CHECK: #6 predecessors={#3, #5} successors={#7} { ; CHECK: si32 %18 = load $5, align 4 ; CHECK: si32 %19 = load $6, align 4 ; CHECK: si32 %20 = %18 sadd.nw %19 ; CHECK: si32 %17 = %20 ; CHECK: } ; CHECK: #7 predecessors={#4, #6} successors={#8, #9} { ; CHECK: store $8, %17, align 4 ; CHECK: si32 %21 = load $7, align 4 ; CHECK: si32 %22 = load $8, align 4 ; CHECK: } ; CHECK: #8 predecessors={#7} successors={#10} { ; CHECK: %21 sigt %22 ; CHECK: si32 %23 = load $4, align 4 ; CHECK: si32 %24 = %23 ; CHECK: } ; CHECK: #9 predecessors={#7} successors={#10} { ; CHECK: %21 sile %22 ; CHECK: si32 %25 = load $5, align 4 ; CHECK: si32 %24 = %25 ; CHECK: } ; CHECK: #10 !exit predecessors={#8, #9} { ; CHECK: return %24 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bitwise-cond-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !11, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11) !13 = !DILocation(line: 1, column: 13, scope: !8) !14 = !DILocalVariable(name: "y", arg: 2, scope: !8, file: !1, line: 1, type: !11) !15 = !DILocation(line: 1, column: 20, scope: !8) !16 = !DILocalVariable(name: "z", arg: 3, scope: !8, file: !1, line: 1, type: !11) !17 = !DILocation(line: 1, column: 27, scope: !8) !18 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 2, type: !11) !19 = !DILocation(line: 2, column: 7, scope: !8) !20 = !DILocation(line: 2, column: 11, scope: !8) !21 = !DILocation(line: 2, column: 15, scope: !8) !22 = !DILocation(line: 2, column: 13, scope: !8) !23 = !DILocalVariable(name: "b", scope: !8, file: !1, line: 3, type: !11) !24 = !DILocation(line: 3, column: 7, scope: !8) !25 = !DILocation(line: 3, column: 12, scope: !8) !26 = !DILocation(line: 3, column: 14, scope: !8) !27 = !DILocation(line: 3, column: 19, scope: !8) !28 = !DILocation(line: 3, column: 22, scope: !8) !29 = !DILocation(line: 3, column: 11, scope: !8) !30 = !DILocation(line: 3, column: 27, scope: !8) !31 = !DILocation(line: 3, column: 31, scope: !8) !32 = !DILocation(line: 3, column: 29, scope: !8) !33 = !DILocation(line: 3, column: 35, scope: !8) !34 = !DILocation(line: 3, column: 39, scope: !8) !35 = !DILocation(line: 3, column: 37, scope: !8) !36 = !DILocation(line: 4, column: 11, scope: !8) !37 = !DILocation(line: 4, column: 15, scope: !8) !38 = !DILocation(line: 4, column: 13, scope: !8) !39 = !DILocation(line: 4, column: 10, scope: !8) !40 = !DILocation(line: 4, column: 20, scope: !8) !41 = !DILocation(line: 4, column: 24, scope: !8) !42 = !DILocation(line: 4, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bitwise-cond-2.c000066400000000000000000000002051473507761200321710ustar00rootroot00000000000000int g; int foo(int x, int y) { int z = x - y; int a; if (g == 0 && z) a = x + y; else a = x * y; return a * 42; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bitwise-cond-2.ll000066400000000000000000000161711473507761200323670ustar00rootroot00000000000000; ModuleID = 'bitwise-cond-2.pp.bc' source_filename = "bitwise-cond-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @g = common global i32 0, align 4, !dbg !0 ; CHECK: define si32* @g, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @g, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32, i32) #0 !dbg !12 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i32, align 4 %6 = alloca i32, align 4 store i32 %0, i32* %3, align 4 call void @llvm.dbg.declare(metadata i32* %3, metadata !15, metadata !DIExpression()), !dbg !16 store i32 %1, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32* %5, metadata !19, metadata !DIExpression()), !dbg !20 %7 = load i32, i32* %3, align 4, !dbg !21 %8 = load i32, i32* %4, align 4, !dbg !22 %9 = sub nsw i32 %7, %8, !dbg !23 store i32 %9, i32* %5, align 4, !dbg !20 call void @llvm.dbg.declare(metadata i32* %6, metadata !24, metadata !DIExpression()), !dbg !25 %10 = load i32, i32* @g, align 4, !dbg !26 %11 = icmp eq i32 %10, 0, !dbg !28 br i1 %11, label %12, label %19, !dbg !29 12: ; preds = %2 %13 = load i32, i32* %5, align 4, !dbg !30 %14 = icmp ne i32 %13, 0, !dbg !30 br i1 %14, label %15, label %19, !dbg !31 15: ; preds = %12 %16 = load i32, i32* %3, align 4, !dbg !32 %17 = load i32, i32* %4, align 4, !dbg !33 %18 = add nsw i32 %16, %17, !dbg !34 store i32 %18, i32* %6, align 4, !dbg !35 br label %23, !dbg !36 19: ; preds = %12, %2 %20 = load i32, i32* %3, align 4, !dbg !37 %21 = load i32, i32* %4, align 4, !dbg !38 %22 = mul nsw i32 %20, %21, !dbg !39 store i32 %22, i32* %6, align 4, !dbg !40 br label %23 23: ; preds = %19, %15 %24 = load i32, i32* %6, align 4, !dbg !41 %25 = mul nsw i32 %24, 42, !dbg !42 ret i32 %25, !dbg !43 } ; CHECK: define si32 @foo(si32 %1, si32 %2) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si32* $5 = allocate si32, 1, align 4 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: store $3, %1, align 4 ; CHECK: store $4, %2, align 4 ; CHECK: si32 %7 = load $3, align 4 ; CHECK: si32 %8 = load $4, align 4 ; CHECK: si32 %9 = %7 ssub.nw %8 ; CHECK: store $5, %9, align 4 ; CHECK: si32 %10 = load @g, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4, #5} { ; CHECK: %10 sieq 0 ; CHECK: si32 %11 = load $5, align 4 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#6} { ; CHECK: %10 sine 0 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: %11 sine 0 ; CHECK: si32 %12 = load $3, align 4 ; CHECK: si32 %13 = load $4, align 4 ; CHECK: si32 %14 = %12 sadd.nw %13 ; CHECK: store $6, %14, align 4 ; CHECK: } ; CHECK: #5 predecessors={#2} successors={#6} { ; CHECK: %11 sieq 0 ; CHECK: } ; CHECK: #6 predecessors={#3, #5} successors={#7} { ; CHECK: si32 %15 = load $3, align 4 ; CHECK: si32 %16 = load $4, align 4 ; CHECK: si32 %17 = %15 smul.nw %16 ; CHECK: store $6, %17, align 4 ; CHECK: } ; CHECK: #7 !exit predecessors={#6, #4} { ; CHECK: si32 %18 = load $6, align 4 ; CHECK: si32 %19 = %18 smul.nw 42 ; CHECK: return %19 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bitwise-cond-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6, !6, !6} !15 = !DILocalVariable(name: "x", arg: 1, scope: !12, file: !3, line: 3, type: !6) !16 = !DILocation(line: 3, column: 13, scope: !12) !17 = !DILocalVariable(name: "y", arg: 2, scope: !12, file: !3, line: 3, type: !6) !18 = !DILocation(line: 3, column: 20, scope: !12) !19 = !DILocalVariable(name: "z", scope: !12, file: !3, line: 4, type: !6) !20 = !DILocation(line: 4, column: 7, scope: !12) !21 = !DILocation(line: 4, column: 11, scope: !12) !22 = !DILocation(line: 4, column: 15, scope: !12) !23 = !DILocation(line: 4, column: 13, scope: !12) !24 = !DILocalVariable(name: "a", scope: !12, file: !3, line: 5, type: !6) !25 = !DILocation(line: 5, column: 7, scope: !12) !26 = !DILocation(line: 6, column: 7, scope: !27) !27 = distinct !DILexicalBlock(scope: !12, file: !3, line: 6, column: 7) !28 = !DILocation(line: 6, column: 9, scope: !27) !29 = !DILocation(line: 6, column: 14, scope: !27) !30 = !DILocation(line: 6, column: 17, scope: !27) !31 = !DILocation(line: 6, column: 7, scope: !12) !32 = !DILocation(line: 7, column: 9, scope: !27) !33 = !DILocation(line: 7, column: 13, scope: !27) !34 = !DILocation(line: 7, column: 11, scope: !27) !35 = !DILocation(line: 7, column: 7, scope: !27) !36 = !DILocation(line: 7, column: 5, scope: !27) !37 = !DILocation(line: 9, column: 9, scope: !27) !38 = !DILocation(line: 9, column: 13, scope: !27) !39 = !DILocation(line: 9, column: 11, scope: !27) !40 = !DILocation(line: 9, column: 7, scope: !27) !41 = !DILocation(line: 10, column: 10, scope: !12) !42 = !DILocation(line: 10, column: 12, scope: !12) !43 = !DILocation(line: 10, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bitwise-op.c000066400000000000000000000000641473507761200315300ustar00rootroot00000000000000int main() { int x = 3, y = 5; int z = x | y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bitwise-op.ll000066400000000000000000000073741473507761200317300ustar00rootroot00000000000000; ModuleID = 'bitwise-op.pp.bc' source_filename = "bitwise-op.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca i32, align 4 %2 = alloca i32, align 4 %3 = alloca i32, align 4 call void @llvm.dbg.declare(metadata i32* %1, metadata !12, metadata !DIExpression()), !dbg !13 store i32 3, i32* %1, align 4, !dbg !13 call void @llvm.dbg.declare(metadata i32* %2, metadata !14, metadata !DIExpression()), !dbg !15 store i32 5, i32* %2, align 4, !dbg !15 call void @llvm.dbg.declare(metadata i32* %3, metadata !16, metadata !DIExpression()), !dbg !17 %4 = load i32, i32* %1, align 4, !dbg !18 %5 = load i32, i32* %2, align 4, !dbg !19 %6 = or i32 %4, %5, !dbg !20 store i32 %6, i32* %3, align 4, !dbg !17 ret i32 0, !dbg !21 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: store $1, 3, align 4 ; CHECK: store $2, 5, align 4 ; CHECK: ui32* %4 = bitcast $1 ; CHECK: ui32 %5 = load %4, align 4 ; CHECK: ui32* %6 = bitcast $2 ; CHECK: ui32 %7 = load %6, align 4 ; CHECK: ui32 %8 = %5 uor %7 ; CHECK: si32 %9 = bitcast %8 ; CHECK: store $3, %9, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "bitwise-op.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !11) !13 = !DILocation(line: 2, column: 7, scope: !8) !14 = !DILocalVariable(name: "y", scope: !8, file: !1, line: 2, type: !11) !15 = !DILocation(line: 2, column: 14, scope: !8) !16 = !DILocalVariable(name: "z", scope: !8, file: !1, line: 3, type: !11) !17 = !DILocation(line: 3, column: 7, scope: !8) !18 = !DILocation(line: 3, column: 11, scope: !8) !19 = !DILocation(line: 3, column: 15, scope: !8) !20 = !DILocation(line: 3, column: 13, scope: !8) !21 = !DILocation(line: 4, column: 1, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bool-op-select.cpp000066400000000000000000000003471473507761200326360ustar00rootroot00000000000000/** * To generate LLVM select instruction, we need to compile * the code with optimization enabled (at least -O1) * * > llvm-g++ -O1 -emit-llvm -o test.bc -g -c test.cpp */ int a; int main() { return a > 0 ? 123 : 321; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bool-op-select.ll000066400000000000000000000073761473507761200324740ustar00rootroot00000000000000; ModuleID = 'bool-op-select.pp.bc' source_filename = "bool-op-select.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = global i32 0, align 4, !dbg !0 ; CHECK: define si32* @a, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !12 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = load i32, i32* @a, align 4, !dbg !15 %3 = icmp sgt i32 %2, 0, !dbg !16 %4 = zext i1 %3 to i64, !dbg !15 br i1 %3, label %5, label %6, !dbg !15 5: ; preds = %0 br label %7, !dbg !15 6: ; preds = %0 br label %7, !dbg !15 7: ; preds = %6, %5 %8 = phi i32 [ 123, %5 ], [ 321, %6 ], !dbg !15 ret i32 %8, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: si32 %2 = load @a, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %2 sigt 0 ; CHECK: ui1 %3 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %2 sile 0 ; CHECK: ui1 %3 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5, #6} { ; CHECK: ui64 %4 = zext %3 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %3 uieq 1 ; CHECK: si32 %5 = 123 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %3 uieq 0 ; CHECK: si32 %5 = 321 ; CHECK: } ; CHECK: #7 !exit predecessors={#5, #6} { ; CHECK: return %5 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 8, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bool-op-select.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 10, type: !13, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 11, column: 10, scope: !12) !16 = !DILocation(line: 11, column: 12, scope: !12) !17 = !DILocation(line: 11, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bool.cpp000066400000000000000000000000751473507761200307430ustar00rootroot00000000000000bool b = true; int f(bool i) {} int main() { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/bool.ll000066400000000000000000000107751473507761200306000ustar00rootroot00000000000000; ModuleID = 'bool.pp.bc' source_filename = "bool.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @b = global i8 1, align 1, !dbg !0 ; CHECK: define ui8* @b, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, 1, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fb(i1 zeroext) #0 !dbg !12 { %2 = alloca i8, align 1 %3 = zext i1 %0 to i8 store i8 %3, i8* %2, align 1 call void @llvm.dbg.declare(metadata i8* %2, metadata !16, metadata !DIExpression()), !dbg !17 call void @llvm.trap(), !dbg !18 unreachable, !dbg !18 } ; CHECK: define si32 @_Z1fb(ui1 %1) { ; CHECK: #1 !entry !exit { ; CHECK: ui8* $2 = allocate ui8, 1, align 1 ; CHECK: ui8 %3 = zext %1 ; CHECK: store $2, %3, align 1 ; CHECK: call @ar.trap() ; CHECK: unreachable ; CHECK: } ; CHECK: } ; Function Attrs: cold noreturn nounwind declare void @llvm.trap() #2 ; CHECK: declare void @ar.trap() ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #3 !dbg !19 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 ret i32 0, !dbg !22 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { cold noreturn nounwind } attributes #3 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "bool.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "f", linkageName: "_Z1fb", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!15, !6} !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !16 = !DILocalVariable(name: "i", arg: 1, scope: !12, file: !3, line: 3, type: !6) !17 = !DILocation(line: 3, column: 12, scope: !12) !18 = !DILocation(line: 3, column: 15, scope: !12) !19 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !20, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !20 = !DISubroutineType(types: !21) !21 = !{!15} !22 = !DILocation(line: 6, column: 3, scope: !19) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/branch-undef.c000066400000000000000000000000571473507761200320040ustar00rootroot00000000000000int main() { return main ? 0 % 0 ?: 1 : 2; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/branch-undef.ll000066400000000000000000000063661473507761200322020ustar00rootroot00000000000000; ModuleID = 'branch-undef.pp.bc' source_filename = "branch-undef.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 br i1 true, label %2, label %7, !dbg !12 2: ; preds = %0 br i1 undef, label %3, label %4, !dbg !13 3: ; preds = %2 br label %5, !dbg !13 4: ; preds = %2 br label %5, !dbg !13 5: ; preds = %4, %3 %6 = phi i32 [ undef, %3 ], [ 1, %4 ], !dbg !13 br label %8, !dbg !12 7: ; preds = %0 br label %8, !dbg !12 8: ; preds = %7, %5 %9 = phi i32 [ %6, %5 ], [ 2, %7 ], !dbg !12 ret i32 %9, !dbg !14 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: si32 %2 = undef ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: si32 %2 = 1 ; CHECK: } ; CHECK: #5 !exit predecessors={#4} { ; CHECK: return %3 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5} { ; CHECK: si32 %3 = %2 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "branch-undef.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 2, column: 10, scope: !8) !13 = !DILocation(line: 2, column: 17, scope: !8) !14 = !DILocation(line: 2, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/call-args.c000066400000000000000000000001341473507761200313110ustar00rootroot00000000000000int foo(int i) { return i + 1; } int main(int argc, char** argv) { return foo(argc); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/call-args.ll000066400000000000000000000113021473507761200314750ustar00rootroot00000000000000; ModuleID = 'call-args.pp.bc' source_filename = "call-args.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32) #0 !dbg !8 { %2 = alloca i32, align 4 store i32 %0, i32* %2, align 4 call void @llvm.dbg.declare(metadata i32* %2, metadata !12, metadata !DIExpression()), !dbg !13 %3 = load i32, i32* %2, align 4, !dbg !14 %4 = add nsw i32 %3, 1, !dbg !15 ret i32 %4, !dbg !16 } ; CHECK: define si32 @foo(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: store $2, %1, align 4 ; CHECK: si32 %3 = load $2, align 4 ; CHECK: si32 %4 = %3 sadd.nw 1 ; CHECK: return %4 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !17 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !23, metadata !DIExpression()), !dbg !24 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !25, metadata !DIExpression()), !dbg !26 %6 = load i32, i32* %4, align 4, !dbg !27 %7 = call i32 @foo(i32 %6), !dbg !28 ret i32 %7, !dbg !29 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: si32 %6 = load $4, align 4 ; CHECK: si32 %7 = call @foo(%6) ; CHECK: return %7 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "call-args.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "i", arg: 1, scope: !8, file: !1, line: 1, type: !11) !13 = !DILocation(line: 1, column: 13, scope: !8) !14 = !DILocation(line: 2, column: 10, scope: !8) !15 = !DILocation(line: 2, column: 12, scope: !8) !16 = !DILocation(line: 2, column: 3, scope: !8) !17 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !18, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !18 = !DISubroutineType(types: !19) !19 = !{!11, !11, !20} !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !23 = !DILocalVariable(name: "argc", arg: 1, scope: !17, file: !1, line: 5, type: !11) !24 = !DILocation(line: 5, column: 14, scope: !17) !25 = !DILocalVariable(name: "argv", arg: 2, scope: !17, file: !1, line: 5, type: !20) !26 = !DILocation(line: 5, column: 27, scope: !17) !27 = !DILocation(line: 6, column: 14, scope: !17) !28 = !DILocation(line: 6, column: 10, scope: !17) !29 = !DILocation(line: 6, column: 3, scope: !17) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/complex.c000066400000000000000000000001341473507761200311130ustar00rootroot00000000000000#include int main() { double complex c = 1.0 + 2.0 * I; return creal(c); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/complex.ll000066400000000000000000000075651473507761200313170ustar00rootroot00000000000000; ModuleID = 'complex.pp.bc' source_filename = "complex.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca i32, align 4 %2 = alloca { double, double }, align 8 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata { double, double }* %2, metadata !12, metadata !DIExpression()), !dbg !14 %3 = getelementptr inbounds { double, double }, { double, double }* %2, i32 0, i32 0, !dbg !14 %4 = getelementptr inbounds { double, double }, { double, double }* %2, i32 0, i32 1, !dbg !14 store double 1.000000e+00, double* %3, align 8, !dbg !14 store double 2.000000e+00, double* %4, align 8, !dbg !14 %5 = getelementptr inbounds { double, double }, { double, double }* %2, i32 0, i32 0, !dbg !15 %6 = load double, double* %5, align 8, !dbg !15 %7 = getelementptr inbounds { double, double }, { double, double }* %2, i32 0, i32 1, !dbg !15 %8 = load double, double* %7, align 8, !dbg !15 %9 = fptosi double %6 to i32, !dbg !16 ret i32 %9, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: {0: double, 8: double}* $2 = allocate {0: double, 8: double}, 1, align 8 ; CHECK: store $1, 0, align 4 ; CHECK: double* %3 = ptrshift $2, 16 * 0, 1 * 0 ; CHECK: double* %4 = ptrshift $2, 16 * 0, 1 * 8 ; CHECK: store %3, 1.0E+0, align 8 ; CHECK: store %4, 2.0E+0, align 8 ; CHECK: double* %5 = ptrshift $2, 16 * 0, 1 * 0 ; CHECK: double %6 = load %5, align 8 ; CHECK: double* %7 = ptrshift $2, 16 * 0, 1 * 8 ; CHECK: double %8 = load %7, align 8 ; CHECK: si32 %9 = fptosi %6 ; CHECK: return %9 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "complex.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "c", scope: !8, file: !1, line: 4, type: !13) !13 = !DIBasicType(name: "complex", size: 128, encoding: DW_ATE_complex_float) !14 = !DILocation(line: 4, column: 18, scope: !8) !15 = !DILocation(line: 5, column: 16, scope: !8) !16 = !DILocation(line: 5, column: 10, scope: !8) !17 = !DILocation(line: 5, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/constructors.cpp000066400000000000000000000006241473507761200325600ustar00rootroot00000000000000extern "C" { extern void __ikos_assert(int); } class Vector { public: int _x; int _y; int _z; Vector(int x, int y, int z) noexcept : _x(x), _y(y), _z(z) {} }; int f(Vector* v) { return v->_y; } class Master { public: Vector* _v; int* _p; Master() { _v = new Vector(1, 2, 3); _p = new int(4); __ikos_assert(f(_v) == 2); } }; int main() { Master master; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/constructors.ll000066400000000000000000000503731473507761200324130ustar00rootroot00000000000000; ModuleID = 'constructors.pp.bc' source_filename = "constructors.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Vector = type { i32, i32, i32 } %class.Master = type { %class.Vector*, i32* } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fP6Vector(%class.Vector*) #0 !dbg !8 { %2 = alloca %class.Vector*, align 8 store %class.Vector* %0, %class.Vector** %2, align 8 call void @llvm.dbg.declare(metadata %class.Vector** %2, metadata !22, metadata !DIExpression()), !dbg !23 %3 = load %class.Vector*, %class.Vector** %2, align 8, !dbg !24 %4 = getelementptr inbounds %class.Vector, %class.Vector* %3, i32 0, i32 1, !dbg !25 %5 = load i32, i32* %4, align 4, !dbg !25 ret i32 %5, !dbg !26 } ; CHECK: define si32 @_Z1fP6Vector({0: si32, 4: si32, 8: si32}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32, 4: si32, 8: si32}** $2 = allocate {0: si32, 4: si32, 8: si32}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32, 4: si32, 8: si32}** %3 = bitcast $2 ; CHECK: {0: si32, 4: si32, 8: si32}* %4 = load %3, align 8 ; CHECK: si32* %5 = ptrshift %4, 12 * 0, 1 * 4 ; CHECK: si32 %6 = load %5, align 4 ; CHECK: return %6 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN6MasterC1Ev(%class.Master*) unnamed_addr #3 align 2 !dbg !42 { %2 = alloca %class.Master*, align 8 store %class.Master* %0, %class.Master** %2, align 8 call void @llvm.dbg.declare(metadata %class.Master** %2, metadata !43, metadata !DIExpression()), !dbg !45 %3 = load %class.Master*, %class.Master** %2, align 8 call void @_ZN6MasterC2Ev(%class.Master* %3), !dbg !46 ret void, !dbg !47 } ; CHECK: define void @_ZN6MasterC1Ev({0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}** $2 = allocate {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %3 = load $2, align 8 ; CHECK: call @_ZN6MasterC2Ev(%3) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define linkonce_odr void @_ZN6MasterC2Ev(%class.Master*) unnamed_addr #3 align 2 !dbg !48 { %2 = alloca %class.Master*, align 8 store %class.Master* %0, %class.Master** %2, align 8 call void @llvm.dbg.declare(metadata %class.Master** %2, metadata !49, metadata !DIExpression()), !dbg !50 %3 = load %class.Master*, %class.Master** %2, align 8 %4 = call i8* @_Znwm(i64 12) #6, !dbg !51 %5 = bitcast i8* %4 to %class.Vector*, !dbg !51 call void @_ZN6VectorC1Eiii(%class.Vector* %5, i32 1, i32 2, i32 3) #7, !dbg !53 %6 = getelementptr inbounds %class.Master, %class.Master* %3, i32 0, i32 0, !dbg !54 store %class.Vector* %5, %class.Vector** %6, align 8, !dbg !55 %7 = call i8* @_Znwm(i64 4) #6, !dbg !56 %8 = bitcast i8* %7 to i32*, !dbg !56 store i32 4, i32* %8, align 4, !dbg !56 %9 = getelementptr inbounds %class.Master, %class.Master* %3, i32 0, i32 1, !dbg !57 store i32* %8, i32** %9, align 8, !dbg !58 %10 = getelementptr inbounds %class.Master, %class.Master* %3, i32 0, i32 0, !dbg !59 %11 = load %class.Vector*, %class.Vector** %10, align 8, !dbg !59 %12 = call i32 @_Z1fP6Vector(%class.Vector* %11), !dbg !60 %13 = icmp eq i32 %12, 2, !dbg !61 %14 = zext i1 %13 to i32, !dbg !60 call void @__ikos_assert(i32 %14), !dbg !62 ret void, !dbg !63 } ; CHECK: define void @_ZN6MasterC2Ev({0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %1) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}** $2 = allocate {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}** %3 = bitcast $2 ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* %4 = load %3, align 8 ; CHECK: si8* %5 = call @ar.libcpp.new(12) ; CHECK: {0: si32, 4: si32, 8: si32}* %6 = bitcast %5 ; CHECK: call @_ZN6VectorC1Eiii(%6, 1, 2, 3) ; CHECK: {0: si32, 4: si32, 8: si32}** %7 = ptrshift %4, 16 * 0, 1 * 0 ; CHECK: store %7, %6, align 8 ; CHECK: si8* %8 = call @ar.libcpp.new(4) ; CHECK: si32* %9 = bitcast %8 ; CHECK: store %9, 4, align 4 ; CHECK: si32** %10 = ptrshift %4, 16 * 0, 1 * 8 ; CHECK: store %10, %9, align 8 ; CHECK: {0: si32, 4: si32, 8: si32}** %11 = ptrshift %4, 16 * 0, 1 * 0 ; CHECK: {0: si32, 4: si32, 8: si32}** %12 = bitcast %11 ; CHECK: {0: si32, 4: si32, 8: si32}* %13 = load %12, align 8 ; CHECK: si32 %14 = call @_Z1fP6Vector(%13) ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %14 sieq 2 ; CHECK: ui1 %15 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %14 sine 2 ; CHECK: ui1 %15 = 0 ; CHECK: } ; CHECK: #4 !exit predecessors={#2, #3} { ; CHECK: ui32 %16 = zext %15 ; CHECK: call @ar.ikos.assert(%16) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN6VectorC1Eiii(%class.Vector*, i32, i32, i32) unnamed_addr #0 align 2 !dbg !64 { %5 = alloca %class.Vector*, align 8 %6 = alloca i32, align 4 %7 = alloca i32, align 4 %8 = alloca i32, align 4 store %class.Vector* %0, %class.Vector** %5, align 8 call void @llvm.dbg.declare(metadata %class.Vector** %5, metadata !65, metadata !DIExpression()), !dbg !66 store i32 %1, i32* %6, align 4 call void @llvm.dbg.declare(metadata i32* %6, metadata !67, metadata !DIExpression()), !dbg !68 store i32 %2, i32* %7, align 4 call void @llvm.dbg.declare(metadata i32* %7, metadata !69, metadata !DIExpression()), !dbg !70 store i32 %3, i32* %8, align 4 call void @llvm.dbg.declare(metadata i32* %8, metadata !71, metadata !DIExpression()), !dbg !72 %9 = load %class.Vector*, %class.Vector** %5, align 8 %10 = load i32, i32* %6, align 4, !dbg !73 %11 = load i32, i32* %7, align 4, !dbg !73 %12 = load i32, i32* %8, align 4, !dbg !73 call void @_ZN6VectorC2Eiii(%class.Vector* %9, i32 %10, i32 %11, i32 %12) #7, !dbg !73 ret void, !dbg !74 } ; CHECK: define void @_ZN6VectorC1Eiii({0: si32, 4: si32, 8: si32}* %1, si32 %2, si32 %3, si32 %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32, 4: si32, 8: si32}** $5 = allocate {0: si32, 4: si32, 8: si32}*, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: si32* $7 = allocate si32, 1, align 4 ; CHECK: si32* $8 = allocate si32, 1, align 4 ; CHECK: store $5, %1, align 8 ; CHECK: store $6, %2, align 4 ; CHECK: store $7, %3, align 4 ; CHECK: store $8, %4, align 4 ; CHECK: {0: si32, 4: si32, 8: si32}* %9 = load $5, align 8 ; CHECK: si32 %10 = load $6, align 4 ; CHECK: si32 %11 = load $7, align 4 ; CHECK: si32 %12 = load $8, align 4 ; CHECK: call @_ZN6VectorC2Eiii(%9, %10, %11, %12) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN6VectorC2Eiii(%class.Vector*, i32, i32, i32) unnamed_addr #0 align 2 !dbg !75 { %5 = alloca %class.Vector*, align 8 %6 = alloca i32, align 4 %7 = alloca i32, align 4 %8 = alloca i32, align 4 store %class.Vector* %0, %class.Vector** %5, align 8 call void @llvm.dbg.declare(metadata %class.Vector** %5, metadata !76, metadata !DIExpression()), !dbg !77 store i32 %1, i32* %6, align 4 call void @llvm.dbg.declare(metadata i32* %6, metadata !78, metadata !DIExpression()), !dbg !79 store i32 %2, i32* %7, align 4 call void @llvm.dbg.declare(metadata i32* %7, metadata !80, metadata !DIExpression()), !dbg !81 store i32 %3, i32* %8, align 4 call void @llvm.dbg.declare(metadata i32* %8, metadata !82, metadata !DIExpression()), !dbg !83 %9 = load %class.Vector*, %class.Vector** %5, align 8 %10 = getelementptr inbounds %class.Vector, %class.Vector* %9, i32 0, i32 0, !dbg !84 %11 = load i32, i32* %6, align 4, !dbg !85 store i32 %11, i32* %10, align 4, !dbg !84 %12 = getelementptr inbounds %class.Vector, %class.Vector* %9, i32 0, i32 1, !dbg !86 %13 = load i32, i32* %7, align 4, !dbg !87 store i32 %13, i32* %12, align 4, !dbg !86 %14 = getelementptr inbounds %class.Vector, %class.Vector* %9, i32 0, i32 2, !dbg !88 %15 = load i32, i32* %8, align 4, !dbg !89 store i32 %15, i32* %14, align 4, !dbg !88 ret void, !dbg !90 } ; CHECK: define void @_ZN6VectorC2Eiii({0: si32, 4: si32, 8: si32}* %1, si32 %2, si32 %3, si32 %4) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32, 4: si32, 8: si32}** $5 = allocate {0: si32, 4: si32, 8: si32}*, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: si32* $7 = allocate si32, 1, align 4 ; CHECK: si32* $8 = allocate si32, 1, align 4 ; CHECK: store $5, %1, align 8 ; CHECK: store $6, %2, align 4 ; CHECK: store $7, %3, align 4 ; CHECK: store $8, %4, align 4 ; CHECK: {0: si32, 4: si32, 8: si32}** %9 = bitcast $5 ; CHECK: {0: si32, 4: si32, 8: si32}* %10 = load %9, align 8 ; CHECK: si32* %11 = ptrshift %10, 12 * 0, 1 * 0 ; CHECK: si32 %12 = load $6, align 4 ; CHECK: store %11, %12, align 4 ; CHECK: si32* %13 = ptrshift %10, 12 * 0, 1 * 4 ; CHECK: si32 %14 = load $7, align 4 ; CHECK: store %13, %14, align 4 ; CHECK: si32* %15 = ptrshift %10, 12 * 0, 1 * 8 ; CHECK: si32 %16 = load $8, align 4 ; CHECK: store %15, %16, align 4 ; CHECK: return ; CHECK: } ; CHECK: } declare void @__ikos_assert(i32) #5 ; CHECK: declare void @ar.ikos.assert(ui32) ; Function Attrs: nobuiltin declare noalias i8* @_Znwm(i64) #4 ; CHECK: declare si8* @ar.libcpp.new(ui64) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #2 !dbg !27 { %1 = alloca i32, align 4 %2 = alloca %class.Master, align 8 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata %class.Master* %2, metadata !30, metadata !DIExpression()), !dbg !40 call void @_ZN6MasterC1Ev(%class.Master* %2), !dbg !40 ret i32 0, !dbg !41 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}* $2 = allocate {0: {0: si32, 4: si32, 8: si32}*, 8: si32*}, 1, align 8 ; CHECK: store $1, 0, align 4 ; CHECK: call @_ZN6MasterC1Ev($2) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { nobuiltin "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #6 = { builtin } attributes #7 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "constructors.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fP6Vector", scope: !1, file: !1, line: 14, type: !9, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Vector", file: !1, line: 5, size: 96, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !14, identifier: "_ZTS6Vector") !14 = !{!15, !16, !17, !18} !15 = !DIDerivedType(tag: DW_TAG_member, name: "_x", scope: !13, file: !1, line: 7, baseType: !11, size: 32, flags: DIFlagPublic) !16 = !DIDerivedType(tag: DW_TAG_member, name: "_y", scope: !13, file: !1, line: 8, baseType: !11, size: 32, offset: 32, flags: DIFlagPublic) !17 = !DIDerivedType(tag: DW_TAG_member, name: "_z", scope: !13, file: !1, line: 9, baseType: !11, size: 32, offset: 64, flags: DIFlagPublic) !18 = !DISubprogram(name: "Vector", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !19 = !DISubroutineType(types: !20) !20 = !{null, !21, !11, !11, !11} !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !22 = !DILocalVariable(name: "v", arg: 1, scope: !8, file: !1, line: 14, type: !12) !23 = !DILocation(line: 14, column: 15, scope: !8) !24 = !DILocation(line: 15, column: 10, scope: !8) !25 = !DILocation(line: 15, column: 13, scope: !8) !26 = !DILocation(line: 15, column: 3, scope: !8) !27 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 30, type: !28, scopeLine: 30, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !28 = !DISubroutineType(types: !29) !29 = !{!11} !30 = !DILocalVariable(name: "master", scope: !27, file: !1, line: 31, type: !31) !31 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Master", file: !1, line: 18, size: 128, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !32, identifier: "_ZTS6Master") !32 = !{!33, !34, !36} !33 = !DIDerivedType(tag: DW_TAG_member, name: "_v", scope: !31, file: !1, line: 20, baseType: !12, size: 64, flags: DIFlagPublic) !34 = !DIDerivedType(tag: DW_TAG_member, name: "_p", scope: !31, file: !1, line: 21, baseType: !35, size: 64, offset: 64, flags: DIFlagPublic) !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !36 = !DISubprogram(name: "Master", scope: !31, file: !1, line: 23, type: !37, scopeLine: 23, flags: DIFlagPublic | DIFlagPrototyped, spFlags: 0) !37 = !DISubroutineType(types: !38) !38 = !{null, !39} !39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !40 = !DILocation(line: 31, column: 10, scope: !27) !41 = !DILocation(line: 32, column: 3, scope: !27) !42 = distinct !DISubprogram(name: "Master", linkageName: "_ZN6MasterC1Ev", scope: !31, file: !1, line: 23, type: !37, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !36, retainedNodes: !2) !43 = !DILocalVariable(name: "this", arg: 1, scope: !42, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer) !44 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64) !45 = !DILocation(line: 0, scope: !42) !46 = !DILocation(line: 23, column: 12, scope: !42) !47 = !DILocation(line: 27, column: 3, scope: !42) !48 = distinct !DISubprogram(name: "Master", linkageName: "_ZN6MasterC2Ev", scope: !31, file: !1, line: 23, type: !37, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !36, retainedNodes: !2) !49 = !DILocalVariable(name: "this", arg: 1, scope: !48, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer) !50 = !DILocation(line: 0, scope: !48) !51 = !DILocation(line: 24, column: 10, scope: !52) !52 = distinct !DILexicalBlock(scope: !48, file: !1, line: 23, column: 12) !53 = !DILocation(line: 24, column: 14, scope: !52) !54 = !DILocation(line: 24, column: 5, scope: !52) !55 = !DILocation(line: 24, column: 8, scope: !52) !56 = !DILocation(line: 25, column: 10, scope: !52) !57 = !DILocation(line: 25, column: 5, scope: !52) !58 = !DILocation(line: 25, column: 8, scope: !52) !59 = !DILocation(line: 26, column: 21, scope: !52) !60 = !DILocation(line: 26, column: 19, scope: !52) !61 = !DILocation(line: 26, column: 25, scope: !52) !62 = !DILocation(line: 26, column: 5, scope: !52) !63 = !DILocation(line: 27, column: 3, scope: !48) !64 = distinct !DISubprogram(name: "Vector", linkageName: "_ZN6VectorC1Eiii", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !18, retainedNodes: !2) !65 = !DILocalVariable(name: "this", arg: 1, scope: !64, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) !66 = !DILocation(line: 0, scope: !64) !67 = !DILocalVariable(name: "x", arg: 2, scope: !64, file: !1, line: 11, type: !11) !68 = !DILocation(line: 11, column: 14, scope: !64) !69 = !DILocalVariable(name: "y", arg: 3, scope: !64, file: !1, line: 11, type: !11) !70 = !DILocation(line: 11, column: 21, scope: !64) !71 = !DILocalVariable(name: "z", arg: 4, scope: !64, file: !1, line: 11, type: !11) !72 = !DILocation(line: 11, column: 28, scope: !64) !73 = !DILocation(line: 11, column: 62, scope: !64) !74 = !DILocation(line: 11, column: 63, scope: !64) !75 = distinct !DISubprogram(name: "Vector", linkageName: "_ZN6VectorC2Eiii", scope: !13, file: !1, line: 11, type: !19, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !18, retainedNodes: !2) !76 = !DILocalVariable(name: "this", arg: 1, scope: !75, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) !77 = !DILocation(line: 0, scope: !75) !78 = !DILocalVariable(name: "x", arg: 2, scope: !75, file: !1, line: 11, type: !11) !79 = !DILocation(line: 11, column: 14, scope: !75) !80 = !DILocalVariable(name: "y", arg: 3, scope: !75, file: !1, line: 11, type: !11) !81 = !DILocation(line: 11, column: 21, scope: !75) !82 = !DILocalVariable(name: "z", arg: 4, scope: !75, file: !1, line: 11, type: !11) !83 = !DILocation(line: 11, column: 28, scope: !75) !84 = !DILocation(line: 11, column: 42, scope: !75) !85 = !DILocation(line: 11, column: 45, scope: !75) !86 = !DILocation(line: 11, column: 49, scope: !75) !87 = !DILocation(line: 11, column: 52, scope: !75) !88 = !DILocation(line: 11, column: 56, scope: !75) !89 = !DILocation(line: 11, column: 59, scope: !75) !90 = !DILocation(line: 11, column: 63, scope: !75) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-array-1.c000066400000000000000000000000731473507761200320560ustar00rootroot00000000000000struct { char a[0]; int* b; double c; } d = {{}, 1}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-array-1.ll000066400000000000000000000046131473507761200322470ustar00rootroot00000000000000; ModuleID = 'empty-array-1.pp.bc' source_filename = "empty-array-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.anon = type { [0 x i8], i32*, double } @d = global %struct.anon { [0 x i8] zeroinitializer, i32* inttoptr (i64 1 to i32*), double 0.000000e+00 }, align 8, !dbg !0 ; CHECK: define {0: [0 x si8], 0: si32*, 8: double}* @d, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si32* %1 = sitoptr 1 ; CHECK: store @d, {0: aggregate_zero, 0: %1, 8: 0.0E+0}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!18, !19, !20, !21} !llvm.ident = !{!22} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 5, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "empty-array-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 128, elements: !7) !7 = !{!8, !13, !16} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !3, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !3, line: 3, baseType: !14, size: 64) !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !16 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !6, file: !3, line: 4, baseType: !17, size: 64, offset: 64) !17 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !18 = !{i32 2, !"Dwarf Version", i32 4} !19 = !{i32 2, !"Debug Info Version", i32 3} !20 = !{i32 1, !"wchar_size", i32 4} !21 = !{i32 7, !"PIC Level", i32 2} !22 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-array-2.c000066400000000000000000000000771473507761200320630ustar00rootroot00000000000000struct { int a[0]; struct { int b; }; } c = {{}, 6}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-array-2.ll000066400000000000000000000043631473507761200322520ustar00rootroot00000000000000; ModuleID = 'empty-array-2.pp.bc' source_filename = "empty-array-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.anon.0 = type { [0 x i32], %struct.anon } %struct.anon = type { i32 } @c = global %struct.anon.0 { [0 x i32] zeroinitializer, %struct.anon { i32 6 } }, align 4, !dbg !0 ; CHECK: define {0: [0 x si32], 0: {0: si32}}* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, {0: aggregate_zero, 0: {0: 6}}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!17, !18, !19, !20} !llvm.ident = !{!21} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 6, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "empty-array-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 32, elements: !7) !7 = !{!8, !13} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !3, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, scope: !6, file: !3, line: 3, baseType: !14, size: 32) !14 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !6, file: !3, line: 3, size: 32, elements: !15) !15 = !{!16} !16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !3, line: 4, baseType: !10, size: 32) !17 = !{i32 2, !"Dwarf Version", i32 4} !18 = !{i32 2, !"Debug Info Version", i32 3} !19 = !{i32 1, !"wchar_size", i32 4} !20 = !{i32 7, !"PIC Level", i32 2} !21 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-array-3.c000066400000000000000000000000501473507761200320530ustar00rootroot00000000000000union { char a[0]; int b; } c = {}; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-array-3.ll000066400000000000000000000040041473507761200322430ustar00rootroot00000000000000; ModuleID = 'empty-array-3.pp.bc' source_filename = "empty-array-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @c = global { [0 x i8], [4 x i8] } { [0 x i8] zeroinitializer, [4 x i8] undef }, align 4, !dbg !0 ; CHECK: define {0: [0 x si8], 0: [4 x si8]}* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, {0: aggregate_zero, 0: undef}, align 1 ; CHECK: } ; CHECK: } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "empty-array-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !3, line: 1, size: 32, elements: !7) !7 = !{!8, !13} !8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !3, line: 2, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, elements: !11) !10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !11 = !{!12} !12 = !DISubrange(count: 0) !13 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !3, line: 3, baseType: !14, size: 32) !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-function-body.c000066400000000000000000000001131473507761200333550ustar00rootroot00000000000000void GEN2_w_test2_terminate(void) { /* (no terminate code required) */ } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/empty-function-body.ll000066400000000000000000000041071473507761200335510ustar00rootroot00000000000000; ModuleID = 'empty-function-body.pp.bc' source_filename = "empty-function-body.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define void @GEN2_w_test2_terminate() #0 !dbg !8 { ret void, !dbg !11 } ; CHECK: define void @GEN2_w_test2_terminate() { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "empty-function-body.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "GEN2_w_test2_terminate", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null} !11 = !DILocation(line: 3, column: 1, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/file-intrinsics.c000066400000000000000000000003521473507761200325500ustar00rootroot00000000000000#include int main() { FILE* f = fopen("/tmp/test", "rw"); char buf[1025]; int x; fgets(buf, 1024, f); fgetc(f); fputs("hello world", f); fprintf(f, "%d", 1); fscanf(f, "%d", &x); fflush(f); fclose(f); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/file-intrinsics.ll000066400000000000000000000374141473507761200327460ustar00rootroot00000000000000; ModuleID = 'file-intrinsics.pp.bc' source_filename = "file-intrinsics.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 } %struct.__sFILEX = type opaque %struct.__sbuf = type { i8*, i32 } @.str = private unnamed_addr constant [10 x i8] c"/tmp/test\00", align 1 ; CHECK: define [10 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [47, 116, 109, 112, 47, 116, 101, 115, 116, 0], align 1 ; CHECK: } ; CHECK: } @.str.1 = private unnamed_addr constant [3 x i8] c"rw\00", align 1 ; CHECK: define [3 x si8]* @.str.1, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.1, [114, 119, 0], align 1 ; CHECK: } ; CHECK: } @.str.2 = private unnamed_addr constant [12 x i8] c"hello world\00", align 1 ; CHECK: define [12 x si8]* @.str.2, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.2, [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0], align 1 ; CHECK: } ; CHECK: } @.str.3 = private unnamed_addr constant [3 x i8] c"%d\00", align 1 ; CHECK: define [3 x si8]* @.str.3, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.3, [37, 100, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @fclose(%struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fclose(opaque*) declare i32 @fflush(%struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fflush(opaque*) declare i32 @fgetc(%struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fgetc(opaque*) declare i8* @fgets(i8*, i32, %struct.__sFILE*) #2 ; CHECK: declare si8* @ar.libc.fgets(si8*, si32, opaque*) declare %struct.__sFILE* @"\01_fopen"(i8*, i8*) #2 ; CHECK: declare opaque* @ar.libc.fopen(si8*, si8*) declare i32 @fprintf(%struct.__sFILE*, i8*, ...) #2 ; CHECK: declare si32 @ar.libc.fprintf(opaque*, si8*, ...) declare i32 @"\01_fputs"(i8*, %struct.__sFILE*) #2 ; CHECK: declare si32 @ar.libc.fputs(si8*, opaque*) declare i32 @fscanf(%struct.__sFILE*, i8*, ...) #2 ; CHECK: declare si32 @ar.libc.fscanf(opaque*, si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca %struct.__sFILE*, align 8 %2 = alloca [1025 x i8], align 16 %3 = alloca i32, align 4 call void @llvm.dbg.declare(metadata %struct.__sFILE** %1, metadata !12, metadata !DIExpression()), !dbg !76 %4 = getelementptr inbounds [10 x i8], [10 x i8]* @.str, i64 0, i64 0, !dbg !77 %5 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.1, i64 0, i64 0, !dbg !77 %6 = call %struct.__sFILE* @"\01_fopen"(i8* %4, i8* %5), !dbg !77 store %struct.__sFILE* %6, %struct.__sFILE** %1, align 8, !dbg !76 call void @llvm.dbg.declare(metadata [1025 x i8]* %2, metadata !78, metadata !DIExpression()), !dbg !82 call void @llvm.dbg.declare(metadata i32* %3, metadata !83, metadata !DIExpression()), !dbg !84 %7 = getelementptr inbounds [1025 x i8], [1025 x i8]* %2, i64 0, i64 0, !dbg !85 %8 = load %struct.__sFILE*, %struct.__sFILE** %1, align 8, !dbg !86 %9 = call i8* @fgets(i8* %7, i32 1024, %struct.__sFILE* %8), !dbg !87 %10 = load %struct.__sFILE*, %struct.__sFILE** %1, align 8, !dbg !88 %11 = call i32 @fgetc(%struct.__sFILE* %10), !dbg !89 %12 = load %struct.__sFILE*, %struct.__sFILE** %1, align 8, !dbg !90 %13 = getelementptr inbounds [12 x i8], [12 x i8]* @.str.2, i64 0, i64 0, !dbg !91 %14 = call i32 @"\01_fputs"(i8* %13, %struct.__sFILE* %12), !dbg !91 %15 = load %struct.__sFILE*, %struct.__sFILE** %1, align 8, !dbg !92 %16 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.3, i64 0, i64 0, !dbg !93 %17 = call i32 (%struct.__sFILE*, i8*, ...) @fprintf(%struct.__sFILE* %15, i8* %16, i32 1), !dbg !93 %18 = load %struct.__sFILE*, %struct.__sFILE** %1, align 8, !dbg !94 %19 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.3, i64 0, i64 0, !dbg !95 %20 = call i32 (%struct.__sFILE*, i8*, ...) @fscanf(%struct.__sFILE* %18, i8* %19, i32* %3), !dbg !95 %21 = load %struct.__sFILE*, %struct.__sFILE** %1, align 8, !dbg !96 %22 = call i32 @fflush(%struct.__sFILE* %21), !dbg !97 %23 = load %struct.__sFILE*, %struct.__sFILE** %1, align 8, !dbg !98 %24 = call i32 @fclose(%struct.__sFILE* %23), !dbg !99 ret i32 0, !dbg !100 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: ui8*, 8: si32, 12: si32, 16: si16, 18: si16, 24: {0: ui8*, 8: si32}, 40: si32, 48: si8*, 56: si32 (si8*)*, 64: si32 (si8*, si8*, si32)*, 72: si64 (si8*, si64, si32)*, 80: si32 (si8*, si8*, si32)*, 88: {0: ui8*, 8: si32}, 104: opaque*, 112: si32, 116: [3 x ui8], 119: [1 x ui8], 120: {0: ui8*, 8: si32}, 136: si32, 144: si64}** $1 = allocate {0: ui8*, 8: si32, 12: si32, 16: si16, 18: si16, 24: {0: ui8*, 8: si32}, 40: si32, 48: si8*, 56: si32 (si8*)*, 64: si32 (si8*, si8*, si32)*, 72: si64 (si8*, si64, si32)*, 80: si32 (si8*, si8*, si32)*, 88: {0: ui8*, 8: si32}, 104: opaque*, 112: si32, 116: [3 x ui8], 119: [1 x ui8], 120: {0: ui8*, 8: si32}, 136: si32, 144: si64}*, 1, align 8 ; CHECK: [1025 x si8]* $2 = allocate [1025 x si8], 1, align 16 ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si8* %4 = ptrshift @.str, 10 * 0, 1 * 0 ; CHECK: si8* %5 = ptrshift @.str.1, 3 * 0, 1 * 0 ; CHECK: opaque* %6 = call @ar.libc.fopen(%4, %5) ; CHECK: {0: ui8*, 8: si32, 12: si32, 16: si16, 18: si16, 24: {0: ui8*, 8: si32}, 40: si32, 48: si8*, 56: si32 (si8*)*, 64: si32 (si8*, si8*, si32)*, 72: si64 (si8*, si64, si32)*, 80: si32 (si8*, si8*, si32)*, 88: {0: ui8*, 8: si32}, 104: opaque*, 112: si32, 116: [3 x ui8], 119: [1 x ui8], 120: {0: ui8*, 8: si32}, 136: si32, 144: si64}* %7 = bitcast %6 ; CHECK: store $1, %7, align 8 ; CHECK: si8* %8 = ptrshift $2, 1025 * 0, 1 * 0 ; CHECK: opaque** %9 = bitcast $1 ; CHECK: opaque* %10 = load %9, align 8 ; CHECK: si8* %11 = call @ar.libc.fgets(%8, 1024, %10) ; CHECK: opaque** %12 = bitcast $1 ; CHECK: opaque* %13 = load %12, align 8 ; CHECK: si32 %14 = call @ar.libc.fgetc(%13) ; CHECK: opaque** %15 = bitcast $1 ; CHECK: opaque* %16 = load %15, align 8 ; CHECK: si8* %17 = ptrshift @.str.2, 12 * 0, 1 * 0 ; CHECK: si32 %18 = call @ar.libc.fputs(%17, %16) ; CHECK: opaque** %19 = bitcast $1 ; CHECK: opaque* %20 = load %19, align 8 ; CHECK: si8* %21 = ptrshift @.str.3, 3 * 0, 1 * 0 ; CHECK: si32 %22 = call @ar.libc.fprintf(%20, %21, 1) ; CHECK: opaque** %23 = bitcast $1 ; CHECK: opaque* %24 = load %23, align 8 ; CHECK: si8* %25 = ptrshift @.str.3, 3 * 0, 1 * 0 ; CHECK: si32 %26 = call @ar.libc.fscanf(%24, %25, $3) ; CHECK: opaque** %27 = bitcast $1 ; CHECK: opaque* %28 = load %27, align 8 ; CHECK: si32 %29 = call @ar.libc.fflush(%28) ; CHECK: opaque** %30 = bitcast $1 ; CHECK: opaque* %31 = load %30, align 8 ; CHECK: si32 %32 = call @ar.libc.fclose(%31) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "file-intrinsics.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 4, type: !13) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIDerivedType(tag: DW_TAG_typedef, name: "FILE", file: !15, line: 157, baseType: !16) !15 = !DIFile(filename: "/usr/include/_stdio.h", directory: "") !16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__sFILE", file: !15, line: 126, size: 1216, elements: !17) !17 = !{!18, !21, !22, !23, !25, !26, !31, !32, !34, !38, !44, !54, !60, !61, !64, !65, !69, !73, !74, !75} !18 = !DIDerivedType(tag: DW_TAG_member, name: "_p", scope: !16, file: !15, line: 127, baseType: !19, size: 64) !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !21 = !DIDerivedType(tag: DW_TAG_member, name: "_r", scope: !16, file: !15, line: 128, baseType: !11, size: 32, offset: 64) !22 = !DIDerivedType(tag: DW_TAG_member, name: "_w", scope: !16, file: !15, line: 129, baseType: !11, size: 32, offset: 96) !23 = !DIDerivedType(tag: DW_TAG_member, name: "_flags", scope: !16, file: !15, line: 130, baseType: !24, size: 16, offset: 128) !24 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) !25 = !DIDerivedType(tag: DW_TAG_member, name: "_file", scope: !16, file: !15, line: 131, baseType: !24, size: 16, offset: 144) !26 = !DIDerivedType(tag: DW_TAG_member, name: "_bf", scope: !16, file: !15, line: 132, baseType: !27, size: 128, offset: 192) !27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__sbuf", file: !15, line: 92, size: 128, elements: !28) !28 = !{!29, !30} !29 = !DIDerivedType(tag: DW_TAG_member, name: "_base", scope: !27, file: !15, line: 93, baseType: !19, size: 64) !30 = !DIDerivedType(tag: DW_TAG_member, name: "_size", scope: !27, file: !15, line: 94, baseType: !11, size: 32, offset: 64) !31 = !DIDerivedType(tag: DW_TAG_member, name: "_lbfsize", scope: !16, file: !15, line: 133, baseType: !11, size: 32, offset: 320) !32 = !DIDerivedType(tag: DW_TAG_member, name: "_cookie", scope: !16, file: !15, line: 136, baseType: !33, size: 64, offset: 384) !33 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !34 = !DIDerivedType(tag: DW_TAG_member, name: "_close", scope: !16, file: !15, line: 137, baseType: !35, size: 64, offset: 448) !35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 64) !36 = !DISubroutineType(types: !37) !37 = !{!11, !33} !38 = !DIDerivedType(tag: DW_TAG_member, name: "_read", scope: !16, file: !15, line: 138, baseType: !39, size: 64, offset: 512) !39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64) !40 = !DISubroutineType(types: !41) !41 = !{!11, !33, !42, !11} !42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !43, size: 64) !43 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !44 = !DIDerivedType(tag: DW_TAG_member, name: "_seek", scope: !16, file: !15, line: 139, baseType: !45, size: 64, offset: 576) !45 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !46, size: 64) !46 = !DISubroutineType(types: !47) !47 = !{!48, !33, !48, !11} !48 = !DIDerivedType(tag: DW_TAG_typedef, name: "fpos_t", file: !15, line: 81, baseType: !49) !49 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_off_t", file: !50, line: 71, baseType: !51) !50 = !DIFile(filename: "/usr/include/sys/_types.h", directory: "") !51 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int64_t", file: !52, line: 46, baseType: !53) !52 = !DIFile(filename: "/usr/include/i386/_types.h", directory: "") !53 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) !54 = !DIDerivedType(tag: DW_TAG_member, name: "_write", scope: !16, file: !15, line: 140, baseType: !55, size: 64, offset: 640) !55 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !56, size: 64) !56 = !DISubroutineType(types: !57) !57 = !{!11, !33, !58, !11} !58 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !59, size: 64) !59 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !43) !60 = !DIDerivedType(tag: DW_TAG_member, name: "_ub", scope: !16, file: !15, line: 143, baseType: !27, size: 128, offset: 704) !61 = !DIDerivedType(tag: DW_TAG_member, name: "_extra", scope: !16, file: !15, line: 144, baseType: !62, size: 64, offset: 832) !62 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !63, size: 64) !63 = !DICompositeType(tag: DW_TAG_structure_type, name: "__sFILEX", file: !15, line: 98, flags: DIFlagFwdDecl) !64 = !DIDerivedType(tag: DW_TAG_member, name: "_ur", scope: !16, file: !15, line: 145, baseType: !11, size: 32, offset: 896) !65 = !DIDerivedType(tag: DW_TAG_member, name: "_ubuf", scope: !16, file: !15, line: 148, baseType: !66, size: 24, offset: 928) !66 = !DICompositeType(tag: DW_TAG_array_type, baseType: !20, size: 24, elements: !67) !67 = !{!68} !68 = !DISubrange(count: 3) !69 = !DIDerivedType(tag: DW_TAG_member, name: "_nbuf", scope: !16, file: !15, line: 149, baseType: !70, size: 8, offset: 952) !70 = !DICompositeType(tag: DW_TAG_array_type, baseType: !20, size: 8, elements: !71) !71 = !{!72} !72 = !DISubrange(count: 1) !73 = !DIDerivedType(tag: DW_TAG_member, name: "_lb", scope: !16, file: !15, line: 152, baseType: !27, size: 128, offset: 960) !74 = !DIDerivedType(tag: DW_TAG_member, name: "_blksize", scope: !16, file: !15, line: 155, baseType: !11, size: 32, offset: 1088) !75 = !DIDerivedType(tag: DW_TAG_member, name: "_offset", scope: !16, file: !15, line: 156, baseType: !48, size: 64, offset: 1152) !76 = !DILocation(line: 4, column: 9, scope: !8) !77 = !DILocation(line: 4, column: 13, scope: !8) !78 = !DILocalVariable(name: "buf", scope: !8, file: !1, line: 5, type: !79) !79 = !DICompositeType(tag: DW_TAG_array_type, baseType: !43, size: 8200, elements: !80) !80 = !{!81} !81 = !DISubrange(count: 1025) !82 = !DILocation(line: 5, column: 8, scope: !8) !83 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 6, type: !11) !84 = !DILocation(line: 6, column: 7, scope: !8) !85 = !DILocation(line: 7, column: 9, scope: !8) !86 = !DILocation(line: 7, column: 20, scope: !8) !87 = !DILocation(line: 7, column: 3, scope: !8) !88 = !DILocation(line: 8, column: 9, scope: !8) !89 = !DILocation(line: 8, column: 3, scope: !8) !90 = !DILocation(line: 9, column: 24, scope: !8) !91 = !DILocation(line: 9, column: 3, scope: !8) !92 = !DILocation(line: 10, column: 11, scope: !8) !93 = !DILocation(line: 10, column: 3, scope: !8) !94 = !DILocation(line: 11, column: 10, scope: !8) !95 = !DILocation(line: 11, column: 3, scope: !8) !96 = !DILocation(line: 12, column: 10, scope: !8) !97 = !DILocation(line: 12, column: 3, scope: !8) !98 = !DILocation(line: 13, column: 10, scope: !8) !99 = !DILocation(line: 13, column: 3, scope: !8) !100 = !DILocation(line: 14, column: 1, scope: !8) flexible-array-member.c000066400000000000000000000001361473507761200335420ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimizationstruct line { int length; char contents[]; }; struct line l; int main() { return 0; } flexible-array-member.ll000066400000000000000000000063241473507761200337340ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization; ModuleID = 'flexible-array-member.pp.bc' source_filename = "flexible-array-member.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.line = type { i32, [0 x i8] } @l = common global %struct.line zeroinitializer, align 4, !dbg !0 ; CHECK: define {0: si32, 4: [0 x si8]}* @l, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @l, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "l", scope: !2, file: !3, line: 6, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "flexible-array-member.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "line", file: !3, line: 1, size: 32, elements: !7) !7 = !{!8, !10} !8 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !6, file: !3, line: 2, baseType: !9, size: 32) !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !10 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !6, file: !3, line: 3, baseType: !11, offset: 32) !11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, elements: !13) !12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !13 = !{!14} !14 = !DISubrange(count: -1) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !21, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!9} !23 = !DILocation(line: 9, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/gv-init.c000066400000000000000000000004321473507761200310220ustar00rootroot00000000000000int a[100][100]; int b[2] = {1, 2}; int c; int d = 5; extern int e; int main(int argc, char** argv) { int i = 0, j = 0; for (; i < 100; i++) for (; j < 100; j++) if (i % 2 == 0) a[i][j] = b[0] + c - e; else a[i][j] = b[1] + d - e; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/gv-init.ll000066400000000000000000000323101473507761200312070ustar00rootroot00000000000000; ModuleID = 'gv-init.pp.bc' source_filename = "gv-init.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global [100 x [100 x i32]] zeroinitializer, align 16, !dbg !9 ; CHECK: define [100 x [100 x si32]]* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = global [2 x i32] [i32 1, i32 2], align 4, !dbg !0 ; CHECK: define [2 x si32]* @b, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, [1, 2], align 1 ; CHECK: } ; CHECK: } @c = common global i32 0, align 4, !dbg !14 ; CHECK: define si32* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, 0, align 1 ; CHECK: } ; CHECK: } @d = global i32 5, align 4, !dbg !6 ; CHECK: define si32* @d, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @d, 5, align 1 ; CHECK: } ; CHECK: } @e = external global i32, align 4 ; CHECK: declare si32* @e, align 4 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !24 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 %7 = alloca i32, align 4 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !30, metadata !DIExpression()), !dbg !31 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !32, metadata !DIExpression()), !dbg !33 call void @llvm.dbg.declare(metadata i32* %6, metadata !34, metadata !DIExpression()), !dbg !35 store i32 0, i32* %6, align 4, !dbg !35 call void @llvm.dbg.declare(metadata i32* %7, metadata !36, metadata !DIExpression()), !dbg !37 store i32 0, i32* %7, align 4, !dbg !37 br label %8, !dbg !38 8: ; preds = %50, %2 %9 = load i32, i32* %6, align 4, !dbg !39 %10 = icmp slt i32 %9, 100, !dbg !42 br i1 %10, label %11, label %53, !dbg !43 11: ; preds = %8 br label %12, !dbg !44 12: ; preds = %46, %11 %13 = load i32, i32* %7, align 4, !dbg !45 %14 = icmp slt i32 %13, 100, !dbg !48 br i1 %14, label %15, label %49, !dbg !49 15: ; preds = %12 %16 = load i32, i32* %6, align 4, !dbg !50 %17 = srem i32 %16, 2, !dbg !52 %18 = icmp eq i32 %17, 0, !dbg !53 br i1 %18, label %19, label %32, !dbg !54 19: ; preds = %15 %20 = getelementptr inbounds [2 x i32], [2 x i32]* @b, i64 0, i64 0, !dbg !55 %21 = load i32, i32* %20, align 4, !dbg !55 %22 = load i32, i32* @c, align 4, !dbg !56 %23 = add nsw i32 %21, %22, !dbg !57 %24 = load i32, i32* @e, align 4, !dbg !58 %25 = sub nsw i32 %23, %24, !dbg !59 %26 = load i32, i32* %6, align 4, !dbg !60 %27 = sext i32 %26 to i64, !dbg !61 %28 = getelementptr inbounds [100 x [100 x i32]], [100 x [100 x i32]]* @a, i64 0, i64 %27, !dbg !61 %29 = load i32, i32* %7, align 4, !dbg !62 %30 = sext i32 %29 to i64, !dbg !61 %31 = getelementptr inbounds [100 x i32], [100 x i32]* %28, i64 0, i64 %30, !dbg !61 store i32 %25, i32* %31, align 4, !dbg !63 br label %45, !dbg !61 32: ; preds = %15 %33 = getelementptr inbounds [2 x i32], [2 x i32]* @b, i64 0, i64 1, !dbg !64 %34 = load i32, i32* %33, align 4, !dbg !64 %35 = load i32, i32* @d, align 4, !dbg !65 %36 = add nsw i32 %34, %35, !dbg !66 %37 = load i32, i32* @e, align 4, !dbg !67 %38 = sub nsw i32 %36, %37, !dbg !68 %39 = load i32, i32* %6, align 4, !dbg !69 %40 = sext i32 %39 to i64, !dbg !70 %41 = getelementptr inbounds [100 x [100 x i32]], [100 x [100 x i32]]* @a, i64 0, i64 %40, !dbg !70 %42 = load i32, i32* %7, align 4, !dbg !71 %43 = sext i32 %42 to i64, !dbg !70 %44 = getelementptr inbounds [100 x i32], [100 x i32]* %41, i64 0, i64 %43, !dbg !70 store i32 %38, i32* %44, align 4, !dbg !72 br label %45 45: ; preds = %32, %19 br label %46, !dbg !73 46: ; preds = %45 %47 = load i32, i32* %7, align 4, !dbg !74 %48 = add nsw i32 %47, 1, !dbg !74 store i32 %48, i32* %7, align 4, !dbg !74 br label %12, !dbg !75, !llvm.loop !76 49: ; preds = %12 br label %50, !dbg !77 50: ; preds = %49 %51 = load i32, i32* %6, align 4, !dbg !78 %52 = add nsw i32 %51, 1, !dbg !78 store i32 %52, i32* %6, align 4, !dbg !78 br label %8, !dbg !79, !llvm.loop !80 53: ; preds = %8 ret i32 0, !dbg !82 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: si32* $7 = allocate si32, 1, align 4 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: store $6, 0, align 4 ; CHECK: store $7, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #7} successors={#3, #4} { ; CHECK: si32 %8 = load $6, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#5} { ; CHECK: %8 silt 100 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %8 sige 100 ; CHECK: return 0 ; CHECK: } ; CHECK: #5 predecessors={#3, #10} successors={#6, #7} { ; CHECK: si32 %9 = load $7, align 4 ; CHECK: } ; CHECK: #6 predecessors={#5} successors={#8, #9} { ; CHECK: %9 silt 100 ; CHECK: si32 %10 = load $6, align 4 ; CHECK: si32 %11 = %10 srem 2 ; CHECK: } ; CHECK: #7 predecessors={#5} successors={#2} { ; CHECK: %9 sige 100 ; CHECK: si32 %12 = load $6, align 4 ; CHECK: si32 %13 = %12 sadd.nw 1 ; CHECK: store $6, %13, align 4 ; CHECK: } ; CHECK: #8 predecessors={#6} successors={#10} { ; CHECK: %11 sieq 0 ; CHECK: si32* %14 = ptrshift @b, 8 * 0, 4 * 0 ; CHECK: si32 %15 = load %14, align 4 ; CHECK: si32 %16 = load @c, align 4 ; CHECK: si32 %17 = %15 sadd.nw %16 ; CHECK: si32 %18 = load @e, align 4 ; CHECK: si32 %19 = %17 ssub.nw %18 ; CHECK: si32 %20 = load $6, align 4 ; CHECK: si64 %21 = sext %20 ; CHECK: [100 x si32]* %22 = ptrshift @a, 40000 * 0, 400 * %21 ; CHECK: si32 %23 = load $7, align 4 ; CHECK: si64 %24 = sext %23 ; CHECK: si32* %25 = ptrshift %22, 400 * 0, 4 * %24 ; CHECK: store %25, %19, align 4 ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#10} { ; CHECK: %11 sine 0 ; CHECK: si32* %26 = ptrshift @b, 8 * 0, 4 * 1 ; CHECK: si32 %27 = load %26, align 4 ; CHECK: si32 %28 = load @d, align 4 ; CHECK: si32 %29 = %27 sadd.nw %28 ; CHECK: si32 %30 = load @e, align 4 ; CHECK: si32 %31 = %29 ssub.nw %30 ; CHECK: si32 %32 = load $6, align 4 ; CHECK: si64 %33 = sext %32 ; CHECK: [100 x si32]* %34 = ptrshift @a, 40000 * 0, 400 * %33 ; CHECK: si32 %35 = load $7, align 4 ; CHECK: si64 %36 = sext %35 ; CHECK: si32* %37 = ptrshift %34, 400 * 0, 4 * %36 ; CHECK: store %37, %31, align 4 ; CHECK: } ; CHECK: #10 predecessors={#8, #9} successors={#5} { ; CHECK: si32 %38 = load $7, align 4 ; CHECK: si32 %39 = %38 sadd.nw 1 ; CHECK: store $7, %39, align 4 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!19, !20, !21, !22} !llvm.ident = !{!23} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 2, type: !16, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "gv-init.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0, !6, !9, !14} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 4, type: !8, isLocal: false, isDefinition: true) !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression()) !10 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !11, isLocal: false, isDefinition: true) !11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 320000, elements: !12) !12 = !{!13, !13} !13 = !DISubrange(count: 100) !14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression()) !15 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 64, elements: !17) !17 = !{!18} !18 = !DISubrange(count: 2) !19 = !{i32 2, !"Dwarf Version", i32 4} !20 = !{i32 2, !"Debug Info Version", i32 3} !21 = !{i32 1, !"wchar_size", i32 4} !22 = !{i32 7, !"PIC Level", i32 2} !23 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !24 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 7, type: !25, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !25 = !DISubroutineType(types: !26) !26 = !{!8, !8, !27} !27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64) !28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64) !29 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !30 = !DILocalVariable(name: "argc", arg: 1, scope: !24, file: !3, line: 7, type: !8) !31 = !DILocation(line: 7, column: 14, scope: !24) !32 = !DILocalVariable(name: "argv", arg: 2, scope: !24, file: !3, line: 7, type: !27) !33 = !DILocation(line: 7, column: 27, scope: !24) !34 = !DILocalVariable(name: "i", scope: !24, file: !3, line: 8, type: !8) !35 = !DILocation(line: 8, column: 7, scope: !24) !36 = !DILocalVariable(name: "j", scope: !24, file: !3, line: 8, type: !8) !37 = !DILocation(line: 8, column: 14, scope: !24) !38 = !DILocation(line: 9, column: 3, scope: !24) !39 = !DILocation(line: 9, column: 10, scope: !40) !40 = distinct !DILexicalBlock(scope: !41, file: !3, line: 9, column: 3) !41 = distinct !DILexicalBlock(scope: !24, file: !3, line: 9, column: 3) !42 = !DILocation(line: 9, column: 12, scope: !40) !43 = !DILocation(line: 9, column: 3, scope: !41) !44 = !DILocation(line: 10, column: 5, scope: !40) !45 = !DILocation(line: 10, column: 12, scope: !46) !46 = distinct !DILexicalBlock(scope: !47, file: !3, line: 10, column: 5) !47 = distinct !DILexicalBlock(scope: !40, file: !3, line: 10, column: 5) !48 = !DILocation(line: 10, column: 14, scope: !46) !49 = !DILocation(line: 10, column: 5, scope: !47) !50 = !DILocation(line: 11, column: 11, scope: !51) !51 = distinct !DILexicalBlock(scope: !46, file: !3, line: 11, column: 11) !52 = !DILocation(line: 11, column: 13, scope: !51) !53 = !DILocation(line: 11, column: 17, scope: !51) !54 = !DILocation(line: 11, column: 11, scope: !46) !55 = !DILocation(line: 12, column: 19, scope: !51) !56 = !DILocation(line: 12, column: 26, scope: !51) !57 = !DILocation(line: 12, column: 24, scope: !51) !58 = !DILocation(line: 12, column: 30, scope: !51) !59 = !DILocation(line: 12, column: 28, scope: !51) !60 = !DILocation(line: 12, column: 11, scope: !51) !61 = !DILocation(line: 12, column: 9, scope: !51) !62 = !DILocation(line: 12, column: 14, scope: !51) !63 = !DILocation(line: 12, column: 17, scope: !51) !64 = !DILocation(line: 14, column: 19, scope: !51) !65 = !DILocation(line: 14, column: 26, scope: !51) !66 = !DILocation(line: 14, column: 24, scope: !51) !67 = !DILocation(line: 14, column: 30, scope: !51) !68 = !DILocation(line: 14, column: 28, scope: !51) !69 = !DILocation(line: 14, column: 11, scope: !51) !70 = !DILocation(line: 14, column: 9, scope: !51) !71 = !DILocation(line: 14, column: 14, scope: !51) !72 = !DILocation(line: 14, column: 17, scope: !51) !73 = !DILocation(line: 11, column: 20, scope: !51) !74 = !DILocation(line: 10, column: 22, scope: !46) !75 = !DILocation(line: 10, column: 5, scope: !46) !76 = distinct !{!76, !49, !77} !77 = !DILocation(line: 14, column: 30, scope: !47) !78 = !DILocation(line: 9, column: 20, scope: !40) !79 = !DILocation(line: 9, column: 3, scope: !40) !80 = distinct !{!80, !43, !81} !81 = !DILocation(line: 14, column: 30, scope: !41) !82 = !DILocation(line: 15, column: 3, scope: !24) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/linked-list.c000066400000000000000000000001671473507761200316710ustar00rootroot00000000000000struct node { int value; struct node* next; }; struct node head; int main(int argc, char** argv) { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/linked-list.ll000066400000000000000000000104021473507761200320470ustar00rootroot00000000000000; ModuleID = 'linked-list.pp.bc' source_filename = "linked-list.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.node = type { i32, %struct.node* } @head = common global %struct.node zeroinitializer, align 8, !dbg !0 ; CHECK: define {0: si32, 8: {...}*}* @head, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @head, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !17 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !23, metadata !DIExpression()), !dbg !24 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !25, metadata !DIExpression()), !dbg !26 ret i32 0, !dbg !27 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!12, !13, !14, !15} !llvm.ident = !{!16} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "head", scope: !2, file: !3, line: 6, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "linked-list.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "node", file: !3, line: 1, size: 128, elements: !7) !7 = !{!8, !10} !8 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !6, file: !3, line: 2, baseType: !9, size: 32) !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !10 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !6, file: !3, line: 3, baseType: !11, size: 64, offset: 64) !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) !12 = !{i32 2, !"Dwarf Version", i32 4} !13 = !{i32 2, !"Debug Info Version", i32 3} !14 = !{i32 1, !"wchar_size", i32 4} !15 = !{i32 7, !"PIC Level", i32 2} !16 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !17 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !18, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !18 = !DISubroutineType(types: !19) !19 = !{!9, !9, !20} !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !23 = !DILocalVariable(name: "argc", arg: 1, scope: !17, file: !3, line: 8, type: !9) !24 = !DILocation(line: 8, column: 14, scope: !17) !25 = !DILocalVariable(name: "argv", arg: 2, scope: !17, file: !3, line: 8, type: !20) !26 = !DILocation(line: 8, column: 27, scope: !17) !27 = !DILocation(line: 9, column: 3, scope: !17) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/local-array-1.c000066400000000000000000000002771473507761200320200ustar00rootroot00000000000000// SAFE #include // To test loops int main(int argc, char** argv) { int i; int a[10]; for (i = 0; i < 10; i++) { a[i] = i; } printf("%d\n", a[i - 1]); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/local-array-1.ll000066400000000000000000000201461473507761200322020ustar00rootroot00000000000000; ModuleID = 'local-array-1.pp.bc' source_filename = "local-array-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 %7 = alloca [10 x i32], align 16 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !15, metadata !DIExpression()), !dbg !16 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32* %6, metadata !19, metadata !DIExpression()), !dbg !20 call void @llvm.dbg.declare(metadata [10 x i32]* %7, metadata !21, metadata !DIExpression()), !dbg !25 store i32 0, i32* %6, align 4, !dbg !26 br label %8, !dbg !28 8: ; preds = %16, %2 %9 = load i32, i32* %6, align 4, !dbg !29 %10 = icmp slt i32 %9, 10, !dbg !31 br i1 %10, label %11, label %19, !dbg !32 11: ; preds = %8 %12 = load i32, i32* %6, align 4, !dbg !33 %13 = load i32, i32* %6, align 4, !dbg !35 %14 = sext i32 %13 to i64, !dbg !36 %15 = getelementptr inbounds [10 x i32], [10 x i32]* %7, i64 0, i64 %14, !dbg !36 store i32 %12, i32* %15, align 4, !dbg !37 br label %16, !dbg !38 16: ; preds = %11 %17 = load i32, i32* %6, align 4, !dbg !39 %18 = add nsw i32 %17, 1, !dbg !39 store i32 %18, i32* %6, align 4, !dbg !39 br label %8, !dbg !40, !llvm.loop !41 19: ; preds = %8 %20 = load i32, i32* %6, align 4, !dbg !43 %21 = sub nsw i32 %20, 1, !dbg !44 %22 = sext i32 %21 to i64, !dbg !45 %23 = getelementptr inbounds [10 x i32], [10 x i32]* %7, i64 0, i64 %22, !dbg !45 %24 = load i32, i32* %23, align 4, !dbg !45 %25 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !46 %26 = call i32 (i8*, ...) @printf(i8* %25, i32 %24), !dbg !46 ret i32 0, !dbg !47 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: [10 x si32]* $7 = allocate [10 x si32], 1, align 16 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: store $6, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: si32 %8 = load $6, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %8 silt 10 ; CHECK: si32 %9 = load $6, align 4 ; CHECK: si32 %10 = load $6, align 4 ; CHECK: si64 %11 = sext %10 ; CHECK: si32* %12 = ptrshift $7, 40 * 0, 4 * %11 ; CHECK: store %12, %9, align 4 ; CHECK: si32 %13 = load $6, align 4 ; CHECK: si32 %14 = %13 sadd.nw 1 ; CHECK: store $6, %14, align 4 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %8 sige 10 ; CHECK: si32 %15 = load $6, align 4 ; CHECK: si32 %16 = %15 ssub.nw 1 ; CHECK: si64 %17 = sext %16 ; CHECK: si32* %18 = ptrshift $7, 40 * 0, 4 * %17 ; CHECK: si32 %19 = load %18, align 4 ; CHECK: si8* %20 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %21 = call @ar.libc.printf(%20, %19) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "local-array-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 6, type: !11) !16 = !DILocation(line: 6, column: 14, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 6, type: !12) !18 = !DILocation(line: 6, column: 27, scope: !8) !19 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 7, type: !11) !20 = !DILocation(line: 7, column: 7, scope: !8) !21 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 8, type: !22) !22 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !23) !23 = !{!24} !24 = !DISubrange(count: 10) !25 = !DILocation(line: 8, column: 7, scope: !8) !26 = !DILocation(line: 9, column: 10, scope: !27) !27 = distinct !DILexicalBlock(scope: !8, file: !1, line: 9, column: 3) !28 = !DILocation(line: 9, column: 8, scope: !27) !29 = !DILocation(line: 9, column: 15, scope: !30) !30 = distinct !DILexicalBlock(scope: !27, file: !1, line: 9, column: 3) !31 = !DILocation(line: 9, column: 17, scope: !30) !32 = !DILocation(line: 9, column: 3, scope: !27) !33 = !DILocation(line: 10, column: 12, scope: !34) !34 = distinct !DILexicalBlock(scope: !30, file: !1, line: 9, column: 28) !35 = !DILocation(line: 10, column: 7, scope: !34) !36 = !DILocation(line: 10, column: 5, scope: !34) !37 = !DILocation(line: 10, column: 10, scope: !34) !38 = !DILocation(line: 11, column: 3, scope: !34) !39 = !DILocation(line: 9, column: 24, scope: !30) !40 = !DILocation(line: 9, column: 3, scope: !30) !41 = distinct !{!41, !32, !42} !42 = !DILocation(line: 11, column: 3, scope: !27) !43 = !DILocation(line: 12, column: 20, scope: !8) !44 = !DILocation(line: 12, column: 22, scope: !8) !45 = !DILocation(line: 12, column: 18, scope: !8) !46 = !DILocation(line: 12, column: 3, scope: !8) !47 = !DILocation(line: 13, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/local-array-2.c000066400000000000000000000006571473507761200320230ustar00rootroot00000000000000#include #include char* foo(char* a, int n) { int i; for (i = 0; i < n; i++) a[i] = 'A'; return a; } int main() { char str[50]; strcpy(str, "This is string.h library function"); puts(str); memset(str, '$', 50); // SAFE char* A = foo(str, 10); // char * B; <- B will be undefined char B[10]; memcpy(B, A, 10); // SAFE char* C = foo(B, 10); // SAFE puts(C); return (0); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/local-array-2.ll000066400000000000000000000276251473507761200322140ustar00rootroot00000000000000; ModuleID = 'local-array-2.pp.bc' source_filename = "local-array-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [34 x i8] c"This is string.h library function\00", align 1 ; CHECK: define [34 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [84, 104, 105, 115, 32, 105, 115, 32, 115, 116, 114, 105, 110, 103, 46, 104, 32, 108, 105, 98, 114, 97, 114, 121, 32, 102, 117, 110, 99, 116, 105, 111, 110, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @puts(i8*) #2 ; CHECK: declare si32 @ar.libc.puts(si8*) declare i8* @strcpy(i8*, i8*) #2 ; CHECK: declare si8* @ar.libc.strcpy(si8*, si8*) ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #3 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #3 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i8* @foo(i8*, i32) #0 !dbg !8 { %3 = alloca i8*, align 8 %4 = alloca i32, align 4 %5 = alloca i32, align 4 store i8* %0, i8** %3, align 8 call void @llvm.dbg.declare(metadata i8** %3, metadata !14, metadata !DIExpression()), !dbg !15 store i32 %1, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !16, metadata !DIExpression()), !dbg !17 call void @llvm.dbg.declare(metadata i32* %5, metadata !18, metadata !DIExpression()), !dbg !19 store i32 0, i32* %5, align 4, !dbg !20 br label %6, !dbg !22 6: ; preds = %15, %2 %7 = load i32, i32* %5, align 4, !dbg !23 %8 = load i32, i32* %4, align 4, !dbg !25 %9 = icmp slt i32 %7, %8, !dbg !26 br i1 %9, label %10, label %18, !dbg !27 10: ; preds = %6 %11 = load i8*, i8** %3, align 8, !dbg !28 %12 = load i32, i32* %5, align 4, !dbg !29 %13 = sext i32 %12 to i64, !dbg !28 %14 = getelementptr inbounds i8, i8* %11, i64 %13, !dbg !28 store i8 65, i8* %14, align 1, !dbg !30 br label %15, !dbg !28 15: ; preds = %10 %16 = load i32, i32* %5, align 4, !dbg !31 %17 = add nsw i32 %16, 1, !dbg !31 store i32 %17, i32* %5, align 4, !dbg !31 br label %6, !dbg !32, !llvm.loop !33 18: ; preds = %6 %19 = load i8*, i8** %3, align 8, !dbg !35 ret i8* %19, !dbg !36 } ; CHECK: define si8* @foo(si8* %1, si32 %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si8** $3 = allocate si8*, 1, align 8 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si32* $5 = allocate si32, 1, align 4 ; CHECK: store $3, %1, align 8 ; CHECK: store $4, %2, align 4 ; CHECK: store $5, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: si32 %6 = load $5, align 4 ; CHECK: si32 %7 = load $4, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %6 silt %7 ; CHECK: si8* %8 = load $3, align 8 ; CHECK: si32 %9 = load $5, align 4 ; CHECK: si64 %10 = sext %9 ; CHECK: si8* %11 = ptrshift %8, 1 * %10 ; CHECK: store %11, 65, align 1 ; CHECK: si32 %12 = load $5, align 4 ; CHECK: si32 %13 = %12 sadd.nw 1 ; CHECK: store $5, %13, align 4 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %6 sige %7 ; CHECK: si8* %14 = load $3, align 8 ; CHECK: return %14 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !37 { %1 = alloca i32, align 4 %2 = alloca [50 x i8], align 16 %3 = alloca i8*, align 8 %4 = alloca [10 x i8], align 1 %5 = alloca i8*, align 8 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata [50 x i8]* %2, metadata !40, metadata !DIExpression()), !dbg !44 %6 = getelementptr inbounds [50 x i8], [50 x i8]* %2, i64 0, i64 0, !dbg !45 %7 = getelementptr inbounds [34 x i8], [34 x i8]* @.str, i64 0, i64 0, !dbg !46 %8 = call i8* @strcpy(i8* %6, i8* %7), !dbg !46 %9 = getelementptr inbounds [50 x i8], [50 x i8]* %2, i64 0, i64 0, !dbg !47 %10 = call i32 @puts(i8* %9), !dbg !48 %11 = getelementptr inbounds [50 x i8], [50 x i8]* %2, i64 0, i64 0, !dbg !49 call void @llvm.memset.p0i8.i64(i8* align 16 %11, i8 36, i64 50, i1 false), !dbg !49 call void @llvm.dbg.declare(metadata i8** %3, metadata !50, metadata !DIExpression()), !dbg !51 %12 = getelementptr inbounds [50 x i8], [50 x i8]* %2, i64 0, i64 0, !dbg !52 %13 = call i8* @foo(i8* %12, i32 10), !dbg !53 store i8* %13, i8** %3, align 8, !dbg !51 call void @llvm.dbg.declare(metadata [10 x i8]* %4, metadata !54, metadata !DIExpression()), !dbg !58 %14 = getelementptr inbounds [10 x i8], [10 x i8]* %4, i64 0, i64 0, !dbg !59 %15 = load i8*, i8** %3, align 8, !dbg !60 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %14, i8* align 1 %15, i64 10, i1 false), !dbg !59 call void @llvm.dbg.declare(metadata i8** %5, metadata !61, metadata !DIExpression()), !dbg !62 %16 = getelementptr inbounds [10 x i8], [10 x i8]* %4, i64 0, i64 0, !dbg !63 %17 = call i8* @foo(i8* %16, i32 10), !dbg !64 store i8* %17, i8** %5, align 8, !dbg !62 %18 = load i8*, i8** %5, align 8, !dbg !65 %19 = call i32 @puts(i8* %18), !dbg !66 ret i32 0, !dbg !67 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: [50 x si8]* $2 = allocate [50 x si8], 1, align 16 ; CHECK: si8** $3 = allocate si8*, 1, align 8 ; CHECK: [10 x si8]* $4 = allocate [10 x si8], 1, align 1 ; CHECK: si8** $5 = allocate si8*, 1, align 8 ; CHECK: store $1, 0, align 4 ; CHECK: si8* %6 = ptrshift $2, 50 * 0, 1 * 0 ; CHECK: si8* %7 = ptrshift @.str, 34 * 0, 1 * 0 ; CHECK: si8* %8 = call @ar.libc.strcpy(%6, %7) ; CHECK: si8* %9 = ptrshift $2, 50 * 0, 1 * 0 ; CHECK: si32 %10 = call @ar.libc.puts(%9) ; CHECK: si8* %11 = ptrshift $2, 50 * 0, 1 * 0 ; CHECK: call @ar.memset(%11, 36, 50, 16, 0) ; CHECK: si8* %12 = ptrshift $2, 50 * 0, 1 * 0 ; CHECK: si8* %13 = call @foo(%12, 10) ; CHECK: store $3, %13, align 8 ; CHECK: si8* %14 = ptrshift $4, 10 * 0, 1 * 0 ; CHECK: si8* %15 = load $3, align 8 ; CHECK: call @ar.memcpy(%14, %15, 10, 1, 1, 0) ; CHECK: si8* %16 = ptrshift $4, 10 * 0, 1 * 0 ; CHECK: si8* %17 = call @foo(%16, 10) ; CHECK: store $5, %17, align 8 ; CHECK: si8* %18 = load $5, align 8 ; CHECK: si32 %19 = call @ar.libc.puts(%18) ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "local-array-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !13} !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) !12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 4, type: !11) !15 = !DILocation(line: 4, column: 17, scope: !8) !16 = !DILocalVariable(name: "n", arg: 2, scope: !8, file: !1, line: 4, type: !13) !17 = !DILocation(line: 4, column: 24, scope: !8) !18 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 5, type: !13) !19 = !DILocation(line: 5, column: 7, scope: !8) !20 = !DILocation(line: 6, column: 10, scope: !21) !21 = distinct !DILexicalBlock(scope: !8, file: !1, line: 6, column: 3) !22 = !DILocation(line: 6, column: 8, scope: !21) !23 = !DILocation(line: 6, column: 15, scope: !24) !24 = distinct !DILexicalBlock(scope: !21, file: !1, line: 6, column: 3) !25 = !DILocation(line: 6, column: 19, scope: !24) !26 = !DILocation(line: 6, column: 17, scope: !24) !27 = !DILocation(line: 6, column: 3, scope: !21) !28 = !DILocation(line: 7, column: 5, scope: !24) !29 = !DILocation(line: 7, column: 7, scope: !24) !30 = !DILocation(line: 7, column: 10, scope: !24) !31 = !DILocation(line: 6, column: 23, scope: !24) !32 = !DILocation(line: 6, column: 3, scope: !24) !33 = distinct !{!33, !27, !34} !34 = !DILocation(line: 7, column: 12, scope: !21) !35 = !DILocation(line: 8, column: 10, scope: !8) !36 = !DILocation(line: 8, column: 3, scope: !8) !37 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 11, type: !38, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !38 = !DISubroutineType(types: !39) !39 = !{!13} !40 = !DILocalVariable(name: "str", scope: !37, file: !1, line: 12, type: !41) !41 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 400, elements: !42) !42 = !{!43} !43 = !DISubrange(count: 50) !44 = !DILocation(line: 12, column: 8, scope: !37) !45 = !DILocation(line: 14, column: 10, scope: !37) !46 = !DILocation(line: 14, column: 3, scope: !37) !47 = !DILocation(line: 15, column: 8, scope: !37) !48 = !DILocation(line: 15, column: 3, scope: !37) !49 = !DILocation(line: 17, column: 3, scope: !37) !50 = !DILocalVariable(name: "A", scope: !37, file: !1, line: 18, type: !11) !51 = !DILocation(line: 18, column: 9, scope: !37) !52 = !DILocation(line: 18, column: 17, scope: !37) !53 = !DILocation(line: 18, column: 13, scope: !37) !54 = !DILocalVariable(name: "B", scope: !37, file: !1, line: 20, type: !55) !55 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 80, elements: !56) !56 = !{!57} !57 = !DISubrange(count: 10) !58 = !DILocation(line: 20, column: 8, scope: !37) !59 = !DILocation(line: 21, column: 3, scope: !37) !60 = !DILocation(line: 21, column: 13, scope: !37) !61 = !DILocalVariable(name: "C", scope: !37, file: !1, line: 22, type: !11) !62 = !DILocation(line: 22, column: 9, scope: !37) !63 = !DILocation(line: 22, column: 17, scope: !37) !64 = !DILocation(line: 22, column: 13, scope: !37) !65 = !DILocation(line: 23, column: 8, scope: !37) !66 = !DILocation(line: 23, column: 3, scope: !37) !67 = !DILocation(line: 24, column: 3, scope: !37) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/mem-intrinsics.c000066400000000000000000000003231473507761200324050ustar00rootroot00000000000000#include int cst() { int G = 0 ? 0 : (((1 + 1) + 3) * 2); return G; } int main() { int *p, *q, *r; r = (int*)memcpy(p, q, 10); r = (int*)memmove(p, q, 50); r = (int*)memset(p, 1, 50); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/mem-intrinsics.ll000066400000000000000000000160711473507761200326010ustar00rootroot00000000000000; ModuleID = 'mem-intrinsics.pp.bc' source_filename = "mem-intrinsics.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: argmemonly nounwind declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1) #2 ; CHECK: declare void @ar.memmove(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #2 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i32 @cst() #0 !dbg !11 { %1 = alloca i32, align 4 call void @llvm.dbg.declare(metadata i32* %1, metadata !14, metadata !DIExpression()), !dbg !15 store i32 10, i32* %1, align 4, !dbg !15 %2 = load i32, i32* %1, align 4, !dbg !16 ret i32 %2, !dbg !17 } ; CHECK: define si32 @cst() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 10, align 4 ; CHECK: si32 %2 = load $1, align 4 ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !18 { %1 = alloca i32*, align 8 %2 = alloca i32*, align 8 %3 = alloca i32*, align 8 call void @llvm.dbg.declare(metadata i32** %1, metadata !19, metadata !DIExpression()), !dbg !20 call void @llvm.dbg.declare(metadata i32** %2, metadata !21, metadata !DIExpression()), !dbg !22 call void @llvm.dbg.declare(metadata i32** %3, metadata !23, metadata !DIExpression()), !dbg !24 %4 = load i32*, i32** %1, align 8, !dbg !25 %5 = bitcast i32* %4 to i8*, !dbg !26 %6 = load i32*, i32** %2, align 8, !dbg !27 %7 = bitcast i32* %6 to i8*, !dbg !26 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %5, i8* align 4 %7, i64 10, i1 false), !dbg !26 %8 = bitcast i8* %5 to i32*, !dbg !28 store i32* %8, i32** %3, align 8, !dbg !29 %9 = load i32*, i32** %1, align 8, !dbg !30 %10 = bitcast i32* %9 to i8*, !dbg !31 %11 = load i32*, i32** %2, align 8, !dbg !32 %12 = bitcast i32* %11 to i8*, !dbg !31 call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 %10, i8* align 4 %12, i64 50, i1 false), !dbg !31 %13 = bitcast i8* %10 to i32*, !dbg !33 store i32* %13, i32** %3, align 8, !dbg !34 %14 = load i32*, i32** %1, align 8, !dbg !35 %15 = bitcast i32* %14 to i8*, !dbg !36 call void @llvm.memset.p0i8.i64(i8* align 4 %15, i8 1, i64 50, i1 false), !dbg !36 %16 = bitcast i8* %15 to i32*, !dbg !37 store i32* %16, i32** %3, align 8, !dbg !38 ret i32 0, !dbg !39 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32** $1 = allocate si32*, 1, align 8 ; CHECK: si32** $2 = allocate si32*, 1, align 8 ; CHECK: si32** $3 = allocate si32*, 1, align 8 ; CHECK: si32* %4 = load $1, align 8 ; CHECK: si8* %5 = bitcast %4 ; CHECK: si32* %6 = load $2, align 8 ; CHECK: si8* %7 = bitcast %6 ; CHECK: call @ar.memcpy(%5, %7, 10, 4, 4, 0) ; CHECK: si32* %8 = bitcast %5 ; CHECK: store $3, %8, align 8 ; CHECK: si32* %9 = load $1, align 8 ; CHECK: si8* %10 = bitcast %9 ; CHECK: si32* %11 = load $2, align 8 ; CHECK: si8* %12 = bitcast %11 ; CHECK: call @ar.memmove(%10, %12, 50, 4, 4, 0) ; CHECK: si32* %13 = bitcast %10 ; CHECK: store $3, %13, align 8 ; CHECK: si32* %14 = load $1, align 8 ; CHECK: si8* %15 = bitcast %14 ; CHECK: call @ar.memset(%15, 1, 50, 4, 0) ; CHECK: si32* %16 = bitcast %15 ; CHECK: store $3, %16, align 8 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!6, !7, !8, !9} !llvm.ident = !{!10} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "mem-intrinsics.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{!4} !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) !5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} !8 = !{i32 1, !"wchar_size", i32 4} !9 = !{i32 7, !"PIC Level", i32 2} !10 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !11 = distinct !DISubprogram(name: "cst", scope: !1, file: !1, line: 3, type: !12, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !12 = !DISubroutineType(types: !13) !13 = !{!5} !14 = !DILocalVariable(name: "G", scope: !11, file: !1, line: 4, type: !5) !15 = !DILocation(line: 4, column: 7, scope: !11) !16 = !DILocation(line: 5, column: 10, scope: !11) !17 = !DILocation(line: 5, column: 3, scope: !11) !18 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !12, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !19 = !DILocalVariable(name: "p", scope: !18, file: !1, line: 9, type: !4) !20 = !DILocation(line: 9, column: 8, scope: !18) !21 = !DILocalVariable(name: "q", scope: !18, file: !1, line: 9, type: !4) !22 = !DILocation(line: 9, column: 12, scope: !18) !23 = !DILocalVariable(name: "r", scope: !18, file: !1, line: 9, type: !4) !24 = !DILocation(line: 9, column: 16, scope: !18) !25 = !DILocation(line: 10, column: 20, scope: !18) !26 = !DILocation(line: 10, column: 13, scope: !18) !27 = !DILocation(line: 10, column: 23, scope: !18) !28 = !DILocation(line: 10, column: 7, scope: !18) !29 = !DILocation(line: 10, column: 5, scope: !18) !30 = !DILocation(line: 11, column: 21, scope: !18) !31 = !DILocation(line: 11, column: 13, scope: !18) !32 = !DILocation(line: 11, column: 24, scope: !18) !33 = !DILocation(line: 11, column: 7, scope: !18) !34 = !DILocation(line: 11, column: 5, scope: !18) !35 = !DILocation(line: 12, column: 20, scope: !18) !36 = !DILocation(line: 12, column: 13, scope: !18) !37 = !DILocation(line: 12, column: 7, scope: !18) !38 = !DILocation(line: 12, column: 5, scope: !18) !39 = !DILocation(line: 13, column: 1, scope: !18) multiple-inheritance.cpp000066400000000000000000000003641473507761200340540ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimizationclass Base { private: int x; int y; }; struct Mixin { private: unsigned z; }; struct Empty { void f() {} }; class Child : public Base, public Mixin, public Empty { private: int tab[10]; }; Child c; int main(void) { return 0; } multiple-inheritance.ll000066400000000000000000000116401473507761200337000ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization; ModuleID = 'multiple-inheritance.pp.bc' source_filename = "multiple-inheritance.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.Child = type { %class.Base, %struct.Mixin, [10 x i32] } %class.Base = type { i32, i32 } %struct.Mixin = type { i32 } @c = global %class.Child zeroinitializer, align 4, !dbg !0 ; CHECK: define {0: {0: si32, 4: si32}, 8: {0: ui32}, 12: [10 x si32]}* @c, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !35 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 ret i32 0, !dbg !38 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!30, !31, !32, !33} !llvm.ident = !{!34} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 21, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "multiple-inheritance.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Child", file: !3, line: 16, size: 416, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS5Child") !7 = !{!8, !14, !19, !26} !8 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !9, flags: DIFlagPublic, extraData: i32 0) !9 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Base", file: !3, line: 1, size: 64, flags: DIFlagTypePassByValue, elements: !10, identifier: "_ZTS4Base") !10 = !{!11, !13} !11 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !9, file: !3, line: 3, baseType: !12, size: 32) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !9, file: !3, line: 4, baseType: !12, size: 32, offset: 32) !14 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !15, offset: 64, flags: DIFlagPublic, extraData: i32 0) !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Mixin", file: !3, line: 7, size: 32, flags: DIFlagTypePassByValue, elements: !16, identifier: "_ZTS5Mixin") !16 = !{!17} !17 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !15, file: !3, line: 9, baseType: !18, size: 32, flags: DIFlagPrivate) !18 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !19 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !6, baseType: !20, flags: DIFlagPublic, extraData: i32 0) !20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Empty", file: !3, line: 12, size: 8, flags: DIFlagTypePassByValue, elements: !21, identifier: "_ZTS5Empty") !21 = !{!22} !22 = !DISubprogram(name: "f", linkageName: "_ZN5Empty1fEv", scope: !20, file: !3, line: 13, type: !23, scopeLine: 13, flags: DIFlagPrototyped, spFlags: 0) !23 = !DISubroutineType(types: !24) !24 = !{null, !25} !25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !26 = !DIDerivedType(tag: DW_TAG_member, name: "tab", scope: !6, file: !3, line: 18, baseType: !27, size: 320, offset: 96) !27 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 320, elements: !28) !28 = !{!29} !29 = !DISubrange(count: 10) !30 = !{i32 2, !"Dwarf Version", i32 4} !31 = !{i32 2, !"Debug Info Version", i32 3} !32 = !{i32 1, !"wchar_size", i32 4} !33 = !{i32 7, !"PIC Level", i32 2} !34 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !35 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 23, type: !36, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !36 = !DISubroutineType(types: !37) !37 = !{!12} !38 = !DILocation(line: 24, column: 3, scope: !35) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/nested-struct.c000066400000000000000000000002411473507761200322470ustar00rootroot00000000000000#include struct Node { struct Node* next; }; int main(int argc, char* argv[]) { struct Node* node = malloc(sizeof(struct Node*)); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/nested-struct.ll000066400000000000000000000117351473507761200324460ustar00rootroot00000000000000; ModuleID = 'nested-struct.pp.bc' source_filename = "nested-struct.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.Node = type { %struct.Node* } ; Function Attrs: allocsize(0) declare i8* @malloc(i64) #2 ; CHECK: declare si8* @ar.libc.malloc(ui64) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca %struct.Node*, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !15, metadata !DIExpression()), !dbg !16 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata %struct.Node** %6, metadata !19, metadata !DIExpression()), !dbg !24 %7 = call i8* @malloc(i64 8) #3, !dbg !25 %8 = bitcast i8* %7 to %struct.Node*, !dbg !25 store %struct.Node* %8, %struct.Node** %6, align 8, !dbg !24 ret i32 0, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: {0: {...}*}** $6 = allocate {0: {...}*}*, 1, align 8 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: si8* %7 = call @ar.libc.malloc(8) ; CHECK: {0: {...}*}* %8 = bitcast %7 ; CHECK: store $6, %8, align 8 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { allocsize(0) "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { allocsize(0) } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "nested-struct.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !9, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 7, type: !11) !16 = !DILocation(line: 7, column: 14, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 7, type: !12) !18 = !DILocation(line: 7, column: 26, scope: !8) !19 = !DILocalVariable(name: "node", scope: !8, file: !1, line: 8, type: !20) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Node", file: !1, line: 3, size: 64, elements: !22) !22 = !{!23} !23 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !21, file: !1, line: 4, baseType: !20, size: 64) !24 = !DILocation(line: 8, column: 16, scope: !8) !25 = !DILocation(line: 8, column: 23, scope: !8) !26 = !DILocation(line: 9, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/noexcept.cpp000066400000000000000000000000641473507761200316330ustar00rootroot00000000000000extern int f(); int g() noexcept { return f(); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/noexcept.ll000066400000000000000000000104761473507761200314700ustar00rootroot00000000000000; ModuleID = 'noexcept.pp.bc' source_filename = "noexcept.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 declare i32 @_Z1fv() #1 ; CHECK: declare si32 @_Z1fv() ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1gv() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !8 { %1 = invoke i32 @_Z1fv() to label %2 unwind label %3, !dbg !12 2: ; preds = %0 ret i32 %1, !dbg !13 3: ; preds = %0 %4 = landingpad { i8*, i32 } catch i8* null, !dbg !12 %5 = extractvalue { i8*, i32 } %4, 0, !dbg !12 call void @__clang_call_terminate(i8* %5) #3, !dbg !12 unreachable, !dbg !12 } ; CHECK: define si32 @_Z1gv() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32 %1 = invoke @_Z1fv() normal=#2 exc=#3 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#unified-exit} { ; CHECK: return %1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#unified-exit} { ; CHECK: {0: si8*, 8: si32} %2 = landingpad ; CHECK: si8* %3 = extractelement %2, 0 ; CHECK: call @__clang_call_terminate(%3) ; CHECK: unreachable ; CHECK: } ; CHECK: #unified-exit !exit predecessors={#2, #3} { ; CHECK: } ; CHECK: } declare void @_ZSt9terminatev() ; CHECK: declare void @_ZSt9terminatev() ; Function Attrs: noinline noreturn nounwind define linkonce_odr hidden void @__clang_call_terminate(i8*) #2 { %2 = call i8* @__cxa_begin_catch(i8* %0) #4 call void @_ZSt9terminatev() #3 unreachable } ; CHECK: define void @__clang_call_terminate(si8* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si8* %2 = call @ar.libcpp.begincatch(%1) ; CHECK: call @_ZSt9terminatev() ; CHECK: unreachable ; CHECK: } ; CHECK: } declare i32 @__gxx_personality_v0(...) ; CHECK: declare si32 @__gxx_personality_v0(...) declare i8* @__cxa_begin_catch(i8*) ; CHECK: declare si8* @ar.libcpp.begincatch(si8*) attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { noinline noreturn nounwind } attributes #3 = { noreturn nounwind } attributes #4 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "noexcept.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "g", linkageName: "_Z1gv", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 4, column: 10, scope: !8) !13 = !DILocation(line: 4, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/non-term-1.c000066400000000000000000000001741473507761200313450ustar00rootroot00000000000000#include int main(int argc, char** argv) { int i; while (1) { if (i == 0) exit(1); i++; } } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/non-term-1.ll000066400000000000000000000132211473507761200315270ustar00rootroot00000000000000; ModuleID = 'non-term-1.pp.bc' source_filename = "non-term-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noreturn declare void @exit(i32) #2 ; CHECK: declare void @ar.libc.exit(si32) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !15, metadata !DIExpression()), !dbg !16 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32* %6, metadata !19, metadata !DIExpression()), !dbg !20 br label %7, !dbg !21 7: ; preds = %2, %11 %8 = load i32, i32* %6, align 4, !dbg !22 %9 = icmp eq i32 %8, 0, !dbg !25 br i1 %9, label %10, label %11, !dbg !26 10: ; preds = %7 call void @exit(i32 1) #3, !dbg !27 unreachable, !dbg !27 11: ; preds = %7 %12 = load i32, i32* %6, align 4, !dbg !28 %13 = add nsw i32 %12, 1, !dbg !28 store i32 %13, i32* %6, align 4, !dbg !28 br label %7, !dbg !21, !llvm.loop !29 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: } ; CHECK: #2 predecessors={#1, #4} successors={#3, #4} { ; CHECK: si32 %7 = load $6, align 4 ; CHECK: } ; CHECK: #3 !exit predecessors={#2} { ; CHECK: %7 sieq 0 ; CHECK: call @ar.libc.exit(1) ; CHECK: unreachable ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#2} { ; CHECK: %7 sine 0 ; CHECK: si32 %8 = load $6, align 4 ; CHECK: si32 %9 = %8 sadd.nw 1 ; CHECK: store $6, %9, align 4 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noreturn "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { noreturn } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "non-term-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 3, column: 14, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 3, type: !12) !18 = !DILocation(line: 3, column: 27, scope: !8) !19 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 4, type: !11) !20 = !DILocation(line: 4, column: 7, scope: !8) !21 = !DILocation(line: 5, column: 3, scope: !8) !22 = !DILocation(line: 6, column: 9, scope: !23) !23 = distinct !DILexicalBlock(scope: !24, file: !1, line: 6, column: 9) !24 = distinct !DILexicalBlock(scope: !8, file: !1, line: 5, column: 13) !25 = !DILocation(line: 6, column: 11, scope: !23) !26 = !DILocation(line: 6, column: 9, scope: !24) !27 = !DILocation(line: 7, column: 7, scope: !23) !28 = !DILocation(line: 8, column: 6, scope: !24) !29 = distinct !{!29, !21, !30} !30 = !DILocation(line: 9, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/non-term-2.c000066400000000000000000000001371473507761200313450ustar00rootroot00000000000000#include int main() { while (1) { printf("hello world\n"); } return 42; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/non-term-2.ll000066400000000000000000000071261473507761200315370ustar00rootroot00000000000000; ModuleID = 'non-term-2.pp.bc' source_filename = "non-term-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1 ; CHECK: define [13 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #1 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 br label %2, !dbg !12 2: ; preds = %0, %2 %3 = getelementptr inbounds [13 x i8], [13 x i8]* @.str, i64 0, i64 0, !dbg !13 %4 = call i32 (i8*, ...) @printf(i8* %3), !dbg !13 br label %2, !dbg !12, !llvm.loop !15 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #2} successors={#2} { ; CHECK: si8* %2 = ptrshift @.str, 13 * 0, 1 * 0 ; CHECK: si32 %3 = call @ar.libc.printf(%2) ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "non-term-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocation(line: 4, column: 3, scope: !8) !13 = !DILocation(line: 5, column: 5, scope: !14) !14 = distinct !DILexicalBlock(scope: !8, file: !1, line: 4, column: 13) !15 = distinct !{!15, !12, !16} !16 = !DILocation(line: 6, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/nullptr.cpp000066400000000000000000000001201473507761200314770ustar00rootroot00000000000000int f(decltype(nullptr) x) { return 1; } int main() { return f(nullptr); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/nullptr.ll000066400000000000000000000100311473507761200313260ustar00rootroot00000000000000; ModuleID = 'nullptr.pp.bc' source_filename = "nullptr.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fDn(i8*) #0 !dbg !8 { %2 = alloca i8*, align 8 store i8* %0, i8** %2, align 8 call void @llvm.dbg.declare(metadata i8** %2, metadata !13, metadata !DIExpression()), !dbg !14 ret i32 1, !dbg !15 } ; CHECK: define si32 @_Z1fDn(si8* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si8** $2 = allocate si8*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: return 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #2 !dbg !16 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = call i32 @_Z1fDn(i8* null), !dbg !19 ret i32 %2, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: si32 %2 = call @_Z1fDn(null) ; CHECK: return %2 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "nullptr.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fDn", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "decltype(nullptr)") !13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !12) !14 = !DILocation(line: 1, column: 25, scope: !8) !15 = !DILocation(line: 2, column: 3, scope: !8) !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!11} !19 = !DILocation(line: 6, column: 10, scope: !16) !20 = !DILocation(line: 6, column: 3, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/opaque-struct.c000066400000000000000000000002011473507761200322530ustar00rootroot00000000000000#include struct X; typedef struct { int* a; struct X* b; } my_struct; my_struct s; int main() { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/opaque-struct.ll000066400000000000000000000065551473507761200324620ustar00rootroot00000000000000; ModuleID = 'opaque-struct.pp.bc' source_filename = "opaque-struct.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.my_struct = type { i32*, %struct.X* } %struct.X = type opaque @s = common global %struct.my_struct zeroinitializer, align 8, !dbg !0 ; CHECK: define {0: si32*, 8: opaque*}* @s, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @s, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 ret i32 0, !dbg !23 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "s", scope: !2, file: !3, line: 10, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "opaque-struct.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "my_struct", file: !3, line: 8, baseType: !7) !7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 5, size: 128, elements: !8) !8 = !{!9, !12} !9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 6, baseType: !10, size: 64) !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 7, baseType: !13, size: 64, offset: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !3, line: 3, flags: DIFlagFwdDecl) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 12, type: !21, scopeLine: 12, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!11} !23 = !DILocation(line: 13, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-1.c000066400000000000000000000001761473507761200303700ustar00rootroot00000000000000double a[10]; int main(int argc, char** argv) { int i; for (i = 0; i < 10; i++) { a[i] = i * 0.88; } a[i] = i; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-1.ll000066400000000000000000000172011473507761200305520ustar00rootroot00000000000000; ModuleID = 'phi-1.pp.bc' source_filename = "phi-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global [10 x double] zeroinitializer, align 16, !dbg !0 ; CHECK: define [10 x double]* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !15 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !22, metadata !DIExpression()), !dbg !23 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !24, metadata !DIExpression()), !dbg !25 call void @llvm.dbg.declare(metadata i32* %6, metadata !26, metadata !DIExpression()), !dbg !27 store i32 0, i32* %6, align 4, !dbg !28 br label %7, !dbg !30 7: ; preds = %17, %2 %8 = load i32, i32* %6, align 4, !dbg !31 %9 = icmp slt i32 %8, 10, !dbg !33 br i1 %9, label %10, label %20, !dbg !34 10: ; preds = %7 %11 = load i32, i32* %6, align 4, !dbg !35 %12 = sitofp i32 %11 to double, !dbg !35 %13 = fmul double %12, 8.800000e-01, !dbg !37 %14 = load i32, i32* %6, align 4, !dbg !38 %15 = sext i32 %14 to i64, !dbg !39 %16 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %15, !dbg !39 store double %13, double* %16, align 8, !dbg !40 br label %17, !dbg !41 17: ; preds = %10 %18 = load i32, i32* %6, align 4, !dbg !42 %19 = add nsw i32 %18, 1, !dbg !42 store i32 %19, i32* %6, align 4, !dbg !42 br label %7, !dbg !43, !llvm.loop !44 20: ; preds = %7 %21 = load i32, i32* %6, align 4, !dbg !46 %22 = sitofp i32 %21 to double, !dbg !46 %23 = load i32, i32* %6, align 4, !dbg !47 %24 = sext i32 %23 to i64, !dbg !48 %25 = getelementptr inbounds [10 x double], [10 x double]* @a, i64 0, i64 %24, !dbg !48 store double %22, double* %25, align 8, !dbg !49 %26 = load i32, i32* %3, align 4, !dbg !50 ret i32 %26, !dbg !50 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: store $6, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: si32 %7 = load $6, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %7 silt 10 ; CHECK: si32 %8 = load $6, align 4 ; CHECK: double %9 = sitofp %8 ; CHECK: double %10 = %9 fmul 8.8E-1 ; CHECK: si32 %11 = load $6, align 4 ; CHECK: si64 %12 = sext %11 ; CHECK: double* %13 = ptrshift @a, 80 * 0, 8 * %12 ; CHECK: store %13, %10, align 8 ; CHECK: si32 %14 = load $6, align 4 ; CHECK: si32 %15 = %14 sadd.nw 1 ; CHECK: store $6, %15, align 4 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %7 sige 10 ; CHECK: si32 %16 = load $6, align 4 ; CHECK: double %17 = sitofp %16 ; CHECK: si32 %18 = load $6, align 4 ; CHECK: si64 %19 = sext %18 ; CHECK: double* %20 = ptrshift @a, 80 * 0, 8 * %19 ; CHECK: store %20, %17, align 8 ; CHECK: si32 %21 = load $3, align 4 ; CHECK: return %21 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!10, !11, !12, !13} !llvm.ident = !{!14} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "phi-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 640, elements: !8) !7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 10) !10 = !{i32 2, !"Dwarf Version", i32 4} !11 = !{i32 2, !"Debug Info Version", i32 3} !12 = !{i32 1, !"wchar_size", i32 4} !13 = !{i32 7, !"PIC Level", i32 2} !14 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !15 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !16 = !DISubroutineType(types: !17) !17 = !{!18, !18, !19} !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !22 = !DILocalVariable(name: "argc", arg: 1, scope: !15, file: !3, line: 3, type: !18) !23 = !DILocation(line: 3, column: 14, scope: !15) !24 = !DILocalVariable(name: "argv", arg: 2, scope: !15, file: !3, line: 3, type: !19) !25 = !DILocation(line: 3, column: 27, scope: !15) !26 = !DILocalVariable(name: "i", scope: !15, file: !3, line: 4, type: !18) !27 = !DILocation(line: 4, column: 7, scope: !15) !28 = !DILocation(line: 5, column: 10, scope: !29) !29 = distinct !DILexicalBlock(scope: !15, file: !3, line: 5, column: 3) !30 = !DILocation(line: 5, column: 8, scope: !29) !31 = !DILocation(line: 5, column: 15, scope: !32) !32 = distinct !DILexicalBlock(scope: !29, file: !3, line: 5, column: 3) !33 = !DILocation(line: 5, column: 17, scope: !32) !34 = !DILocation(line: 5, column: 3, scope: !29) !35 = !DILocation(line: 6, column: 12, scope: !36) !36 = distinct !DILexicalBlock(scope: !32, file: !3, line: 5, column: 28) !37 = !DILocation(line: 6, column: 14, scope: !36) !38 = !DILocation(line: 6, column: 7, scope: !36) !39 = !DILocation(line: 6, column: 5, scope: !36) !40 = !DILocation(line: 6, column: 10, scope: !36) !41 = !DILocation(line: 7, column: 3, scope: !36) !42 = !DILocation(line: 5, column: 24, scope: !32) !43 = !DILocation(line: 5, column: 3, scope: !32) !44 = distinct !{!44, !34, !45} !45 = !DILocation(line: 7, column: 3, scope: !29) !46 = !DILocation(line: 8, column: 10, scope: !15) !47 = !DILocation(line: 8, column: 5, scope: !15) !48 = !DILocation(line: 8, column: 3, scope: !15) !49 = !DILocation(line: 8, column: 8, scope: !15) !50 = !DILocation(line: 9, column: 1, scope: !15) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-2.c000066400000000000000000000010751473507761200303700ustar00rootroot00000000000000// SAFE #include #define MAX_ARRAY 10 struct bar { int x; float y; }; struct foo { int x; struct bar y; int a[MAX_ARRAY][MAX_ARRAY][MAX_ARRAY - 1]; }; // To test loops int main(int argc, char** argv) { int i, j, k; struct foo x; for (i = 0; i < MAX_ARRAY; i++) { for (j = 0; j < MAX_ARRAY; j++) { for (k = 0; k < MAX_ARRAY - 1; k++) { x.a[i][j][k] = argc; // some unknown value here x.y.x = x.a[i][j][k]; } } } for (i = 0; i < MAX_ARRAY; i++) { printf("%d\n", x.a[i][i][i - 1]); } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-2.ll000066400000000000000000000456371473507761200305710ustar00rootroot00000000000000; ModuleID = 'phi-2.pp.bc' source_filename = "phi-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.foo = type { i32, %struct.bar, [10 x [10 x [9 x i32]]] } %struct.bar = type { i32, float } @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 %7 = alloca i32, align 4 %8 = alloca i32, align 4 %9 = alloca %struct.foo, align 4 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !15, metadata !DIExpression()), !dbg !16 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32* %6, metadata !19, metadata !DIExpression()), !dbg !20 call void @llvm.dbg.declare(metadata i32* %7, metadata !21, metadata !DIExpression()), !dbg !22 call void @llvm.dbg.declare(metadata i32* %8, metadata !23, metadata !DIExpression()), !dbg !24 call void @llvm.dbg.declare(metadata %struct.foo* %9, metadata !25, metadata !DIExpression()), !dbg !40 store i32 0, i32* %6, align 4, !dbg !41 br label %10, !dbg !43 10: ; preds = %54, %2 %11 = load i32, i32* %6, align 4, !dbg !44 %12 = icmp slt i32 %11, 10, !dbg !46 br i1 %12, label %13, label %57, !dbg !47 13: ; preds = %10 store i32 0, i32* %7, align 4, !dbg !48 br label %14, !dbg !51 14: ; preds = %50, %13 %15 = load i32, i32* %7, align 4, !dbg !52 %16 = icmp slt i32 %15, 10, !dbg !54 br i1 %16, label %17, label %53, !dbg !55 17: ; preds = %14 store i32 0, i32* %8, align 4, !dbg !56 br label %18, !dbg !59 18: ; preds = %46, %17 %19 = load i32, i32* %8, align 4, !dbg !60 %20 = icmp slt i32 %19, 9, !dbg !62 br i1 %20, label %21, label %49, !dbg !63 21: ; preds = %18 %22 = load i32, i32* %4, align 4, !dbg !64 %23 = getelementptr inbounds %struct.foo, %struct.foo* %9, i32 0, i32 2, !dbg !66 %24 = load i32, i32* %6, align 4, !dbg !67 %25 = sext i32 %24 to i64, !dbg !68 %26 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %23, i64 0, i64 %25, !dbg !68 %27 = load i32, i32* %7, align 4, !dbg !69 %28 = sext i32 %27 to i64, !dbg !68 %29 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %26, i64 0, i64 %28, !dbg !68 %30 = load i32, i32* %8, align 4, !dbg !70 %31 = sext i32 %30 to i64, !dbg !68 %32 = getelementptr inbounds [9 x i32], [9 x i32]* %29, i64 0, i64 %31, !dbg !68 store i32 %22, i32* %32, align 4, !dbg !71 %33 = getelementptr inbounds %struct.foo, %struct.foo* %9, i32 0, i32 2, !dbg !72 %34 = load i32, i32* %6, align 4, !dbg !73 %35 = sext i32 %34 to i64, !dbg !74 %36 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %33, i64 0, i64 %35, !dbg !74 %37 = load i32, i32* %7, align 4, !dbg !75 %38 = sext i32 %37 to i64, !dbg !74 %39 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %36, i64 0, i64 %38, !dbg !74 %40 = load i32, i32* %8, align 4, !dbg !76 %41 = sext i32 %40 to i64, !dbg !74 %42 = getelementptr inbounds [9 x i32], [9 x i32]* %39, i64 0, i64 %41, !dbg !74 %43 = load i32, i32* %42, align 4, !dbg !74 %44 = getelementptr inbounds %struct.foo, %struct.foo* %9, i32 0, i32 1, !dbg !77 %45 = getelementptr inbounds %struct.bar, %struct.bar* %44, i32 0, i32 0, !dbg !78 store i32 %43, i32* %45, align 4, !dbg !79 br label %46, !dbg !80 46: ; preds = %21 %47 = load i32, i32* %8, align 4, !dbg !81 %48 = add nsw i32 %47, 1, !dbg !81 store i32 %48, i32* %8, align 4, !dbg !81 br label %18, !dbg !82, !llvm.loop !83 49: ; preds = %18 br label %50, !dbg !85 50: ; preds = %49 %51 = load i32, i32* %7, align 4, !dbg !86 %52 = add nsw i32 %51, 1, !dbg !86 store i32 %52, i32* %7, align 4, !dbg !86 br label %14, !dbg !87, !llvm.loop !88 53: ; preds = %14 br label %54, !dbg !90 54: ; preds = %53 %55 = load i32, i32* %6, align 4, !dbg !91 %56 = add nsw i32 %55, 1, !dbg !91 store i32 %56, i32* %6, align 4, !dbg !91 br label %10, !dbg !92, !llvm.loop !93 57: ; preds = %10 store i32 0, i32* %6, align 4, !dbg !95 br label %58, !dbg !97 58: ; preds = %76, %57 %59 = load i32, i32* %6, align 4, !dbg !98 %60 = icmp slt i32 %59, 10, !dbg !100 br i1 %60, label %61, label %79, !dbg !101 61: ; preds = %58 %62 = getelementptr inbounds %struct.foo, %struct.foo* %9, i32 0, i32 2, !dbg !102 %63 = load i32, i32* %6, align 4, !dbg !104 %64 = sext i32 %63 to i64, !dbg !105 %65 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %62, i64 0, i64 %64, !dbg !105 %66 = load i32, i32* %6, align 4, !dbg !106 %67 = sext i32 %66 to i64, !dbg !105 %68 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %65, i64 0, i64 %67, !dbg !105 %69 = load i32, i32* %6, align 4, !dbg !107 %70 = sub nsw i32 %69, 1, !dbg !108 %71 = sext i32 %70 to i64, !dbg !105 %72 = getelementptr inbounds [9 x i32], [9 x i32]* %68, i64 0, i64 %71, !dbg !105 %73 = load i32, i32* %72, align 4, !dbg !105 %74 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i64 0, i64 0, !dbg !109 %75 = call i32 (i8*, ...) @printf(i8* %74, i32 %73), !dbg !109 br label %76, !dbg !110 76: ; preds = %61 %77 = load i32, i32* %6, align 4, !dbg !111 %78 = add nsw i32 %77, 1, !dbg !111 store i32 %78, i32* %6, align 4, !dbg !111 br label %58, !dbg !112, !llvm.loop !113 79: ; preds = %58 ret i32 0, !dbg !115 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: si32* $7 = allocate si32, 1, align 4 ; CHECK: si32* $8 = allocate si32, 1, align 4 ; CHECK: {0: si32, 4: {0: si32, 4: float}, 12: [10 x [10 x [9 x si32]]]}* $9 = allocate {0: si32, 4: {0: si32, 4: float}, 12: [10 x [10 x [9 x si32]]]}, 1, align 4 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: store $6, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #8} successors={#3, #4} { ; CHECK: si32 %10 = load $6, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#5} { ; CHECK: %10 silt 10 ; CHECK: store $7, 0, align 4 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#6} { ; CHECK: %10 sige 10 ; CHECK: store $6, 0, align 4 ; CHECK: } ; CHECK: #5 predecessors={#3, #13} successors={#7, #8} { ; CHECK: si32 %11 = load $7, align 4 ; CHECK: } ; CHECK: #7 predecessors={#5} successors={#11} { ; CHECK: %11 silt 10 ; CHECK: store $8, 0, align 4 ; CHECK: } ; CHECK: #8 predecessors={#5} successors={#2} { ; CHECK: %11 sige 10 ; CHECK: si32 %13 = load $6, align 4 ; CHECK: si32 %14 = %13 sadd.nw 1 ; CHECK: store $6, %14, align 4 ; CHECK: } ; CHECK: #6 predecessors={#4, #9} successors={#9, #10} { ; CHECK: si32 %12 = load $6, align 4 ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#6} { ; CHECK: %12 silt 10 ; CHECK: [10 x [10 x [9 x si32]]]* %15 = ptrshift $9, 3612 * 0, 1 * 12 ; CHECK: si32 %16 = load $6, align 4 ; CHECK: si64 %17 = sext %16 ; CHECK: [10 x [9 x si32]]* %18 = ptrshift %15, 3600 * 0, 360 * %17 ; CHECK: si32 %19 = load $6, align 4 ; CHECK: si64 %20 = sext %19 ; CHECK: [9 x si32]* %21 = ptrshift %18, 360 * 0, 36 * %20 ; CHECK: si32 %22 = load $6, align 4 ; CHECK: si32 %23 = %22 ssub.nw 1 ; CHECK: si64 %24 = sext %23 ; CHECK: si32* %25 = ptrshift %21, 36 * 0, 4 * %24 ; CHECK: si32 %26 = load %25, align 4 ; CHECK: si8* %27 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: si32 %28 = call @ar.libc.printf(%27, %26) ; CHECK: si32 %29 = load $6, align 4 ; CHECK: si32 %30 = %29 sadd.nw 1 ; CHECK: store $6, %30, align 4 ; CHECK: } ; CHECK: #10 !exit predecessors={#6} { ; CHECK: %12 sige 10 ; CHECK: return 0 ; CHECK: } ; CHECK: #11 predecessors={#7, #12} successors={#12, #13} { ; CHECK: si32 %31 = load $8, align 4 ; CHECK: } ; CHECK: #12 predecessors={#11} successors={#11} { ; CHECK: %31 silt 9 ; CHECK: si32 %32 = load $4, align 4 ; CHECK: [10 x [10 x [9 x si32]]]* %33 = ptrshift $9, 3612 * 0, 1 * 12 ; CHECK: si32 %34 = load $6, align 4 ; CHECK: si64 %35 = sext %34 ; CHECK: [10 x [9 x si32]]* %36 = ptrshift %33, 3600 * 0, 360 * %35 ; CHECK: si32 %37 = load $7, align 4 ; CHECK: si64 %38 = sext %37 ; CHECK: [9 x si32]* %39 = ptrshift %36, 360 * 0, 36 * %38 ; CHECK: si32 %40 = load $8, align 4 ; CHECK: si64 %41 = sext %40 ; CHECK: si32* %42 = ptrshift %39, 36 * 0, 4 * %41 ; CHECK: store %42, %32, align 4 ; CHECK: [10 x [10 x [9 x si32]]]* %43 = ptrshift $9, 3612 * 0, 1 * 12 ; CHECK: si32 %44 = load $6, align 4 ; CHECK: si64 %45 = sext %44 ; CHECK: [10 x [9 x si32]]* %46 = ptrshift %43, 3600 * 0, 360 * %45 ; CHECK: si32 %47 = load $7, align 4 ; CHECK: si64 %48 = sext %47 ; CHECK: [9 x si32]* %49 = ptrshift %46, 360 * 0, 36 * %48 ; CHECK: si32 %50 = load $8, align 4 ; CHECK: si64 %51 = sext %50 ; CHECK: si32* %52 = ptrshift %49, 36 * 0, 4 * %51 ; CHECK: si32 %53 = load %52, align 4 ; CHECK: {0: si32, 4: float}* %54 = ptrshift $9, 3612 * 0, 1 * 4 ; CHECK: si32* %55 = ptrshift %54, 8 * 0, 1 * 0 ; CHECK: store %55, %53, align 4 ; CHECK: si32 %56 = load $8, align 4 ; CHECK: si32 %57 = %56 sadd.nw 1 ; CHECK: store $8, %57, align 4 ; CHECK: } ; CHECK: #13 predecessors={#11} successors={#5} { ; CHECK: %31 sige 9 ; CHECK: si32 %58 = load $7, align 4 ; CHECK: si32 %59 = %58 sadd.nw 1 ; CHECK: store $7, %59, align 4 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 18, type: !9, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 18, type: !11) !16 = !DILocation(line: 18, column: 14, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 18, type: !12) !18 = !DILocation(line: 18, column: 27, scope: !8) !19 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 19, type: !11) !20 = !DILocation(line: 19, column: 7, scope: !8) !21 = !DILocalVariable(name: "j", scope: !8, file: !1, line: 19, type: !11) !22 = !DILocation(line: 19, column: 10, scope: !8) !23 = !DILocalVariable(name: "k", scope: !8, file: !1, line: 19, type: !11) !24 = !DILocation(line: 19, column: 13, scope: !8) !25 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 20, type: !26) !26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 11, size: 28896, elements: !27) !27 = !{!28, !29, !35} !28 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !26, file: !1, line: 12, baseType: !11, size: 32) !29 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !26, file: !1, line: 13, baseType: !30, size: 64, offset: 32) !30 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !1, line: 6, size: 64, elements: !31) !31 = !{!32, !33} !32 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !30, file: !1, line: 7, baseType: !11, size: 32) !33 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !30, file: !1, line: 8, baseType: !34, size: 32, offset: 32) !34 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !35 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !26, file: !1, line: 14, baseType: !36, size: 28800, offset: 96) !36 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 28800, elements: !37) !37 = !{!38, !38, !39} !38 = !DISubrange(count: 10) !39 = !DISubrange(count: 9) !40 = !DILocation(line: 20, column: 14, scope: !8) !41 = !DILocation(line: 21, column: 10, scope: !42) !42 = distinct !DILexicalBlock(scope: !8, file: !1, line: 21, column: 3) !43 = !DILocation(line: 21, column: 8, scope: !42) !44 = !DILocation(line: 21, column: 15, scope: !45) !45 = distinct !DILexicalBlock(scope: !42, file: !1, line: 21, column: 3) !46 = !DILocation(line: 21, column: 17, scope: !45) !47 = !DILocation(line: 21, column: 3, scope: !42) !48 = !DILocation(line: 22, column: 12, scope: !49) !49 = distinct !DILexicalBlock(scope: !50, file: !1, line: 22, column: 5) !50 = distinct !DILexicalBlock(scope: !45, file: !1, line: 21, column: 35) !51 = !DILocation(line: 22, column: 10, scope: !49) !52 = !DILocation(line: 22, column: 17, scope: !53) !53 = distinct !DILexicalBlock(scope: !49, file: !1, line: 22, column: 5) !54 = !DILocation(line: 22, column: 19, scope: !53) !55 = !DILocation(line: 22, column: 5, scope: !49) !56 = !DILocation(line: 23, column: 14, scope: !57) !57 = distinct !DILexicalBlock(scope: !58, file: !1, line: 23, column: 7) !58 = distinct !DILexicalBlock(scope: !53, file: !1, line: 22, column: 37) !59 = !DILocation(line: 23, column: 12, scope: !57) !60 = !DILocation(line: 23, column: 19, scope: !61) !61 = distinct !DILexicalBlock(scope: !57, file: !1, line: 23, column: 7) !62 = !DILocation(line: 23, column: 21, scope: !61) !63 = !DILocation(line: 23, column: 7, scope: !57) !64 = !DILocation(line: 24, column: 24, scope: !65) !65 = distinct !DILexicalBlock(scope: !61, file: !1, line: 23, column: 43) !66 = !DILocation(line: 24, column: 11, scope: !65) !67 = !DILocation(line: 24, column: 13, scope: !65) !68 = !DILocation(line: 24, column: 9, scope: !65) !69 = !DILocation(line: 24, column: 16, scope: !65) !70 = !DILocation(line: 24, column: 19, scope: !65) !71 = !DILocation(line: 24, column: 22, scope: !65) !72 = !DILocation(line: 25, column: 19, scope: !65) !73 = !DILocation(line: 25, column: 21, scope: !65) !74 = !DILocation(line: 25, column: 17, scope: !65) !75 = !DILocation(line: 25, column: 24, scope: !65) !76 = !DILocation(line: 25, column: 27, scope: !65) !77 = !DILocation(line: 25, column: 11, scope: !65) !78 = !DILocation(line: 25, column: 13, scope: !65) !79 = !DILocation(line: 25, column: 15, scope: !65) !80 = !DILocation(line: 26, column: 7, scope: !65) !81 = !DILocation(line: 23, column: 39, scope: !61) !82 = !DILocation(line: 23, column: 7, scope: !61) !83 = distinct !{!83, !63, !84} !84 = !DILocation(line: 26, column: 7, scope: !57) !85 = !DILocation(line: 27, column: 5, scope: !58) !86 = !DILocation(line: 22, column: 33, scope: !53) !87 = !DILocation(line: 22, column: 5, scope: !53) !88 = distinct !{!88, !55, !89} !89 = !DILocation(line: 27, column: 5, scope: !49) !90 = !DILocation(line: 28, column: 3, scope: !50) !91 = !DILocation(line: 21, column: 31, scope: !45) !92 = !DILocation(line: 21, column: 3, scope: !45) !93 = distinct !{!93, !47, !94} !94 = !DILocation(line: 28, column: 3, scope: !42) !95 = !DILocation(line: 30, column: 10, scope: !96) !96 = distinct !DILexicalBlock(scope: !8, file: !1, line: 30, column: 3) !97 = !DILocation(line: 30, column: 8, scope: !96) !98 = !DILocation(line: 30, column: 15, scope: !99) !99 = distinct !DILexicalBlock(scope: !96, file: !1, line: 30, column: 3) !100 = !DILocation(line: 30, column: 17, scope: !99) !101 = !DILocation(line: 30, column: 3, scope: !96) !102 = !DILocation(line: 31, column: 22, scope: !103) !103 = distinct !DILexicalBlock(scope: !99, file: !1, line: 30, column: 35) !104 = !DILocation(line: 31, column: 24, scope: !103) !105 = !DILocation(line: 31, column: 20, scope: !103) !106 = !DILocation(line: 31, column: 27, scope: !103) !107 = !DILocation(line: 31, column: 30, scope: !103) !108 = !DILocation(line: 31, column: 32, scope: !103) !109 = !DILocation(line: 31, column: 5, scope: !103) !110 = !DILocation(line: 32, column: 3, scope: !103) !111 = !DILocation(line: 30, column: 31, scope: !99) !112 = !DILocation(line: 30, column: 3, scope: !99) !113 = distinct !{!113, !101, !114} !114 = !DILocation(line: 32, column: 3, scope: !96) !115 = !DILocation(line: 34, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-3.c000066400000000000000000000010271473507761200303660ustar00rootroot00000000000000// SAFE extern void __ikos_assert(int); int foo(int* a, int* b, int* c) { int* p; int* q; p = a + 1; q = b + 2; if (p == q) { q = q - 10; p = p + 42; } __ikos_assert(*p == 3); __ikos_assert(*q == 6); int res = c[*p + *q]; c[*p + *q] = 555; return res; } int main(int argc, char** argv) { int a[2]; int b[3]; int c[10]; c[9] = 666; a[0] = 1; a[1] = 3; b[0] = 4; b[1] = 5; b[2] = 6; int x = foo(a, b, c); __ikos_assert(x == 666); __ikos_assert(c[9] == 555); return x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-3.ll000066400000000000000000000461051473507761200305610ustar00rootroot00000000000000; ModuleID = 'phi-3.pp.bc' source_filename = "phi-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 declare void @__ikos_assert(i32) #2 ; CHECK: declare void @ar.ikos.assert(ui32) ; Function Attrs: noinline nounwind ssp uwtable define i32 @foo(i32*, i32*, i32*) #0 !dbg !8 { %4 = alloca i32*, align 8 %5 = alloca i32*, align 8 %6 = alloca i32*, align 8 %7 = alloca i32*, align 8 %8 = alloca i32*, align 8 %9 = alloca i32, align 4 store i32* %0, i32** %4, align 8 call void @llvm.dbg.declare(metadata i32** %4, metadata !13, metadata !DIExpression()), !dbg !14 store i32* %1, i32** %5, align 8 call void @llvm.dbg.declare(metadata i32** %5, metadata !15, metadata !DIExpression()), !dbg !16 store i32* %2, i32** %6, align 8 call void @llvm.dbg.declare(metadata i32** %6, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32** %7, metadata !19, metadata !DIExpression()), !dbg !20 call void @llvm.dbg.declare(metadata i32** %8, metadata !21, metadata !DIExpression()), !dbg !22 %10 = load i32*, i32** %4, align 8, !dbg !23 %11 = getelementptr inbounds i32, i32* %10, i64 1, !dbg !24 store i32* %11, i32** %7, align 8, !dbg !25 %12 = load i32*, i32** %5, align 8, !dbg !26 %13 = getelementptr inbounds i32, i32* %12, i64 2, !dbg !27 store i32* %13, i32** %8, align 8, !dbg !28 %14 = load i32*, i32** %7, align 8, !dbg !29 %15 = load i32*, i32** %8, align 8, !dbg !31 %16 = icmp eq i32* %14, %15, !dbg !32 br i1 %16, label %17, label %22, !dbg !33 17: ; preds = %3 %18 = load i32*, i32** %8, align 8, !dbg !34 %19 = getelementptr inbounds i32, i32* %18, i64 -10, !dbg !36 store i32* %19, i32** %8, align 8, !dbg !37 %20 = load i32*, i32** %7, align 8, !dbg !38 %21 = getelementptr inbounds i32, i32* %20, i64 42, !dbg !39 store i32* %21, i32** %7, align 8, !dbg !40 br label %22, !dbg !41 22: ; preds = %17, %3 %23 = load i32*, i32** %7, align 8, !dbg !42 %24 = load i32, i32* %23, align 4, !dbg !43 %25 = icmp eq i32 %24, 3, !dbg !44 %26 = zext i1 %25 to i32, !dbg !44 call void @__ikos_assert(i32 %26), !dbg !45 %27 = load i32*, i32** %8, align 8, !dbg !46 %28 = load i32, i32* %27, align 4, !dbg !47 %29 = icmp eq i32 %28, 6, !dbg !48 %30 = zext i1 %29 to i32, !dbg !48 call void @__ikos_assert(i32 %30), !dbg !49 call void @llvm.dbg.declare(metadata i32* %9, metadata !50, metadata !DIExpression()), !dbg !51 %31 = load i32*, i32** %6, align 8, !dbg !52 %32 = load i32*, i32** %7, align 8, !dbg !53 %33 = load i32, i32* %32, align 4, !dbg !54 %34 = load i32*, i32** %8, align 8, !dbg !55 %35 = load i32, i32* %34, align 4, !dbg !56 %36 = add nsw i32 %33, %35, !dbg !57 %37 = sext i32 %36 to i64, !dbg !52 %38 = getelementptr inbounds i32, i32* %31, i64 %37, !dbg !52 %39 = load i32, i32* %38, align 4, !dbg !52 store i32 %39, i32* %9, align 4, !dbg !51 %40 = load i32*, i32** %6, align 8, !dbg !58 %41 = load i32*, i32** %7, align 8, !dbg !59 %42 = load i32, i32* %41, align 4, !dbg !60 %43 = load i32*, i32** %8, align 8, !dbg !61 %44 = load i32, i32* %43, align 4, !dbg !62 %45 = add nsw i32 %42, %44, !dbg !63 %46 = sext i32 %45 to i64, !dbg !58 %47 = getelementptr inbounds i32, i32* %40, i64 %46, !dbg !58 store i32 555, i32* %47, align 4, !dbg !64 %48 = load i32, i32* %9, align 4, !dbg !65 ret i32 %48, !dbg !66 } ; CHECK: define si32 @foo(si32* %1, si32* %2, si32* %3) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32** $4 = allocate si32*, 1, align 8 ; CHECK: si32** $5 = allocate si32*, 1, align 8 ; CHECK: si32** $6 = allocate si32*, 1, align 8 ; CHECK: si32** $7 = allocate si32*, 1, align 8 ; CHECK: si32** $8 = allocate si32*, 1, align 8 ; CHECK: si32* $9 = allocate si32, 1, align 4 ; CHECK: store $4, %1, align 8 ; CHECK: store $5, %2, align 8 ; CHECK: store $6, %3, align 8 ; CHECK: si32* %10 = load $4, align 8 ; CHECK: si32* %11 = ptrshift %10, 4 * 1 ; CHECK: store $7, %11, align 8 ; CHECK: si32* %12 = load $5, align 8 ; CHECK: si32* %13 = ptrshift %12, 4 * 2 ; CHECK: store $8, %13, align 8 ; CHECK: si32* %14 = load $7, align 8 ; CHECK: si32* %15 = load $8, align 8 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %14 peq %15 ; CHECK: si32* %16 = load $8, align 8 ; CHECK: si32* %17 = ptrshift %16, 4 * -10 ; CHECK: store $8, %17, align 8 ; CHECK: si32* %18 = load $7, align 8 ; CHECK: si32* %19 = ptrshift %18, 4 * 42 ; CHECK: store $7, %19, align 8 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %14 pne %15 ; CHECK: } ; CHECK: #4 predecessors={#3, #2} successors={#5, #6} { ; CHECK: si32* %20 = load $7, align 8 ; CHECK: si32 %21 = load %20, align 4 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %21 sieq 3 ; CHECK: ui1 %22 = 1 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %21 sine 3 ; CHECK: ui1 %22 = 0 ; CHECK: } ; CHECK: #7 predecessors={#5, #6} successors={#8, #9} { ; CHECK: ui32 %23 = zext %22 ; CHECK: call @ar.ikos.assert(%23) ; CHECK: si32* %24 = load $8, align 8 ; CHECK: si32 %25 = load %24, align 4 ; CHECK: } ; CHECK: #8 predecessors={#7} successors={#10} { ; CHECK: %25 sieq 6 ; CHECK: ui1 %26 = 1 ; CHECK: } ; CHECK: #9 predecessors={#7} successors={#10} { ; CHECK: %25 sine 6 ; CHECK: ui1 %26 = 0 ; CHECK: } ; CHECK: #10 !exit predecessors={#8, #9} { ; CHECK: ui32 %27 = zext %26 ; CHECK: call @ar.ikos.assert(%27) ; CHECK: si32* %28 = load $6, align 8 ; CHECK: si32* %29 = load $7, align 8 ; CHECK: si32 %30 = load %29, align 4 ; CHECK: si32* %31 = load $8, align 8 ; CHECK: si32 %32 = load %31, align 4 ; CHECK: si32 %33 = %30 sadd.nw %32 ; CHECK: si64 %34 = sext %33 ; CHECK: si32* %35 = ptrshift %28, 4 * %34 ; CHECK: si32 %36 = load %35, align 4 ; CHECK: store $9, %36, align 4 ; CHECK: si32* %37 = load $6, align 8 ; CHECK: si32* %38 = load $7, align 8 ; CHECK: si32 %39 = load %38, align 4 ; CHECK: si32* %40 = load $8, align 8 ; CHECK: si32 %41 = load %40, align 4 ; CHECK: si32 %42 = %39 sadd.nw %41 ; CHECK: si64 %43 = sext %42 ; CHECK: si32* %44 = ptrshift %37, 4 * %43 ; CHECK: store %44, 555, align 4 ; CHECK: si32 %45 = load $9, align 4 ; CHECK: return %45 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !67 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca [2 x i32], align 4 %7 = alloca [3 x i32], align 4 %8 = alloca [10 x i32], align 16 %9 = alloca i32, align 4 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !73, metadata !DIExpression()), !dbg !74 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !75, metadata !DIExpression()), !dbg !76 call void @llvm.dbg.declare(metadata [2 x i32]* %6, metadata !77, metadata !DIExpression()), !dbg !81 call void @llvm.dbg.declare(metadata [3 x i32]* %7, metadata !82, metadata !DIExpression()), !dbg !86 call void @llvm.dbg.declare(metadata [10 x i32]* %8, metadata !87, metadata !DIExpression()), !dbg !91 %10 = getelementptr inbounds [10 x i32], [10 x i32]* %8, i64 0, i64 9, !dbg !92 store i32 666, i32* %10, align 4, !dbg !93 %11 = getelementptr inbounds [2 x i32], [2 x i32]* %6, i64 0, i64 0, !dbg !94 store i32 1, i32* %11, align 4, !dbg !95 %12 = getelementptr inbounds [2 x i32], [2 x i32]* %6, i64 0, i64 1, !dbg !96 store i32 3, i32* %12, align 4, !dbg !97 %13 = getelementptr inbounds [3 x i32], [3 x i32]* %7, i64 0, i64 0, !dbg !98 store i32 4, i32* %13, align 4, !dbg !99 %14 = getelementptr inbounds [3 x i32], [3 x i32]* %7, i64 0, i64 1, !dbg !100 store i32 5, i32* %14, align 4, !dbg !101 %15 = getelementptr inbounds [3 x i32], [3 x i32]* %7, i64 0, i64 2, !dbg !102 store i32 6, i32* %15, align 4, !dbg !103 call void @llvm.dbg.declare(metadata i32* %9, metadata !104, metadata !DIExpression()), !dbg !105 %16 = getelementptr inbounds [2 x i32], [2 x i32]* %6, i64 0, i64 0, !dbg !106 %17 = getelementptr inbounds [3 x i32], [3 x i32]* %7, i64 0, i64 0, !dbg !107 %18 = getelementptr inbounds [10 x i32], [10 x i32]* %8, i64 0, i64 0, !dbg !108 %19 = call i32 @foo(i32* %16, i32* %17, i32* %18), !dbg !109 store i32 %19, i32* %9, align 4, !dbg !105 %20 = load i32, i32* %9, align 4, !dbg !110 %21 = icmp eq i32 %20, 666, !dbg !111 %22 = zext i1 %21 to i32, !dbg !111 call void @__ikos_assert(i32 %22), !dbg !112 %23 = getelementptr inbounds [10 x i32], [10 x i32]* %8, i64 0, i64 9, !dbg !113 %24 = load i32, i32* %23, align 4, !dbg !113 %25 = icmp eq i32 %24, 555, !dbg !114 %26 = zext i1 %25 to i32, !dbg !114 call void @__ikos_assert(i32 %26), !dbg !115 %27 = load i32, i32* %9, align 4, !dbg !116 ret i32 %27, !dbg !117 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: [2 x si32]* $6 = allocate [2 x si32], 1, align 4 ; CHECK: [3 x si32]* $7 = allocate [3 x si32], 1, align 4 ; CHECK: [10 x si32]* $8 = allocate [10 x si32], 1, align 16 ; CHECK: si32* $9 = allocate si32, 1, align 4 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: si32* %10 = ptrshift $8, 40 * 0, 4 * 9 ; CHECK: store %10, 666, align 4 ; CHECK: si32* %11 = ptrshift $6, 8 * 0, 4 * 0 ; CHECK: store %11, 1, align 4 ; CHECK: si32* %12 = ptrshift $6, 8 * 0, 4 * 1 ; CHECK: store %12, 3, align 4 ; CHECK: si32* %13 = ptrshift $7, 12 * 0, 4 * 0 ; CHECK: store %13, 4, align 4 ; CHECK: si32* %14 = ptrshift $7, 12 * 0, 4 * 1 ; CHECK: store %14, 5, align 4 ; CHECK: si32* %15 = ptrshift $7, 12 * 0, 4 * 2 ; CHECK: store %15, 6, align 4 ; CHECK: si32* %16 = ptrshift $6, 8 * 0, 4 * 0 ; CHECK: si32* %17 = ptrshift $7, 12 * 0, 4 * 0 ; CHECK: si32* %18 = ptrshift $8, 40 * 0, 4 * 0 ; CHECK: si32 %19 = call @foo(%16, %17, %18) ; CHECK: store $9, %19, align 4 ; CHECK: si32 %20 = load $9, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %20 sieq 666 ; CHECK: ui1 %21 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %20 sine 666 ; CHECK: ui1 %21 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5, #6} { ; CHECK: ui32 %22 = zext %21 ; CHECK: call @ar.ikos.assert(%22) ; CHECK: si32* %23 = ptrshift $8, 40 * 0, 4 * 9 ; CHECK: si32 %24 = load %23, align 4 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %24 sieq 555 ; CHECK: ui1 %25 = 1 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %24 sine 555 ; CHECK: ui1 %25 = 0 ; CHECK: } ; CHECK: #7 !exit predecessors={#5, #6} { ; CHECK: ui32 %26 = zext %25 ; CHECK: call @ar.ikos.assert(%26) ; CHECK: si32 %27 = load $9, align 4 ; CHECK: return %27 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, type: !9, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !12, !12, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !13 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 5, type: !12) !14 = !DILocation(line: 5, column: 14, scope: !8) !15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 5, type: !12) !16 = !DILocation(line: 5, column: 22, scope: !8) !17 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 5, type: !12) !18 = !DILocation(line: 5, column: 30, scope: !8) !19 = !DILocalVariable(name: "p", scope: !8, file: !1, line: 6, type: !12) !20 = !DILocation(line: 6, column: 8, scope: !8) !21 = !DILocalVariable(name: "q", scope: !8, file: !1, line: 7, type: !12) !22 = !DILocation(line: 7, column: 8, scope: !8) !23 = !DILocation(line: 9, column: 7, scope: !8) !24 = !DILocation(line: 9, column: 9, scope: !8) !25 = !DILocation(line: 9, column: 5, scope: !8) !26 = !DILocation(line: 10, column: 7, scope: !8) !27 = !DILocation(line: 10, column: 9, scope: !8) !28 = !DILocation(line: 10, column: 5, scope: !8) !29 = !DILocation(line: 12, column: 7, scope: !30) !30 = distinct !DILexicalBlock(scope: !8, file: !1, line: 12, column: 7) !31 = !DILocation(line: 12, column: 12, scope: !30) !32 = !DILocation(line: 12, column: 9, scope: !30) !33 = !DILocation(line: 12, column: 7, scope: !8) !34 = !DILocation(line: 13, column: 9, scope: !35) !35 = distinct !DILexicalBlock(scope: !30, file: !1, line: 12, column: 15) !36 = !DILocation(line: 13, column: 11, scope: !35) !37 = !DILocation(line: 13, column: 7, scope: !35) !38 = !DILocation(line: 14, column: 9, scope: !35) !39 = !DILocation(line: 14, column: 11, scope: !35) !40 = !DILocation(line: 14, column: 7, scope: !35) !41 = !DILocation(line: 15, column: 3, scope: !35) !42 = !DILocation(line: 16, column: 18, scope: !8) !43 = !DILocation(line: 16, column: 17, scope: !8) !44 = !DILocation(line: 16, column: 20, scope: !8) !45 = !DILocation(line: 16, column: 3, scope: !8) !46 = !DILocation(line: 17, column: 18, scope: !8) !47 = !DILocation(line: 17, column: 17, scope: !8) !48 = !DILocation(line: 17, column: 20, scope: !8) !49 = !DILocation(line: 17, column: 3, scope: !8) !50 = !DILocalVariable(name: "res", scope: !8, file: !1, line: 19, type: !11) !51 = !DILocation(line: 19, column: 7, scope: !8) !52 = !DILocation(line: 19, column: 13, scope: !8) !53 = !DILocation(line: 19, column: 16, scope: !8) !54 = !DILocation(line: 19, column: 15, scope: !8) !55 = !DILocation(line: 19, column: 21, scope: !8) !56 = !DILocation(line: 19, column: 20, scope: !8) !57 = !DILocation(line: 19, column: 18, scope: !8) !58 = !DILocation(line: 20, column: 3, scope: !8) !59 = !DILocation(line: 20, column: 6, scope: !8) !60 = !DILocation(line: 20, column: 5, scope: !8) !61 = !DILocation(line: 20, column: 11, scope: !8) !62 = !DILocation(line: 20, column: 10, scope: !8) !63 = !DILocation(line: 20, column: 8, scope: !8) !64 = !DILocation(line: 20, column: 14, scope: !8) !65 = !DILocation(line: 21, column: 10, scope: !8) !66 = !DILocation(line: 21, column: 3, scope: !8) !67 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 24, type: !68, scopeLine: 24, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !68 = !DISubroutineType(types: !69) !69 = !{!11, !11, !70} !70 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !71, size: 64) !71 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !72, size: 64) !72 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !73 = !DILocalVariable(name: "argc", arg: 1, scope: !67, file: !1, line: 24, type: !11) !74 = !DILocation(line: 24, column: 14, scope: !67) !75 = !DILocalVariable(name: "argv", arg: 2, scope: !67, file: !1, line: 24, type: !70) !76 = !DILocation(line: 24, column: 27, scope: !67) !77 = !DILocalVariable(name: "a", scope: !67, file: !1, line: 25, type: !78) !78 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 64, elements: !79) !79 = !{!80} !80 = !DISubrange(count: 2) !81 = !DILocation(line: 25, column: 7, scope: !67) !82 = !DILocalVariable(name: "b", scope: !67, file: !1, line: 26, type: !83) !83 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 96, elements: !84) !84 = !{!85} !85 = !DISubrange(count: 3) !86 = !DILocation(line: 26, column: 7, scope: !67) !87 = !DILocalVariable(name: "c", scope: !67, file: !1, line: 27, type: !88) !88 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !89) !89 = !{!90} !90 = !DISubrange(count: 10) !91 = !DILocation(line: 27, column: 7, scope: !67) !92 = !DILocation(line: 29, column: 3, scope: !67) !93 = !DILocation(line: 29, column: 8, scope: !67) !94 = !DILocation(line: 31, column: 3, scope: !67) !95 = !DILocation(line: 31, column: 8, scope: !67) !96 = !DILocation(line: 32, column: 3, scope: !67) !97 = !DILocation(line: 32, column: 8, scope: !67) !98 = !DILocation(line: 34, column: 3, scope: !67) !99 = !DILocation(line: 34, column: 8, scope: !67) !100 = !DILocation(line: 35, column: 3, scope: !67) !101 = !DILocation(line: 35, column: 8, scope: !67) !102 = !DILocation(line: 36, column: 3, scope: !67) !103 = !DILocation(line: 36, column: 8, scope: !67) !104 = !DILocalVariable(name: "x", scope: !67, file: !1, line: 38, type: !11) !105 = !DILocation(line: 38, column: 7, scope: !67) !106 = !DILocation(line: 38, column: 15, scope: !67) !107 = !DILocation(line: 38, column: 18, scope: !67) !108 = !DILocation(line: 38, column: 21, scope: !67) !109 = !DILocation(line: 38, column: 11, scope: !67) !110 = !DILocation(line: 40, column: 17, scope: !67) !111 = !DILocation(line: 40, column: 19, scope: !67) !112 = !DILocation(line: 40, column: 3, scope: !67) !113 = !DILocation(line: 41, column: 17, scope: !67) !114 = !DILocation(line: 41, column: 22, scope: !67) !115 = !DILocation(line: 41, column: 3, scope: !67) !116 = !DILocation(line: 42, column: 10, scope: !67) !117 = !DILocation(line: 42, column: 3, scope: !67) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-4.cpp000066400000000000000000000002741473507761200307320ustar00rootroot00000000000000int main(int argc, char** argv) { int i = 0, a[10]; bool flag = argc % 5 == 0; for (; i < 10; i++) { if (flag) a[i] = i ^ 2; else a[i] = i * 2; } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/phi-4.ll000066400000000000000000000224401473507761200305560ustar00rootroot00000000000000; ModuleID = 'phi-4.pp.bc' source_filename = "phi-4.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 %7 = alloca [10 x i32], align 16 %8 = alloca i8, align 1 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !15, metadata !DIExpression()), !dbg !16 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32* %6, metadata !19, metadata !DIExpression()), !dbg !20 store i32 0, i32* %6, align 4, !dbg !20 call void @llvm.dbg.declare(metadata [10 x i32]* %7, metadata !21, metadata !DIExpression()), !dbg !25 call void @llvm.dbg.declare(metadata i8* %8, metadata !26, metadata !DIExpression()), !dbg !28 %9 = load i32, i32* %4, align 4, !dbg !29 %10 = srem i32 %9, 5, !dbg !30 %11 = icmp eq i32 %10, 0, !dbg !31 %12 = zext i1 %11 to i8, !dbg !28 store i8 %12, i8* %8, align 1, !dbg !28 br label %13, !dbg !32 13: ; preds = %32, %2 %14 = load i32, i32* %6, align 4, !dbg !33 %15 = icmp slt i32 %14, 10, !dbg !36 br i1 %15, label %16, label %35, !dbg !37 16: ; preds = %13 %17 = load i8, i8* %8, align 1, !dbg !38 %18 = trunc i8 %17 to i1, !dbg !38 br i1 %18, label %19, label %25, !dbg !41 19: ; preds = %16 %20 = load i32, i32* %6, align 4, !dbg !42 %21 = xor i32 %20, 2, !dbg !43 %22 = load i32, i32* %6, align 4, !dbg !44 %23 = sext i32 %22 to i64, !dbg !45 %24 = getelementptr inbounds [10 x i32], [10 x i32]* %7, i64 0, i64 %23, !dbg !45 store i32 %21, i32* %24, align 4, !dbg !46 br label %31, !dbg !45 25: ; preds = %16 %26 = load i32, i32* %6, align 4, !dbg !47 %27 = mul nsw i32 %26, 2, !dbg !48 %28 = load i32, i32* %6, align 4, !dbg !49 %29 = sext i32 %28 to i64, !dbg !50 %30 = getelementptr inbounds [10 x i32], [10 x i32]* %7, i64 0, i64 %29, !dbg !50 store i32 %27, i32* %30, align 4, !dbg !51 br label %31 31: ; preds = %25, %19 br label %32, !dbg !52 32: ; preds = %31 %33 = load i32, i32* %6, align 4, !dbg !53 %34 = add nsw i32 %33, 1, !dbg !53 store i32 %34, i32* %6, align 4, !dbg !53 br label %13, !dbg !54, !llvm.loop !55 35: ; preds = %13 ret i32 0, !dbg !57 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: [10 x si32]* $7 = allocate [10 x si32], 1, align 16 ; CHECK: ui8* $8 = allocate ui8, 1, align 1 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: store $6, 0, align 4 ; CHECK: si32 %9 = load $4, align 4 ; CHECK: si32 %10 = %9 srem 5 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %10 sieq 0 ; CHECK: ui1 %11 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %10 sine 0 ; CHECK: ui1 %11 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5} { ; CHECK: ui8 %12 = zext %11 ; CHECK: store $8, %12, align 1 ; CHECK: } ; CHECK: #5 predecessors={#4, #10} successors={#6, #7} { ; CHECK: si32 %13 = load $6, align 4 ; CHECK: } ; CHECK: #6 predecessors={#5} successors={#8, #9} { ; CHECK: %13 silt 10 ; CHECK: si8* %14 = bitcast $8 ; CHECK: si8 %15 = load %14, align 1 ; CHECK: ui8 %16 = bitcast %15 ; CHECK: ui1 %17 = utrunc %16 ; CHECK: } ; CHECK: #7 !exit predecessors={#5} { ; CHECK: %13 sige 10 ; CHECK: return 0 ; CHECK: } ; CHECK: #8 predecessors={#6} successors={#10} { ; CHECK: ui32* %18 = bitcast $6 ; CHECK: ui32 %19 = load %18, align 4 ; CHECK: ui32 %20 = %19 uxor 2 ; CHECK: si32 %21 = bitcast %20 ; CHECK: si32 %22 = load $6, align 4 ; CHECK: si64 %23 = sext %22 ; CHECK: si32* %24 = ptrshift $7, 40 * 0, 4 * %23 ; CHECK: store %24, %21, align 4 ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#10} { ; CHECK: si32 %25 = load $6, align 4 ; CHECK: si32 %26 = %25 smul.nw 2 ; CHECK: si32 %27 = load $6, align 4 ; CHECK: si64 %28 = sext %27 ; CHECK: si32* %29 = ptrshift $7, 40 * 0, 4 * %28 ; CHECK: store %29, %26, align 4 ; CHECK: } ; CHECK: #10 predecessors={#8, #9} successors={#5} { ; CHECK: si32 %30 = load $6, align 4 ; CHECK: si32 %31 = %30 sadd.nw 1 ; CHECK: store $6, %31, align 4 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "phi-4.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 1, type: !11) !16 = !DILocation(line: 1, column: 14, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 1, type: !12) !18 = !DILocation(line: 1, column: 27, scope: !8) !19 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 2, type: !11) !20 = !DILocation(line: 2, column: 7, scope: !8) !21 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 2, type: !22) !22 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 320, elements: !23) !23 = !{!24} !24 = !DISubrange(count: 10) !25 = !DILocation(line: 2, column: 14, scope: !8) !26 = !DILocalVariable(name: "flag", scope: !8, file: !1, line: 3, type: !27) !27 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !28 = !DILocation(line: 3, column: 8, scope: !8) !29 = !DILocation(line: 3, column: 15, scope: !8) !30 = !DILocation(line: 3, column: 20, scope: !8) !31 = !DILocation(line: 3, column: 24, scope: !8) !32 = !DILocation(line: 4, column: 3, scope: !8) !33 = !DILocation(line: 4, column: 10, scope: !34) !34 = distinct !DILexicalBlock(scope: !35, file: !1, line: 4, column: 3) !35 = distinct !DILexicalBlock(scope: !8, file: !1, line: 4, column: 3) !36 = !DILocation(line: 4, column: 12, scope: !34) !37 = !DILocation(line: 4, column: 3, scope: !35) !38 = !DILocation(line: 5, column: 9, scope: !39) !39 = distinct !DILexicalBlock(scope: !40, file: !1, line: 5, column: 9) !40 = distinct !DILexicalBlock(scope: !34, file: !1, line: 4, column: 23) !41 = !DILocation(line: 5, column: 9, scope: !40) !42 = !DILocation(line: 6, column: 14, scope: !39) !43 = !DILocation(line: 6, column: 16, scope: !39) !44 = !DILocation(line: 6, column: 9, scope: !39) !45 = !DILocation(line: 6, column: 7, scope: !39) !46 = !DILocation(line: 6, column: 12, scope: !39) !47 = !DILocation(line: 8, column: 14, scope: !39) !48 = !DILocation(line: 8, column: 16, scope: !39) !49 = !DILocation(line: 8, column: 9, scope: !39) !50 = !DILocation(line: 8, column: 7, scope: !39) !51 = !DILocation(line: 8, column: 12, scope: !39) !52 = !DILocation(line: 9, column: 3, scope: !40) !53 = !DILocation(line: 4, column: 19, scope: !34) !54 = !DILocation(line: 4, column: 3, scope: !34) !55 = distinct !{!55, !37, !56} !56 = !DILocation(line: 9, column: 3, scope: !35) !57 = !DILocation(line: 10, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/pod-types.c000066400000000000000000000003001473507761200313630ustar00rootroot00000000000000unsigned int i; float f; double d; void* p; int* q; unsigned char b; short tab[10][12]; void fun() {} int main(int argc, char** argv) { int xxx[10] = {1, -1, 255, 42}; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/pod-types.ll000066400000000000000000000214661473507761200315700ustar00rootroot00000000000000; ModuleID = 'pod-types.pp.bc' source_filename = "pod-types.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @b = common global i8 0, align 1, !dbg !19 ; CHECK: define ui8* @b, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, 0, align 1 ; CHECK: } ; CHECK: } @d = common global double 0.000000e+00, align 8, !dbg !9 ; CHECK: define double* @d, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @d, 0.0E+0, align 1 ; CHECK: } ; CHECK: } @f = common global float 0.000000e+00, align 4, !dbg !6 ; CHECK: define float* @f, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @f, 0.0E+0, align 1 ; CHECK: } ; CHECK: } @i = common global i32 0, align 4, !dbg !0 ; CHECK: define ui32* @i, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @i, 0, align 1 ; CHECK: } ; CHECK: } @p = common global i8* null, align 8, !dbg !12 ; CHECK: define si8** @p, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @p, null, align 1 ; CHECK: } ; CHECK: } @q = common global i32* null, align 8, !dbg !15 ; CHECK: define si32** @q, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @q, null, align 1 ; CHECK: } ; CHECK: } @tab = common global [10 x [12 x i16]] zeroinitializer, align 16, !dbg !22 ; CHECK: define [10 x [12 x si16]]* @tab, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @tab, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #2 ; CHECK: declare void @ar.memset(si8*, si8, ui64, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define void @fun() #0 !dbg !35 { ret void, !dbg !38 } ; CHECK: define void @fun() { ; CHECK: #1 !entry !exit { ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !39 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca [10 x i32], align 16 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !45, metadata !DIExpression()), !dbg !46 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !47, metadata !DIExpression()), !dbg !48 call void @llvm.dbg.declare(metadata [10 x i32]* %6, metadata !49, metadata !DIExpression()), !dbg !52 %7 = bitcast [10 x i32]* %6 to i8*, !dbg !52 call void @llvm.memset.p0i8.i64(i8* align 16 %7, i8 0, i64 40, i1 false), !dbg !52 %8 = bitcast i8* %7 to [10 x i32]*, !dbg !52 %9 = getelementptr inbounds [10 x i32], [10 x i32]* %8, i32 0, i32 0, !dbg !52 store i32 1, i32* %9, align 16, !dbg !52 %10 = getelementptr inbounds [10 x i32], [10 x i32]* %8, i32 0, i32 1, !dbg !52 store i32 -1, i32* %10, align 4, !dbg !52 %11 = getelementptr inbounds [10 x i32], [10 x i32]* %8, i32 0, i32 2, !dbg !52 store i32 255, i32* %11, align 8, !dbg !52 %12 = getelementptr inbounds [10 x i32], [10 x i32]* %8, i32 0, i32 3, !dbg !52 store i32 42, i32* %12, align 4, !dbg !52 ret i32 0, !dbg !53 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: [10 x si32]* $6 = allocate [10 x si32], 1, align 16 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: si8* %7 = bitcast $6 ; CHECK: call @ar.memset(%7, 0, 40, 16, 0) ; CHECK: [10 x si32]* %8 = bitcast %7 ; CHECK: si32* %9 = ptrshift %8, 40 * 0, 4 * 0 ; CHECK: store %9, 1, align 16 ; CHECK: si32* %10 = ptrshift %8, 40 * 0, 4 * 1 ; CHECK: store %10, -1, align 4 ; CHECK: si32* %11 = ptrshift %8, 40 * 0, 4 * 2 ; CHECK: store %11, 255, align 8 ; CHECK: si32* %12 = ptrshift %8, 40 * 0, 4 * 3 ; CHECK: store %12, 42, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!30, !31, !32, !33} !llvm.ident = !{!34} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "i", scope: !2, file: !3, line: 1, type: !29, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "pod-types.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0, !6, !9, !12, !15, !19, !22} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "f", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression()) !10 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 5, type: !11, isLocal: false, isDefinition: true) !11 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression()) !13 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 7, type: !14, isLocal: false, isDefinition: true) !14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !15 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression()) !16 = distinct !DIGlobalVariable(name: "q", scope: !2, file: !3, line: 9, type: !17, isLocal: false, isDefinition: true) !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) !18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression()) !20 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 11, type: !21, isLocal: false, isDefinition: true) !21 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !22 = !DIGlobalVariableExpression(var: !23, expr: !DIExpression()) !23 = distinct !DIGlobalVariable(name: "tab", scope: !2, file: !3, line: 13, type: !24, isLocal: false, isDefinition: true) !24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !25, size: 1920, elements: !26) !25 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) !26 = !{!27, !28} !27 = !DISubrange(count: 10) !28 = !DISubrange(count: 12) !29 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !30 = !{i32 2, !"Dwarf Version", i32 4} !31 = !{i32 2, !"Debug Info Version", i32 3} !32 = !{i32 1, !"wchar_size", i32 4} !33 = !{i32 7, !"PIC Level", i32 2} !34 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !35 = distinct !DISubprogram(name: "fun", scope: !3, file: !3, line: 15, type: !36, scopeLine: 15, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !36 = !DISubroutineType(types: !37) !37 = !{null} !38 = !DILocation(line: 15, column: 13, scope: !35) !39 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 17, type: !40, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !40 = !DISubroutineType(types: !41) !41 = !{!18, !18, !42} !42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !43, size: 64) !43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !44, size: 64) !44 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !45 = !DILocalVariable(name: "argc", arg: 1, scope: !39, file: !3, line: 17, type: !18) !46 = !DILocation(line: 17, column: 14, scope: !39) !47 = !DILocalVariable(name: "argv", arg: 2, scope: !39, file: !3, line: 17, type: !42) !48 = !DILocation(line: 17, column: 27, scope: !39) !49 = !DILocalVariable(name: "xxx", scope: !39, file: !3, line: 18, type: !50) !50 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 320, elements: !51) !51 = !{!27} !52 = !DILocation(line: 18, column: 7, scope: !39) !53 = !DILocation(line: 19, column: 3, scope: !39) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/pointer-arithmetic.cpp000066400000000000000000000004561473507761200336220ustar00rootroot00000000000000#include int f() { return 6; } unsigned char* ptr_fun = (unsigned char*)&f + 1; const char* string_map[] = {"aaa", "bbb"}; struct vector { int x; int y; int z; }; struct vector v[] = {{1, 2, 3}, {4, 5, 6}}; int* ptr = &(v[1].z); int main() { return printf("%d\n", v[1].z); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/pointer-arithmetic.ll000066400000000000000000000207441473507761200334510ustar00rootroot00000000000000; ModuleID = 'pointer-arithmetic.pp.bc' source_filename = "pointer-arithmetic.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.vector = type { i32, i32, i32 } @.str = private unnamed_addr constant [4 x i8] c"aaa\00", align 1 ; CHECK: define [4 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [97, 97, 97, 0], align 1 ; CHECK: } ; CHECK: } @.str.1 = private unnamed_addr constant [4 x i8] c"bbb\00", align 1 ; CHECK: define [4 x si8]* @.str.1, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.1, [98, 98, 98, 0], align 1 ; CHECK: } ; CHECK: } @.str.2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; CHECK: define [4 x si8]* @.str.2, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str.2, [37, 100, 10, 0], align 1 ; CHECK: } ; CHECK: } @ptr = global i32* bitcast (i8* getelementptr (i8, i8* bitcast ([2 x %struct.vector]* @v to i8*), i64 20) to i32*), align 8, !dbg !23 ; CHECK: define si32** @ptr, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @v ; CHECK: si8* %2 = ptrshift %1, 1 * 20 ; CHECK: si32* %3 = bitcast %2 ; CHECK: store @ptr, %3, align 1 ; CHECK: } ; CHECK: } @ptr_fun = global i8* getelementptr (i8, i8* bitcast (i32 ()* @_Z1fv to i8*), i64 1), align 8, !dbg !0 ; CHECK: define ui8** @ptr_fun, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_Z1fv ; CHECK: ui8* %2 = ptrshift %1, 1 * 1 ; CHECK: store @ptr_fun, %2, align 1 ; CHECK: } ; CHECK: } @string_map = global [2 x i8*] [i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0)], align 16, !dbg !6 ; CHECK: define [2 x si8*]* @string_map, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = ptrshift @.str.1, 4 * 0, 1 * 0 ; CHECK: si8* %2 = ptrshift @.str, 4 * 0, 1 * 0 ; CHECK: store @string_map, [%2, %1], align 1 ; CHECK: } ; CHECK: } @v = global [2 x %struct.vector] [%struct.vector { i32 1, i32 2, i32 3 }, %struct.vector { i32 4, i32 5, i32 6 }], align 16, !dbg !14 ; CHECK: define [2 x {0: si32, 4: si32, 8: si32}]* @v, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @v, [{0: 1, 4: 2, 8: 3}, {0: 4, 4: 5, 8: 6}], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z1fv() #0 !dbg !33 { ret i32 6, !dbg !36 } ; CHECK: define si32 @_Z1fv() { ; CHECK: #1 !entry !exit { ; CHECK: return 6 ; CHECK: } ; CHECK: } declare i32 @printf(i8*, ...) #2 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #1 !dbg !37 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = getelementptr inbounds [2 x %struct.vector], [2 x %struct.vector]* @v, i64 0, i64 1, i32 2, !dbg !38 %3 = load i32, i32* %2, align 4, !dbg !38 %4 = getelementptr inbounds [4 x i8], [4 x i8]* @.str.2, i64 0, i64 0, !dbg !39 %5 = call i32 (i8*, ...) @printf(i8* %4, i32 %3), !dbg !39 ret i32 %5, !dbg !40 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: si32* %2 = ptrshift @v, 24 * 0, 12 * 1, 1 * 8 ; CHECK: si32 %3 = load %2, align 4 ; CHECK: si8* %4 = ptrshift @.str.2, 4 * 0, 1 * 0 ; CHECK: si32 %5 = call @ar.libc.printf(%4, %3) ; CHECK: return %5 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!28, !29, !30, !31} !llvm.ident = !{!32} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "ptr_fun", scope: !2, file: !3, line: 7, type: !26, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "pointer-arithmetic.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0, !6, !14, !23} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "string_map", scope: !2, file: !3, line: 9, type: !8, isLocal: false, isDefinition: true) !8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 128, elements: !12) !9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) !10 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !11) !11 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !12 = !{!13} !13 = !DISubrange(count: 2) !14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression()) !15 = distinct !DIGlobalVariable(name: "v", scope: !2, file: !3, line: 17, type: !16, isLocal: false, isDefinition: true) !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !17, size: 192, elements: !12) !17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "vector", file: !3, line: 11, size: 96, flags: DIFlagTypePassByValue, elements: !18, identifier: "_ZTS6vector") !18 = !{!19, !21, !22} !19 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !17, file: !3, line: 12, baseType: !20, size: 32) !20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !21 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !17, file: !3, line: 13, baseType: !20, size: 32, offset: 32) !22 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !17, file: !3, line: 14, baseType: !20, size: 32, offset: 64) !23 = !DIGlobalVariableExpression(var: !24, expr: !DIExpression()) !24 = distinct !DIGlobalVariable(name: "ptr", scope: !2, file: !3, line: 19, type: !25, isLocal: false, isDefinition: true) !25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) !26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !27, size: 64) !27 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) !28 = !{i32 2, !"Dwarf Version", i32 4} !29 = !{i32 2, !"Debug Info Version", i32 3} !30 = !{i32 1, !"wchar_size", i32 4} !31 = !{i32 7, !"PIC Level", i32 2} !32 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !33 = distinct !DISubprogram(name: "f", linkageName: "_Z1fv", scope: !3, file: !3, line: 3, type: !34, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !34 = !DISubroutineType(types: !35) !35 = !{!20} !36 = !DILocation(line: 4, column: 3, scope: !33) !37 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 21, type: !34, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !38 = !DILocation(line: 22, column: 30, scope: !37) !39 = !DILocation(line: 22, column: 10, scope: !37) !40 = !DILocation(line: 22, column: 3, scope: !37) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/ptr-to-int.c000066400000000000000000000001121473507761200314550ustar00rootroot00000000000000#include int f() { return 0; } uintptr_t x = (intptr_t)&f; NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/ptr-to-int.ll000066400000000000000000000053171473507761200316560ustar00rootroot00000000000000; ModuleID = 'ptr-to-int.pp.bc' source_filename = "ptr-to-int.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @x = global i64 ptrtoint (i32 ()* @f to i64), align 8, !dbg !0 ; CHECK: define ui64* @x, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: ui64 %1 = ptrtoui @f ; CHECK: store @x, %1, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @f() #0 !dbg !14 { ret i32 0, !dbg !18 } ; CHECK: define si32 @f() { ; CHECK: #1 !entry !exit { ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!9, !10, !11, !12} !llvm.ident = !{!13} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "ptr-to-int.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "uintptr_t", file: !7, line: 30, baseType: !8) !7 = !DIFile(filename: "/usr/include/sys/_types/_uintptr_t.h", directory: "") !8 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) !9 = !{i32 2, !"Dwarf Version", i32 4} !10 = !{i32 2, !"Debug Info Version", i32 3} !11 = !{i32 1, !"wchar_size", i32 4} !12 = !{i32 7, !"PIC Level", i32 2} !13 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !14 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 3, type: !15, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !15 = !DISubroutineType(types: !16) !16 = !{!17} !17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !18 = !DILocation(line: 4, column: 3, scope: !14) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/reference.cpp000066400000000000000000000001151473507761200317410ustar00rootroot00000000000000void f(int& x) { x = 1; } int main() { int y = 0; f(y); return y; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/reference.ll000066400000000000000000000114631473507761200315760ustar00rootroot00000000000000; ModuleID = 'reference.pp.bc' source_filename = "reference.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define void @_Z1fRi(i32* dereferenceable(4)) #0 !dbg !8 { %2 = alloca i32*, align 8 store i32* %0, i32** %2, align 8 call void @llvm.dbg.declare(metadata i32** %2, metadata !13, metadata !DIExpression()), !dbg !14 %3 = load i32*, i32** %2, align 8, !dbg !15 store i32 1, i32* %3, align 4, !dbg !16 ret void, !dbg !17 } ; CHECK: define void @_Z1fRi(si32* %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32** $2 = allocate si32*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: si32* %3 = load $2, align 8 ; CHECK: store %3, 1, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #2 !dbg !18 { %1 = alloca i32, align 4 %2 = alloca i32, align 4 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata i32* %2, metadata !21, metadata !DIExpression()), !dbg !22 store i32 0, i32* %2, align 4, !dbg !22 call void @_Z1fRi(i32* dereferenceable(4) %2), !dbg !23 %3 = load i32, i32* %2, align 4, !dbg !24 ret i32 %3, !dbg !25 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: store $2, 0, align 4 ; CHECK: call @_Z1fRi($2) ; CHECK: si32 %3 = load $2, align 4 ; CHECK: return %3 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "reference.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", linkageName: "_Z1fRi", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null, !11} !11 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !12, size: 64) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11) !14 = !DILocation(line: 1, column: 13, scope: !8) !15 = !DILocation(line: 2, column: 3, scope: !8) !16 = !DILocation(line: 2, column: 5, scope: !8) !17 = !DILocation(line: 3, column: 1, scope: !8) !18 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !19 = !DISubroutineType(types: !20) !20 = !{!12} !21 = !DILocalVariable(name: "y", scope: !18, file: !1, line: 6, type: !12) !22 = !DILocation(line: 6, column: 7, scope: !18) !23 = !DILocation(line: 7, column: 3, scope: !18) !24 = !DILocation(line: 8, column: 10, scope: !18) !25 = !DILocation(line: 8, column: 3, scope: !18) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/regenerate-ll000077500000000000000000000027001473507761200317550ustar00rootroot00000000000000#!/bin/bash # Use this script to regenerate all the .ll files from the .c and .cpp files clang="clang" ikos_pp="ikos-pp" opt="opt" opt_level="none" cflags="-c -emit-llvm -Wall -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone" cxxflags="$cflags -std=c++17" ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" set -e function run { echo "#" "$@" "$@" } for filename in *.c do echo "[*] $filename ..." filename="${filename%.c}" if [[ -f "$filename.ll" ]]; then echo "$filename.ll already exists, skipping" continue fi run "$clang" $cflags "$filename.c" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.ll" "$ikos_import" $ikos_import_opts "$filename.ll" | sed 's/^/; CHECK: /' >> "$filename.ll" rm -f "$filename.bc" "$filename.pp.bc" done for filename in *.cpp do echo "[*] $filename ..." filename="${filename%.cpp}" if [[ -f "$filename.ll" ]]; then echo "$filename.ll already exists, skipping" continue fi run "$clang" $cxxflags "$filename.cpp" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.ll" "$ikos_import" $ikos_import_opts "$filename.ll" | sed 's/^/; CHECK: /' >> "$filename.ll" rm -f "$filename.bc" "$filename.pp.bc" done NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/runtest000077500000000000000000000066651473507761200307510ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing ikos-import without optimizations # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" file_check="FileCheck" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h]" echo " [--ikos-import IKOS-IMPORT]" echo " [--file-check FILE-CHECK]" echo "" echo "Run regression tests for llvm-to-ar" exit 1 elif [[ "$1" = "--ikos-import" ]]; then shift ikos_import=$1 elif [[ "$1" = "--file-check" ]]; then shift file_check=$1 else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-import if ! command -v "$ikos_import" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_import" >&2 exit 2 fi # Check FileCheck if ! command -v "$file_check" >/dev/null 2>&1; then echo "error: $progname: could not find $file_check" >&2 exit 2 fi # Run the tests echo "# Running regression tests for ikos-import" for filename in *.ll do echo -en "$filename ... \r" "$ikos_import" $ikos_import_opts "$filename" \ | "$file_check" "$filename" \ || { echo "Test Failed"; exit 1; } echo "$filename ... Passed" rm -f "$filename_pp" done echo "All tests passed successfully." exit 0 NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/select.cpp000066400000000000000000000003461473507761200312700ustar00rootroot00000000000000/** * To generate LLVM select instruction, we need to compile * the code with optimization enabled (at least -O1) * * > clang++ -O1 -emit-llvm -o test.bc -g -c test.cpp */ int a; int main() { return a > 0 ? 123 : 321; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/select.ll000066400000000000000000000073461473507761200311240ustar00rootroot00000000000000; ModuleID = 'select.pp.bc' source_filename = "select.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = global i32 0, align 4, !dbg !0 ; CHECK: define si32* @a, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !12 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = load i32, i32* @a, align 4, !dbg !15 %3 = icmp sgt i32 %2, 0, !dbg !16 %4 = zext i1 %3 to i64, !dbg !15 br i1 %3, label %5, label %6, !dbg !15 5: ; preds = %0 br label %7, !dbg !15 6: ; preds = %0 br label %7, !dbg !15 7: ; preds = %6, %5 %8 = phi i32 [ 123, %5 ], [ 321, %6 ], !dbg !15 ret i32 %8, !dbg !17 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: si32 %2 = load @a, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4} { ; CHECK: %2 sigt 0 ; CHECK: ui1 %3 = 1 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#4} { ; CHECK: %2 sile 0 ; CHECK: ui1 %3 = 0 ; CHECK: } ; CHECK: #4 predecessors={#2, #3} successors={#5, #6} { ; CHECK: ui64 %4 = zext %3 ; CHECK: } ; CHECK: #5 predecessors={#4} successors={#7} { ; CHECK: %3 uieq 1 ; CHECK: si32 %5 = 123 ; CHECK: } ; CHECK: #6 predecessors={#4} successors={#7} { ; CHECK: %3 uieq 0 ; CHECK: si32 %5 = 321 ; CHECK: } ; CHECK: #7 !exit predecessors={#5, #6} { ; CHECK: return %5 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 8, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "select.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 10, type: !13, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 11, column: 10, scope: !12) !16 = !DILocation(line: 11, column: 12, scope: !12) !17 = !DILocation(line: 11, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/shufflevector.c000066400000000000000000000002551473507761200323270ustar00rootroot00000000000000#include extern void printv(__m128); int main(int argc, char** argv) { __m128 m = _mm_set_ps(4, 3, 2, 1); m = _mm_shuffle_ps(m, m, 0x1B); printv(m); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/shufflevector.ll000066400000000000000000000167051473507761200325230ustar00rootroot00000000000000; ModuleID = 'shufflevector.pp.bc' source_filename = "shufflevector.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !16 { %3 = alloca float, align 4 %4 = alloca float, align 4 %5 = alloca float, align 4 %6 = alloca float, align 4 %7 = alloca <4 x float>, align 16 %8 = alloca i32, align 4 %9 = alloca i8**, align 8 %10 = alloca <4 x float>, align 16 store i32 %0, i32* %8, align 4 call void @llvm.dbg.declare(metadata i32* %8, metadata !23, metadata !DIExpression()), !dbg !24 store i8** %1, i8*** %9, align 8 call void @llvm.dbg.declare(metadata i8*** %9, metadata !25, metadata !DIExpression()), !dbg !26 call void @llvm.dbg.declare(metadata <4 x float>* %10, metadata !27, metadata !DIExpression()), !dbg !28 store float 4.000000e+00, float* %3, align 4, !dbg !29 store float 3.000000e+00, float* %4, align 4, !dbg !29 store float 2.000000e+00, float* %5, align 4, !dbg !29 store float 1.000000e+00, float* %6, align 4, !dbg !29 %11 = load float, float* %6, align 4, !dbg !29 %12 = insertelement <4 x float> undef, float %11, i32 0, !dbg !29 %13 = load float, float* %5, align 4, !dbg !29 %14 = insertelement <4 x float> %12, float %13, i32 1, !dbg !29 %15 = load float, float* %4, align 4, !dbg !29 %16 = insertelement <4 x float> %14, float %15, i32 2, !dbg !29 %17 = load float, float* %3, align 4, !dbg !29 %18 = insertelement <4 x float> %16, float %17, i32 3, !dbg !29 store <4 x float> %18, <4 x float>* %7, align 16, !dbg !29 %19 = load <4 x float>, <4 x float>* %7, align 16, !dbg !29 store <4 x float> %19, <4 x float>* %10, align 16, !dbg !28 %20 = load <4 x float>, <4 x float>* %10, align 16, !dbg !30 %21 = load <4 x float>, <4 x float>* %10, align 16, !dbg !30 %22 = shufflevector <4 x float> %20, <4 x float> %21, <4 x i32> , !dbg !30 store <4 x float> %22, <4 x float>* %10, align 16, !dbg !31 %23 = load <4 x float>, <4 x float>* %10, align 16, !dbg !32 call void @printv(<4 x float> %23), !dbg !33 ret i32 0, !dbg !34 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: float* $3 = allocate float, 1, align 4 ; CHECK: float* $4 = allocate float, 1, align 4 ; CHECK: float* $5 = allocate float, 1, align 4 ; CHECK: float* $6 = allocate float, 1, align 4 ; CHECK: <4 x float>* $7 = allocate <4 x float>, 1, align 16 ; CHECK: si32* $8 = allocate si32, 1, align 4 ; CHECK: si8*** $9 = allocate si8**, 1, align 8 ; CHECK: <4 x float>* $10 = allocate <4 x float>, 1, align 16 ; CHECK: store $8, %1, align 4 ; CHECK: store $9, %2, align 8 ; CHECK: store $3, 4.0E+0, align 4 ; CHECK: store $4, 3.0E+0, align 4 ; CHECK: store $5, 2.0E+0, align 4 ; CHECK: store $6, 1.0E+0, align 4 ; CHECK: float %11 = load $6, align 4 ; CHECK: <4 x float> %12 = insertelement undef, 0, %11 ; CHECK: float %13 = load $5, align 4 ; CHECK: <4 x float> %14 = insertelement %12, 4, %13 ; CHECK: float %15 = load $4, align 4 ; CHECK: <4 x float> %16 = insertelement %14, 8, %15 ; CHECK: float %17 = load $3, align 4 ; CHECK: <4 x float> %18 = insertelement %16, 12, %17 ; CHECK: store $7, %18, align 16 ; CHECK: <4 x float> %19 = load $7, align 16 ; CHECK: store $10, %19, align 16 ; CHECK: <4 x float> %20 = load $10, align 16 ; CHECK: <4 x float> %21 = load $10, align 16 ; CHECK: <4 x float> %22 = shufflevector %20, %21 ; CHECK: store $10, %22, align 16 ; CHECK: <4 x float> %23 = load $10, align 16 ; CHECK: call @printv(%23) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 declare void @printv(<4 x float>) #2 ; CHECK: declare void @printv(<4 x float>) attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="128" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!11, !12, !13, !14} !llvm.ident = !{!15} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "shufflevector.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{!4, !10} !4 = !DIDerivedType(tag: DW_TAG_typedef, name: "__m128", file: !5, line: 17, baseType: !6) !5 = !DIFile(filename: "Homebrew/Cellar/llvm/9.0.0/lib/clang/9.0.0/include/xmmintrin.h", directory: "/Users/marthaud") !6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 128, flags: DIFlagVector, elements: !8) !7 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !8 = !{!9} !9 = !DISubrange(count: 4) !10 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v4sf", file: !5, line: 16, baseType: !6) !11 = !{i32 2, !"Dwarf Version", i32 4} !12 = !{i32 2, !"Debug Info Version", i32 3} !13 = !{i32 1, !"wchar_size", i32 4} !14 = !{i32 7, !"PIC Level", i32 2} !15 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !16 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !17 = !DISubroutineType(types: !18) !18 = !{!19, !19, !20} !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) !22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !23 = !DILocalVariable(name: "argc", arg: 1, scope: !16, file: !1, line: 5, type: !19) !24 = !DILocation(line: 5, column: 14, scope: !16) !25 = !DILocalVariable(name: "argv", arg: 2, scope: !16, file: !1, line: 5, type: !20) !26 = !DILocation(line: 5, column: 27, scope: !16) !27 = !DILocalVariable(name: "m", scope: !16, file: !1, line: 6, type: !4) !28 = !DILocation(line: 6, column: 10, scope: !16) !29 = !DILocation(line: 6, column: 14, scope: !16) !30 = !DILocation(line: 7, column: 7, scope: !16) !31 = !DILocation(line: 7, column: 5, scope: !16) !32 = !DILocation(line: 8, column: 10, scope: !16) !33 = !DILocation(line: 8, column: 3, scope: !16) !34 = !DILocation(line: 9, column: 1, scope: !16) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/struct-parameters.c000066400000000000000000000003271473507761200331350ustar00rootroot00000000000000#include typedef struct { char buf[10]; char buf1[10]; char buf2[10]; } my_struct; my_struct f(my_struct* s) { return *s; } my_struct g(my_struct s) { return s; } int main() { return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/struct-parameters.ll000066400000000000000000000150671473507761200333310ustar00rootroot00000000000000; ModuleID = 'struct-parameters.pp.bc' source_filename = "struct-parameters.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.my_struct = type { [10 x i8], [10 x i8], [10 x i8] } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define void @f(%struct.my_struct* noalias sret(%struct.my_struct), %struct.my_struct*) #0 !dbg !8 { %3 = alloca %struct.my_struct*, align 8 store %struct.my_struct* %1, %struct.my_struct** %3, align 8 call void @llvm.dbg.declare(metadata %struct.my_struct** %3, metadata !22, metadata !DIExpression()), !dbg !23 %4 = load %struct.my_struct*, %struct.my_struct** %3, align 8, !dbg !24 %5 = bitcast %struct.my_struct* %0 to i8*, !dbg !25 %6 = bitcast %struct.my_struct* %4 to i8*, !dbg !25 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %5, i8* align 1 %6, i64 30, i1 false), !dbg !25 ret void, !dbg !26 } ; CHECK: define void @f({0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %1, {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %2) { ; CHECK: #1 !entry !exit { ; CHECK: {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}** $3 = allocate {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}*, 1, align 8 ; CHECK: store $3, %2, align 8 ; CHECK: {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}** %4 = bitcast $3 ; CHECK: {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %5 = load %4, align 8 ; CHECK: si8* %6 = bitcast %1 ; CHECK: si8* %7 = bitcast %5 ; CHECK: call @ar.memcpy(%6, %7, 30, 1, 1, 0) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: noinline nounwind ssp uwtable define void @g(%struct.my_struct* noalias sret(%struct.my_struct), %struct.my_struct* byval(%struct.my_struct) align 8) #0 !dbg !27 { call void @llvm.dbg.declare(metadata %struct.my_struct* %1, metadata !30, metadata !DIExpression()), !dbg !31 %3 = bitcast %struct.my_struct* %0 to i8*, !dbg !32 %4 = bitcast %struct.my_struct* %1 to i8*, !dbg !32 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %3, i8* align 8 %4, i64 30, i1 false), !dbg !32 ret void, !dbg !33 } ; CHECK: define void @g({0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %1, {0: [10 x si8], 10: [10 x si8], 20: [10 x si8]}* %2) { ; CHECK: #1 !entry !exit { ; CHECK: si8* %3 = bitcast %1 ; CHECK: si8* %4 = bitcast %2 ; CHECK: call @ar.memcpy(%3, %4, 30, 1, 8, 0) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !34 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 ret i32 0, !dbg !38 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "struct-parameters.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 9, type: !9, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !21} !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "my_struct", file: !1, line: 7, baseType: !12) !12 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 3, size: 240, elements: !13) !13 = !{!14, !19, !20} !14 = !DIDerivedType(tag: DW_TAG_member, name: "buf", scope: !12, file: !1, line: 4, baseType: !15, size: 80) !15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !16, size: 80, elements: !17) !16 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !17 = !{!18} !18 = !DISubrange(count: 10) !19 = !DIDerivedType(tag: DW_TAG_member, name: "buf1", scope: !12, file: !1, line: 5, baseType: !15, size: 80, offset: 80) !20 = !DIDerivedType(tag: DW_TAG_member, name: "buf2", scope: !12, file: !1, line: 6, baseType: !15, size: 80, offset: 160) !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !22 = !DILocalVariable(name: "s", arg: 1, scope: !8, file: !1, line: 9, type: !21) !23 = !DILocation(line: 9, column: 24, scope: !8) !24 = !DILocation(line: 10, column: 11, scope: !8) !25 = !DILocation(line: 10, column: 10, scope: !8) !26 = !DILocation(line: 10, column: 3, scope: !8) !27 = distinct !DISubprogram(name: "g", scope: !1, file: !1, line: 13, type: !28, scopeLine: 13, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !28 = !DISubroutineType(types: !29) !29 = !{!11, !11} !30 = !DILocalVariable(name: "s", arg: 1, scope: !27, file: !1, line: 13, type: !11) !31 = !DILocation(line: 13, column: 23, scope: !27) !32 = !DILocation(line: 14, column: 10, scope: !27) !33 = !DILocation(line: 14, column: 3, scope: !27) !34 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 17, type: !35, scopeLine: 17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !35 = !DISubroutineType(types: !36) !36 = !{!37} !37 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !38 = !DILocation(line: 18, column: 3, scope: !34) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/thread-local.cpp000066400000000000000000000000671473507761200323500ustar00rootroot00000000000000static thread_local int x; int main() { return x; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/thread-local.ll000066400000000000000000000071551473507761200322020ustar00rootroot00000000000000; ModuleID = 'thread-local.pp.bc' source_filename = "thread-local.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @_ZL1x = internal thread_local global i32 0, align 4, !dbg !0 ; CHECK: define si32* @_ZL1x, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZL1x, 0, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define internal cxx_fast_tlscc i32* @_ZTWL1x() #1 { ret i32* @_ZL1x } ; CHECK: define si32* @_ZTWL1x() { ; CHECK: #1 !entry !exit { ; CHECK: return @_ZL1x ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !12 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = call cxx_fast_tlscc i32* @_ZTWL1x(), !dbg !15 %3 = load i32, i32* %2, align 4, !dbg !15 ret i32 %3, !dbg !16 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: si32* %2 = call @_ZTWL1x() ; CHECK: si32 %3 = load %2, align 4 ; CHECK: return %3 ; CHECK: } ; CHECK: } attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "x", linkageName: "_ZL1x", scope: !2, file: !3, line: 1, type: !6, isLocal: true, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "thread-local.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{!6} !15 = !DILocation(line: 4, column: 10, scope: !12) !16 = !DILocation(line: 4, column: 3, scope: !12) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/try-catch.cpp000066400000000000000000000010071473507761200317020ustar00rootroot00000000000000int G; class A { public: virtual void f(int x) {} virtual int g() { return 0; } }; class B : public A { public: virtual void f(int x) { G = x; } virtual int g() { return 0; } }; class C : public B { public: virtual void f(int x) { G = -x; } virtual int g() { return 1; } }; void h(int x) {} int hh(int x) { return x * x; } void run(A* p) { int x; p->f(12); x = p->g(); h(14); x = hh(15); } int main() { B b; C c; try { run(&b); run(&c); } catch (A& e) { } return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/try-catch.ll000066400000000000000000001174011473507761200315350ustar00rootroot00000000000000; ModuleID = 'try-catch.pp.bc' source_filename = "try-catch.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %class.A = type { i32 (...)** } %class.B = type { %class.A } %class.C = type { %class.B } @G = global i32 0, align 4, !dbg !0 ; CHECK: define si32* @G, align 4, init { ; CHECK: #1 !entry !exit { ; CHECK: store @G, 0, align 1 ; CHECK: } ; CHECK: } @_ZTI1A = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1A, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1A, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1A, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1B = linkonce_odr constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0), i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*) }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si8*}* @_ZTI1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv120__si_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1B, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1B, {0: %4, 8: %3, 16: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1C = linkonce_odr constant { i8*, i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1B to i8*) }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si8*}* @_ZTI1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv120__si_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1B ; CHECK: si8* %3 = ptrshift @_ZTS1C, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1C, {0: %4, 8: %3, 16: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1A, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1A, [49, 65, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1B = linkonce_odr constant [3 x i8] c"1B\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1B, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1B, [49, 66, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1C = linkonce_odr constant [3 x i8] c"1C\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1C, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1C, [49, 67, 0], align 1 ; CHECK: } ; CHECK: } @_ZTV1A = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast (void (%class.A*, i32)* @_ZN1A1fEi to i8*), i8* bitcast (i32 (%class.A*)* @_ZN1A1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1A1gEv ; CHECK: si8* %2 = bitcast @_ZN1A1fEi ; CHECK: si8* %3 = bitcast @_ZTI1A ; CHECK: store @_ZTV1A, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1B = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1B to i8*), i8* bitcast (void (%class.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%class.B*)* @_ZN1B1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1B1gEv ; CHECK: si8* %2 = bitcast @_ZN1B1fEi ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: store @_ZTV1B, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1C = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1C to i8*), i8* bitcast (void (%class.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%class.C*)* @_ZN1C1gEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1C1gEv ; CHECK: si8* %2 = bitcast @_ZN1C1fEi ; CHECK: si8* %3 = bitcast @_ZTI1C ; CHECK: store @_ZTV1C, {0: [null, %3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTVN10__cxxabiv117__class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv117__class_type_infoE @_ZTVN10__cxxabiv120__si_class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv120__si_class_type_infoE ; Function Attrs: noinline nounwind ssp uwtable define void @_Z1hi(i32) #0 !dbg !12 { %2 = alloca i32, align 4 store i32 %0, i32* %2, align 4 call void @llvm.dbg.declare(metadata i32* %2, metadata !15, metadata !DIExpression()), !dbg !16 ret void, !dbg !17 } ; CHECK: define void @_Z1hi(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: store $2, %1, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @_Z2hhi(i32) #0 !dbg !18 { %2 = alloca i32, align 4 store i32 %0, i32* %2, align 4 call void @llvm.dbg.declare(metadata i32* %2, metadata !21, metadata !DIExpression()), !dbg !22 %3 = load i32, i32* %2, align 4, !dbg !23 %4 = load i32, i32* %2, align 4, !dbg !24 %5 = mul nsw i32 %3, %4, !dbg !25 ret i32 %5, !dbg !26 } ; CHECK: define si32 @_Z2hhi(si32 %1) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: store $2, %1, align 4 ; CHECK: si32 %3 = load $2, align 4 ; CHECK: si32 %4 = load $2, align 4 ; CHECK: si32 %5 = %3 smul.nw %4 ; CHECK: return %5 ; CHECK: } ; CHECK: } ; Function Attrs: noinline ssp uwtable define void @_Z3runP1A(%class.A*) #2 !dbg !27 { %2 = alloca %class.A*, align 8 %3 = alloca i32, align 4 store %class.A* %0, %class.A** %2, align 8 call void @llvm.dbg.declare(metadata %class.A** %2, metadata !45, metadata !DIExpression()), !dbg !46 call void @llvm.dbg.declare(metadata i32* %3, metadata !47, metadata !DIExpression()), !dbg !48 %4 = load %class.A*, %class.A** %2, align 8, !dbg !49 %5 = bitcast %class.A* %4 to void (%class.A*, i32)***, !dbg !50 %6 = load void (%class.A*, i32)**, void (%class.A*, i32)*** %5, align 8, !dbg !50 %7 = getelementptr inbounds void (%class.A*, i32)*, void (%class.A*, i32)** %6, i64 0, !dbg !50 %8 = load void (%class.A*, i32)*, void (%class.A*, i32)** %7, align 8, !dbg !50 call void %8(%class.A* %4, i32 12), !dbg !50 %9 = load %class.A*, %class.A** %2, align 8, !dbg !51 %10 = bitcast %class.A* %9 to i32 (%class.A*)***, !dbg !52 %11 = load i32 (%class.A*)**, i32 (%class.A*)*** %10, align 8, !dbg !52 %12 = getelementptr inbounds i32 (%class.A*)*, i32 (%class.A*)** %11, i64 1, !dbg !52 %13 = load i32 (%class.A*)*, i32 (%class.A*)** %12, align 8, !dbg !52 %14 = call i32 %13(%class.A* %9), !dbg !52 store i32 %14, i32* %3, align 4, !dbg !53 call void @_Z1hi(i32 14), !dbg !54 %15 = call i32 @_Z2hhi(i32 15), !dbg !55 store i32 %15, i32* %3, align 4, !dbg !56 ret void, !dbg !57 } ; CHECK: define void @_Z3runP1A({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**}** $2 = allocate {0: si32 (...)**}*, 1, align 8 ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32 (...)**}** %4 = bitcast $2 ; CHECK: {0: si32 (...)**}* %5 = load %4, align 8 ; CHECK: void ({0: si32 (...)**}*, si32)*** %6 = bitcast %5 ; CHECK: void ({0: si32 (...)**}*, si32)** %7 = load %6, align 8 ; CHECK: void ({0: si32 (...)**}*, si32)** %8 = ptrshift %7, 8 * 0 ; CHECK: void ({0: si32 (...)**}*, si32)* %9 = load %8, align 8 ; CHECK: call %9(%5, 12) ; CHECK: {0: si32 (...)**}** %10 = bitcast $2 ; CHECK: {0: si32 (...)**}* %11 = load %10, align 8 ; CHECK: si32 ({0: si32 (...)**}*)*** %12 = bitcast %11 ; CHECK: si32 ({0: si32 (...)**}*)** %13 = load %12, align 8 ; CHECK: si32 ({0: si32 (...)**}*)** %14 = ptrshift %13, 8 * 1 ; CHECK: si32 ({0: si32 (...)**}*)* %15 = load %14, align 8 ; CHECK: si32 %16 = call %15(%11) ; CHECK: store $3, %16, align 4 ; CHECK: call @_Z1hi(14) ; CHECK: si32 %17 = call @_Z2hhi(15) ; CHECK: store $3, %17, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1A1fEi(%class.A*, i32) unnamed_addr #0 align 2 !dbg !135 { %3 = alloca %class.A*, align 8 %4 = alloca i32, align 4 store %class.A* %0, %class.A** %3, align 8 call void @llvm.dbg.declare(metadata %class.A** %3, metadata !136, metadata !DIExpression()), !dbg !137 store i32 %1, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !138, metadata !DIExpression()), !dbg !139 %5 = load %class.A*, %class.A** %3, align 8 ret void, !dbg !140 } ; CHECK: define void @_ZN1A1fEi({0: si32 (...)**}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**}** $3 = allocate {0: si32 (...)**}*, 1, align 8 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: store $3, %1, align 8 ; CHECK: store $4, %2, align 4 ; CHECK: {0: si32 (...)**}** %5 = bitcast $3 ; CHECK: {0: si32 (...)**}* %6 = load %5, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr i32 @_ZN1A1gEv(%class.A*) unnamed_addr #0 align 2 !dbg !141 { %2 = alloca %class.A*, align 8 store %class.A* %0, %class.A** %2, align 8 call void @llvm.dbg.declare(metadata %class.A** %2, metadata !142, metadata !DIExpression()), !dbg !143 %3 = load %class.A*, %class.A** %2, align 8 ret i32 0, !dbg !144 } ; CHECK: define si32 @_ZN1A1gEv({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**}** $2 = allocate {0: si32 (...)**}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32 (...)**}** %3 = bitcast $2 ; CHECK: {0: si32 (...)**}* %4 = load %3, align 8 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1AC2Ev(%class.A*) unnamed_addr #0 align 2 !dbg !116 { %2 = alloca %class.A*, align 8 store %class.A* %0, %class.A** %2, align 8 call void @llvm.dbg.declare(metadata %class.A** %2, metadata !120, metadata !DIExpression()), !dbg !121 %3 = load %class.A*, %class.A** %2, align 8 %4 = bitcast %class.A* %3 to i32 (...)***, !dbg !122 %5 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1A, i32 0, i32 0, i32 2, !dbg !122 %6 = bitcast i8** %5 to i32 (...)**, !dbg !122 store i32 (...)** %6, i32 (...)*** %4, align 8, !dbg !122 ret void, !dbg !122 } ; CHECK: define void @_ZN1AC2Ev({0: si32 (...)**}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**}** $2 = allocate {0: si32 (...)**}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32 (...)**}** %3 = bitcast $2 ; CHECK: {0: si32 (...)**}* %4 = load %3, align 8 ; CHECK: si32 (...)*** %5 = bitcast %4 ; CHECK: si8** %6 = ptrshift @_ZTV1A, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %7 = bitcast %6 ; CHECK: store %5, %7, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1B1fEi(%class.B*, i32) unnamed_addr #0 align 2 !dbg !123 { %3 = alloca %class.B*, align 8 %4 = alloca i32, align 4 store %class.B* %0, %class.B** %3, align 8 call void @llvm.dbg.declare(metadata %class.B** %3, metadata !124, metadata !DIExpression()), !dbg !125 store i32 %1, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !126, metadata !DIExpression()), !dbg !127 %5 = load %class.B*, %class.B** %3, align 8 %6 = load i32, i32* %4, align 4, !dbg !128 store i32 %6, i32* @G, align 4, !dbg !129 ret void, !dbg !130 } ; CHECK: define void @_ZN1B1fEi({0: {0: si32 (...)**}}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32 (...)**}}** $3 = allocate {0: {0: si32 (...)**}}*, 1, align 8 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: store $3, %1, align 8 ; CHECK: store $4, %2, align 4 ; CHECK: {0: {0: si32 (...)**}}** %5 = bitcast $3 ; CHECK: {0: {0: si32 (...)**}}* %6 = load %5, align 8 ; CHECK: si32 %7 = load $4, align 4 ; CHECK: store @G, %7, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr i32 @_ZN1B1gEv(%class.B*) unnamed_addr #0 align 2 !dbg !131 { %2 = alloca %class.B*, align 8 store %class.B* %0, %class.B** %2, align 8 call void @llvm.dbg.declare(metadata %class.B** %2, metadata !132, metadata !DIExpression()), !dbg !133 %3 = load %class.B*, %class.B** %2, align 8 ret i32 0, !dbg !134 } ; CHECK: define si32 @_ZN1B1gEv({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32 (...)**}}** $2 = allocate {0: {0: si32 (...)**}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: si32 (...)**}}** %3 = bitcast $2 ; CHECK: {0: {0: si32 (...)**}}* %4 = load %3, align 8 ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1BC1Ev(%class.B*) unnamed_addr #0 align 2 !dbg !96 { %2 = alloca %class.B*, align 8 store %class.B* %0, %class.B** %2, align 8 call void @llvm.dbg.declare(metadata %class.B** %2, metadata !100, metadata !DIExpression()), !dbg !102 %3 = load %class.B*, %class.B** %2, align 8 call void @_ZN1BC2Ev(%class.B* %3) #5, !dbg !103 ret void, !dbg !103 } ; CHECK: define void @_ZN1BC1Ev({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32 (...)**}}** $2 = allocate {0: {0: si32 (...)**}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: si32 (...)**}}* %3 = load $2, align 8 ; CHECK: call @_ZN1BC2Ev(%3) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1BC2Ev(%class.B*) unnamed_addr #0 align 2 !dbg !112 { %2 = alloca %class.B*, align 8 store %class.B* %0, %class.B** %2, align 8 call void @llvm.dbg.declare(metadata %class.B** %2, metadata !113, metadata !DIExpression()), !dbg !114 %3 = load %class.B*, %class.B** %2, align 8 %4 = bitcast %class.B* %3 to %class.A*, !dbg !115 call void @_ZN1AC2Ev(%class.A* %4) #5, !dbg !115 %5 = bitcast %class.B* %3 to i32 (...)***, !dbg !115 %6 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1B, i32 0, i32 0, i32 2, !dbg !115 %7 = bitcast i8** %6 to i32 (...)**, !dbg !115 store i32 (...)** %7, i32 (...)*** %5, align 8, !dbg !115 ret void, !dbg !115 } ; CHECK: define void @_ZN1BC2Ev({0: {0: si32 (...)**}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: si32 (...)**}}** $2 = allocate {0: {0: si32 (...)**}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: si32 (...)**}}** %3 = bitcast $2 ; CHECK: {0: {0: si32 (...)**}}* %4 = load %3, align 8 ; CHECK: {0: si32 (...)**}* %5 = bitcast %4 ; CHECK: call @_ZN1AC2Ev(%5) ; CHECK: si32 (...)*** %6 = bitcast %4 ; CHECK: si8** %7 = ptrshift @_ZTV1B, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %8 = bitcast %7 ; CHECK: store %6, %8, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1C1fEi(%class.C*, i32) unnamed_addr #0 align 2 !dbg !149 { %3 = alloca %class.C*, align 8 %4 = alloca i32, align 4 store %class.C* %0, %class.C** %3, align 8 call void @llvm.dbg.declare(metadata %class.C** %3, metadata !150, metadata !DIExpression()), !dbg !151 store i32 %1, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !152, metadata !DIExpression()), !dbg !153 %5 = load %class.C*, %class.C** %3, align 8 %6 = load i32, i32* %4, align 4, !dbg !154 %7 = sub nsw i32 0, %6, !dbg !155 store i32 %7, i32* @G, align 4, !dbg !156 ret void, !dbg !157 } ; CHECK: define void @_ZN1C1fEi({0: {0: {0: si32 (...)**}}}* %1, si32 %2) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: {0: si32 (...)**}}}** $3 = allocate {0: {0: {0: si32 (...)**}}}*, 1, align 8 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: store $3, %1, align 8 ; CHECK: store $4, %2, align 4 ; CHECK: {0: {0: {0: si32 (...)**}}}** %5 = bitcast $3 ; CHECK: {0: {0: {0: si32 (...)**}}}* %6 = load %5, align 8 ; CHECK: si32 %7 = load $4, align 4 ; CHECK: si32 %8 = 0 ssub.nw %7 ; CHECK: store @G, %8, align 4 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr i32 @_ZN1C1gEv(%class.C*) unnamed_addr #0 align 2 !dbg !158 { %2 = alloca %class.C*, align 8 store %class.C* %0, %class.C** %2, align 8 call void @llvm.dbg.declare(metadata %class.C** %2, metadata !159, metadata !DIExpression()), !dbg !160 %3 = load %class.C*, %class.C** %2, align 8 ret i32 1, !dbg !161 } ; CHECK: define si32 @_ZN1C1gEv({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: {0: si32 (...)**}}}** $2 = allocate {0: {0: {0: si32 (...)**}}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: {0: si32 (...)**}}}** %3 = bitcast $2 ; CHECK: {0: {0: {0: si32 (...)**}}}* %4 = load %3, align 8 ; CHECK: return 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1CC1Ev(%class.C*) unnamed_addr #0 align 2 !dbg !104 { %2 = alloca %class.C*, align 8 store %class.C* %0, %class.C** %2, align 8 call void @llvm.dbg.declare(metadata %class.C** %2, metadata !108, metadata !DIExpression()), !dbg !110 %3 = load %class.C*, %class.C** %2, align 8 call void @_ZN1CC2Ev(%class.C* %3) #5, !dbg !111 ret void, !dbg !111 } ; CHECK: define void @_ZN1CC1Ev({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: {0: si32 (...)**}}}** $2 = allocate {0: {0: {0: si32 (...)**}}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: {0: si32 (...)**}}}* %3 = load $2, align 8 ; CHECK: call @_ZN1CC2Ev(%3) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1CC2Ev(%class.C*) unnamed_addr #0 align 2 !dbg !145 { %2 = alloca %class.C*, align 8 store %class.C* %0, %class.C** %2, align 8 call void @llvm.dbg.declare(metadata %class.C** %2, metadata !146, metadata !DIExpression()), !dbg !147 %3 = load %class.C*, %class.C** %2, align 8 %4 = bitcast %class.C* %3 to %class.B*, !dbg !148 call void @_ZN1BC2Ev(%class.B* %4) #5, !dbg !148 %5 = bitcast %class.C* %3 to i32 (...)***, !dbg !148 %6 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1C, i32 0, i32 0, i32 2, !dbg !148 %7 = bitcast i8** %6 to i32 (...)**, !dbg !148 store i32 (...)** %7, i32 (...)*** %5, align 8, !dbg !148 ret void, !dbg !148 } ; CHECK: define void @_ZN1CC2Ev({0: {0: {0: si32 (...)**}}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: {0: {0: si32 (...)**}}}** $2 = allocate {0: {0: {0: si32 (...)**}}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: {0: {0: si32 (...)**}}}** %3 = bitcast $2 ; CHECK: {0: {0: {0: si32 (...)**}}}* %4 = load %3, align 8 ; CHECK: {0: {0: si32 (...)**}}* %5 = bitcast %4 ; CHECK: call @_ZN1BC2Ev(%5) ; CHECK: si32 (...)*** %6 = bitcast %4 ; CHECK: si8** %7 = ptrshift @_ZTV1C, 32 * 0, 1 * 0, 8 * 2 ; CHECK: si32 (...)** %8 = bitcast %7 ; CHECK: store %6, %8, align 8 ; CHECK: return ; CHECK: } ; CHECK: } declare i32 @__gxx_personality_v0(...) ; CHECK: declare si32 @__gxx_personality_v0(...) ; Function Attrs: nounwind readnone declare i32 @llvm.eh.typeid.for(i8*) #4 ; CHECK: declare si32 @ar.eh.typeid.for(si8*) declare i8* @__cxa_begin_catch(i8*) ; CHECK: declare si8* @ar.libcpp.begincatch(si8*) declare void @__cxa_end_catch() ; CHECK: declare void @ar.libcpp.endcatch() ; Function Attrs: noinline norecurse ssp uwtable define i32 @main() #3 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !58 { %1 = alloca i32, align 4 %2 = alloca %class.B, align 8 %3 = alloca %class.C, align 8 %4 = alloca i8* %5 = alloca i32 %6 = alloca %class.A*, align 8 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata %class.B* %2, metadata !59, metadata !DIExpression()), !dbg !70 call void @_ZN1BC1Ev(%class.B* %2) #5, !dbg !70 call void @llvm.dbg.declare(metadata %class.C* %3, metadata !71, metadata !DIExpression()), !dbg !82 call void @_ZN1CC1Ev(%class.C* %3) #5, !dbg !82 %7 = bitcast %class.B* %2 to %class.A*, !dbg !83 invoke void @_Z3runP1A(%class.A* %7) to label %8 unwind label %11, !dbg !85 8: ; preds = %0 %9 = bitcast %class.C* %3 to %class.A*, !dbg !86 invoke void @_Z3runP1A(%class.A* %9) to label %10 unwind label %11, !dbg !87 10: ; preds = %8 br label %24, !dbg !88 11: ; preds = %8, %0 %12 = landingpad { i8*, i32 } catch i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), !dbg !89 %13 = extractvalue { i8*, i32 } %12, 0, !dbg !89 store i8* %13, i8** %4, align 8, !dbg !89 %14 = extractvalue { i8*, i32 } %12, 1, !dbg !89 store i32 %14, i32* %5, align 4, !dbg !89 br label %15, !dbg !89 15: ; preds = %11 %16 = load i32, i32* %5, align 4, !dbg !88 %17 = bitcast { i8*, i8* }* @_ZTI1A to i8*, !dbg !88 %18 = call i32 @llvm.eh.typeid.for(i8* %17) #5, !dbg !88 %19 = icmp eq i32 %16, %18, !dbg !88 br i1 %19, label %20, label %25, !dbg !88 20: ; preds = %15 call void @llvm.dbg.declare(metadata %class.A** %6, metadata !90, metadata !DIExpression()), !dbg !92 %21 = load i8*, i8** %4, align 8, !dbg !88 %22 = call i8* @__cxa_begin_catch(i8* %21) #5, !dbg !88 %23 = bitcast i8* %22 to %class.A*, !dbg !88 store %class.A* %23, %class.A** %6, align 8, !dbg !88 call void @__cxa_end_catch(), !dbg !93 br label %24, !dbg !93 24: ; preds = %20, %10 ret i32 0, !dbg !95 25: ; preds = %15 %26 = load i8*, i8** %4, align 8, !dbg !88 %27 = load i32, i32* %5, align 4, !dbg !88 %28 = insertvalue { i8*, i32 } undef, i8* %26, 0, !dbg !88 %29 = insertvalue { i8*, i32 } %28, i32 %27, 1, !dbg !88 resume { i8*, i32 } %29, !dbg !88 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry successors={#2, #3} { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: {0: {0: si32 (...)**}}* $2 = allocate {0: {0: si32 (...)**}}, 1, align 8 ; CHECK: {0: {0: {0: si32 (...)**}}}* $3 = allocate {0: {0: {0: si32 (...)**}}}, 1, align 8 ; CHECK: si8** $4 = allocate si8*, 1 ; CHECK: si32* $5 = allocate si32, 1 ; CHECK: {0: si32 (...)**}** $6 = allocate {0: si32 (...)**}*, 1, align 8 ; CHECK: store $1, 0, align 4 ; CHECK: call @_ZN1BC1Ev($2) ; CHECK: call @_ZN1CC1Ev($3) ; CHECK: {0: si32 (...)**}* %7 = bitcast $2 ; CHECK: invoke @_Z3runP1A(%7) normal=#2 exc=#3 ; CHECK: } ; CHECK: #2 predecessors={#1} successors={#4, #5} { ; CHECK: {0: si32 (...)**}* %8 = bitcast $3 ; CHECK: invoke @_Z3runP1A(%8) normal=#4 exc=#5 ; CHECK: } ; CHECK: #3 predecessors={#1} successors={#6} { ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: } ; CHECK: #5 predecessors={#2} successors={#6} { ; CHECK: } ; CHECK: #6 predecessors={#3, #5} successors={#8, #9} { ; CHECK: {0: si8*, 8: si32} %9 = landingpad ; CHECK: si8* %10 = extractelement %9, 0 ; CHECK: store $4, %10, align 8 ; CHECK: si32 %11 = extractelement %9, 8 ; CHECK: store $5, %11, align 4 ; CHECK: si32 %12 = load $5, align 4 ; CHECK: si8* %13 = bitcast @_ZTI1A ; CHECK: si32 %14 = call @ar.eh.typeid.for(%13) ; CHECK: } ; CHECK: #8 predecessors={#6} successors={#7} { ; CHECK: %12 sieq %14 ; CHECK: si8* %15 = load $4, align 8 ; CHECK: si8* %16 = call @ar.libcpp.begincatch(%15) ; CHECK: {0: si32 (...)**}* %17 = bitcast %16 ; CHECK: store $6, %17, align 8 ; CHECK: call @ar.libcpp.endcatch() ; CHECK: } ; CHECK: #9 predecessors={#6} successors={#unified-exit} { ; CHECK: %12 sine %14 ; CHECK: si8* %18 = load $4, align 8 ; CHECK: si32 %19 = load $5, align 4 ; CHECK: {0: si8*, 8: si32} %20 = insertelement undef, 0, %18 ; CHECK: {0: si8*, 8: si32} %21 = insertelement %20, 8, %19 ; CHECK: resume %21 ; CHECK: } ; CHECK: #7 predecessors={#4, #8} successors={#unified-exit} { ; CHECK: return 0 ; CHECK: } ; CHECK: #unified-exit !exit predecessors={#7, #9} { ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { noinline norecurse ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { nounwind readnone } attributes #5 = { nounwind } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!7, !8, !9, !10} !llvm.ident = !{!11} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "G", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "try-catch.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0} !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !7 = !{i32 2, !"Dwarf Version", i32 4} !8 = !{i32 2, !"Debug Info Version", i32 3} !9 = !{i32 1, !"wchar_size", i32 4} !10 = !{i32 7, !"PIC Level", i32 2} !11 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !12 = distinct !DISubprogram(name: "h", linkageName: "_Z1hi", scope: !3, file: !3, line: 21, type: !13, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !13 = !DISubroutineType(types: !14) !14 = !{null, !6} !15 = !DILocalVariable(name: "x", arg: 1, scope: !12, file: !3, line: 21, type: !6) !16 = !DILocation(line: 21, column: 12, scope: !12) !17 = !DILocation(line: 21, column: 16, scope: !12) !18 = distinct !DISubprogram(name: "hh", linkageName: "_Z2hhi", scope: !3, file: !3, line: 23, type: !19, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !19 = !DISubroutineType(types: !20) !20 = !{!6, !6} !21 = !DILocalVariable(name: "x", arg: 1, scope: !18, file: !3, line: 23, type: !6) !22 = !DILocation(line: 23, column: 12, scope: !18) !23 = !DILocation(line: 24, column: 10, scope: !18) !24 = !DILocation(line: 24, column: 14, scope: !18) !25 = !DILocation(line: 24, column: 12, scope: !18) !26 = !DILocation(line: 24, column: 3, scope: !18) !27 = distinct !DISubprogram(name: "run", linkageName: "_Z3runP1A", scope: !3, file: !3, line: 27, type: !28, scopeLine: 27, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !28 = !DISubroutineType(types: !29) !29 = !{null, !30} !30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64) !31 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A", file: !3, line: 3, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !32, vtableHolder: !31, identifier: "_ZTS1A") !32 = !{!33, !38, !42} !33 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$A", scope: !3, file: !3, baseType: !34, size: 64, flags: DIFlagArtificial) !34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !35, size: 64) !35 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: !36, size: 64) !36 = !DISubroutineType(types: !37) !37 = !{!6} !38 = !DISubprogram(name: "f", linkageName: "_ZN1A1fEi", scope: !31, file: !3, line: 5, type: !39, scopeLine: 5, containingType: !31, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !39 = !DISubroutineType(types: !40) !40 = !{null, !41, !6} !41 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !42 = !DISubprogram(name: "g", linkageName: "_ZN1A1gEv", scope: !31, file: !3, line: 6, type: !43, scopeLine: 6, containingType: !31, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !43 = !DISubroutineType(types: !44) !44 = !{!6, !41} !45 = !DILocalVariable(name: "p", arg: 1, scope: !27, file: !3, line: 27, type: !30) !46 = !DILocation(line: 27, column: 13, scope: !27) !47 = !DILocalVariable(name: "x", scope: !27, file: !3, line: 28, type: !6) !48 = !DILocation(line: 28, column: 7, scope: !27) !49 = !DILocation(line: 29, column: 3, scope: !27) !50 = !DILocation(line: 29, column: 6, scope: !27) !51 = !DILocation(line: 30, column: 7, scope: !27) !52 = !DILocation(line: 30, column: 10, scope: !27) !53 = !DILocation(line: 30, column: 5, scope: !27) !54 = !DILocation(line: 31, column: 3, scope: !27) !55 = !DILocation(line: 32, column: 7, scope: !27) !56 = !DILocation(line: 32, column: 5, scope: !27) !57 = !DILocation(line: 33, column: 1, scope: !27) !58 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 35, type: !36, scopeLine: 35, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !59 = !DILocalVariable(name: "b", scope: !58, file: !3, line: 36, type: !60) !60 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "B", file: !3, line: 9, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !61, vtableHolder: !31, identifier: "_ZTS1B") !61 = !{!62, !63, !67} !62 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !60, baseType: !31, flags: DIFlagPublic, extraData: i32 0) !63 = !DISubprogram(name: "f", linkageName: "_ZN1B1fEi", scope: !60, file: !3, line: 11, type: !64, scopeLine: 11, containingType: !60, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !64 = !DISubroutineType(types: !65) !65 = !{null, !66, !6} !66 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !60, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !67 = !DISubprogram(name: "g", linkageName: "_ZN1B1gEv", scope: !60, file: !3, line: 12, type: !68, scopeLine: 12, containingType: !60, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !68 = !DISubroutineType(types: !69) !69 = !{!6, !66} !70 = !DILocation(line: 36, column: 5, scope: !58) !71 = !DILocalVariable(name: "c", scope: !58, file: !3, line: 37, type: !72) !72 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C", file: !3, line: 15, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !73, vtableHolder: !31, identifier: "_ZTS1C") !73 = !{!74, !75, !79} !74 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !72, baseType: !60, flags: DIFlagPublic, extraData: i32 0) !75 = !DISubprogram(name: "f", linkageName: "_ZN1C1fEi", scope: !72, file: !3, line: 17, type: !76, scopeLine: 17, containingType: !72, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !76 = !DISubroutineType(types: !77) !77 = !{null, !78, !6} !78 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !72, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !79 = !DISubprogram(name: "g", linkageName: "_ZN1C1gEv", scope: !72, file: !3, line: 18, type: !80, scopeLine: 18, containingType: !72, virtualIndex: 1, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagVirtual) !80 = !DISubroutineType(types: !81) !81 = !{!6, !78} !82 = !DILocation(line: 37, column: 5, scope: !58) !83 = !DILocation(line: 39, column: 9, scope: !84) !84 = distinct !DILexicalBlock(scope: !58, file: !3, line: 38, column: 7) !85 = !DILocation(line: 39, column: 5, scope: !84) !86 = !DILocation(line: 40, column: 9, scope: !84) !87 = !DILocation(line: 40, column: 5, scope: !84) !88 = !DILocation(line: 41, column: 3, scope: !84) !89 = !DILocation(line: 44, column: 1, scope: !84) !90 = !DILocalVariable(name: "e", scope: !58, file: !3, line: 41, type: !91) !91 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !31, size: 64) !92 = !DILocation(line: 41, column: 15, scope: !58) !93 = !DILocation(line: 42, column: 3, scope: !94) !94 = distinct !DILexicalBlock(scope: !58, file: !3, line: 41, column: 18) !95 = !DILocation(line: 43, column: 3, scope: !58) !96 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC1Ev", scope: !60, file: !3, line: 9, type: !97, scopeLine: 9, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !99, retainedNodes: !4) !97 = !DISubroutineType(types: !98) !98 = !{null, !66} !99 = !DISubprogram(name: "B", scope: !60, type: !97, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !100 = !DILocalVariable(name: "this", arg: 1, scope: !96, type: !101, flags: DIFlagArtificial | DIFlagObjectPointer) !101 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !60, size: 64) !102 = !DILocation(line: 0, scope: !96) !103 = !DILocation(line: 9, column: 7, scope: !96) !104 = distinct !DISubprogram(name: "C", linkageName: "_ZN1CC1Ev", scope: !72, file: !3, line: 15, type: !105, scopeLine: 15, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !107, retainedNodes: !4) !105 = !DISubroutineType(types: !106) !106 = !{null, !78} !107 = !DISubprogram(name: "C", scope: !72, type: !105, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !108 = !DILocalVariable(name: "this", arg: 1, scope: !104, type: !109, flags: DIFlagArtificial | DIFlagObjectPointer) !109 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !72, size: 64) !110 = !DILocation(line: 0, scope: !104) !111 = !DILocation(line: 15, column: 7, scope: !104) !112 = distinct !DISubprogram(name: "B", linkageName: "_ZN1BC2Ev", scope: !60, file: !3, line: 9, type: !97, scopeLine: 9, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !99, retainedNodes: !4) !113 = !DILocalVariable(name: "this", arg: 1, scope: !112, type: !101, flags: DIFlagArtificial | DIFlagObjectPointer) !114 = !DILocation(line: 0, scope: !112) !115 = !DILocation(line: 9, column: 7, scope: !112) !116 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AC2Ev", scope: !31, file: !3, line: 3, type: !117, scopeLine: 3, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !119, retainedNodes: !4) !117 = !DISubroutineType(types: !118) !118 = !{null, !41} !119 = !DISubprogram(name: "A", scope: !31, type: !117, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !120 = !DILocalVariable(name: "this", arg: 1, scope: !116, type: !30, flags: DIFlagArtificial | DIFlagObjectPointer) !121 = !DILocation(line: 0, scope: !116) !122 = !DILocation(line: 3, column: 7, scope: !116) !123 = distinct !DISubprogram(name: "f", linkageName: "_ZN1B1fEi", scope: !60, file: !3, line: 11, type: !64, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !63, retainedNodes: !4) !124 = !DILocalVariable(name: "this", arg: 1, scope: !123, type: !101, flags: DIFlagArtificial | DIFlagObjectPointer) !125 = !DILocation(line: 0, scope: !123) !126 = !DILocalVariable(name: "x", arg: 2, scope: !123, file: !3, line: 11, type: !6) !127 = !DILocation(line: 11, column: 22, scope: !123) !128 = !DILocation(line: 11, column: 31, scope: !123) !129 = !DILocation(line: 11, column: 29, scope: !123) !130 = !DILocation(line: 11, column: 34, scope: !123) !131 = distinct !DISubprogram(name: "g", linkageName: "_ZN1B1gEv", scope: !60, file: !3, line: 12, type: !68, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !67, retainedNodes: !4) !132 = !DILocalVariable(name: "this", arg: 1, scope: !131, type: !101, flags: DIFlagArtificial | DIFlagObjectPointer) !133 = !DILocation(line: 0, scope: !131) !134 = !DILocation(line: 12, column: 21, scope: !131) !135 = distinct !DISubprogram(name: "f", linkageName: "_ZN1A1fEi", scope: !31, file: !3, line: 5, type: !39, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !38, retainedNodes: !4) !136 = !DILocalVariable(name: "this", arg: 1, scope: !135, type: !30, flags: DIFlagArtificial | DIFlagObjectPointer) !137 = !DILocation(line: 0, scope: !135) !138 = !DILocalVariable(name: "x", arg: 2, scope: !135, file: !3, line: 5, type: !6) !139 = !DILocation(line: 5, column: 22, scope: !135) !140 = !DILocation(line: 5, column: 26, scope: !135) !141 = distinct !DISubprogram(name: "g", linkageName: "_ZN1A1gEv", scope: !31, file: !3, line: 6, type: !43, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !42, retainedNodes: !4) !142 = !DILocalVariable(name: "this", arg: 1, scope: !141, type: !30, flags: DIFlagArtificial | DIFlagObjectPointer) !143 = !DILocation(line: 0, scope: !141) !144 = !DILocation(line: 6, column: 21, scope: !141) !145 = distinct !DISubprogram(name: "C", linkageName: "_ZN1CC2Ev", scope: !72, file: !3, line: 15, type: !105, scopeLine: 15, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !107, retainedNodes: !4) !146 = !DILocalVariable(name: "this", arg: 1, scope: !145, type: !109, flags: DIFlagArtificial | DIFlagObjectPointer) !147 = !DILocation(line: 0, scope: !145) !148 = !DILocation(line: 15, column: 7, scope: !145) !149 = distinct !DISubprogram(name: "f", linkageName: "_ZN1C1fEi", scope: !72, file: !3, line: 17, type: !76, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !75, retainedNodes: !4) !150 = !DILocalVariable(name: "this", arg: 1, scope: !149, type: !109, flags: DIFlagArtificial | DIFlagObjectPointer) !151 = !DILocation(line: 0, scope: !149) !152 = !DILocalVariable(name: "x", arg: 2, scope: !149, file: !3, line: 17, type: !6) !153 = !DILocation(line: 17, column: 22, scope: !149) !154 = !DILocation(line: 17, column: 32, scope: !149) !155 = !DILocation(line: 17, column: 31, scope: !149) !156 = !DILocation(line: 17, column: 29, scope: !149) !157 = !DILocation(line: 17, column: 35, scope: !149) !158 = distinct !DISubprogram(name: "g", linkageName: "_ZN1C1gEv", scope: !72, file: !3, line: 18, type: !80, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !79, retainedNodes: !4) !159 = !DILocalVariable(name: "this", arg: 1, scope: !158, type: !109, flags: DIFlagArtificial | DIFlagObjectPointer) !160 = !DILocation(line: 0, scope: !158) !161 = !DILocation(line: 18, column: 21, scope: !158) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/undef.c000066400000000000000000000001241473507761200305440ustar00rootroot00000000000000extern int flag; int main(int argc, char** argv) { int* v; return flag + *v; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/undef.ll000066400000000000000000000104401473507761200307330ustar00rootroot00000000000000; ModuleID = 'undef.pp.bc' source_filename = "undef.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @flag = external global i32, align 4 ; CHECK: declare si32* @flag, align 4 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !8 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32*, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !15, metadata !DIExpression()), !dbg !16 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32** %6, metadata !19, metadata !DIExpression()), !dbg !21 %7 = load i32, i32* @flag, align 4, !dbg !22 %8 = load i32*, i32** %6, align 8, !dbg !23 %9 = load i32, i32* %8, align 4, !dbg !24 %10 = add nsw i32 %7, %9, !dbg !25 ret i32 %10, !dbg !26 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32** $6 = allocate si32*, 1, align 8 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: si32 %7 = load @flag, align 4 ; CHECK: si32* %8 = load $6, align 8 ; CHECK: si32 %9 = load %8, align 4 ; CHECK: si32 %10 = %7 sadd.nw %9 ; CHECK: return %10 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "undef.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11, !12} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) !14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !15 = !DILocalVariable(name: "argc", arg: 1, scope: !8, file: !1, line: 3, type: !11) !16 = !DILocation(line: 3, column: 14, scope: !8) !17 = !DILocalVariable(name: "argv", arg: 2, scope: !8, file: !1, line: 3, type: !12) !18 = !DILocation(line: 3, column: 27, scope: !8) !19 = !DILocalVariable(name: "v", scope: !8, file: !1, line: 4, type: !20) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) !21 = !DILocation(line: 4, column: 8, scope: !8) !22 = !DILocation(line: 5, column: 10, scope: !8) !23 = !DILocation(line: 5, column: 18, scope: !8) !24 = !DILocation(line: 5, column: 17, scope: !8) !25 = !DILocation(line: 5, column: 15, scope: !8) !26 = !DILocation(line: 5, column: 3, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/union.c000066400000000000000000000001431473507761200305740ustar00rootroot00000000000000union my_union { int m_int; char* m_ptr; }; int main() { union my_union x = {.m_int = 1}; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/union.ll000066400000000000000000000076051473507761200307730ustar00rootroot00000000000000; ModuleID = 'union.pp.bc' source_filename = "union.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %union.my_union = type { i8* } @__const.main.x = private unnamed_addr constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8 ; CHECK: define {0: si32, 4: [4 x si8]}* @__const.main.x, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: store @__const.main.x, {0: 1, 4: undef}, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: argmemonly nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #2 ; CHECK: declare void @ar.memcpy(si8*, si8*, ui64, ui32, ui32, ui1) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca %union.my_union, align 8 call void @llvm.dbg.declare(metadata %union.my_union* %1, metadata !12, metadata !DIExpression()), !dbg !19 %2 = bitcast %union.my_union* %1 to i8*, !dbg !19 %3 = bitcast { i32, [4 x i8] }* @__const.main.x to i8*, !dbg !19 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %2, i8* align 8 %3, i64 8, i1 false), !dbg !19 ret i32 0, !dbg !20 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: {0: si8*}* $1 = allocate {0: si8*}, 1, align 8 ; CHECK: si8* %2 = bitcast $1 ; CHECK: si8* %3 = bitcast @__const.main.x ; CHECK: call @ar.memcpy(%2, %3, 8, 8, 8, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { argmemonly nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "union.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !9, scopeLine: 6, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 7, type: !13) !13 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "my_union", file: !1, line: 1, size: 64, elements: !14) !14 = !{!15, !16} !15 = !DIDerivedType(tag: DW_TAG_member, name: "m_int", scope: !13, file: !1, line: 2, baseType: !11, size: 32) !16 = !DIDerivedType(tag: DW_TAG_member, name: "m_ptr", scope: !13, file: !1, line: 3, baseType: !17, size: 64) !17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) !18 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !19 = !DILocation(line: 7, column: 18, scope: !8) !20 = !DILocation(line: 8, column: 1, scope: !8) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/update-ll000077500000000000000000000022461473507761200311230ustar00rootroot00000000000000#!/bin/bash # Use this script to update all the .ll files from the .c and .cpp files clang="clang" ikos_pp="ikos-pp" opt="opt" opt_level="none" cflags="-c -emit-llvm -Wall -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone" cxxflags="$cflags -std=c++17" ikos_import="ikos-import" ikos_import_opts="-format=text -order-globals -allow-dbg-mismatch" set -e function run { echo "#" "$@" "$@" } for filename in *.c do echo "[*] $filename ..." filename="${filename%.c}" run "$clang" $cflags "$filename.c" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.new.ll" vimdiff "$filename.ll" "$filename.new.ll" rm -f "$filename.bc" "$filename.pp.bc" "$filename.new.ll" done for filename in *.cpp do echo "[*] $filename ..." filename="${filename%.cpp}" run "$clang" $cxxflags "$filename.cpp" -o "$filename.bc" run "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" run "$opt" -S "$filename.pp.bc" -o "$filename.new.ll" vimdiff "$filename.ll" "$filename.new.ll" rm -f "$filename.bc" "$filename.pp.bc" "$filename.new.ll" done NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/var-args.c000066400000000000000000000016441473507761200311750ustar00rootroot00000000000000/* va_copy example */ #include /* va_list, va_start, va_copy, va_arg, va_end */ #include /* printf, vprintf*/ #include /* malloc */ #include /* strlen, strcat */ /* print ints until a zero is found: */ void PrintInts(int first, ...) { char* buffer; const char* format = "[%d] "; int count = 0; int val = first; va_list vl, vl_count; va_start(vl, first); /* count number of arguments: */ va_copy(vl_count, vl); while (val != 0) { val = va_arg(vl_count, int); ++count; } va_end(vl_count); /* allocate storage for format string: */ buffer = (char*)malloc(strlen(format) * count + 1); buffer[0] = '\0'; /* generate format string: */ for (; count > 0; --count) { strcat(buffer, format); } /* print integers: */ printf(format, first); vprintf(buffer, vl); va_end(vl); } int main() { PrintInts(10, 20, 30, 40, 50, 0); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/var-args.ll000066400000000000000000000473021473507761200313630ustar00rootroot00000000000000; ModuleID = 'var-args.pp.bc' source_filename = "var-args.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.__va_list_tag = type { i32, i32, i8*, i8* } @.str = private unnamed_addr constant [6 x i8] c"[%d] \00", align 1 ; CHECK: define [6 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [91, 37, 100, 93, 32, 0], align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define void @PrintInts(i32, ...) #0 !dbg !11 { %2 = alloca i32, align 4 %3 = alloca i8*, align 8 %4 = alloca i8*, align 8 %5 = alloca i32, align 4 %6 = alloca i32, align 4 %7 = alloca [1 x %struct.__va_list_tag], align 16 %8 = alloca [1 x %struct.__va_list_tag], align 16 store i32 %0, i32* %2, align 4 call void @llvm.dbg.declare(metadata i32* %2, metadata !15, metadata !DIExpression()), !dbg !16 call void @llvm.dbg.declare(metadata i8** %3, metadata !17, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i8** %4, metadata !19, metadata !DIExpression()), !dbg !22 %9 = getelementptr inbounds [6 x i8], [6 x i8]* @.str, i64 0, i64 0, !dbg !22 store i8* %9, i8** %4, align 8, !dbg !22 call void @llvm.dbg.declare(metadata i32* %5, metadata !23, metadata !DIExpression()), !dbg !24 store i32 0, i32* %5, align 4, !dbg !24 call void @llvm.dbg.declare(metadata i32* %6, metadata !25, metadata !DIExpression()), !dbg !26 %10 = load i32, i32* %2, align 4, !dbg !27 store i32 %10, i32* %6, align 4, !dbg !26 call void @llvm.dbg.declare(metadata [1 x %struct.__va_list_tag]* %7, metadata !28, metadata !DIExpression()), !dbg !45 call void @llvm.dbg.declare(metadata [1 x %struct.__va_list_tag]* %8, metadata !46, metadata !DIExpression()), !dbg !47 %11 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %7, i64 0, i64 0, !dbg !48 %12 = bitcast %struct.__va_list_tag* %11 to i8*, !dbg !48 call void @llvm.va_start(i8* %12), !dbg !48 %13 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %8, i64 0, i64 0, !dbg !49 %14 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %7, i64 0, i64 0, !dbg !49 %15 = bitcast %struct.__va_list_tag* %13 to i8*, !dbg !49 %16 = bitcast %struct.__va_list_tag* %14 to i8*, !dbg !49 call void @llvm.va_copy(i8* %15, i8* %16), !dbg !49 br label %17, !dbg !50 17: ; preds = %36, %1 %18 = load i32, i32* %6, align 4, !dbg !51 %19 = icmp ne i32 %18, 0, !dbg !52 br i1 %19, label %20, label %41, !dbg !50 20: ; preds = %17 %21 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %8, i64 0, i64 0, !dbg !53 %22 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %21, i32 0, i32 0, !dbg !53 %23 = load i32, i32* %22, align 16, !dbg !53 %24 = icmp ule i32 %23, 40, !dbg !53 br i1 %24, label %25, label %31, !dbg !53 25: ; preds = %20 %26 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %21, i32 0, i32 3, !dbg !53 %27 = load i8*, i8** %26, align 16, !dbg !53 %28 = getelementptr i8, i8* %27, i32 %23, !dbg !53 %29 = bitcast i8* %28 to i32*, !dbg !53 %30 = add i32 %23, 8, !dbg !53 store i32 %30, i32* %22, align 16, !dbg !53 br label %36, !dbg !53 31: ; preds = %20 %32 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %21, i32 0, i32 2, !dbg !53 %33 = load i8*, i8** %32, align 8, !dbg !53 %34 = bitcast i8* %33 to i32*, !dbg !53 %35 = getelementptr i8, i8* %33, i32 8, !dbg !53 store i8* %35, i8** %32, align 8, !dbg !53 br label %36, !dbg !53 36: ; preds = %31, %25 %37 = phi i32* [ %29, %25 ], [ %34, %31 ], !dbg !53 %38 = load i32, i32* %37, align 4, !dbg !53 store i32 %38, i32* %6, align 4, !dbg !55 %39 = load i32, i32* %5, align 4, !dbg !56 %40 = add nsw i32 %39, 1, !dbg !56 store i32 %40, i32* %5, align 4, !dbg !56 br label %17, !dbg !50, !llvm.loop !57 41: ; preds = %17 %42 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %8, i64 0, i64 0, !dbg !59 %43 = bitcast %struct.__va_list_tag* %42 to i8*, !dbg !59 call void @llvm.va_end(i8* %43), !dbg !59 %44 = load i8*, i8** %4, align 8, !dbg !60 %45 = call i64 @strlen(i8* %44), !dbg !61 %46 = load i32, i32* %5, align 4, !dbg !62 %47 = sext i32 %46 to i64, !dbg !62 %48 = mul i64 %45, %47, !dbg !63 %49 = add i64 %48, 1, !dbg !64 %50 = call i8* @malloc(i64 %49) #5, !dbg !65 store i8* %50, i8** %3, align 8, !dbg !66 %51 = load i8*, i8** %3, align 8, !dbg !67 %52 = getelementptr inbounds i8, i8* %51, i64 0, !dbg !67 store i8 0, i8* %52, align 1, !dbg !68 br label %53, !dbg !69 53: ; preds = %60, %41 %54 = load i32, i32* %5, align 4, !dbg !70 %55 = icmp sgt i32 %54, 0, !dbg !73 br i1 %55, label %56, label %63, !dbg !74 56: ; preds = %53 %57 = load i8*, i8** %3, align 8, !dbg !75 %58 = load i8*, i8** %4, align 8, !dbg !77 %59 = call i8* @strcat(i8* %57, i8* %58), !dbg !78 br label %60, !dbg !79 60: ; preds = %56 %61 = load i32, i32* %5, align 4, !dbg !80 %62 = add nsw i32 %61, -1, !dbg !80 store i32 %62, i32* %5, align 4, !dbg !80 br label %53, !dbg !81, !llvm.loop !82 63: ; preds = %53 %64 = load i8*, i8** %4, align 8, !dbg !84 %65 = load i32, i32* %2, align 4, !dbg !85 %66 = call i32 (i8*, ...) @printf(i8* %64, i32 %65), !dbg !86 %67 = load i8*, i8** %3, align 8, !dbg !87 %68 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %7, i64 0, i64 0, !dbg !88 %69 = call i32 @vprintf(i8* %67, %struct.__va_list_tag* %68), !dbg !89 %70 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %7, i64 0, i64 0, !dbg !90 %71 = bitcast %struct.__va_list_tag* %70 to i8*, !dbg !90 call void @llvm.va_end(i8* %71), !dbg !90 ret void, !dbg !91 } ; CHECK: define void @PrintInts(si32 %1, ...) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: si8** $3 = allocate si8*, 1, align 8 ; CHECK: si8** $4 = allocate si8*, 1, align 8 ; CHECK: si32* $5 = allocate si32, 1, align 4 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}]* $7 = allocate [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}], 1, align 16 ; CHECK: [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}]* $8 = allocate [1 x {0: ui32, 4: ui32, 8: si8*, 16: si8*}], 1, align 16 ; CHECK: store $2, %1, align 4 ; CHECK: si8* %9 = ptrshift @.str, 6 * 0, 1 * 0 ; CHECK: store $4, %9, align 8 ; CHECK: store $5, 0, align 4 ; CHECK: si32 %10 = load $2, align 4 ; CHECK: store $6, %10, align 4 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %11 = ptrshift $7, 24 * 0, 24 * 0 ; CHECK: si8* %12 = bitcast %11 ; CHECK: call @ar.va_start(%12) ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %13 = ptrshift $8, 24 * 0, 24 * 0 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %14 = ptrshift $7, 24 * 0, 24 * 0 ; CHECK: si8* %15 = bitcast %13 ; CHECK: si8* %16 = bitcast %14 ; CHECK: call @ar.va_copy(%15, %16) ; CHECK: } ; CHECK: #2 predecessors={#1, #8} successors={#3, #4} { ; CHECK: si32 %17 = load $6, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#5, #6} { ; CHECK: %17 sine 0 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %18 = ptrshift $8, 24 * 0, 24 * 0 ; CHECK: si32* %19 = ptrshift %18, 24 * 0, 1 * 0 ; CHECK: ui32* %20 = bitcast %19 ; CHECK: ui32 %21 = load %20, align 16 ; CHECK: } ; CHECK: #4 predecessors={#2} successors={#7} { ; CHECK: %17 sieq 0 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %22 = ptrshift $8, 24 * 0, 24 * 0 ; CHECK: si8* %23 = bitcast %22 ; CHECK: call @ar.va_end(%23) ; CHECK: si8* %24 = load $4, align 8 ; CHECK: ui64 %25 = call @ar.libc.strlen(%24) ; CHECK: si32 %26 = load $5, align 4 ; CHECK: si64 %27 = sext %26 ; CHECK: ui64 %28 = bitcast %27 ; CHECK: ui64 %29 = %25 umul %28 ; CHECK: ui64 %30 = %29 uadd 1 ; CHECK: si8* %31 = call @ar.libc.malloc(%30) ; CHECK: store $3, %31, align 8 ; CHECK: si8* %32 = load $3, align 8 ; CHECK: si8* %33 = ptrshift %32, 1 * 0 ; CHECK: store %33, 0, align 1 ; CHECK: } ; CHECK: #5 predecessors={#3} successors={#8} { ; CHECK: %21 uile 40 ; CHECK: si8** %34 = ptrshift %18, 24 * 0, 1 * 16 ; CHECK: si8* %35 = load %34, align 16 ; CHECK: si8* %36 = ptrshift %35, 1 * %21 ; CHECK: si32* %37 = bitcast %36 ; CHECK: ui32 %38 = %21 uadd 8 ; CHECK: si32 %39 = bitcast %38 ; CHECK: store %19, %39, align 16 ; CHECK: si32* %40 = %37 ; CHECK: } ; CHECK: #6 predecessors={#3} successors={#8} { ; CHECK: %21 uigt 40 ; CHECK: si8** %41 = ptrshift %18, 24 * 0, 1 * 8 ; CHECK: si8* %42 = load %41, align 8 ; CHECK: si32* %43 = bitcast %42 ; CHECK: si8* %44 = ptrshift %42, 1 * 8 ; CHECK: store %41, %44, align 8 ; CHECK: si32* %40 = %43 ; CHECK: } ; CHECK: #7 predecessors={#4, #9} successors={#9, #10} { ; CHECK: si32 %45 = load $5, align 4 ; CHECK: } ; CHECK: #9 predecessors={#7} successors={#7} { ; CHECK: %45 sigt 0 ; CHECK: si8* %49 = load $3, align 8 ; CHECK: si8* %50 = load $4, align 8 ; CHECK: si8* %51 = call @ar.libc.strcat(%49, %50) ; CHECK: si32 %52 = load $5, align 4 ; CHECK: si32 %53 = %52 sadd.nw -1 ; CHECK: store $5, %53, align 4 ; CHECK: } ; CHECK: #10 !exit predecessors={#7} { ; CHECK: %45 sile 0 ; CHECK: si8* %54 = load $4, align 8 ; CHECK: si32 %55 = load $2, align 4 ; CHECK: si32 %56 = call @ar.libc.printf(%54, %55) ; CHECK: si8* %57 = load $3, align 8 ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %58 = ptrshift $7, 24 * 0, 24 * 0 ; CHECK: si32 %59 = call @vprintf(%57, %58) ; CHECK: {0: si32, 4: si32, 8: si8*, 16: si8*}* %60 = ptrshift $7, 24 * 0, 24 * 0 ; CHECK: si8* %61 = bitcast %60 ; CHECK: call @ar.va_end(%61) ; CHECK: return ; CHECK: } ; CHECK: #8 predecessors={#5, #6} successors={#2} { ; CHECK: si32 %46 = load %40, align 4 ; CHECK: store $6, %46, align 4 ; CHECK: si32 %47 = load $5, align 4 ; CHECK: si32 %48 = %47 sadd.nw 1 ; CHECK: store $5, %48, align 4 ; CHECK: } ; CHECK: } ; Function Attrs: allocsize(0) declare i8* @malloc(i64) #3 ; CHECK: declare si8* @ar.libc.malloc(ui64) declare i32 @printf(i8*, ...) #4 ; CHECK: declare si32 @ar.libc.printf(si8*, ...) declare i8* @strcat(i8*, i8*) #4 ; CHECK: declare si8* @ar.libc.strcat(si8*, si8*) declare i64 @strlen(i8*) #4 ; CHECK: declare ui64 @ar.libc.strlen(si8*) ; Function Attrs: nounwind declare void @llvm.va_copy(i8*, i8*) #2 ; CHECK: declare void @ar.va_copy(si8*, si8*) ; Function Attrs: nounwind declare void @llvm.va_end(i8*) #2 ; CHECK: declare void @ar.va_end(si8*) ; Function Attrs: nounwind declare void @llvm.va_start(i8*) #2 ; CHECK: declare void @ar.va_start(si8*) ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !92 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 call void (i32, ...) @PrintInts(i32 10, i32 20, i32 30, i32 40, i32 50, i32 0), !dbg !95 ret i32 0, !dbg !96 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: call @PrintInts(10, 20, 30, 40, 50, 0) ; CHECK: return 0 ; CHECK: } ; CHECK: } declare i32 @vprintf(i8*, %struct.__va_list_tag*) #4 ; CHECK: declare si32 @vprintf(si8*, {0: si32, 4: si32, 8: si8*, 16: si8*}*) ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { nounwind } attributes #3 = { allocsize(0) "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #5 = { allocsize(0) } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!6, !7, !8, !9} !llvm.ident = !{!10} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: GNU) !1 = !DIFile(filename: "var-args.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{!4} !4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) !5 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} !8 = !{i32 1, !"wchar_size", i32 4} !9 = !{i32 7, !"PIC Level", i32 2} !10 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !11 = distinct !DISubprogram(name: "PrintInts", scope: !1, file: !1, line: 8, type: !12, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !12 = !DISubroutineType(types: !13) !13 = !{null, !14, null} !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !15 = !DILocalVariable(name: "first", arg: 1, scope: !11, file: !1, line: 8, type: !14) !16 = !DILocation(line: 8, column: 20, scope: !11) !17 = !DILocalVariable(name: "buffer", scope: !11, file: !1, line: 9, type: !4) !18 = !DILocation(line: 9, column: 9, scope: !11) !19 = !DILocalVariable(name: "format", scope: !11, file: !1, line: 10, type: !20) !20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64) !21 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !5) !22 = !DILocation(line: 10, column: 15, scope: !11) !23 = !DILocalVariable(name: "count", scope: !11, file: !1, line: 11, type: !14) !24 = !DILocation(line: 11, column: 7, scope: !11) !25 = !DILocalVariable(name: "val", scope: !11, file: !1, line: 12, type: !14) !26 = !DILocation(line: 12, column: 7, scope: !11) !27 = !DILocation(line: 12, column: 13, scope: !11) !28 = !DILocalVariable(name: "vl", scope: !11, file: !1, line: 13, type: !29) !29 = !DIDerivedType(tag: DW_TAG_typedef, name: "va_list", file: !30, line: 32, baseType: !31) !30 = !DIFile(filename: "/usr/include/sys/_types/_va_list.h", directory: "") !31 = !DIDerivedType(tag: DW_TAG_typedef, name: "__darwin_va_list", file: !32, line: 98, baseType: !33) !32 = !DIFile(filename: "/usr/include/i386/_types.h", directory: "") !33 = !DIDerivedType(tag: DW_TAG_typedef, name: "__builtin_va_list", file: !1, line: 13, baseType: !34) !34 = !DICompositeType(tag: DW_TAG_array_type, baseType: !35, size: 192, elements: !43) !35 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", file: !1, line: 13, size: 192, elements: !36) !36 = !{!37, !39, !40, !42} !37 = !DIDerivedType(tag: DW_TAG_member, name: "gp_offset", scope: !35, file: !1, line: 13, baseType: !38, size: 32) !38 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) !39 = !DIDerivedType(tag: DW_TAG_member, name: "fp_offset", scope: !35, file: !1, line: 13, baseType: !38, size: 32, offset: 32) !40 = !DIDerivedType(tag: DW_TAG_member, name: "overflow_arg_area", scope: !35, file: !1, line: 13, baseType: !41, size: 64, offset: 64) !41 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !42 = !DIDerivedType(tag: DW_TAG_member, name: "reg_save_area", scope: !35, file: !1, line: 13, baseType: !41, size: 64, offset: 128) !43 = !{!44} !44 = !DISubrange(count: 1) !45 = !DILocation(line: 13, column: 11, scope: !11) !46 = !DILocalVariable(name: "vl_count", scope: !11, file: !1, line: 13, type: !29) !47 = !DILocation(line: 13, column: 15, scope: !11) !48 = !DILocation(line: 14, column: 3, scope: !11) !49 = !DILocation(line: 17, column: 3, scope: !11) !50 = !DILocation(line: 18, column: 3, scope: !11) !51 = !DILocation(line: 18, column: 10, scope: !11) !52 = !DILocation(line: 18, column: 14, scope: !11) !53 = !DILocation(line: 19, column: 11, scope: !54) !54 = distinct !DILexicalBlock(scope: !11, file: !1, line: 18, column: 20) !55 = !DILocation(line: 19, column: 9, scope: !54) !56 = !DILocation(line: 20, column: 5, scope: !54) !57 = distinct !{!57, !50, !58} !58 = !DILocation(line: 21, column: 3, scope: !11) !59 = !DILocation(line: 22, column: 3, scope: !11) !60 = !DILocation(line: 25, column: 33, scope: !11) !61 = !DILocation(line: 25, column: 26, scope: !11) !62 = !DILocation(line: 25, column: 43, scope: !11) !63 = !DILocation(line: 25, column: 41, scope: !11) !64 = !DILocation(line: 25, column: 49, scope: !11) !65 = !DILocation(line: 25, column: 19, scope: !11) !66 = !DILocation(line: 25, column: 10, scope: !11) !67 = !DILocation(line: 26, column: 3, scope: !11) !68 = !DILocation(line: 26, column: 13, scope: !11) !69 = !DILocation(line: 29, column: 3, scope: !11) !70 = !DILocation(line: 29, column: 10, scope: !71) !71 = distinct !DILexicalBlock(scope: !72, file: !1, line: 29, column: 3) !72 = distinct !DILexicalBlock(scope: !11, file: !1, line: 29, column: 3) !73 = !DILocation(line: 29, column: 16, scope: !71) !74 = !DILocation(line: 29, column: 3, scope: !72) !75 = !DILocation(line: 30, column: 12, scope: !76) !76 = distinct !DILexicalBlock(scope: !71, file: !1, line: 29, column: 30) !77 = !DILocation(line: 30, column: 20, scope: !76) !78 = !DILocation(line: 30, column: 5, scope: !76) !79 = !DILocation(line: 31, column: 3, scope: !76) !80 = !DILocation(line: 29, column: 21, scope: !71) !81 = !DILocation(line: 29, column: 3, scope: !71) !82 = distinct !{!82, !74, !83} !83 = !DILocation(line: 31, column: 3, scope: !72) !84 = !DILocation(line: 34, column: 10, scope: !11) !85 = !DILocation(line: 34, column: 18, scope: !11) !86 = !DILocation(line: 34, column: 3, scope: !11) !87 = !DILocation(line: 35, column: 11, scope: !11) !88 = !DILocation(line: 35, column: 19, scope: !11) !89 = !DILocation(line: 35, column: 3, scope: !11) !90 = !DILocation(line: 37, column: 3, scope: !11) !91 = !DILocation(line: 38, column: 1, scope: !11) !92 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 40, type: !93, scopeLine: 40, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !93 = !DISubroutineType(types: !94) !94 = !{!14} !95 = !DILocation(line: 41, column: 3, scope: !92) !96 = !DILocation(line: 42, column: 3, scope: !92) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-1.c000066400000000000000000000001711473507761200311050ustar00rootroot00000000000000typedef float vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a + b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-1.ll000066400000000000000000000103751473507761200313010ustar00rootroot00000000000000; ModuleID = 'vector-1.pp.bc' source_filename = "vector-1.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global <4 x float> zeroinitializer, align 16, !dbg !0 ; CHECK: define <4 x float>* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = common global <4 x float> zeroinitializer, align 16, !dbg !6 ; CHECK: define <4 x float>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @c = common global <4 x float> zeroinitializer, align 16, !dbg !13 ; CHECK: define <4 x float>* @c, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = load <4 x float>, <4 x float>* @a, align 16, !dbg !24 %3 = load <4 x float>, <4 x float>* @b, align 16, !dbg !25 %4 = fadd <4 x float> %2, %3, !dbg !26 store <4 x float> %4, <4 x float>* @c, align 16, !dbg !27 ret i32 0, !dbg !28 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: <4 x float> %2 = load @a, align 16 ; CHECK: <4 x float> %3 = load @b, align 16 ; CHECK: <4 x float> %4 = %2 fadd %3 ; CHECK: store @c, %4, align 16 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "vector-1.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0, !6, !13} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !3, line: 1, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 128, flags: DIFlagVector, elements: !11) !10 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !11 = !{!12} !12 = !DISubrange(count: 4) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!23} !23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !24 = !DILocation(line: 6, column: 7, scope: !20) !25 = !DILocation(line: 6, column: 11, scope: !20) !26 = !DILocation(line: 6, column: 9, scope: !20) !27 = !DILocation(line: 6, column: 5, scope: !20) !28 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-2.c000066400000000000000000000001721473507761200311070ustar00rootroot00000000000000typedef double vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a * b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-2.ll000066400000000000000000000104161473507761200312760ustar00rootroot00000000000000; ModuleID = 'vector-2.pp.bc' source_filename = "vector-2.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global <2 x double> zeroinitializer, align 16, !dbg !0 ; CHECK: define <2 x double>* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = common global <2 x double> zeroinitializer, align 16, !dbg !6 ; CHECK: define <2 x double>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @c = common global <2 x double> zeroinitializer, align 16, !dbg !13 ; CHECK: define <2 x double>* @c, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = load <2 x double>, <2 x double>* @a, align 16, !dbg !24 %3 = load <2 x double>, <2 x double>* @b, align 16, !dbg !25 %4 = fmul <2 x double> %2, %3, !dbg !26 store <2 x double> %4, <2 x double>* @c, align 16, !dbg !27 ret i32 0, !dbg !28 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: <2 x double> %2 = load @a, align 16 ; CHECK: <2 x double> %3 = load @b, align 16 ; CHECK: <2 x double> %4 = %2 fmul %3 ; CHECK: store @c, %4, align 16 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "vector-2.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0, !6, !13} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !3, line: 1, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 128, flags: DIFlagVector, elements: !11) !10 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) !11 = !{!12} !12 = !DISubrange(count: 2) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!23} !23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !24 = !DILocation(line: 6, column: 7, scope: !20) !25 = !DILocation(line: 6, column: 11, scope: !20) !26 = !DILocation(line: 6, column: 9, scope: !20) !27 = !DILocation(line: 6, column: 5, scope: !20) !28 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-3.c000066400000000000000000000001671473507761200311140ustar00rootroot00000000000000typedef int vector_t __attribute__((__vector_size__(16))); vector_t a, b, c; int main() { c = a + b; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-3.ll000066400000000000000000000104221473507761200312740ustar00rootroot00000000000000; ModuleID = 'vector-3.pp.bc' source_filename = "vector-3.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @a = common global <4 x i32> zeroinitializer, align 16, !dbg !0 ; CHECK: define <4 x si32>* @a, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @a, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @b = common global <4 x i32> zeroinitializer, align 16, !dbg !6 ; CHECK: define <4 x si32>* @b, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @b, aggregate_zero, align 1 ; CHECK: } ; CHECK: } @c = common global <4 x i32> zeroinitializer, align 16, !dbg !13 ; CHECK: define <4 x si32>* @c, align 16, init { ; CHECK: #1 !entry !exit { ; CHECK: store @c, aggregate_zero, align 1 ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 !dbg !20 { %1 = alloca i32, align 4 store i32 0, i32* %1, align 4 %2 = load <4 x i32>, <4 x i32>* @a, align 16, !dbg !23 %3 = load <4 x i32>, <4 x i32>* @b, align 16, !dbg !24 %4 = add <4 x i32> %2, %3, !dbg !25 store <4 x i32> %4, <4 x i32>* @c, align 16, !dbg !26 ret i32 0, !dbg !27 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: store $1, 0, align 4 ; CHECK: <4 x ui32>* %2 = bitcast @a ; CHECK: <4 x ui32> %3 = load %2, align 16 ; CHECK: <4 x ui32>* %4 = bitcast @b ; CHECK: <4 x ui32> %5 = load %4, align 16 ; CHECK: <4 x ui32> %6 = %3 uadd %5 ; CHECK: <4 x si32> %7 = bitcast %6 ; CHECK: store @c, %7, align 16 ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!2} !llvm.module.flags = !{!15, !16, !17, !18} !llvm.ident = !{!19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: GNU) !3 = !DIFile(filename: "vector-3.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !4 = !{} !5 = !{!0, !6, !13} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !8 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !3, line: 1, baseType: !9) !9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 128, flags: DIFlagVector, elements: !11) !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !11 = !{!12} !12 = !DISubrange(count: 4) !13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) !14 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 3, type: !8, isLocal: false, isDefinition: true) !15 = !{i32 2, !"Dwarf Version", i32 4} !16 = !{i32 2, !"Debug Info Version", i32 3} !17 = !{i32 1, !"wchar_size", i32 4} !18 = !{i32 7, !"PIC Level", i32 2} !19 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !20 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 5, type: !21, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{!10} !23 = !DILocation(line: 6, column: 7, scope: !20) !24 = !DILocation(line: 6, column: 11, scope: !20) !25 = !DILocation(line: 6, column: 9, scope: !20) !26 = !DILocation(line: 6, column: 5, scope: !20) !27 = !DILocation(line: 7, column: 3, scope: !20) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-4.c000066400000000000000000000001761473507761200311150ustar00rootroot00000000000000typedef long vector_t __attribute__((__vector_size__(16))); vector_t f(vector_t x) { return __builtin_ia32_pshufd(x, 0); } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vector-4.ll000066400000000000000000000066351473507761200313100ustar00rootroot00000000000000; ModuleID = 'vector-4.pp.bc' source_filename = "vector-4.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 ; Function Attrs: noinline nounwind ssp uwtable define <2 x i64> @f(<2 x i64>) #0 !dbg !8 { %2 = alloca <2 x i64>, align 16 store <2 x i64> %0, <2 x i64>* %2, align 16 call void @llvm.dbg.declare(metadata <2 x i64>* %2, metadata !16, metadata !DIExpression()), !dbg !17 %3 = load <2 x i64>, <2 x i64>* %2, align 16, !dbg !18 %4 = bitcast <2 x i64> %3 to <4 x i32>, !dbg !18 %5 = shufflevector <4 x i32> %4, <4 x i32> undef, <4 x i32> zeroinitializer, !dbg !19 %6 = bitcast <4 x i32> %5 to <2 x i64>, !dbg !19 ret <2 x i64> %6, !dbg !20 } ; CHECK: define <2 x si64> @f(<2 x si64> %1) { ; CHECK: #1 !entry !exit { ; CHECK: <2 x si64>* $2 = allocate <2 x si64>, 1, align 16 ; CHECK: store $2, %1, align 16 ; CHECK: <2 x si64> %3 = load $2, align 16 ; CHECK: <4 x si32> %4 = bitcast %3 ; CHECK: <4 x si32> %5 = shufflevector %4, undef ; CHECK: <2 x si64> %6 = bitcast %5 ; CHECK: return %6 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="128" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "vector-4.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !9, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11, !11} !11 = !DIDerivedType(tag: DW_TAG_typedef, name: "vector_t", file: !1, line: 1, baseType: !12) !12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 128, flags: DIFlagVector, elements: !14) !13 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) !14 = !{!15} !15 = !DISubrange(count: 2) !16 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type: !11) !17 = !DILocation(line: 3, column: 21, scope: !8) !18 = !DILocation(line: 4, column: 32, scope: !8) !19 = !DILocation(line: 4, column: 10, scope: !8) !20 = !DILocation(line: 4, column: 3, scope: !8) virtual-inheritance.cpp000066400000000000000000000006431473507761200337070ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimizationstruct A { int x; }; struct B { char* y; }; struct C { bool a; }; struct E : public virtual A, public B, public C { int x; virtual void f() {} }; struct D : public virtual A, public virtual B, public C { float z; }; struct F : public virtual A { int y; }; struct G : public virtual A { char* z; }; struct H : public F, public G {}; int main() { E e; D d; F f; G g; H h; return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/virtual-inheritance.ll000066400000000000000000001320051473507761200336110ustar00rootroot00000000000000; ModuleID = 'virtual-inheritance.pp.bc' source_filename = "virtual-inheritance.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 %struct.E = type { i32 (...)**, %struct.B, %struct.C, i32, %struct.A } %struct.B = type { i8* } %struct.C = type { i8 } %struct.A = type { i32 } %struct.D = type { i32 (...)**, %struct.C, float, %struct.A, %struct.B } %struct.F = type <{ i32 (...)**, i32, %struct.A }> %struct.G = type { i32 (...)**, i8*, %struct.A } %struct.H = type { %struct.F.base, %struct.G.base, %struct.A } %struct.F.base = type <{ i32 (...)**, i32 }> %struct.G.base = type { i32 (...)**, i8* } @_ZTC1H0_1F = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTC1H0_1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1F ; CHECK: si8* %2 = sitoptr 32 ; CHECK: store @_ZTC1H0_1F, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTC1H16_1G = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTC1H16_1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1G ; CHECK: si8* %2 = sitoptr 16 ; CHECK: store @_ZTC1H16_1G, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTI1A = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1A, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1A, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1A, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1A, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1B = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1B, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1B, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1B, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1C = linkonce_odr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0) }, align 8 ; CHECK: define {0: si8*, 8: si8*}* @_ZTI1C, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv117__class_type_infoE, 8 * 2 ; CHECK: si8* %2 = ptrshift @_ZTS1C, 3 * 0, 1 * 0 ; CHECK: si8* %3 = bitcast %1 ; CHECK: store @_ZTI1C, {0: %3, 8: %2}, align 1 ; CHECK: } ; CHECK: } @_ZTI1D = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1D, i32 0, i32 0), i32 0, i32 3, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141, i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i64 -8189, i8* bitcast ({ i8*, i8* }* @_ZTI1C to i8*), i64 2050 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64, 56: si8*, 64: si64}* @_ZTI1D, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1C ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: si8* %4 = bitcast @_ZTI1A ; CHECK: si8* %5 = ptrshift @_ZTS1D, 3 * 0, 1 * 0 ; CHECK: si8* %6 = bitcast %1 ; CHECK: store @_ZTI1D, {0: %6, 8: %5, 16: 0, 20: 3, 24: %4, 32: -6141, 40: %3, 48: -8189, 56: %2, 64: 2050}, align 1 ; CHECK: } ; CHECK: } @_ZTI1E = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1E, i32 0, i32 0), i32 0, i32 3, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141, i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i64 2050, i8* bitcast ({ i8*, i8* }* @_ZTI1C to i8*), i64 4098 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64, 56: si8*, 64: si64}* @_ZTI1E, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1C ; CHECK: si8* %3 = bitcast @_ZTI1B ; CHECK: si8* %4 = bitcast @_ZTI1A ; CHECK: si8* %5 = ptrshift @_ZTS1E, 3 * 0, 1 * 0 ; CHECK: si8* %6 = bitcast %1 ; CHECK: store @_ZTI1E, {0: %6, 8: %5, 16: 0, 20: 3, 24: %4, 32: -6141, 40: %3, 48: 2050, 56: %2, 64: 4098}, align 1 ; CHECK: } ; CHECK: } @_ZTI1F = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1F, i32 0, i32 0), i32 0, i32 1, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64}* @_ZTI1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1F, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1F, {0: %4, 8: %3, 16: 0, 20: 1, 24: %2, 32: -6141}, align 1 ; CHECK: } ; CHECK: } @_ZTI1G = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1G, i32 0, i32 0), i32 0, i32 1, i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i64 -6141 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64}* @_ZTI1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1A ; CHECK: si8* %3 = ptrshift @_ZTS1G, 3 * 0, 1 * 0 ; CHECK: si8* %4 = bitcast %1 ; CHECK: store @_ZTI1G, {0: %4, 8: %3, 16: 0, 20: 1, 24: %2, 32: -6141}, align 1 ; CHECK: } ; CHECK: } @_ZTI1H = linkonce_odr constant { i8*, i8*, i32, i32, i8*, i64, i8*, i64 } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1H, i32 0, i32 0), i32 2, i32 2, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*), i64 2, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*), i64 4098 }, align 8 ; CHECK: define {0: si8*, 8: si8*, 16: si32, 20: si32, 24: si8*, 32: si64, 40: si8*, 48: si64}* @_ZTI1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTVN10__cxxabiv121__vmi_class_type_infoE, 8 * 2 ; CHECK: si8* %2 = bitcast @_ZTI1G ; CHECK: si8* %3 = bitcast @_ZTI1F ; CHECK: si8* %4 = ptrshift @_ZTS1H, 3 * 0, 1 * 0 ; CHECK: si8* %5 = bitcast %1 ; CHECK: store @_ZTI1H, {0: %5, 8: %4, 16: 2, 20: 2, 24: %3, 32: 2, 40: %2, 48: 4098}, align 1 ; CHECK: } ; CHECK: } @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1A, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1A, [49, 65, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1B = linkonce_odr constant [3 x i8] c"1B\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1B, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1B, [49, 66, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1C = linkonce_odr constant [3 x i8] c"1C\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1C, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1C, [49, 67, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1D = linkonce_odr constant [3 x i8] c"1D\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1D, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1D, [49, 68, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1E = linkonce_odr constant [3 x i8] c"1E\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1E, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1E, [49, 69, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1F = linkonce_odr constant [3 x i8] c"1F\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1F, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1F, [49, 70, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1G = linkonce_odr constant [3 x i8] c"1G\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1G, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1G, [49, 71, 0], align 1 ; CHECK: } ; CHECK: } @_ZTS1H = linkonce_odr constant [3 x i8] c"1H\00", align 1 ; CHECK: define [3 x si8]* @_ZTS1H, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @_ZTS1H, [49, 72, 0], align 1 ; CHECK: } ; CHECK: } @_ZTT1D = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1D, i32 0, inrange i32 0, i32 4) to i8*)], align 8 ; CHECK: define [1 x si8*]* @_ZTT1D, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTV1D, 32 * 0, 1 * 0, 8 * 4 ; CHECK: si8* %2 = bitcast %1 ; CHECK: store @_ZTT1D, [%2], align 1 ; CHECK: } ; CHECK: } @_ZTT1E = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [4 x i8*] }, { [4 x i8*] }* @_ZTV1E, i32 0, inrange i32 0, i32 3) to i8*)], align 8 ; CHECK: define [1 x si8*]* @_ZTT1E, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTV1E, 32 * 0, 1 * 0, 8 * 3 ; CHECK: si8* %2 = bitcast %1 ; CHECK: store @_ZTT1E, [%2], align 1 ; CHECK: } ; CHECK: } @_ZTT1F = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1F, i32 0, inrange i32 0, i32 3) to i8*)], align 8 ; CHECK: define [1 x si8*]* @_ZTT1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTV1F, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8* %2 = bitcast %1 ; CHECK: store @_ZTT1F, [%2], align 1 ; CHECK: } ; CHECK: } @_ZTT1G = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTV1G, i32 0, inrange i32 0, i32 3) to i8*)], align 8 ; CHECK: define [1 x si8*]* @_ZTT1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTV1G, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8* %2 = bitcast %1 ; CHECK: store @_ZTT1G, [%2], align 1 ; CHECK: } ; CHECK: } @_ZTT1H = linkonce_odr unnamed_addr constant [4 x i8*] [i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTC1H0_1F, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*] }, { [3 x i8*] }* @_ZTC1H16_1G, i32 0, inrange i32 0, i32 3) to i8*), i8* bitcast (i8** getelementptr inbounds ({ [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, inrange i32 1, i32 3) to i8*)], align 8 ; CHECK: define [4 x si8*]* @_ZTT1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8** %1 = ptrshift @_ZTV1H, 48 * 0, 1 * 24, 8 * 3 ; CHECK: si8** %2 = ptrshift @_ZTC1H16_1G, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8** %3 = ptrshift @_ZTC1H0_1F, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si8** %4 = ptrshift @_ZTV1H, 48 * 0, 1 * 0, 8 * 3 ; CHECK: si8* %5 = bitcast %1 ; CHECK: si8* %6 = bitcast %2 ; CHECK: si8* %7 = bitcast %3 ; CHECK: si8* %8 = bitcast %4 ; CHECK: store @_ZTT1H, [%8, %7, %6, %5], align 1 ; CHECK: } ; CHECK: } @_ZTV1D = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1D to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1D, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1D ; CHECK: si8* %2 = sitoptr 16 ; CHECK: si8* %3 = sitoptr 24 ; CHECK: store @_ZTV1D, {0: [%3, %2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1E = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* inttoptr (i64 24 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1E to i8*), i8* bitcast (void (%struct.E*)* @_ZN1E1fEv to i8*)] }, align 8 ; CHECK: define {0: [4 x si8*]}* @_ZTV1E, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZN1E1fEv ; CHECK: si8* %2 = bitcast @_ZTI1E ; CHECK: si8* %3 = sitoptr 24 ; CHECK: store @_ZTV1E, {0: [%3, null, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1F = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 12 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTV1F, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1F ; CHECK: si8* %2 = sitoptr 12 ; CHECK: store @_ZTV1F, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1G = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*]}* @_ZTV1G, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1G ; CHECK: si8* %2 = sitoptr 16 ; CHECK: store @_ZTV1G, {0: [%2, null, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTV1H = linkonce_odr unnamed_addr constant { [3 x i8*], [3 x i8*] } { [3 x i8*] [i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1H to i8*)], [3 x i8*] [i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1H to i8*)] }, align 8 ; CHECK: define {0: [3 x si8*], 24: [3 x si8*]}* @_ZTV1H, align 8, init { ; CHECK: #1 !entry !exit { ; CHECK: si8* %1 = bitcast @_ZTI1H ; CHECK: si8* %2 = sitoptr -16 ; CHECK: si8* %3 = sitoptr 16 ; CHECK: si8* %4 = bitcast @_ZTI1H ; CHECK: si8* %5 = sitoptr 32 ; CHECK: store @_ZTV1H, {0: [%5, null, %4], 24: [%3, %2, %1]}, align 1 ; CHECK: } ; CHECK: } @_ZTVN10__cxxabiv117__class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv117__class_type_infoE @_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global i8* ; CHECK: declare si8** @_ZTVN10__cxxabiv121__vmi_class_type_infoE ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1DC1Ev(%struct.D*) unnamed_addr #2 align 2 !dbg !76 { %2 = alloca %struct.D*, align 8 store %struct.D* %0, %struct.D** %2, align 8 call void @llvm.dbg.declare(metadata %struct.D** %2, metadata !81, metadata !DIExpression()), !dbg !83 %3 = load %struct.D*, %struct.D** %2, align 8 %4 = bitcast %struct.D* %3 to i8*, !dbg !84 %5 = getelementptr inbounds i8, i8* %4, i64 16, !dbg !84 %6 = bitcast i8* %5 to %struct.A*, !dbg !84 %7 = bitcast %struct.D* %3 to i8*, !dbg !84 %8 = getelementptr inbounds i8, i8* %7, i64 24, !dbg !84 %9 = bitcast i8* %8 to %struct.B*, !dbg !84 %10 = bitcast %struct.D* %3 to i8*, !dbg !84 %11 = getelementptr inbounds i8, i8* %10, i64 8, !dbg !84 %12 = bitcast i8* %11 to %struct.C*, !dbg !84 %13 = bitcast %struct.D* %3 to i32 (...)***, !dbg !84 %14 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1D, i32 0, i32 0, i32 4, !dbg !84 %15 = bitcast i8** %14 to i32 (...)**, !dbg !84 store i32 (...)** %15, i32 (...)*** %13, align 8, !dbg !84 ret void, !dbg !84 } ; CHECK: define void @_ZN1DC1Ev({0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}** $2 = allocate {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32 (...)**, 8: {0: si8}, 12: float, 16: {0: si32}, 24: {0: si8*}}** %3 = bitcast $2 ; CHECK: {0: si32 (...)**, 8: {0: si8}, 12: float, 16: {0: si32}, 24: {0: si8*}}* %4 = load %3, align 8 ; CHECK: si8* %5 = bitcast %4 ; CHECK: si8* %6 = ptrshift %5, 1 * 16 ; CHECK: {0: si32}* %7 = bitcast %6 ; CHECK: si8* %8 = bitcast %4 ; CHECK: si8* %9 = ptrshift %8, 1 * 24 ; CHECK: {0: si8*}* %10 = bitcast %9 ; CHECK: si8* %11 = bitcast %4 ; CHECK: si8* %12 = ptrshift %11, 1 * 8 ; CHECK: {0: si8}* %13 = bitcast %12 ; CHECK: si32 (...)*** %14 = bitcast %4 ; CHECK: si8** %15 = ptrshift @_ZTV1D, 32 * 0, 1 * 0, 8 * 4 ; CHECK: si32 (...)** %16 = bitcast %15 ; CHECK: store %14, %16, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1E1fEv(%struct.E*) unnamed_addr #2 align 2 !dbg !112 { %2 = alloca %struct.E*, align 8 store %struct.E* %0, %struct.E** %2, align 8 call void @llvm.dbg.declare(metadata %struct.E** %2, metadata !113, metadata !DIExpression()), !dbg !114 %3 = load %struct.E*, %struct.E** %2, align 8 ret void, !dbg !115 } ; CHECK: define void @_ZN1E1fEv({0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}** $2 = allocate {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: si8}, 20: si32, 24: {0: si32}}** %3 = bitcast $2 ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: si8}, 20: si32, 24: {0: si32}}* %4 = load %3, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1EC1Ev(%struct.E*) unnamed_addr #2 align 2 !dbg !70 { %2 = alloca %struct.E*, align 8 store %struct.E* %0, %struct.E** %2, align 8 call void @llvm.dbg.declare(metadata %struct.E** %2, metadata !72, metadata !DIExpression()), !dbg !74 %3 = load %struct.E*, %struct.E** %2, align 8 %4 = bitcast %struct.E* %3 to i8*, !dbg !75 %5 = getelementptr inbounds i8, i8* %4, i64 24, !dbg !75 %6 = bitcast i8* %5 to %struct.A*, !dbg !75 %7 = bitcast %struct.E* %3 to i8*, !dbg !75 %8 = getelementptr inbounds i8, i8* %7, i64 8, !dbg !75 %9 = bitcast i8* %8 to %struct.B*, !dbg !75 %10 = bitcast %struct.E* %3 to i8*, !dbg !75 %11 = getelementptr inbounds i8, i8* %10, i64 16, !dbg !75 %12 = bitcast i8* %11 to %struct.C*, !dbg !75 %13 = bitcast %struct.E* %3 to i32 (...)***, !dbg !75 %14 = getelementptr inbounds { [4 x i8*] }, { [4 x i8*] }* @_ZTV1E, i32 0, i32 0, i32 3, !dbg !75 %15 = bitcast i8** %14 to i32 (...)**, !dbg !75 store i32 (...)** %15, i32 (...)*** %13, align 8, !dbg !75 ret void, !dbg !75 } ; CHECK: define void @_ZN1EC1Ev({0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}** $2 = allocate {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: si8}, 20: si32, 24: {0: si32}}** %3 = bitcast $2 ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: si8}, 20: si32, 24: {0: si32}}* %4 = load %3, align 8 ; CHECK: si8* %5 = bitcast %4 ; CHECK: si8* %6 = ptrshift %5, 1 * 24 ; CHECK: {0: si32}* %7 = bitcast %6 ; CHECK: si8* %8 = bitcast %4 ; CHECK: si8* %9 = ptrshift %8, 1 * 8 ; CHECK: {0: si8*}* %10 = bitcast %9 ; CHECK: si8* %11 = bitcast %4 ; CHECK: si8* %12 = ptrshift %11, 1 * 16 ; CHECK: {0: si8}* %13 = bitcast %12 ; CHECK: si32 (...)*** %14 = bitcast %4 ; CHECK: si8** %15 = ptrshift @_ZTV1E, 32 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %16 = bitcast %15 ; CHECK: store %14, %16, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1FC1Ev(%struct.F*) unnamed_addr #2 align 2 !dbg !85 { %2 = alloca %struct.F*, align 8 store %struct.F* %0, %struct.F** %2, align 8 call void @llvm.dbg.declare(metadata %struct.F** %2, metadata !90, metadata !DIExpression()), !dbg !92 %3 = load %struct.F*, %struct.F** %2, align 8 %4 = bitcast %struct.F* %3 to i8*, !dbg !93 %5 = getelementptr inbounds i8, i8* %4, i64 12, !dbg !93 %6 = bitcast i8* %5 to %struct.A*, !dbg !93 %7 = bitcast %struct.F* %3 to i32 (...)***, !dbg !93 %8 = getelementptr inbounds { [3 x i8*] }, { [3 x i8*] }* @_ZTV1F, i32 0, i32 0, i32 3, !dbg !93 %9 = bitcast i8** %8 to i32 (...)**, !dbg !93 store i32 (...)** %9, i32 (...)*** %7, align 8, !dbg !93 ret void, !dbg !93 } ; CHECK: define void @_ZN1FC1Ev(<{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %1) { ; CHECK: #1 !entry !exit { ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>** $2 = allocate <{0: si32 (...)**, 8: si32, 12: {0: si32}}>*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>** %3 = bitcast $2 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %4 = load %3, align 8 ; CHECK: si8* %5 = bitcast %4 ; CHECK: si8* %6 = ptrshift %5, 1 * 12 ; CHECK: {0: si32}* %7 = bitcast %6 ; CHECK: si32 (...)*** %8 = bitcast %4 ; CHECK: si8** %9 = ptrshift @_ZTV1F, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %10 = bitcast %9 ; CHECK: store %8, %10, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1FC2Ev(%struct.F*, i8**) unnamed_addr #2 align 2 !dbg !116 { %3 = alloca %struct.F*, align 8 %4 = alloca i8**, align 8 store %struct.F* %0, %struct.F** %3, align 8 call void @llvm.dbg.declare(metadata %struct.F** %3, metadata !117, metadata !DIExpression()), !dbg !118 store i8** %1, i8*** %4, align 8 call void @llvm.dbg.declare(metadata i8*** %4, metadata !119, metadata !DIExpression()), !dbg !118 %5 = load %struct.F*, %struct.F** %3, align 8 %6 = load i8**, i8*** %4, align 8 %7 = load i8*, i8** %6, align 8, !dbg !122 %8 = bitcast %struct.F* %5 to i32 (...)***, !dbg !122 %9 = bitcast i8* %7 to i32 (...)**, !dbg !122 store i32 (...)** %9, i32 (...)*** %8, align 8, !dbg !122 ret void, !dbg !122 } ; CHECK: define void @_ZN1FC2Ev(<{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>** $3 = allocate <{0: si32 (...)**, 8: si32, 12: {0: si32}}>*, 1, align 8 ; CHECK: si8*** $4 = allocate si8**, 1, align 8 ; CHECK: store $3, %1, align 8 ; CHECK: store $4, %2, align 8 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>** %5 = bitcast $3 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %6 = load %5, align 8 ; CHECK: si8** %7 = load $4, align 8 ; CHECK: si8* %8 = load %7, align 8 ; CHECK: si32 (...)*** %9 = bitcast %6 ; CHECK: si32 (...)** %10 = bitcast %8 ; CHECK: store %9, %10, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1GC1Ev(%struct.G*) unnamed_addr #2 align 2 !dbg !94 { %2 = alloca %struct.G*, align 8 store %struct.G* %0, %struct.G** %2, align 8 call void @llvm.dbg.declare(metadata %struct.G** %2, metadata !99, metadata !DIExpression()), !dbg !101 %3 = load %struct.G*, %struct.G** %2, align 8 %4 = bitcast %struct.G* %3 to i8*, !dbg !102 %5 = getelementptr inbounds i8, i8* %4, i64 16, !dbg !102 %6 = bitcast i8* %5 to %struct.A*, !dbg !102 %7 = bitcast %struct.G* %3 to i32 (...)***, !dbg !102 %8 = getelementptr inbounds { [3 x i8*] }, { [3 x i8*] }* @_ZTV1G, i32 0, i32 0, i32 3, !dbg !102 %9 = bitcast i8** %8 to i32 (...)**, !dbg !102 store i32 (...)** %9, i32 (...)*** %7, align 8, !dbg !102 ret void, !dbg !102 } ; CHECK: define void @_ZN1GC1Ev({0: si32 (...)**, 8: si8*, 16: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}** $2 = allocate {0: si32 (...)**, 8: si8*, 16: {0: si32}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}** %3 = bitcast $2 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* %4 = load %3, align 8 ; CHECK: si8* %5 = bitcast %4 ; CHECK: si8* %6 = ptrshift %5, 1 * 16 ; CHECK: {0: si32}* %7 = bitcast %6 ; CHECK: si32 (...)*** %8 = bitcast %4 ; CHECK: si8** %9 = ptrshift @_ZTV1G, 24 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %10 = bitcast %9 ; CHECK: store %8, %10, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1GC2Ev(%struct.G*, i8**) unnamed_addr #2 align 2 !dbg !123 { %3 = alloca %struct.G*, align 8 %4 = alloca i8**, align 8 store %struct.G* %0, %struct.G** %3, align 8 call void @llvm.dbg.declare(metadata %struct.G** %3, metadata !124, metadata !DIExpression()), !dbg !125 store i8** %1, i8*** %4, align 8 call void @llvm.dbg.declare(metadata i8*** %4, metadata !126, metadata !DIExpression()), !dbg !125 %5 = load %struct.G*, %struct.G** %3, align 8 %6 = load i8**, i8*** %4, align 8 %7 = load i8*, i8** %6, align 8, !dbg !127 %8 = bitcast %struct.G* %5 to i32 (...)***, !dbg !127 %9 = bitcast i8* %7 to i32 (...)**, !dbg !127 store i32 (...)** %9, i32 (...)*** %8, align 8, !dbg !127 ret void, !dbg !127 } ; CHECK: define void @_ZN1GC2Ev({0: si32 (...)**, 8: si8*, 16: {0: si32}}* %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}** $3 = allocate {0: si32 (...)**, 8: si8*, 16: {0: si32}}*, 1, align 8 ; CHECK: si8*** $4 = allocate si8**, 1, align 8 ; CHECK: store $3, %1, align 8 ; CHECK: store $4, %2, align 8 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}** %5 = bitcast $3 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* %6 = load %5, align 8 ; CHECK: si8** %7 = load $4, align 8 ; CHECK: si8* %8 = load %7, align 8 ; CHECK: si32 (...)*** %9 = bitcast %6 ; CHECK: si32 (...)** %10 = bitcast %8 ; CHECK: store %9, %10, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline nounwind ssp uwtable define linkonce_odr void @_ZN1HC1Ev(%struct.H*) unnamed_addr #2 align 2 !dbg !103 { %2 = alloca %struct.H*, align 8 store %struct.H* %0, %struct.H** %2, align 8 call void @llvm.dbg.declare(metadata %struct.H** %2, metadata !108, metadata !DIExpression()), !dbg !110 %3 = load %struct.H*, %struct.H** %2, align 8 %4 = bitcast %struct.H* %3 to i8*, !dbg !111 %5 = getelementptr inbounds i8, i8* %4, i64 32, !dbg !111 %6 = bitcast i8* %5 to %struct.A*, !dbg !111 %7 = bitcast %struct.H* %3 to %struct.F*, !dbg !111 %8 = getelementptr inbounds [4 x i8*], [4 x i8*]* @_ZTT1H, i64 0, i64 1, !dbg !111 call void @_ZN1FC2Ev(%struct.F* %7, i8** %8) #3, !dbg !111 %9 = bitcast %struct.H* %3 to i8*, !dbg !111 %10 = getelementptr inbounds i8, i8* %9, i64 16, !dbg !111 %11 = bitcast i8* %10 to %struct.G*, !dbg !111 %12 = getelementptr inbounds [4 x i8*], [4 x i8*]* @_ZTT1H, i64 0, i64 2, !dbg !111 call void @_ZN1GC2Ev(%struct.G* %11, i8** %12) #3, !dbg !111 %13 = bitcast %struct.H* %3 to i32 (...)***, !dbg !111 %14 = getelementptr inbounds { [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, i32 0, i32 3, !dbg !111 %15 = bitcast i8** %14 to i32 (...)**, !dbg !111 store i32 (...)** %15, i32 (...)*** %13, align 8, !dbg !111 %16 = bitcast %struct.H* %3 to i8*, !dbg !111 %17 = getelementptr inbounds i8, i8* %16, i64 16, !dbg !111 %18 = bitcast i8* %17 to i32 (...)***, !dbg !111 %19 = getelementptr inbounds { [3 x i8*], [3 x i8*] }, { [3 x i8*], [3 x i8*] }* @_ZTV1H, i32 0, i32 1, i32 3, !dbg !111 %20 = bitcast i8** %19 to i32 (...)**, !dbg !111 store i32 (...)** %20, i32 (...)*** %18, align 8, !dbg !111 ret void, !dbg !111 } ; CHECK: define void @_ZN1HC1Ev({0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}* %1) { ; CHECK: #1 !entry !exit { ; CHECK: {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}** $2 = allocate {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}*, 1, align 8 ; CHECK: store $2, %1, align 8 ; CHECK: {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}** %3 = bitcast $2 ; CHECK: {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}* %4 = load %3, align 8 ; CHECK: si8* %5 = bitcast %4 ; CHECK: si8* %6 = ptrshift %5, 1 * 32 ; CHECK: {0: si32}* %7 = bitcast %6 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* %8 = bitcast %4 ; CHECK: si8** %9 = ptrshift @_ZTT1H, 32 * 0, 8 * 1 ; CHECK: call @_ZN1FC2Ev(%8, %9) ; CHECK: si8* %10 = bitcast %4 ; CHECK: si8* %11 = ptrshift %10, 1 * 16 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* %12 = bitcast %11 ; CHECK: si8** %13 = ptrshift @_ZTT1H, 32 * 0, 8 * 2 ; CHECK: call @_ZN1GC2Ev(%12, %13) ; CHECK: si32 (...)*** %14 = bitcast %4 ; CHECK: si8** %15 = ptrshift @_ZTV1H, 48 * 0, 1 * 0, 8 * 3 ; CHECK: si32 (...)** %16 = bitcast %15 ; CHECK: store %14, %16, align 8 ; CHECK: si8* %17 = bitcast %4 ; CHECK: si8* %18 = ptrshift %17, 1 * 16 ; CHECK: si32 (...)*** %19 = bitcast %18 ; CHECK: si8** %20 = ptrshift @_ZTV1H, 48 * 0, 1 * 24, 8 * 3 ; CHECK: si32 (...)** %21 = bitcast %20 ; CHECK: store %19, %21, align 8 ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: noinline norecurse nounwind ssp uwtable define i32 @main() #0 !dbg !8 { %1 = alloca i32, align 4 %2 = alloca %struct.E, align 8 %3 = alloca %struct.D, align 8 %4 = alloca %struct.F, align 8 %5 = alloca %struct.G, align 8 %6 = alloca %struct.H, align 8 store i32 0, i32* %1, align 4 call void @llvm.dbg.declare(metadata %struct.E* %2, metadata !12, metadata !DIExpression()), !dbg !38 call void @_ZN1EC1Ev(%struct.E* %2) #3, !dbg !38 call void @llvm.dbg.declare(metadata %struct.D* %3, metadata !39, metadata !DIExpression()), !dbg !48 call void @_ZN1DC1Ev(%struct.D* %3) #3, !dbg !48 call void @llvm.dbg.declare(metadata %struct.F* %4, metadata !49, metadata !DIExpression()), !dbg !55 call void @_ZN1FC1Ev(%struct.F* %4) #3, !dbg !55 call void @llvm.dbg.declare(metadata %struct.G* %5, metadata !56, metadata !DIExpression()), !dbg !62 call void @_ZN1GC1Ev(%struct.G* %5) #3, !dbg !62 call void @llvm.dbg.declare(metadata %struct.H* %6, metadata !63, metadata !DIExpression()), !dbg !68 call void @_ZN1HC1Ev(%struct.H* %6) #3, !dbg !68 ret i32 0, !dbg !69 } ; CHECK: define si32 @main() { ; CHECK: #1 !entry !exit { ; CHECK: si32* $1 = allocate si32, 1, align 4 ; CHECK: {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}* $2 = allocate {0: si32 (...)**, 8: {0: si8*}, 16: {0: ui8}, 20: si32, 24: {0: si32}}, 1, align 8 ; CHECK: {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}* $3 = allocate {0: si32 (...)**, 8: {0: ui8}, 12: float, 16: {0: si32}, 24: {0: si8*}}, 1, align 8 ; CHECK: <{0: si32 (...)**, 8: si32, 12: {0: si32}}>* $4 = allocate <{0: si32 (...)**, 8: si32, 12: {0: si32}}>, 1, align 8 ; CHECK: {0: si32 (...)**, 8: si8*, 16: {0: si32}}* $5 = allocate {0: si32 (...)**, 8: si8*, 16: {0: si32}}, 1, align 8 ; CHECK: {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}* $6 = allocate {0: <{0: si32 (...)**, 8: si32}>, 16: {0: si32 (...)**, 8: si8*}, 32: {0: si32}}, 1, align 8 ; CHECK: store $1, 0, align 4 ; CHECK: call @_ZN1EC1Ev($2) ; CHECK: call @_ZN1DC1Ev($3) ; CHECK: call @_ZN1FC1Ev($4) ; CHECK: call @_ZN1GC1Ev($5) ; CHECK: call @_ZN1HC1Ev($6) ; CHECK: return 0 ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 attributes #0 = { noinline norecurse nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "virtual-inheritance.cpp", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 33, type: !9, scopeLine: 33, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{!11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "e", scope: !8, file: !1, line: 34, type: !13) !13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "E", file: !1, line: 13, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !14, vtableHolder: !13, identifier: "_ZTS1E") !14 = !{!15, !19, !25, !30, !33, !34} !15 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !1, line: 1, size: 32, flags: DIFlagTypePassByValue, elements: !17, identifier: "_ZTS1A") !17 = !{!18} !18 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !16, file: !1, line: 2, baseType: !11, size: 32) !19 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !20, offset: 64, extraData: i32 0) !20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "B", file: !1, line: 5, size: 64, flags: DIFlagTypePassByValue, elements: !21, identifier: "_ZTS1B") !21 = !{!22} !22 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !20, file: !1, line: 6, baseType: !23, size: 64) !23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) !24 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !25 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !13, baseType: !26, offset: 128, extraData: i32 0) !26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C", file: !1, line: 9, size: 8, flags: DIFlagTypePassByValue, elements: !27, identifier: "_ZTS1C") !27 = !{!28} !28 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !26, file: !1, line: 10, baseType: !29, size: 8) !29 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) !30 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$E", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64) !32 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: !9, size: 64) !33 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !13, file: !1, line: 14, baseType: !11, size: 32, offset: 160) !34 = !DISubprogram(name: "f", linkageName: "_ZN1E1fEv", scope: !13, file: !1, line: 16, type: !35, scopeLine: 16, containingType: !13, virtualIndex: 0, flags: DIFlagPrototyped, spFlags: DISPFlagVirtual) !35 = !DISubroutineType(types: !36) !36 = !{null, !37} !37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !38 = !DILocation(line: 34, column: 5, scope: !8) !39 = !DILocalVariable(name: "d", scope: !8, file: !1, line: 35, type: !40) !40 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "D", file: !1, line: 19, size: 256, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !41, vtableHolder: !40, identifier: "_ZTS1D") !41 = !{!42, !43, !44, !45, !46} !42 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !40, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !43 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !40, baseType: !20, offset: 32, flags: DIFlagVirtual, extraData: i32 0) !44 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !40, baseType: !26, offset: 64, extraData: i32 0) !45 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$D", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !46 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !40, file: !1, line: 20, baseType: !47, size: 32, offset: 96) !47 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) !48 = !DILocation(line: 35, column: 5, scope: !8) !49 = !DILocalVariable(name: "f", scope: !8, file: !1, line: 36, type: !50) !50 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "F", file: !1, line: 23, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !51, vtableHolder: !50, identifier: "_ZTS1F") !51 = !{!52, !53, !54} !52 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !50, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !53 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$F", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !54 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !50, file: !1, line: 24, baseType: !11, size: 32, offset: 64) !55 = !DILocation(line: 36, column: 5, scope: !8) !56 = !DILocalVariable(name: "g", scope: !8, file: !1, line: 37, type: !57) !57 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "G", file: !1, line: 27, size: 192, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !58, vtableHolder: !57, identifier: "_ZTS1G") !58 = !{!59, !60, !61} !59 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !57, baseType: !16, offset: 24, flags: DIFlagVirtual, extraData: i32 0) !60 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$G", scope: !1, file: !1, baseType: !31, size: 64, flags: DIFlagArtificial) !61 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !57, file: !1, line: 28, baseType: !23, size: 64, offset: 64) !62 = !DILocation(line: 37, column: 5, scope: !8) !63 = !DILocalVariable(name: "h", scope: !8, file: !1, line: 38, type: !64) !64 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "H", file: !1, line: 31, size: 320, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !65, vtableHolder: !50, identifier: "_ZTS1H") !65 = !{!66, !67} !66 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !64, baseType: !50, extraData: i32 0) !67 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !64, baseType: !57, offset: 128, extraData: i32 0) !68 = !DILocation(line: 38, column: 5, scope: !8) !69 = !DILocation(line: 39, column: 3, scope: !8) !70 = distinct !DISubprogram(name: "E", linkageName: "_ZN1EC1Ev", scope: !13, file: !1, line: 13, type: !35, scopeLine: 13, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !71, retainedNodes: !2) !71 = !DISubprogram(name: "E", scope: !13, type: !35, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !72 = !DILocalVariable(name: "this", arg: 1, scope: !70, type: !73, flags: DIFlagArtificial | DIFlagObjectPointer) !73 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) !74 = !DILocation(line: 0, scope: !70) !75 = !DILocation(line: 13, column: 8, scope: !70) !76 = distinct !DISubprogram(name: "D", linkageName: "_ZN1DC1Ev", scope: !40, file: !1, line: 19, type: !77, scopeLine: 19, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !80, retainedNodes: !2) !77 = !DISubroutineType(types: !78) !78 = !{null, !79} !79 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !80 = !DISubprogram(name: "D", scope: !40, type: !77, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !81 = !DILocalVariable(name: "this", arg: 1, scope: !76, type: !82, flags: DIFlagArtificial | DIFlagObjectPointer) !82 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64) !83 = !DILocation(line: 0, scope: !76) !84 = !DILocation(line: 19, column: 8, scope: !76) !85 = distinct !DISubprogram(name: "F", linkageName: "_ZN1FC1Ev", scope: !50, file: !1, line: 23, type: !86, scopeLine: 23, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !89, retainedNodes: !2) !86 = !DISubroutineType(types: !87) !87 = !{null, !88} !88 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !50, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !89 = !DISubprogram(name: "F", scope: !50, type: !86, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !90 = !DILocalVariable(name: "this", arg: 1, scope: !85, type: !91, flags: DIFlagArtificial | DIFlagObjectPointer) !91 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !50, size: 64) !92 = !DILocation(line: 0, scope: !85) !93 = !DILocation(line: 23, column: 8, scope: !85) !94 = distinct !DISubprogram(name: "G", linkageName: "_ZN1GC1Ev", scope: !57, file: !1, line: 27, type: !95, scopeLine: 27, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !98, retainedNodes: !2) !95 = !DISubroutineType(types: !96) !96 = !{null, !97} !97 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !98 = !DISubprogram(name: "G", scope: !57, type: !95, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !99 = !DILocalVariable(name: "this", arg: 1, scope: !94, type: !100, flags: DIFlagArtificial | DIFlagObjectPointer) !100 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64) !101 = !DILocation(line: 0, scope: !94) !102 = !DILocation(line: 27, column: 8, scope: !94) !103 = distinct !DISubprogram(name: "H", linkageName: "_ZN1HC1Ev", scope: !64, file: !1, line: 31, type: !104, scopeLine: 31, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !107, retainedNodes: !2) !104 = !DISubroutineType(types: !105) !105 = !{null, !106} !106 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !64, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) !107 = !DISubprogram(name: "H", scope: !64, type: !104, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: 0) !108 = !DILocalVariable(name: "this", arg: 1, scope: !103, type: !109, flags: DIFlagArtificial | DIFlagObjectPointer) !109 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !64, size: 64) !110 = !DILocation(line: 0, scope: !103) !111 = !DILocation(line: 31, column: 8, scope: !103) !112 = distinct !DISubprogram(name: "f", linkageName: "_ZN1E1fEv", scope: !13, file: !1, line: 16, type: !35, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !34, retainedNodes: !2) !113 = !DILocalVariable(name: "this", arg: 1, scope: !112, type: !73, flags: DIFlagArtificial | DIFlagObjectPointer) !114 = !DILocation(line: 0, scope: !112) !115 = !DILocation(line: 16, column: 21, scope: !112) !116 = distinct !DISubprogram(name: "F", linkageName: "_ZN1FC2Ev", scope: !50, file: !1, line: 23, type: !86, scopeLine: 23, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !89, retainedNodes: !2) !117 = !DILocalVariable(name: "this", arg: 1, scope: !116, type: !91, flags: DIFlagArtificial | DIFlagObjectPointer) !118 = !DILocation(line: 0, scope: !116) !119 = !DILocalVariable(name: "vtt", arg: 2, scope: !116, type: !120, flags: DIFlagArtificial) !120 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !121, size: 64) !121 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) !122 = !DILocation(line: 23, column: 8, scope: !116) !123 = distinct !DISubprogram(name: "G", linkageName: "_ZN1GC2Ev", scope: !57, file: !1, line: 27, type: !95, scopeLine: 27, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, declaration: !98, retainedNodes: !2) !124 = !DILocalVariable(name: "this", arg: 1, scope: !123, type: !100, flags: DIFlagArtificial | DIFlagObjectPointer) !125 = !DILocation(line: 0, scope: !123) !126 = !DILocalVariable(name: "vtt", arg: 2, scope: !123, type: !120, flags: DIFlagArtificial) !127 = !DILocation(line: 27, column: 8, scope: !123) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vla.c000066400000000000000000000003171473507761200302310ustar00rootroot00000000000000#include void foo(int n) { int a[n], i; for (i = 0; i < n; i++) { a[i] = i * i; } a[n] = n * n; } int main(int argc, char** argv) { int v; scanf("%d", &v); foo(v); return 0; } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/import/no_optimization/vla.ll000066400000000000000000000266671473507761200304360ustar00rootroot00000000000000; ModuleID = 'vla.pp.bc' source_filename = "vla.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.14.0" ; CHECK-LABEL: Bundle ; CHECK: target-endianness = little-endian ; CHECK: target-pointer-size = 64 bits ; CHECK: target-triple = x86_64-apple-macosx10.14.0 @.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 ; CHECK: define [3 x si8]* @.str, align 1, init { ; CHECK: #1 !entry !exit { ; CHECK: store @.str, [37, 100, 0], align 1 ; CHECK: } ; CHECK: } declare i32 @scanf(i8*, ...) #3 ; CHECK: declare si32 @ar.libc.scanf(si8*, ...) ; Function Attrs: nounwind declare void @llvm.stackrestore(i8*) #2 ; CHECK: declare void @ar.stackrestore(si8*) ; Function Attrs: nounwind declare i8* @llvm.stacksave() #2 ; CHECK: declare si8* @ar.stacksave() ; Function Attrs: noinline nounwind ssp uwtable define void @foo(i32) #0 !dbg !8 { %2 = alloca i32, align 4 %3 = alloca i8*, align 8 %4 = alloca i64, align 8 %5 = alloca i32, align 4 store i32 %0, i32* %2, align 4 call void @llvm.dbg.declare(metadata i32* %2, metadata !12, metadata !DIExpression()), !dbg !13 %6 = load i32, i32* %2, align 4, !dbg !14 %7 = zext i32 %6 to i64, !dbg !15 %8 = call i8* @llvm.stacksave(), !dbg !15 store i8* %8, i8** %3, align 8, !dbg !15 %9 = alloca i32, i64 %7, align 16, !dbg !15 store i64 %7, i64* %4, align 8, !dbg !15 call void @llvm.dbg.declare(metadata i64* %4, metadata !16, metadata !DIExpression()), !dbg !18 call void @llvm.dbg.declare(metadata i32* %9, metadata !19, metadata !DIExpression()), !dbg !23 call void @llvm.dbg.declare(metadata i32* %5, metadata !24, metadata !DIExpression()), !dbg !25 store i32 0, i32* %5, align 4, !dbg !26 br label %10, !dbg !28 10: ; preds = %21, %1 %11 = load i32, i32* %5, align 4, !dbg !29 %12 = load i32, i32* %2, align 4, !dbg !31 %13 = icmp slt i32 %11, %12, !dbg !32 br i1 %13, label %14, label %24, !dbg !33 14: ; preds = %10 %15 = load i32, i32* %5, align 4, !dbg !34 %16 = load i32, i32* %5, align 4, !dbg !36 %17 = mul nsw i32 %15, %16, !dbg !37 %18 = load i32, i32* %5, align 4, !dbg !38 %19 = sext i32 %18 to i64, !dbg !39 %20 = getelementptr inbounds i32, i32* %9, i64 %19, !dbg !39 store i32 %17, i32* %20, align 4, !dbg !40 br label %21, !dbg !41 21: ; preds = %14 %22 = load i32, i32* %5, align 4, !dbg !42 %23 = add nsw i32 %22, 1, !dbg !42 store i32 %23, i32* %5, align 4, !dbg !42 br label %10, !dbg !43, !llvm.loop !44 24: ; preds = %10 %25 = load i32, i32* %2, align 4, !dbg !46 %26 = load i32, i32* %2, align 4, !dbg !47 %27 = mul nsw i32 %25, %26, !dbg !48 %28 = load i32, i32* %2, align 4, !dbg !49 %29 = sext i32 %28 to i64, !dbg !50 %30 = getelementptr inbounds i32, i32* %9, i64 %29, !dbg !50 store i32 %27, i32* %30, align 4, !dbg !51 %31 = load i8*, i8** %3, align 8, !dbg !52 call void @llvm.stackrestore(i8* %31), !dbg !52 ret void, !dbg !52 } ; CHECK: define void @foo(si32 %1) { ; CHECK: #1 !entry successors={#2} { ; CHECK: si32* $2 = allocate si32, 1, align 4 ; CHECK: si8** $3 = allocate si8*, 1, align 8 ; CHECK: ui64* $4 = allocate ui64, 1, align 8 ; CHECK: si32* $5 = allocate si32, 1, align 4 ; CHECK: store $2, %1, align 4 ; CHECK: ui32* %6 = bitcast $2 ; CHECK: ui32 %7 = load %6, align 4 ; CHECK: ui64 %8 = zext %7 ; CHECK: si8* %9 = call @ar.stacksave() ; CHECK: store $3, %9, align 8 ; CHECK: si32* $10 = allocate si32, %8, align 16 ; CHECK: store $4, %8, align 8 ; CHECK: store $5, 0, align 4 ; CHECK: } ; CHECK: #2 predecessors={#1, #3} successors={#3, #4} { ; CHECK: si32 %11 = load $5, align 4 ; CHECK: si32 %12 = load $2, align 4 ; CHECK: } ; CHECK: #3 predecessors={#2} successors={#2} { ; CHECK: %11 silt %12 ; CHECK: si32 %13 = load $5, align 4 ; CHECK: si32 %14 = load $5, align 4 ; CHECK: si32 %15 = %13 smul.nw %14 ; CHECK: si32 %16 = load $5, align 4 ; CHECK: si64 %17 = sext %16 ; CHECK: si32* %18 = ptrshift $10, 4 * %17 ; CHECK: store %18, %15, align 4 ; CHECK: si32 %19 = load $5, align 4 ; CHECK: si32 %20 = %19 sadd.nw 1 ; CHECK: store $5, %20, align 4 ; CHECK: } ; CHECK: #4 !exit predecessors={#2} { ; CHECK: %11 sige %12 ; CHECK: si32 %21 = load $2, align 4 ; CHECK: si32 %22 = load $2, align 4 ; CHECK: si32 %23 = %21 smul.nw %22 ; CHECK: si32 %24 = load $2, align 4 ; CHECK: si64 %25 = sext %24 ; CHECK: si32* %26 = ptrshift $10, 4 * %25 ; CHECK: store %26, %23, align 4 ; CHECK: si8* %27 = load $3, align 8 ; CHECK: call @ar.stackrestore(%27) ; CHECK: return ; CHECK: } ; CHECK: } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main(i32, i8**) #0 !dbg !53 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 %6 = alloca i32, align 4 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !59, metadata !DIExpression()), !dbg !60 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !61, metadata !DIExpression()), !dbg !62 call void @llvm.dbg.declare(metadata i32* %6, metadata !63, metadata !DIExpression()), !dbg !64 %7 = getelementptr inbounds [3 x i8], [3 x i8]* @.str, i64 0, i64 0, !dbg !65 %8 = call i32 (i8*, ...) @scanf(i8* %7, i32* %6), !dbg !65 %9 = load i32, i32* %6, align 4, !dbg !66 call void @foo(i32 %9), !dbg !67 ret i32 0, !dbg !68 } ; CHECK: define si32 @main(si32 %1, si8** %2) { ; CHECK: #1 !entry !exit { ; CHECK: si32* $3 = allocate si32, 1, align 4 ; CHECK: si32* $4 = allocate si32, 1, align 4 ; CHECK: si8*** $5 = allocate si8**, 1, align 8 ; CHECK: si32* $6 = allocate si32, 1, align 4 ; CHECK: store $3, 0, align 4 ; CHECK: store $4, %1, align 4 ; CHECK: store $5, %2, align 8 ; CHECK: si8* %7 = ptrshift @.str, 3 * 0, 1 * 0 ; CHECK: si32 %8 = call @ar.libc.scanf(%7, $6) ; CHECK: si32 %9 = load $6, align 4 ; CHECK: call @foo(%9) ; CHECK: return 0 ; CHECK: } ; CHECK: } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone speculatable } attributes #2 = { nounwind } attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4, !5, !6} !llvm.ident = !{!7} !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (tags/RELEASE_900/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) !1 = !DIFile(filename: "vla.c", directory: "/Users/marthaud/ikos/ikos-git/frontend/llvm/test/regression/import/no_optimization") !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 4} !6 = !{i32 7, !"PIC Level", i32 2} !7 = !{!"clang version 9.0.0 (tags/RELEASE_900/final)"} !8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !9 = !DISubroutineType(types: !10) !10 = !{null, !11} !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !12 = !DILocalVariable(name: "n", arg: 1, scope: !8, file: !1, line: 2, type: !11) !13 = !DILocation(line: 2, column: 14, scope: !8) !14 = !DILocation(line: 3, column: 9, scope: !8) !15 = !DILocation(line: 3, column: 3, scope: !8) !16 = !DILocalVariable(name: "__vla_expr0", scope: !8, type: !17, flags: DIFlagArtificial) !17 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) !18 = !DILocation(line: 0, scope: !8) !19 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 3, type: !20) !20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, elements: !21) !21 = !{!22} !22 = !DISubrange(count: !16) !23 = !DILocation(line: 3, column: 7, scope: !8) !24 = !DILocalVariable(name: "i", scope: !8, file: !1, line: 3, type: !11) !25 = !DILocation(line: 3, column: 13, scope: !8) !26 = !DILocation(line: 4, column: 10, scope: !27) !27 = distinct !DILexicalBlock(scope: !8, file: !1, line: 4, column: 3) !28 = !DILocation(line: 4, column: 8, scope: !27) !29 = !DILocation(line: 4, column: 15, scope: !30) !30 = distinct !DILexicalBlock(scope: !27, file: !1, line: 4, column: 3) !31 = !DILocation(line: 4, column: 19, scope: !30) !32 = !DILocation(line: 4, column: 17, scope: !30) !33 = !DILocation(line: 4, column: 3, scope: !27) !34 = !DILocation(line: 5, column: 12, scope: !35) !35 = distinct !DILexicalBlock(scope: !30, file: !1, line: 4, column: 27) !36 = !DILocation(line: 5, column: 16, scope: !35) !37 = !DILocation(line: 5, column: 14, scope: !35) !38 = !DILocation(line: 5, column: 7, scope: !35) !39 = !DILocation(line: 5, column: 5, scope: !35) !40 = !DILocation(line: 5, column: 10, scope: !35) !41 = !DILocation(line: 6, column: 3, scope: !35) !42 = !DILocation(line: 4, column: 23, scope: !30) !43 = !DILocation(line: 4, column: 3, scope: !30) !44 = distinct !{!44, !33, !45} !45 = !DILocation(line: 6, column: 3, scope: !27) !46 = !DILocation(line: 7, column: 10, scope: !8) !47 = !DILocation(line: 7, column: 14, scope: !8) !48 = !DILocation(line: 7, column: 12, scope: !8) !49 = !DILocation(line: 7, column: 5, scope: !8) !50 = !DILocation(line: 7, column: 3, scope: !8) !51 = !DILocation(line: 7, column: 8, scope: !8) !52 = !DILocation(line: 8, column: 1, scope: !8) !53 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 10, type: !54, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) !54 = !DISubroutineType(types: !55) !55 = !{!11, !11, !56} !56 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !57, size: 64) !57 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !58, size: 64) !58 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !59 = !DILocalVariable(name: "argc", arg: 1, scope: !53, file: !1, line: 10, type: !11) !60 = !DILocation(line: 10, column: 14, scope: !53) !61 = !DILocalVariable(name: "argv", arg: 2, scope: !53, file: !1, line: 10, type: !56) !62 = !DILocation(line: 10, column: 27, scope: !53) !63 = !DILocalVariable(name: "v", scope: !53, file: !1, line: 11, type: !11) !64 = !DILocation(line: 11, column: 7, scope: !53) !65 = !DILocation(line: 12, column: 3, scope: !53) !66 = !DILocation(line: 13, column: 7, scope: !53) !67 = !DILocation(line: 13, column: 3, scope: !53) !68 = !DILocation(line: 14, column: 3, scope: !53) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/000077500000000000000000000000001473507761200235145ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/CMakeLists.txt000066400000000000000000000022731473507761200262600ustar00rootroot00000000000000# Dependencies to run the tests add_dependencies(build-frontend-llvm-tests ikos-pp) # Try to find bash find_program(BASH_EXECUTABLE CACHE NAMES bash DOC "Path to bash binary") if (NOT BASH_EXECUTABLE) message(WARNING "Could NOT find bash. Tests for ikos-pp are disabled.") endif() # Try to find FileCheck find_program(LLVM_FILE_CHECK_EXECUTABLE CACHE NAMES FileCheck HINTS ${LLVM_TOOLS_BINARY_DIR} DOC "Path to FileCheck binary") if (NOT LLVM_FILE_CHECK_EXECUTABLE) message(WARNING "Could NOT find FileCheck. Tests for ikos-pp are disabled.") endif() function(add_pass_test test_name test_directory) if ((NOT LLVM_FILE_CHECK_EXECUTABLE) OR (NOT BASH_EXECUTABLE)) return() # Skip the test endif() add_test(NAME "pass-${test_name}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${test_directory}" COMMAND ${BASH_EXECUTABLE} runtest --ikos-pp "$" --file-check "${LLVM_FILE_CHECK_EXECUTABLE}") endfunction() add_pass_test(lower-cst-expr lower_cst_expr) add_pass_test(lower-select lower_select) add_pass_test(remove-printf-calls remove_printf_calls) add_pass_test(remove-unreachable-blocks remove_unreachable_blocks) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/000077500000000000000000000000001473507761200265535ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/runtest000077500000000000000000000064341473507761200302140ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing the LowerCstExprPass # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") pass="lower-cst-expr" ikos_pp="ikos-pp" file_check="FileCheck" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h] [--ikos-pp IKOS-PP] [--file-check FILE-CHECK]" echo "" echo "Run regression tests for pass $pass" exit 1 elif [[ "$1" = "--ikos-pp" ]]; then shift ikos_pp=$1 elif [[ "$1" = "--file-check" ]]; then shift file_check=$1 else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-pp if ! command -v "$ikos_pp" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_pp" >&2 exit 2 fi # Check FileCheck if ! command -v "$file_check" >/dev/null 2>&1; then echo "error: $progname: could not find $file_check" >&2 exit 2 fi # Run the tests echo "# Running regression tests for pass $pass" for filename in *.ll do echo -en "$filename ... \r" "$ikos_pp" -opt=custom -$pass -S "$filename" \ | "$file_check" "$filename" \ || { echo "Test Failed"; exit 1; } echo "$filename ... Passed" done echo "All tests passed successfully." exit 0 NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/test-1.ll000066400000000000000000000062571473507761200302330ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" %struct.foo = type { i32 } @x = global i32 6, align 4 @B = common global [10 x i32] zeroinitializer, align 16 define i32 @main(i32 %arg_1, i8** %arg_2) { ; CHECK-LABEL: @main( ; CHECK: %_1 = alloca i32, align 4 ; CHECK: %_2 = alloca i32, align 4 ; CHECK: %_3 = alloca i8**, align 8 ; CHECK: %_4 = alloca [5 x i32], align 16 ; CHECK: %_5 = alloca %struct.foo, align 4 ; CHECK: %_6 = alloca i32, align 4 ; CHECK: store i32 0, i32* %_1, align 4 ; CHECK: store i32 %arg_1, i32* %_2, align 4 ; CHECK: store i8** %arg_2, i8*** %_3, align 8 ; CHECK: %_7 = bitcast [5 x i32]* %_4 to i8* ; CHECK: call void @llvm.memset.p0i8.i64(i8* align 16 %_7, i8 0, i64 20, i1 false) ; CHECK: %_8 = getelementptr inbounds %struct.foo, %struct.foo* %_5, i32 0, i32 0 ; CHECK: store i32 59, i32* %_8, align 4 ; CHECK: %_9 = load i32, i32* @x, align 4 ; CHECK: %_10 = add nsw i32 %_9, 1 ; CHECK: store i32 %_10, i32* @x, align 4 ; CHECK: %0 = getelementptr inbounds [10 x i32], [10 x i32]* @B, i64 0, i64 8 ; CHECK: store i32 23, i32* %0, align 16 ; CHECK: %_11 = load i32, i32* @x, align 4 ; CHECK: %_12 = add nsw i32 %_11, 7 ; CHECK: %_13 = getelementptr inbounds %struct.foo, %struct.foo* %_5, i32 0, i32 0 ; CHECK: %_14 = load i32, i32* %_13, align 4 ; CHECK: %_15 = add nsw i32 %_12, %_14 ; CHECK: %_16 = getelementptr inbounds [5 x i32], [5 x i32]* %_4, i64 0, i64 4 ; CHECK: %_17 = load i32, i32* %_16, align 16 ; CHECK: %_18 = add nsw i32 %_15, %_17 ; CHECK: %1 = getelementptr inbounds [10 x i32], [10 x i32]* @B, i64 0, i64 9 ; CHECK: %_19 = load i32, i32* %1, align 4 ; CHECK: %_20 = add nsw i32 %_18, %_19 ; CHECK: store i32 %_20, i32* %_6, align 4 ; CHECK: %_21 = load i32, i32* %_6, align 4 ; CHECK: ret i32 %_21 bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 %_3 = alloca i8**, align 8 %_4 = alloca [5 x i32], align 16 %_5 = alloca %struct.foo, align 4 %_6 = alloca i32, align 4 store i32 0, i32* %_1, align 4 store i32 %arg_1, i32* %_2, align 4 store i8** %arg_2, i8*** %_3, align 8 %_7 = bitcast [5 x i32]* %_4 to i8* call void @llvm.memset.p0i8.i64(i8* align 16 %_7, i8 0, i64 20, i1 false) %_8 = getelementptr inbounds %struct.foo, %struct.foo* %_5, i32 0, i32 0 store i32 59, i32* %_8, align 4 %_9 = load i32, i32* @x, align 4 %_10 = add nsw i32 %_9, 1 store i32 %_10, i32* @x, align 4 store i32 23, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @B, i64 0, i64 8), align 16 %_11 = load i32, i32* @x, align 4 %_12 = add nsw i32 %_11, 7 %_13 = getelementptr inbounds %struct.foo, %struct.foo* %_5, i32 0, i32 0 %_14 = load i32, i32* %_13, align 4 %_15 = add nsw i32 %_12, %_14 %_16 = getelementptr inbounds [5 x i32], [5 x i32]* %_4, i64 0, i64 4 %_17 = load i32, i32* %_16, align 16 %_18 = add nsw i32 %_15, %_17 %_19 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @B, i64 0, i64 9), align 4 %_20 = add nsw i32 %_18, %_19 store i32 %_20, i32* %_6, align 4 %_21 = load i32, i32* %_6, align 4 ret i32 %_21 } ; Function Attrs: argmemonly nounwind declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #0 attributes #0 = { argmemonly nounwind } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/test-2.ll000066400000000000000000000071121473507761200302230ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 define i32 @main(i32 %arg_1, i8** %arg_2) { bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 %_3 = alloca i8**, align 8 %_4 = alloca i32, align 4 %_5 = alloca i32, align 4 %_6 = alloca [10 x [10 x i32]], align 16 store i32 0, i32* %_1, align 4 store i32 %arg_1, i32* %_2, align 4 store i8** %arg_2, i8*** %_3, align 8 store i32 0, i32* %_4, align 4 br label %bb_2 bb_2: ; preds = %bb_8, %bb_1 %_7 = load i32, i32* %_4, align 4 %_8 = icmp slt i32 %_7, 10 br i1 %_8, label %bb_3, label %bb_9 bb_3: ; preds = %bb_2 store i32 0, i32* %_5, align 4 br label %bb_4 bb_4: ; preds = %bb_6, %bb_3 %_9 = load i32, i32* %_5, align 4 %_10 = icmp slt i32 %_9, 10 br i1 %_10, label %bb_5, label %bb_7 bb_5: ; preds = %bb_4 %_11 = load i32, i32* %_2, align 4 %_12 = load i32, i32* %_4, align 4 %_13 = sext i32 %_12 to i64 %_14 = getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* %_6, i64 0, i64 %_13 %_15 = load i32, i32* %_5, align 4 %_16 = sext i32 %_15 to i64 %_17 = getelementptr inbounds [10 x i32], [10 x i32]* %_14, i64 0, i64 %_16 store i32 %_11, i32* %_17, align 4 br label %bb_6 bb_6: ; preds = %bb_5 %_18 = load i32, i32* %_5, align 4 %_19 = add nsw i32 %_18, 1 store i32 %_19, i32* %_5, align 4 br label %bb_4 bb_7: ; preds = %bb_4 br label %bb_8 bb_8: ; preds = %bb_7 %_20 = load i32, i32* %_4, align 4 %_21 = add nsw i32 %_20, 1 store i32 %_21, i32* %_4, align 4 br label %bb_2 bb_9: ; preds = %bb_2 store i32 0, i32* %_4, align 4 br label %bb_10 bb_10: ; preds = %bb_12, %bb_9 %_22 = load i32, i32* %_4, align 4 %_23 = icmp slt i32 %_22, 10 br i1 %_23, label %bb_11, label %bb_13 bb_11: ; preds = %bb_10 ; CHECK-LABEL: bb_11: ; CHECK: %_24 = load i32, i32* %_4, align 4 ; CHECK: %_25 = sext i32 %_24 to i64 ; CHECK: %_26 = getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* %_6, i64 0, i64 %_25 ; CHECK: %_27 = load i32, i32* %_4, align 4 ; CHECK: %_28 = sext i32 %_27 to i64 ; CHECK: %_29 = getelementptr inbounds [10 x i32], [10 x i32]* %_26, i64 0, i64 %_28 ; CHECK: %_30 = load i32, i32* %_29, align 4 ; CHECK: %0 = getelementptr inbounds [4 x i8], [4 x i8]* @.str, i32 0, i32 0 ; CHECK: %_31 = call i32 (i8*, ...) @printf(i8* %0, i32 %_30) ; CHECK: br label %bb_12 %_24 = load i32, i32* %_4, align 4 %_25 = sext i32 %_24 to i64 %_26 = getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* %_6, i64 0, i64 %_25 %_27 = load i32, i32* %_4, align 4 %_28 = sext i32 %_27 to i64 %_29 = getelementptr inbounds [10 x i32], [10 x i32]* %_26, i64 0, i64 %_28 %_30 = load i32, i32* %_29, align 4 %_31 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %_30) br label %bb_12 bb_12: ; preds = %bb_11 %_32 = load i32, i32* %_4, align 4 %_33 = add nsw i32 %_32, 1 store i32 %_33, i32* %_4, align 4 br label %bb_10 bb_13: ; preds = %bb_10 ret i32 0 } declare i32 @printf(i8*, ...) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/test-3.ll000066400000000000000000000053731473507761200302330ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @p = common global [2 x [2 x [2 x i32]]] zeroinitializer, align 16 define void @kalman_global() { ; CHECK-LABEL: @kalman_global( ; CHECK: %0 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 0, i64 0 ; CHECK: store i32 1, i32* %0, align 16 ; CHECK: %1 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 0, i64 1 ; CHECK: store i32 1, i32* %1, align 4 ; CHECK: %2 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 1, i64 0 ; CHECK: store i32 1, i32* %2, align 8 ; CHECK: %3 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 1, i64 1 ; CHECK: store i32 1, i32* %3, align 4 ; CHECK: %4 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 0, i64 0 ; CHECK: store i32 1, i32* %4, align 16 ; CHECK: %5 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 0, i64 1 ; CHECK: store i32 1, i32* %5, align 4 ; CHECK: %6 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 1, i64 0 ; CHECK: store i32 1, i32* %6, align 8 ; CHECK: %7 = getelementptr inbounds [2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 1, i64 1 ; CHECK: store i32 1, i32* %7, align 4 ; CHECK: ret void bb_1: store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 0, i64 0), align 16 store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 0, i64 1), align 4 store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 1, i64 0), align 8 store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 0, i64 1, i64 1), align 4 store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 0, i64 0), align 16 store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 0, i64 1), align 4 store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 1, i64 0), align 8 store i32 1, i32* getelementptr inbounds ([2 x [2 x [2 x i32]]], [2 x [2 x [2 x i32]]]* @p, i64 0, i64 1, i64 1, i64 1), align 4 ret void } define i32 @main(i32 %arg_1, i8** %arg_2) { bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 %_3 = alloca i8**, align 8 store i32 0, i32* %_1, align 4 store i32 %arg_1, i32* %_2, align 4 store i8** %arg_2, i8*** %_3, align 8 call void @kalman_global() ret i32 0 } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/test-4.ll000066400000000000000000000270501473507761200302300ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" %struct.__va_list_tag = type { i32, i32, i8*, i8* } @.str = private unnamed_addr constant [11 x i8] c"string %s\0A\00", align 1 @.str.1 = private unnamed_addr constant [8 x i8] c"int %d\0A\00", align 1 @.str.2 = private unnamed_addr constant [9 x i8] c"char %c\0A\00", align 1 @.str.3 = private unnamed_addr constant [11 x i8] c"double %f\0A\00", align 1 @.str.4 = private unnamed_addr constant [5 x i8] c"sdcd\00", align 1 @.str.5 = private unnamed_addr constant [10 x i8] c"my string\00", align 1 ; Function Attrs: noinline nounwind ssp uwtable define void @foo(i8* %arg_1, ...) #0 { bb_1: %_1 = alloca i8*, align 8 %_2 = alloca [1 x %struct.__va_list_tag], align 16 %_3 = alloca i32, align 4 %_4 = alloca i8, align 1 %_5 = alloca i8*, align 8 %_6 = alloca double, align 8 store i8* %arg_1, i8** %_1, align 8 %_7 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %_2, i32 0, i32 0 %_8 = bitcast %struct.__va_list_tag* %_7 to i8* call void @llvm.va_start(i8* %_8) br label %bb_2 bb_2: ; preds = %bb_21, %bb_1 %_9 = load i8*, i8** %_1, align 8 %_10 = load i8, i8* %_9, align 1 %_11 = icmp ne i8 %_10, 0 br i1 %_11, label %bb_3, label %bb_22 bb_3: ; preds = %bb_2 %_12 = load i8*, i8** %_1, align 8 %_13 = getelementptr inbounds i8, i8* %_12, i32 1 store i8* %_13, i8** %_1, align 8 %_14 = load i8, i8* %_12, align 1 %_15 = sext i8 %_14 to i32 switch i32 %_15, label %bb_20 [ i32 115, label %bb_4 i32 100, label %bb_8 i32 99, label %bb_12 i32 102, label %bb_16 ] bb_4: ; preds = %bb_3 %_16 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %_2, i32 0, i32 0 %_17 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_16, i32 0, i32 0 %_18 = load i32, i32* %_17, align 16 %_19 = icmp ule i32 %_18, 40 br i1 %_19, label %bb_5, label %bb_6 bb_5: ; preds = %bb_4 %_20 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_16, i32 0, i32 3 %_21 = load i8*, i8** %_20, align 16 %_22 = getelementptr i8, i8* %_21, i32 %_18 %_23 = bitcast i8* %_22 to i8** %_24 = add i32 %_18, 8 store i32 %_24, i32* %_17, align 16 br label %bb_7 bb_6: ; preds = %bb_4 %_25 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_16, i32 0, i32 2 %_26 = load i8*, i8** %_25, align 8 %_27 = bitcast i8* %_26 to i8** %_28 = getelementptr i8, i8* %_26, i32 8 store i8* %_28, i8** %_25, align 8 br label %bb_7 bb_7: ; preds = %bb_6, %bb_5 ; CHECK-LABEL: bb_7: ; CHECK: %_29 = phi i8** [ %_23, %bb_5 ], [ %_27, %bb_6 ] ; CHECK: %_30 = load i8*, i8** %_29, align 8 ; CHECK: store i8* %_30, i8** %_5, align 8 ; CHECK: %_31 = load i8*, i8** %_5, align 8 ; CHECK: %0 = getelementptr inbounds [11 x i8], [11 x i8]* @.str, i32 0, i32 0 ; CHECK: %_32 = call i32 (i8*, ...) @printf(i8* %0, i8* %_31) ; CHECK: br label %bb_21 %_29 = phi i8** [ %_23, %bb_5 ], [ %_27, %bb_6 ] %_30 = load i8*, i8** %_29, align 8 store i8* %_30, i8** %_5, align 8 %_31 = load i8*, i8** %_5, align 8 %_32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i8* %_31) br label %bb_21 bb_8: ; preds = %bb_3 %_33 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %_2, i32 0, i32 0 %_34 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_33, i32 0, i32 0 %_35 = load i32, i32* %_34, align 16 %_36 = icmp ule i32 %_35, 40 br i1 %_36, label %bb_9, label %bb_10 bb_9: ; preds = %bb_8 %_37 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_33, i32 0, i32 3 %_38 = load i8*, i8** %_37, align 16 %_39 = getelementptr i8, i8* %_38, i32 %_35 %_40 = bitcast i8* %_39 to i32* %_41 = add i32 %_35, 8 store i32 %_41, i32* %_34, align 16 br label %bb_11 bb_10: ; preds = %bb_8 %_42 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_33, i32 0, i32 2 %_43 = load i8*, i8** %_42, align 8 %_44 = bitcast i8* %_43 to i32* %_45 = getelementptr i8, i8* %_43, i32 8 store i8* %_45, i8** %_42, align 8 br label %bb_11 bb_11: ; preds = %bb_10, %bb_9 ; CHECK-LABEL: bb_11: ; CHECK: %_46 = phi i32* [ %_40, %bb_9 ], [ %_44, %bb_10 ] ; CHECK: %_47 = load i32, i32* %_46, align 4 ; CHECK: store i32 %_47, i32* %_3, align 4 ; CHECK: %_48 = load i32, i32* %_3, align 4 ; CHECK: %1 = getelementptr inbounds [8 x i8], [8 x i8]* @.str.1, i32 0, i32 0 ; CHECK: %_49 = call i32 (i8*, ...) @printf(i8* %1, i32 %_48) ; CHECK: br label %bb_21 %_46 = phi i32* [ %_40, %bb_9 ], [ %_44, %bb_10 ] %_47 = load i32, i32* %_46, align 4 store i32 %_47, i32* %_3, align 4 %_48 = load i32, i32* %_3, align 4 %_49 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i32 0, i32 0), i32 %_48) br label %bb_21 bb_12: ; preds = %bb_3 %_50 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %_2, i32 0, i32 0 %_51 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_50, i32 0, i32 0 %_52 = load i32, i32* %_51, align 16 %_53 = icmp ule i32 %_52, 40 br i1 %_53, label %bb_13, label %bb_14 bb_13: ; preds = %bb_12 %_54 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_50, i32 0, i32 3 %_55 = load i8*, i8** %_54, align 16 %_56 = getelementptr i8, i8* %_55, i32 %_52 %_57 = bitcast i8* %_56 to i32* %_58 = add i32 %_52, 8 store i32 %_58, i32* %_51, align 16 br label %bb_15 bb_14: ; preds = %bb_12 %_59 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_50, i32 0, i32 2 %_60 = load i8*, i8** %_59, align 8 %_61 = bitcast i8* %_60 to i32* %_62 = getelementptr i8, i8* %_60, i32 8 store i8* %_62, i8** %_59, align 8 br label %bb_15 bb_15: ; preds = %bb_14, %bb_13 ; CHECK-LABEL: bb_15: ; CHECK: %_63 = phi i32* [ %_57, %bb_13 ], [ %_61, %bb_14 ] ; CHECK: %_64 = load i32, i32* %_63, align 4 ; CHECK: %_65 = trunc i32 %_64 to i8 ; CHECK: store i8 %_65, i8* %_4, align 1 ; CHECK: %_66 = load i8, i8* %_4, align 1 ; CHECK: %_67 = sext i8 %_66 to i32 ; CHECK: %2 = getelementptr inbounds [9 x i8], [9 x i8]* @.str.2, i32 0, i32 0 ; CHECK: %_68 = call i32 (i8*, ...) @printf(i8* %2, i32 %_67) ; CHECK: br label %bb_21 %_63 = phi i32* [ %_57, %bb_13 ], [ %_61, %bb_14 ] %_64 = load i32, i32* %_63, align 4 %_65 = trunc i32 %_64 to i8 store i8 %_65, i8* %_4, align 1 %_66 = load i8, i8* %_4, align 1 %_67 = sext i8 %_66 to i32 %_68 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.2, i32 0, i32 0), i32 %_67) br label %bb_21 bb_16: ; preds = %bb_3 %_69 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %_2, i32 0, i32 0 %_70 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_69, i32 0, i32 1 %_71 = load i32, i32* %_70, align 4 %_72 = icmp ule i32 %_71, 160 br i1 %_72, label %bb_17, label %bb_18 bb_17: ; preds = %bb_16 %_73 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_69, i32 0, i32 3 %_74 = load i8*, i8** %_73, align 16 %_75 = getelementptr i8, i8* %_74, i32 %_71 %_76 = bitcast i8* %_75 to double* %_77 = add i32 %_71, 16 store i32 %_77, i32* %_70, align 4 br label %bb_19 bb_18: ; preds = %bb_16 %_78 = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %_69, i32 0, i32 2 %_79 = load i8*, i8** %_78, align 8 %_80 = bitcast i8* %_79 to double* %_81 = getelementptr i8, i8* %_79, i32 8 store i8* %_81, i8** %_78, align 8 br label %bb_19 bb_19: ; preds = %bb_18, %bb_17 ; CHECK-LABEL: bb_19: ; CHECK: %_82 = phi double* [ %_76, %bb_17 ], [ %_80, %bb_18 ] ; CHECK: %_83 = load double, double* %_82, align 8 ; CHECK: store double %_83, double* %_6, align 8 ; CHECK: %_84 = load double, double* %_6, align 8 ; CHECK: %3 = getelementptr inbounds [11 x i8], [11 x i8]* @.str.3, i32 0, i32 0 ; CHECK: %_85 = call i32 (i8*, ...) @printf(i8* %3, double %_84) ; CHECK: br label %bb_21 %_82 = phi double* [ %_76, %bb_17 ], [ %_80, %bb_18 ] %_83 = load double, double* %_82, align 8 store double %_83, double* %_6, align 8 %_84 = load double, double* %_6, align 8 %_85 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.3, i32 0, i32 0), double %_84) br label %bb_21 bb_20: ; preds = %bb_3 br label %bb_21 bb_21: ; preds = %bb_20, %bb_19, %bb_15, %bb_11, %bb_7 br label %bb_2 bb_22: ; preds = %bb_2 %_86 = getelementptr inbounds [1 x %struct.__va_list_tag], [1 x %struct.__va_list_tag]* %_2, i32 0, i32 0 %_87 = bitcast %struct.__va_list_tag* %_86 to i8* call void @llvm.va_end(i8* %_87) ret void } ; Function Attrs: nounwind readnone declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 ; Function Attrs: nounwind declare void @llvm.va_start(i8*) #2 declare i32 @printf(i8*, ...) #3 ; Function Attrs: nounwind declare void @llvm.va_end(i8*) #2 ; Function Attrs: noinline nounwind ssp uwtable define i32 @main() #0 { bb_1: ; CHECK-LABEL: @main( ; CHECK: %_1 = alloca i32, align 4 ; CHECK: store i32 0, i32* %_1, align 4 ; CHECK: %0 = getelementptr inbounds [5 x i8], [5 x i8]* @.str.4, i32 0, i32 0 ; CHECK: %1 = getelementptr inbounds [10 x i8], [10 x i8]* @.str.5, i32 0, i32 0 ; CHECK: call void (i8*, ...) @foo(i8* %0, i8* %1, i32 1, i32 97, i32 3, double 1.123000e+00) ; CHECK: ret i32 0 %_1 = alloca i32, align 4 store i32 0, i32* %_1, align 4 call void (i8*, ...) @foo(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.5, i32 0, i32 0), i32 1, i32 97, i32 3, double 1.123000e+00) ret i32 0 } attributes #0 = { noinline nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone } attributes #2 = { nounwind } attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/test-5.ll000066400000000000000000000106301473507761200302250ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @main.STRING_MAP = internal constant [6 x i8*] [i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.3, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.4, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.5, i32 0, i32 0)], align 16 @.str = private unnamed_addr constant [10 x i8] c"brown-out\00", align 1 @.str.1 = private unnamed_addr constant [23 x i8] c"configuration mismatch\00", align 1 @.str.2 = private unnamed_addr constant [13 x i8] c"master clear\00", align 1 @.str.3 = private unnamed_addr constant [9 x i8] c"power on\00", align 1 @.str.4 = private unnamed_addr constant [9 x i8] c"software\00", align 1 @.str.5 = private unnamed_addr constant [17 x i8] c"watchdog timeout\00", align 1 @.str.6 = private unnamed_addr constant [8 x i8] c"unknown\00", align 1 @.str.7 = private unnamed_addr constant [33 x i8] c"The cause of the last reset was \00", align 1 @.str.8 = private unnamed_addr constant [22 x i8] c"../../src/init/init.c\00", align 1 @.str.9 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 define i32 @main(i32 %arg_1, i8** %arg_2) { bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 %_3 = alloca i8**, align 8 %_4 = alloca i32, align 4 %_5 = alloca i8*, align 8 %_6 = alloca [55 x i8], align 16 store i32 0, i32* %_1, align 4 store i32 %arg_1, i32* %_2, align 4 store i8** %arg_2, i8*** %_3, align 8 %_7 = call i32 (...) @bsp_reset_get() store i32 %_7, i32* %_4, align 4 %_8 = load i32, i32* %_4, align 4 %_9 = icmp ule i32 0, %_8 br i1 %_9, label %bb_2, label %bb_4 bb_2: ; preds = %bb_1 %_10 = load i32, i32* %_4, align 4 %_11 = icmp ult i32 %_10, 6 br i1 %_11, label %bb_3, label %bb_4 bb_3: ; preds = %bb_2 %_12 = load i32, i32* %_4, align 4 %_13 = zext i32 %_12 to i64 %_14 = getelementptr inbounds [6 x i8*], [6 x i8*]* @main.STRING_MAP, i64 0, i64 %_13 %_15 = load i8*, i8** %_14, align 8 br label %bb_5 bb_4: ; preds = %bb_2, %bb_1 ; CHECK-LABEL: bb_4: ; CHECK: %0 = getelementptr inbounds [8 x i8], [8 x i8]* @.str.6, i32 0, i32 0 ; CHECK: br label %bb_5 br label %bb_5 bb_5: ; preds = %bb_4, %bb_3 ; CHECK-LABEL: bb_5: ; CHECK: %_16 = phi i8* [ %_15, %bb_3 ], [ %0, %bb_4 ] ; CHECK: store i8* %_16, i8** %_5, align 8 ; CHECK: %_17 = getelementptr inbounds [55 x i8], [55 x i8]* %_6, i32 0, i32 0 ; CHECK: %1 = getelementptr inbounds [33 x i8], [33 x i8]* @.str.7, i32 0, i32 0 ; CHECK: %_18 = call i8* @__strcpy_chk(i8* %_17, i8* %1, i64 55) ; CHECK: %_19 = getelementptr inbounds [55 x i8], [55 x i8]* %_6, i32 0, i32 0 ; CHECK: %_20 = load i8*, i8** %_5, align 8 ; CHECK: %_21 = call i8* @__strcat_chk(i8* %_19, i8* %_20, i64 55) ; CHECK: %_22 = getelementptr inbounds [55 x i8], [55 x i8]* %_6, i32 0, i32 0 ; CHECK: %2 = getelementptr inbounds [22 x i8], [22 x i8]* @.str.8, i32 0, i32 0 ; CHECK: %3 = getelementptr inbounds [1 x i8], [1 x i8]* @.str.9, i32 0, i32 0 ; CHECK: call void (i32, i8*, i32, i8*, ...) @util_log(i32 1, i8* %2, i32 356, i8* %_22, i8* %3) ; CHECK: ret i32 0 %_16 = phi i8* [ %_15, %bb_3 ], [ getelementptr inbounds ([8 x i8], [8 x i8]* @.str.6, i32 0, i32 0), %bb_4 ] store i8* %_16, i8** %_5, align 8 %_17 = getelementptr inbounds [55 x i8], [55 x i8]* %_6, i32 0, i32 0 %_18 = call i8* @__strcpy_chk(i8* %_17, i8* getelementptr inbounds ([33 x i8], [33 x i8]* @.str.7, i32 0, i32 0), i64 55) #4 %_19 = getelementptr inbounds [55 x i8], [55 x i8]* %_6, i32 0, i32 0 %_20 = load i8*, i8** %_5, align 8 %_21 = call i8* @__strcat_chk(i8* %_19, i8* %_20, i64 55) #4 %_22 = getelementptr inbounds [55 x i8], [55 x i8]* %_6, i32 0, i32 0 call void (i32, i8*, i32, i8*, ...) @util_log(i32 1, i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.8, i32 0, i32 0), i32 356, i8* %_22, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.9, i32 0, i32 0)) ret i32 0 } declare i32 @bsp_reset_get(...) declare i8* @__strcpy_chk(i8*, i8*, i64) declare i8* @__strcat_chk(i8*, i8*, i64) declare void @util_log(i32, i8*, i32, i8*, ...) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/test-6.ll000066400000000000000000000055631473507761200302370ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" %struct.foo = type { i8, i64, i8, %struct.bar } %struct.bar = type { i32, i8 } @x = common global %struct.foo zeroinitializer, align 8 define i32 @main() { bb_1: ; CHECK-LABEL: bb_1: ; CHECK: %_1 = alloca i32, align 4 ; CHECK: store i32 0, i32* %_1, align 4 ; CHECK: %0 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 0 ; CHECK: store i8 5, i8* %0, align 8 ; CHECK: %1 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 1 ; CHECK: store i64 2000, i64* %1, align 8 ; CHECK: %2 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 2 ; CHECK: store i8 10, i8* %2, align 8 ; CHECK: %3 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 3, i32 0 ; CHECK: store i32 32, i32* %3, align 4 ; CHECK: %4 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 3, i32 1 ; CHECK: store i8 5, i8* %4, align 4 ; CHECK: %5 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 3, i32 0 ; CHECK: %_2 = load i32, i32* %5, align 4 ; CHECK: %_3 = icmp sgt i32 %_2, 0 ; CHECK: br i1 %_3, label %bb_2, label %bb_3 %_1 = alloca i32, align 4 store i32 0, i32* %_1, align 4 store i8 5, i8* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 0), align 8 store i64 2000, i64* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 1), align 8 store i8 10, i8* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 2), align 8 store i32 32, i32* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 3, i32 0), align 4 store i8 5, i8* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 3, i32 1), align 4 %_2 = load i32, i32* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 3, i32 0), align 4 %_3 = icmp sgt i32 %_2, 0 br i1 %_3, label %bb_2, label %bb_3 bb_2: ; preds = %bb_1 ; CHECK-LABEL: bb_2: ; CHECK: %6 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 3, i32 0 ; CHECK: %_4 = load i32, i32* %6, align 4 ; CHECK: %7 = getelementptr inbounds %struct.foo, %struct.foo* @x, i32 0, i32 2 ; CHECK: %_5 = load i8, i8* %7, align 8 ; CHECK: %_6 = zext i8 %_5 to i32 ; CHECK: %_7 = add nsw i32 %_4, %_6 ; CHECK: %_8 = icmp eq i32 %_7, 42 ; CHECK: %_9 = zext i1 %_8 to i32 ; CHECK: call void @__ikos_assert(i32 %_9) ; CHECK: br label %bb_3 %_4 = load i32, i32* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 3, i32 0), align 4 %_5 = load i8, i8* getelementptr inbounds (%struct.foo, %struct.foo* @x, i32 0, i32 2), align 8 %_6 = zext i8 %_5 to i32 %_7 = add nsw i32 %_4, %_6 %_8 = icmp eq i32 %_7, 42 %_9 = zext i1 %_8 to i32 call void @__ikos_assert(i32 %_9) br label %bb_3 bb_3: ; preds = %bb_2, %bb_1 ret i32 42 } declare void @__ikos_assert(i32) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_cst_expr/test-7.ll000066400000000000000000000074731473507761200302420ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" %union.anon = type { %struct.anon.0 } %struct.anon.0 = type { i16, i16 } %struct.anon = type { i8, i8, i8, i8 } @regs = internal global %union.anon zeroinitializer, align 2 define i32 @main() { bb_1: ; CHECK-LABEL: bb_1: ; CHECK: %_1 = alloca i32, align 4 ; CHECK: store i32 0, i32* %_1, align 4 ; CHECK: %0 = getelementptr inbounds %union.anon, %union.anon* @regs, i32 0, i32 0, i32 0 ; CHECK: store i16 5, i16* %0, align 2 ; CHECK: %1 = bitcast %union.anon* @regs to %struct.anon* ; CHECK: %2 = getelementptr inbounds %struct.anon, %struct.anon* %1, i32 0, i32 1 ; CHECK: %_2 = load i8, i8* %2, align 1 ; CHECK: %_3 = icmp ne i8 %_2, 0 ; CHECK: br i1 %_3, label %bb_3, label %bb_2 %_1 = alloca i32, align 4 store i32 0, i32* %_1, align 4 store i16 5, i16* getelementptr inbounds (%union.anon, %union.anon* @regs, i32 0, i32 0, i32 0), align 2 %_2 = load i8, i8* getelementptr inbounds (%struct.anon, %struct.anon* bitcast (%union.anon* @regs to %struct.anon*), i32 0, i32 1), align 1 %_3 = icmp ne i8 %_2, 0 br i1 %_3, label %bb_3, label %bb_2 bb_2: ; preds = %bb_1 ; CHECK-LABEL: bb_2: ; CHECK: %3 = bitcast %union.anon* @regs to %struct.anon* ; CHECK: %4 = getelementptr inbounds %struct.anon, %struct.anon* %3, i32 0, i32 0 ; CHECK: %_4 = load i8, i8* %4, align 2 ; CHECK: %5 = bitcast %union.anon* @regs to %struct.anon* ; CHECK: %6 = getelementptr inbounds %struct.anon, %struct.anon* %5, i32 0, i32 2 ; CHECK: store i8 %_4, i8* %6, align 2 ; CHECK: br label %bb_4 %_4 = load i8, i8* getelementptr inbounds (%struct.anon, %struct.anon* bitcast (%union.anon* @regs to %struct.anon*), i32 0, i32 0), align 2 store i8 %_4, i8* getelementptr inbounds (%struct.anon, %struct.anon* bitcast (%union.anon* @regs to %struct.anon*), i32 0, i32 2), align 2 br label %bb_4 bb_3: ; preds = %bb_1 ; CHECK-LABEL: bb_3: ; CHECK: %7 = bitcast %union.anon* @regs to %struct.anon* ; CHECK: %8 = getelementptr inbounds %struct.anon, %struct.anon* %7, i32 0, i32 0 ; CHECK: %_5 = load i8, i8* %8, align 2 ; CHECK: %9 = bitcast %union.anon* @regs to %struct.anon* ; CHECK: %10 = getelementptr inbounds %struct.anon, %struct.anon* %9, i32 0, i32 3 ; CHECK: store i8 %_5, i8* %10, align 1 ; CHECK: br label %bb_4 %_5 = load i8, i8* getelementptr inbounds (%struct.anon, %struct.anon* bitcast (%union.anon* @regs to %struct.anon*), i32 0, i32 0), align 2 store i8 %_5, i8* getelementptr inbounds (%struct.anon, %struct.anon* bitcast (%union.anon* @regs to %struct.anon*), i32 0, i32 3), align 1 br label %bb_4 bb_4: ; preds = %bb_3, %bb_2 ; CHECK-LABEL: bb_4: ; CHECK: %11 = getelementptr inbounds %union.anon, %union.anon* @regs, i32 0, i32 0, i32 0 ; CHECK: %_6 = load i16, i16* %11, align 2 ; CHECK: %_7 = zext i16 %_6 to i32 ; CHECK: %_8 = icmp eq i32 %_7, 5 ; CHECK: %_9 = zext i1 %_8 to i32 ; CHECK: call void @__ikos_assert(i32 %_9) ; CHECK: %12 = getelementptr inbounds %union.anon, %union.anon* @regs, i32 0, i32 0, i32 1 ; CHECK: %_10 = load i16, i16* %12, align 2 ; CHECK: %_11 = zext i16 %_10 to i32 ; CHECK: %_12 = icmp eq i32 %_11, 5 ; CHECK: %_13 = zext i1 %_12 to i32 ; CHECK: call void @__ikos_assert(i32 %_13) ; CHECK: ret i32 0 %_6 = load i16, i16* getelementptr inbounds (%union.anon, %union.anon* @regs, i32 0, i32 0, i32 0), align 2 %_7 = zext i16 %_6 to i32 %_8 = icmp eq i32 %_7, 5 %_9 = zext i1 %_8 to i32 call void @__ikos_assert(i32 %_9) %_10 = load i16, i16* getelementptr inbounds (%union.anon, %union.anon* @regs, i32 0, i32 0, i32 1), align 2 %_11 = zext i16 %_10 to i32 %_12 = icmp eq i32 %_11, 5 %_13 = zext i1 %_12 to i32 call void @__ikos_assert(i32 %_13) ret i32 0 } declare void @__ikos_assert(i32) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_select/000077500000000000000000000000001473507761200262035ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_select/runtest000077500000000000000000000064301473507761200276400ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing the LowerSelectPass # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") pass="lower-select" ikos_pp="ikos-pp" file_check="FileCheck" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h] [--ikos-pp IKOS-PP] [--file-check FILE-CHECK]" echo "" echo "Run regression tests for pass $pass" exit 1 elif [[ "$1" = "--ikos-pp" ]]; then shift ikos_pp=$1 elif [[ "$1" = "--file-check" ]]; then shift file_check=$1 else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-pp if ! command -v "$ikos_pp" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_pp" >&2 exit 2 fi # Check FileCheck if ! command -v "$file_check" >/dev/null 2>&1; then echo "error: $progname: could not find $file_check" >&2 exit 2 fi # Run the tests echo "# Running regression tests for pass $pass" for filename in *.ll do echo -en "$filename ... \r" "$ikos_pp" -opt=custom -$pass -S "$filename" \ | "$file_check" "$filename" \ || { echo "Test Failed"; exit 1; } echo "$filename ... Passed" done echo "All tests passed successfully." exit 0 NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_select/test-1.ll000066400000000000000000000113071473507761200276530ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" define internal fastcc i32 @foo(float* %arg_1, i32 %arg_2, float %arg_3) unnamed_addr { bb_1: %_1 = add nsw i32 %arg_2, -1 %_2 = load float, float* %arg_1, align 4 %_3 = fcmp ult float %_2, %arg_3 br i1 %_3, label %bb_2, label %.thread bb_2: ; preds = %bb_1 ; CHECK-LABEL: bb_2: ; CHECK: %_4 = sext i32 %_1 to i64 ; CHECK: %_5 = getelementptr inbounds float, float* %arg_1, i64 %_4 ; CHECK: %_6 = load float, float* %_5, align 4 ; CHECK: %_7 = fcmp ole float %_6, %arg_3 ; CHECK: %_8 = add nsw i32 %arg_2, -2 ; CHECK: br i1 %_7, label %bb_2.TrueSelect, label %bb_2.FalseSelect %_4 = sext i32 %_1 to i64 %_5 = getelementptr inbounds float, float* %arg_1, i64 %_4 %_6 = load float, float* %_5, align 4 %_7 = fcmp ole float %_6, %arg_3 %_8 = add nsw i32 %arg_2, -2 %.01 = select i1 %_7, i32 %_8, i32 0 %phitmp = xor i1 %_7, true br i1 %phitmp, label %bb_3, label %.thread ; CHECK: bb_2.TrueSelect: ; preds = %bb_2 ; CHECK: br label %bb_2.AfterSelect ; CHECK: bb_2.FalseSelect: ; preds = %bb_2 ; CHECK: br label %bb_2.AfterSelect ; CHECK: bb_2.AfterSelect: ; preds = %bb_2.FalseSelect, %bb_2.TrueSelect ; CHECK: %.01.phi = phi i32 [ %_8, %bb_2.TrueSelect ], [ 0, %bb_2.FalseSelect ] ; CHECK: %phitmp = xor i1 %_7, true ; CHECK: br i1 %phitmp, label %bb_3, label %.thread bb_3: ; preds = %bb_2 ; CHECK-LABEL: bb_3: ; preds = %bb_2.AfterSelect ; CHECK: %_9 = fcmp olt float %arg_3, 0.000000e+00 ; CHECK: br i1 %_9, label %.outer, label %.outer13 %_9 = fcmp olt float %arg_3, 0.000000e+00 br i1 %_9, label %.outer, label %.outer13 .outer: ; preds = %bb_6, %bb_3 %.07.ph = phi i32 [ %_17, %bb_6 ], [ 0, %bb_3 ] %.03.ph = phi i32 [ %.03.lcssa, %bb_6 ], [ %_1, %bb_3 ] br label %bb_4 bb_4: ; preds = %bb_5, %.outer %.03 = phi i32 [ %_16, %bb_5 ], [ %.03.ph, %.outer ] %_10 = add nsw i32 %.07.ph, %.03 %_11 = sdiv i32 %_10, 2 %_12 = sext i32 %_11 to i64 %_13 = getelementptr inbounds float, float* %arg_1, i64 %_12 %_14 = load float, float* %_13, align 4 %_15 = fcmp ogt float %_14, %arg_3 br i1 %_15, label %bb_5, label %bb_6 bb_5: ; preds = %bb_4 %_16 = add nsw i32 %_11, -1 br label %bb_4 bb_6: ; preds = %bb_4 %.03.lcssa = phi i32 [ %.03, %bb_4 ] %.lcssa = phi i32 [ %_11, %bb_4 ] %_17 = add nsw i32 %.lcssa, 1 %_18 = sext i32 %_17 to i64 %_19 = getelementptr inbounds float, float* %arg_1, i64 %_18 %_20 = load float, float* %_19, align 4 %_21 = fcmp ugt float %_20, %arg_3 br i1 %_21, label %.thread, label %.outer bb_7: ; preds = %.outer13, %bb_8 %.25 = phi i32 [ %_28, %bb_8 ], [ %.25.ph, %.outer13 ] %_22 = add nsw i32 %.29.ph, %.25 %_23 = sdiv i32 %_22, 2 %_24 = sext i32 %_23 to i64 %_25 = getelementptr inbounds float, float* %arg_1, i64 %_24 %_26 = load float, float* %_25, align 4 %_27 = fcmp ult float %_26, %arg_3 br i1 %_27, label %bb_9, label %bb_8 bb_8: ; preds = %bb_7 %_28 = add nsw i32 %_23, -1 br label %bb_7 bb_9: ; preds = %bb_7 %.25.lcssa = phi i32 [ %.25, %bb_7 ] %.lcssa14 = phi i32 [ %_23, %bb_7 ] %_29 = add nsw i32 %.lcssa14, 1 %_30 = sext i32 %_29 to i64 %_31 = getelementptr inbounds float, float* %arg_1, i64 %_30 %_32 = load float, float* %_31, align 4 %_33 = fcmp olt float %_32, %arg_3 br i1 %_33, label %.outer13, label %.thread .outer13: ; preds = %bb_9, %bb_3 %.29.ph = phi i32 [ %_29, %bb_9 ], [ 0, %bb_3 ] %.25.ph = phi i32 [ %.25.lcssa, %bb_9 ], [ %_1, %bb_3 ] br label %bb_7 .thread: ; preds = %bb_9, %bb_6, %bb_2, %bb_1 ; CHECK-LABEL: .thread: ; preds = %bb_9, %bb_6, %bb_2.AfterSelect, %bb_1 ; CHECK: %.3 = phi i32 [ %.01.phi, %bb_2.AfterSelect ], [ 0, %bb_1 ], [ %.lcssa, %bb_6 ], [ %.lcssa14, %bb_9 ] ; CHECK: ret i32 %.3 %.3 = phi i32 [ %.01, %bb_2 ], [ 0, %bb_1 ], [ %.lcssa, %bb_6 ], [ %.lcssa14, %bb_9 ] ret i32 %.3 } define i32 @main(i32 %arg_1, i8** %arg_2) local_unnamed_addr { bb_1: %_1 = alloca [100 x float], align 16 %.sub = getelementptr inbounds [100 x float], [100 x float]* %_1, i64 0, i64 0 %_2 = call fastcc i32 @foo(float* %.sub, i32 100, float 3.400000e+01) ret i32 %_2 } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_select/test-2.ll000066400000000000000000000044471473507761200276630ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @buffer = internal global [6 x i8] zeroinitializer, align 1 define internal i8* @my_malloc(i64 %arg_1) { bb_1: %_1 = getelementptr inbounds [6 x i8], [6 x i8]* @buffer, i64 0, i64 0 ret i8* %_1 } define i32 @main() local_unnamed_addr { bb_1: ; CHECK-LABEL: bb_1: ; CHECK: %_1 = call i32 (...) @__ikos_unknown() ; CHECK: %_2 = icmp ne i32 %_1, 0 ; CHECK: br i1 %_2, label %bb_1.TrueSelect, label %bb_1.FalseSelect %_1 = call i32 (...) @__ikos_unknown() #3 %_2 = icmp ne i32 %_1, 0 %malloc.my_malloc = select i1 %_2, i8* (i64)* @malloc, i8* (i64)* @my_malloc %_3 = call i8* %malloc.my_malloc(i64 8) #3 %_4 = icmp eq i8* %_3, null br i1 %_4, label %bb_3, label %bb_2 ; CHECK: bb_1.TrueSelect: ; preds = %bb_1 ; CHECK: br label %bb_1.AfterSelect ; CHECK: bb_1.FalseSelect: ; preds = %bb_1 ; CHECK: br label %bb_1.AfterSelect ; CHECK: bb_1.AfterSelect: ; preds = %bb_1.FalseSelect, %bb_1.TrueSelect ; CHECK: %malloc.my_malloc.phi = phi i8* (i64)* [ @malloc, %bb_1.TrueSelect ], [ @my_malloc, %bb_1.FalseSelect ] ; CHECK: %_3 = call i8* %malloc.my_malloc.phi(i64 8) ; CHECK: %_4 = icmp eq i8* %_3, null ; CHECK: br i1 %_4, label %bb_3, label %bb_2 bb_2: ; preds = %bb_1 ; CHECK-LABEL: bb_2: ; preds = %bb_1.AfterSelect ; CHECK: %_5 = bitcast i8* %_3 to i32* ; CHECK: store i32 1, i32* %_5, align 4 ; CHECK: %_6 = getelementptr inbounds i8, i8* %_3, i64 4 ; CHECK: %_7 = bitcast i8* %_6 to i32* ; CHECK: store i32 2, i32* %_7, align 4 ; CHECK: br label %bb_3 %_5 = bitcast i8* %_3 to i32* store i32 1, i32* %_5, align 4 %_6 = getelementptr inbounds i8, i8* %_3, i64 4 %_7 = bitcast i8* %_6 to i32* store i32 2, i32* %_7, align 4 br label %bb_3 bb_3: ; preds = %bb_2, %bb_1 ; CHECK-LABEL: bb_3: ; preds = %bb_2, %bb_1.AfterSelect ; CHECK: %.0 = phi i32 [ 0, %bb_2 ], [ 1, %bb_1.AfterSelect ] ; CHECK: ret i32 %.0 %.0 = phi i32 [ 0, %bb_2 ], [ 1, %bb_1 ] ret i32 %.0 } declare i32 @__ikos_unknown(...) local_unnamed_addr declare i8* @malloc(i64) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_select/test-3.ll000066400000000000000000000106751473507761200276640ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" define internal fastcc i32 @foo(i32* %arg_1, i32* %arg_2, i32* %arg_3) unnamed_addr { bb_1: ; CHECK-LABEL: bb_1: ; CHECK: %_1 = getelementptr inbounds i32, i32* %arg_1, i64 1 ; CHECK: %_2 = getelementptr inbounds i32, i32* %arg_2, i64 2 ; CHECK: %_3 = icmp eq i32* %_1, %_2 ; CHECK: %_4 = getelementptr inbounds i32, i32* %arg_2, i64 -8 ; CHECK: %_5 = getelementptr inbounds i32, i32* %arg_1, i64 43 ; CHECK: br i1 %_3, label %bb_1.TrueSelect, label %bb_1.FalseSelect %_1 = getelementptr inbounds i32, i32* %arg_1, i64 1 %_2 = getelementptr inbounds i32, i32* %arg_2, i64 2 %_3 = icmp eq i32* %_1, %_2 %_4 = getelementptr inbounds i32, i32* %arg_2, i64 -8 %_5 = getelementptr inbounds i32, i32* %arg_1, i64 43 %.01 = select i1 %_3, i32* %_5, i32* %_1 %.0 = select i1 %_3, i32* %_4, i32* %_2 %_6 = load i32, i32* %.01, align 4 %_7 = icmp eq i32 %_6, 3 %_8 = zext i1 %_7 to i32 call void @__ikos_assert(i32 %_8) #3 %_9 = load i32, i32* %.0, align 4 %_10 = icmp eq i32 %_9, 6 %_11 = zext i1 %_10 to i32 call void @__ikos_assert(i32 %_11) #3 %_12 = load i32, i32* %.01, align 4 %_13 = load i32, i32* %.0, align 4 %_14 = add nsw i32 %_12, %_13 %_15 = sext i32 %_14 to i64 %_16 = getelementptr inbounds i32, i32* %arg_3, i64 %_15 %_17 = load i32, i32* %_16, align 4 store i32 555, i32* %_16, align 4 ret i32 %_17 ; CHECK: bb_1.TrueSelect: ; preds = %bb_1 ; CHECK: br label %bb_1.AfterSelect ; CHECK: bb_1.FalseSelect: ; preds = %bb_1 ; CHECK: br label %bb_1.AfterSelect ; CHECK: bb_1.AfterSelect: ; preds = %bb_1.FalseSelect, %bb_1.TrueSelect ; CHECK: %.01.phi = phi i32* [ %_5, %bb_1.TrueSelect ], [ %_1, %bb_1.FalseSelect ] ; CHECK: br i1 %_3, label %bb_1.AfterSelect.TrueSelect, label %bb_1.AfterSelect.FalseSelect ; CHECK: bb_1.AfterSelect.TrueSelect: ; preds = %bb_1.AfterSelect ; CHECK: br label %bb_1.AfterSelect.AfterSelect ; CHECK: bb_1.AfterSelect.FalseSelect: ; preds = %bb_1.AfterSelect ; CHECK: br label %bb_1.AfterSelect.AfterSelect ; CHECK: bb_1.AfterSelect.AfterSelect: ; preds = %bb_1.AfterSelect.FalseSelect, %bb_1.AfterSelect.TrueSelect ; CHECK: %.0.phi = phi i32* [ %_4, %bb_1.AfterSelect.TrueSelect ], [ %_2, %bb_1.AfterSelect.FalseSelect ] ; CHECK: %_6 = load i32, i32* %.01.phi, align 4 ; CHECK: %_7 = icmp eq i32 %_6, 3 ; CHECK: %_8 = zext i1 %_7 to i32 ; CHECK: call void @__ikos_assert(i32 %_8) ; CHECK: %_9 = load i32, i32* %.0.phi, align 4 ; CHECK: %_10 = icmp eq i32 %_9, 6 ; CHECK: %_11 = zext i1 %_10 to i32 ; CHECK: call void @__ikos_assert(i32 %_11) ; CHECK: %_12 = load i32, i32* %.01.phi, align 4 ; CHECK: %_13 = load i32, i32* %.0.phi, align 4 ; CHECK: %_14 = add nsw i32 %_12, %_13 ; CHECK: %_15 = sext i32 %_14 to i64 ; CHECK: %_16 = getelementptr inbounds i32, i32* %arg_3, i64 %_15 ; CHECK: %_17 = load i32, i32* %_16, align 4 ; CHECK: store i32 555, i32* %_16, align 4 ; CHECK: ret i32 %_17 } declare void @__ikos_assert(i32) local_unnamed_addr define i32 @main(i32 %arg_1, i8** %arg_2) local_unnamed_addr { bb_1: %_1 = alloca [2 x i32], align 4 %_2 = alloca [3 x i32], align 4 %_3 = alloca [10 x i32], align 16 %_4 = getelementptr inbounds [10 x i32], [10 x i32]* %_3, i64 0, i64 9 store i32 666, i32* %_4, align 4 %_5 = getelementptr inbounds [2 x i32], [2 x i32]* %_1, i64 0, i64 0 store i32 1, i32* %_5, align 4 %_6 = getelementptr inbounds [2 x i32], [2 x i32]* %_1, i64 0, i64 1 store i32 3, i32* %_6, align 4 %_7 = getelementptr inbounds [3 x i32], [3 x i32]* %_2, i64 0, i64 0 store i32 4, i32* %_7, align 4 %_8 = getelementptr inbounds [3 x i32], [3 x i32]* %_2, i64 0, i64 1 store i32 5, i32* %_8, align 4 %_9 = getelementptr inbounds [3 x i32], [3 x i32]* %_2, i64 0, i64 2 store i32 6, i32* %_9, align 4 %_10 = getelementptr inbounds [2 x i32], [2 x i32]* %_1, i64 0, i64 0 %_11 = getelementptr inbounds [3 x i32], [3 x i32]* %_2, i64 0, i64 0 %_12 = getelementptr inbounds [10 x i32], [10 x i32]* %_3, i64 0, i64 0 %_13 = call fastcc i32 @foo(i32* %_10, i32* %_11, i32* %_12) %_14 = icmp eq i32 %_13, 666 %_15 = zext i1 %_14 to i32 call void @__ikos_assert(i32 %_15) #3 %_16 = load i32, i32* %_4, align 4 %_17 = icmp eq i32 %_16, 555 %_18 = zext i1 %_17 to i32 call void @__ikos_assert(i32 %_18) #3 ret i32 %_13 } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_select/test-4.ll000066400000000000000000000056651473507761200276700ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" define i32 @main() local_unnamed_addr { bb_1: %_1 = call i8* @malloc(i64 8) #4 %_2 = icmp eq i8* %_1, null br i1 %_2, label %bb_2, label %bb_3 bb_2: ; preds = %bb_1 call void @exit(i32 0) #5 unreachable bb_3: ; preds = %bb_1 ; CHECK-LABEL: bb_3: ; CHECK: %_3 = bitcast i8* %_1 to i32* ; CHECK: store i32 9, i32* %_3, align 4 ; CHECK: %_4 = getelementptr inbounds i8, i8* %_1, i64 4 ; CHECK: %_5 = bitcast i8* %_4 to i32* ; CHECK: store i32 20, i32* %_5, align 4 ; CHECK: %_6 = call i32 (...) @__ikos_unknown() ; CHECK: %_7 = icmp ne i32 %_6, 0 ; CHECK: br i1 %_7, label %bb_3.TrueSelect, label %bb_3.FalseSelect %_3 = bitcast i8* %_1 to i32* store i32 9, i32* %_3, align 4 %_4 = getelementptr inbounds i8, i8* %_1, i64 4 %_5 = bitcast i8* %_4 to i32* store i32 20, i32* %_5, align 4 %_6 = call i32 (...) @__ikos_unknown() #4 %_7 = icmp ne i32 %_6, 0 %.sink = select i1 %_7, i32* %_3, i32* %_5 %_8 = load i32, i32* %.sink, align 4 %_9 = load i32, i32* %_5, align 4 %.off = add i32 %_8, -9 %_10 = icmp ult i32 %.off, 12 %_11 = zext i1 %_10 to i32 call void @__ikos_assert(i32 %_11) #4 %_12 = icmp eq i32 %_9, 20 %_13 = zext i1 %_12 to i32 call void @__ikos_assert(i32 %_13) #4 %_14 = add nsw i32 %_8, %_9 ret i32 %_14 ; CHECK: bb_3.TrueSelect: ; preds = %bb_3 ; CHECK: br label %bb_3.AfterSelect ; CHECK: bb_3.FalseSelect: ; preds = %bb_3 ; CHECK: br label %bb_3.AfterSelect ; CHECK: bb_3.AfterSelect: ; preds = %bb_3.FalseSelect, %bb_3.TrueSelect ; CHECK: %.sink.phi = phi i32* [ %_3, %bb_3.TrueSelect ], [ %_5, %bb_3.FalseSelect ] ; CHECK: %_8 = load i32, i32* %.sink.phi, align 4 ; CHECK: %_9 = load i32, i32* %_5, align 4 ; CHECK: %.off = add i32 %_8, -9 ; CHECK: %_10 = icmp ult i32 %.off, 12 ; CHECK: %_11 = zext i1 %_10 to i32 ; CHECK: call void @__ikos_assert(i32 %_11) ; CHECK: %_12 = icmp eq i32 %_9, 20 ; CHECK: %_13 = zext i1 %_12 to i32 ; CHECK: call void @__ikos_assert(i32 %_13) ; CHECK: %_14 = add nsw i32 %_8, %_9 ; CHECK: ret i32 %_14 } declare i8* @malloc(i64) local_unnamed_addr ; Function Attrs: noreturn declare void @exit(i32) local_unnamed_addr #0 declare i32 @__ikos_unknown(...) local_unnamed_addr declare void @__ikos_assert(i32) local_unnamed_addr attributes #0 = { noreturn "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/lower_select/test-5.ll000066400000000000000000000044221473507761200276570ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" define internal fastcc i32 @foo(i32 %arg_1, i32 %arg_2) unnamed_addr { bb_1: br label %bb_2 bb_2: ; preds = %bb_3, %bb_1 ; CHECK-LABEL: bb_2: ; preds = %bb_3.AfterSelect, %bb_1 ; CHECK: %.01 = phi i32 [ %arg_2, %bb_1 ], [ %..01.phi, %bb_3.AfterSelect ] ; CHECK: %.0 = phi i32 [ %arg_1, %bb_1 ], [ %_4, %bb_3.AfterSelect ] ; CHECK: %_1 = icmp slt i32 %.0, 100 ; CHECK: br i1 %_1, label %bb_3, label %bb_4 %.01 = phi i32 [ %arg_2, %bb_1 ], [ %..01, %bb_3 ] %.0 = phi i32 [ %arg_1, %bb_1 ], [ %_4, %bb_3 ] %_1 = icmp slt i32 %.0, 100 br i1 %_1, label %bb_3, label %bb_4 bb_3: ; preds = %bb_2 ; CHECK-LABEL: bb_3: ; CHECK: %_2 = call i32 (...) @__ikos_unknown() ; CHECK: %_3 = icmp ne i32 %_2, 0 ; CHECK: br i1 %_3, label %bb_3.TrueSelect, label %bb_3.FalseSelect %_2 = call i32 (...) @__ikos_unknown() #3 %_3 = icmp ne i32 %_2, 0 %..01 = select i1 %_3, i32 1, i32 %.01 %_4 = add nsw i32 %.0, 4 br label %bb_2 ; CHECK: bb_3.TrueSelect: ; preds = %bb_3 ; CHECK: br label %bb_3.AfterSelect ; CHECK: bb_3.FalseSelect: ; preds = %bb_3 ; CHECK: br label %bb_3.AfterSelect ; CHECK: bb_3.AfterSelect: ; preds = %bb_3.FalseSelect, %bb_3.TrueSelect ; CHECK: %..01.phi = phi i32 [ 1, %bb_3.TrueSelect ], [ %.01, %bb_3.FalseSelect ] ; CHECK: %_4 = add nsw i32 %.0, 4 ; CHECK: br label %bb_2 bb_4: ; preds = %bb_2 %.01.lcssa = phi i32 [ %.01, %bb_2 ] %.0.lcssa = phi i32 [ %.0, %bb_2 ] %_5 = icmp ult i32 %.01.lcssa, 2 %_6 = zext i1 %_5 to i32 call void @__ikos_assert(i32 %_6) #3 %_7 = icmp slt i32 %.0.lcssa, 104 %_8 = zext i1 %_7 to i32 call void @__ikos_assert(i32 %_8) #3 %_9 = add nsw i32 %.0.lcssa, %.01.lcssa ret i32 %_9 } declare i32 @__ikos_unknown(...) local_unnamed_addr declare void @__ikos_assert(i32) local_unnamed_addr define i32 @main() local_unnamed_addr { bb_1: %_1 = call fastcc i32 @foo(i32 0, i32 0) %_2 = icmp slt i32 %_1, 105 %_3 = zext i1 %_2 to i32 call void @__ikos_assert(i32 %_3) #3 ret i32 0 } NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_printf_calls/000077500000000000000000000000001473507761200275515ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_printf_calls/runtest000077500000000000000000000064451473507761200312140ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing the RemovePrintfCallsPass # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") pass="remove-printf-calls" ikos_pp="ikos-pp" file_check="FileCheck" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h] [--ikos-pp IKOS-PP] [--file-check FILE-CHECK]" echo "" echo "Run regression tests for pass $pass" exit 1 elif [[ "$1" = "--ikos-pp" ]]; then shift ikos_pp=$1 elif [[ "$1" = "--file-check" ]]; then shift file_check=$1 else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-pp if ! command -v "$ikos_pp" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_pp" >&2 exit 2 fi # Check FileCheck if ! command -v "$file_check" >/dev/null 2>&1; then echo "error: $progname: could not find $file_check" >&2 exit 2 fi # Run the tests echo "# Running regression tests for pass $pass" for filename in *.ll do echo -en "$filename ... \r" "$ikos_pp" -opt=custom -$pass -S "$filename" \ | "$file_check" "$filename" \ || { echo "Test Failed"; exit 1; } echo "$filename ... Passed" done echo "All tests passed successfully." exit 0 NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_printf_calls/test-1.ll000066400000000000000000000035331473507761200312230ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 define i32 @main(i32 %arg_1, i8** %arg_2) { bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 %_3 = alloca i8**, align 8 %_4 = alloca i32, align 4 %_5 = alloca [10 x i32], align 16 store i32 0, i32* %_1, align 4 store i32 %arg_1, i32* %_2, align 4 store i8** %arg_2, i8*** %_3, align 8 store i32 0, i32* %_4, align 4 br label %bb_2 bb_2: ; preds = %bb_4, %bb_1 %_6 = load i32, i32* %_4, align 4 %_7 = icmp slt i32 %_6, 10 br i1 %_7, label %bb_3, label %bb_5 bb_3: ; preds = %bb_2 %_8 = load i32, i32* %_4, align 4 %_9 = load i32, i32* %_4, align 4 %_10 = sext i32 %_9 to i64 %_11 = getelementptr inbounds [10 x i32], [10 x i32]* %_5, i64 0, i64 %_10 store i32 %_8, i32* %_11, align 4 br label %bb_4 bb_4: ; preds = %bb_3 %_12 = load i32, i32* %_4, align 4 %_13 = add nsw i32 %_12, 1 store i32 %_13, i32* %_4, align 4 br label %bb_2 bb_5: ; preds = %bb_2 ; CHECK-LABEL: bb_5: ; CHECK: %_14 = load i32, i32* %_4, align 4 ; CHECK: %_15 = sub nsw i32 %_14, 1 ; CHECK: %_16 = sext i32 %_15 to i64 ; CHECK: %_17 = getelementptr inbounds [10 x i32], [10 x i32]* %_5, i64 0, i64 %_16 ; CHECK: %_18 = load i32, i32* %_17, align 4 ; CHECK: ret i32 0 %_14 = load i32, i32* %_4, align 4 %_15 = sub nsw i32 %_14, 1 %_16 = sext i32 %_15 to i64 %_17 = getelementptr inbounds [10 x i32], [10 x i32]* %_5, i64 0, i64 %_16 %_18 = load i32, i32* %_17, align 4 %_19 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %_18) ret i32 0 } declare i32 @printf(i8*, ...) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_printf_calls/test-2.ll000066400000000000000000000044641473507761200312300ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 define i32 @main(i32 %arg_1, i8** %arg_2) { bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 %_3 = alloca i8**, align 8 %_4 = alloca i32*, align 8 %_5 = alloca i32, align 4 store i32 0, i32* %_1, align 4 store i32 %arg_1, i32* %_2, align 4 store i8** %arg_2, i8*** %_3, align 8 %_6 = call i8* @malloc(i64 40) %_7 = bitcast i8* %_6 to i32* store i32* %_7, i32** %_4, align 8 %_8 = load i32*, i32** %_4, align 8 %_9 = icmp ne i32* %_8, null br i1 %_9, label %bb_3, label %bb_2 bb_2: ; preds = %bb_1 store i32 1, i32* %_1, align 4 br label %bb_8 bb_3: ; preds = %bb_1 store i32 9, i32* %_5, align 4 br label %bb_4 bb_4: ; preds = %bb_6, %bb_3 %_10 = load i32, i32* %_5, align 4 %_11 = icmp sge i32 %_10, 0 br i1 %_11, label %bb_5, label %bb_7 bb_5: ; preds = %bb_4 %_12 = load i32, i32* %_5, align 4 %_13 = load i32*, i32** %_4, align 8 %_14 = load i32, i32* %_5, align 4 %_15 = sext i32 %_14 to i64 %_16 = getelementptr inbounds i32, i32* %_13, i64 %_15 store i32 %_12, i32* %_16, align 4 br label %bb_6 bb_6: ; preds = %bb_5 %_17 = load i32, i32* %_5, align 4 %_18 = add nsw i32 %_17, -1 store i32 %_18, i32* %_5, align 4 br label %bb_4 bb_7: ; preds = %bb_4 ; CHECK-LABEL: bb_7: ; CHECK: %_19 = load i32*, i32** %_4, align 8 ; CHECK: %_20 = getelementptr inbounds i32, i32* %_19, i64 9 ; CHECK: %_21 = load i32, i32* %_20, align 4 ; CHECK: store i32 0, i32* %_1, align 4 ; CHECK: br label %bb_8 %_19 = load i32*, i32** %_4, align 8 %_20 = getelementptr inbounds i32, i32* %_19, i64 9 %_21 = load i32, i32* %_20, align 4 %_22 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %_21) store i32 0, i32* %_1, align 4 br label %bb_8 bb_8: ; preds = %bb_7, %bb_2 %_23 = load i32, i32* %_1, align 4 ret i32 %_23 } declare i8* @malloc(i64) declare i32 @printf(i8*, ...) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_printf_calls/test-3.ll000066400000000000000000000132611473507761200312240ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" %struct.foo = type { i32, %struct.bar, [10 x [10 x [9 x i32]]] } %struct.bar = type { i32, float } @.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 define i32 @main(i32 %arg_1, i8** %arg_2) { bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 %_3 = alloca i8**, align 8 %_4 = alloca i32, align 4 %_5 = alloca i32, align 4 %_6 = alloca i32, align 4 %_7 = alloca %struct.foo, align 4 store i32 0, i32* %_1, align 4 store i32 %arg_1, i32* %_2, align 4 store i8** %arg_2, i8*** %_3, align 8 store i32 0, i32* %_4, align 4 br label %bb_2 bb_2: ; preds = %bb_12, %bb_1 %_8 = load i32, i32* %_4, align 4 %_9 = icmp slt i32 %_8, 10 br i1 %_9, label %bb_3, label %bb_13 bb_3: ; preds = %bb_2 store i32 0, i32* %_5, align 4 br label %bb_4 bb_4: ; preds = %bb_10, %bb_3 %_10 = load i32, i32* %_5, align 4 %_11 = icmp slt i32 %_10, 10 br i1 %_11, label %bb_5, label %bb_11 bb_5: ; preds = %bb_4 store i32 0, i32* %_6, align 4 br label %bb_6 bb_6: ; preds = %bb_8, %bb_5 %_12 = load i32, i32* %_6, align 4 %_13 = icmp slt i32 %_12, 9 br i1 %_13, label %bb_7, label %bb_9 bb_7: ; preds = %bb_6 %_14 = load i32, i32* %_2, align 4 %_15 = getelementptr inbounds %struct.foo, %struct.foo* %_7, i32 0, i32 2 %_16 = load i32, i32* %_4, align 4 %_17 = sext i32 %_16 to i64 %_18 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %_15, i64 0, i64 %_17 %_19 = load i32, i32* %_5, align 4 %_20 = sext i32 %_19 to i64 %_21 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %_18, i64 0, i64 %_20 %_22 = load i32, i32* %_6, align 4 %_23 = sext i32 %_22 to i64 %_24 = getelementptr inbounds [9 x i32], [9 x i32]* %_21, i64 0, i64 %_23 store i32 %_14, i32* %_24, align 4 %_25 = getelementptr inbounds %struct.foo, %struct.foo* %_7, i32 0, i32 2 %_26 = load i32, i32* %_4, align 4 %_27 = sext i32 %_26 to i64 %_28 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %_25, i64 0, i64 %_27 %_29 = load i32, i32* %_5, align 4 %_30 = sext i32 %_29 to i64 %_31 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %_28, i64 0, i64 %_30 %_32 = load i32, i32* %_6, align 4 %_33 = sext i32 %_32 to i64 %_34 = getelementptr inbounds [9 x i32], [9 x i32]* %_31, i64 0, i64 %_33 %_35 = load i32, i32* %_34, align 4 %_36 = getelementptr inbounds %struct.foo, %struct.foo* %_7, i32 0, i32 1 %_37 = getelementptr inbounds %struct.bar, %struct.bar* %_36, i32 0, i32 0 store i32 %_35, i32* %_37, align 4 br label %bb_8 bb_8: ; preds = %bb_7 %_38 = load i32, i32* %_6, align 4 %_39 = add nsw i32 %_38, 1 store i32 %_39, i32* %_6, align 4 br label %bb_6 bb_9: ; preds = %bb_6 br label %bb_10 bb_10: ; preds = %bb_9 %_40 = load i32, i32* %_5, align 4 %_41 = add nsw i32 %_40, 1 store i32 %_41, i32* %_5, align 4 br label %bb_4 bb_11: ; preds = %bb_4 br label %bb_12 bb_12: ; preds = %bb_11 %_42 = load i32, i32* %_4, align 4 %_43 = add nsw i32 %_42, 1 store i32 %_43, i32* %_4, align 4 br label %bb_2 bb_13: ; preds = %bb_2 store i32 0, i32* %_4, align 4 br label %bb_14 bb_14: ; preds = %bb_16, %bb_13 %_44 = load i32, i32* %_4, align 4 %_45 = icmp slt i32 %_44, 10 br i1 %_45, label %bb_15, label %bb_17 bb_15: ; preds = %bb_14 ; CHECK-LABEL: b_15: ; CHECK: %_46 = getelementptr inbounds %struct.foo, %struct.foo* %_7, i32 0, i32 2 ; CHECK: %_47 = load i32, i32* %_4, align 4 ; CHECK: %_48 = sext i32 %_47 to i64 ; CHECK: %_49 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %_46, i64 0, i64 %_48 ; CHECK: %_50 = load i32, i32* %_4, align 4 ; CHECK: %_51 = sext i32 %_50 to i64 ; CHECK: %_52 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %_49, i64 0, i64 %_51 ; CHECK: %_53 = load i32, i32* %_4, align 4 ; CHECK: %_54 = sub nsw i32 %_53, 1 ; CHECK: %_55 = sext i32 %_54 to i64 ; CHECK: %_56 = getelementptr inbounds [9 x i32], [9 x i32]* %_52, i64 0, i64 %_55 ; CHECK: %_57 = load i32, i32* %_56, align 4 ; CHECK: br label %bb_16 %_46 = getelementptr inbounds %struct.foo, %struct.foo* %_7, i32 0, i32 2 %_47 = load i32, i32* %_4, align 4 %_48 = sext i32 %_47 to i64 %_49 = getelementptr inbounds [10 x [10 x [9 x i32]]], [10 x [10 x [9 x i32]]]* %_46, i64 0, i64 %_48 %_50 = load i32, i32* %_4, align 4 %_51 = sext i32 %_50 to i64 %_52 = getelementptr inbounds [10 x [9 x i32]], [10 x [9 x i32]]* %_49, i64 0, i64 %_51 %_53 = load i32, i32* %_4, align 4 %_54 = sub nsw i32 %_53, 1 %_55 = sext i32 %_54 to i64 %_56 = getelementptr inbounds [9 x i32], [9 x i32]* %_52, i64 0, i64 %_55 %_57 = load i32, i32* %_56, align 4 %_58 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %_57) br label %bb_16 bb_16: ; preds = %bb_15 %_59 = load i32, i32* %_4, align 4 %_60 = add nsw i32 %_59, 1 store i32 %_60, i32* %_4, align 4 br label %bb_14 bb_17: ; preds = %bb_14 ret i32 0 } declare i32 @printf(i8*, ...) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_unreachable_blocks/000077500000000000000000000000001473507761200306775ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_unreachable_blocks/runtest000077500000000000000000000064611473507761200323400ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing the RemoveUnreachableBlocksPass # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") pass="remove-unreachable-blocks" ikos_pp="ikos-pp" file_check="FileCheck" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h] [--ikos-pp IKOS-PP] [--file-check FILE-CHECK]" echo "" echo "Run regression tests for pass $pass" exit 1 elif [[ "$1" = "--ikos-pp" ]]; then shift ikos_pp=$1 elif [[ "$1" = "--file-check" ]]; then shift file_check=$1 else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-pp if ! command -v "$ikos_pp" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_pp" >&2 exit 2 fi # Check FileCheck if ! command -v "$file_check" >/dev/null 2>&1; then echo "error: $progname: could not find $file_check" >&2 exit 2 fi # Run the tests echo "# Running regression tests for pass $pass" for filename in *.ll do echo -en "$filename ... \r" "$ikos_pp" -opt=custom -$pass -S "$filename" \ | "$file_check" "$filename" \ || { echo "Test Failed"; exit 1; } echo "$filename ... Passed" done echo "All tests passed successfully." exit 0 NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/regression/pass/remove_unreachable_blocks/test-1.ll000066400000000000000000000034001473507761200323420ustar00rootroot00000000000000target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" define i32 @main() { bb_1: %_1 = alloca i32, align 4 %_2 = alloca i32, align 4 store i32 0, i32* %_1, align 4 store i32 0, i32* %_2, align 4 br label %bb_2 bb_2: ; preds = %bb_9, %bb_3, %bb_1 %_3 = call i32 (...) @__ikos_unknown() %_4 = icmp ne i32 %_3, 0 br i1 %_4, label %bb_3, label %bb_4 bb_3: ; preds = %bb_2 br label %bb_2 bb_4: ; preds = %bb_2 %_5 = load i32, i32* %_2, align 4 %_6 = icmp slt i32 %_5, 60 br i1 %_6, label %bb_5, label %bb_6 bb_5: ; preds = %bb_4 %_7 = load i32, i32* %_2, align 4 %_8 = add nsw i32 %_7, 1 store i32 %_8, i32* %_2, align 4 br label %bb_7 bb_6: ; preds = %bb_4 store i32 0, i32* %_2, align 4 br label %bb_7 bb_7: ; preds = %bb_6, %bb_5 %_9 = load i32, i32* %_2, align 4 %_10 = icmp sge i32 %_9, 0 br i1 %_10, label %bb_8, label %bb_9 bb_8: ; preds = %bb_7 %_11 = load i32, i32* %_2, align 4 %_12 = icmp sle i32 %_11, 60 br label %bb_9 bb_9: ; preds = %bb_8, %bb_7 %_13 = phi i1 [ false, %bb_7 ], [ %_12, %bb_8 ] %_14 = zext i1 %_13 to i32 call void @__ikos_assert(i32 %_14) br label %bb_2 bb_10: ; No predecessors! ; CHECK-NOT: bb_10: ; CHECK-NOT: %_15 = load i32, i32* %_1, align 4 ; CHECK-NOT: ret i32 %_15 %_15 = load i32, i32* %_1, align 4 ret i32 %_15 } declare i32 @__ikos_unknown(...) declare void @__ikos_assert(i32) NASA-SW-VnV-ikos-1d98c65/frontend/llvm/test/runtest-sv-benchmarks000077500000000000000000000114231473507761200245620ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing the translation from LLVM to AR on SV-COMP Benchmarks # # See https://github.com/sosy-lab/sv-benchmarks # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") ikos_pp="ikos-pp" opt_level="basic" ikos_import="ikos-import" ikos_import_opts="-format=no" cc="clang" cflags="-c -emit-llvm -D_FORTIFY_SOURCE=0 -D__IKOS__ -g -O0 -Xclang -disable-O0-optnone -I. -Imodel" # Parse arguments while [[ ! -z $1 ]] do if [[ "$1" = "-h" ]] || [[ "$1" = "-help" ]]; then echo "usage: $progname [-h]" echo " [--ikos-pp IKOS-PP]" echo " [--opt-level LEVEL]" echo " [--ikos-import IKOS-IMPORT]" echo " [--allow-dbg-mismatch]" echo "" echo "Run ikos-import over sv-comp benchmarks" exit 1 elif [[ "$1" = "--ikos-pp" ]]; then shift ikos_pp=$1 elif [[ "$1" = "--opt-level" ]]; then shift opt_level=$1 elif [[ "$1" = "--ikos-import" ]]; then shift ikos_import=$1 elif [[ "$1" = "--allow-dbg-mismatch" ]]; then ikos_import_opts="$ikos_import_opts -allow-dbg-mismatch" else echo "error: $progname: unknown command line argument '$1'" >&2 exit 1 fi shift done # Check ikos-pp if ! command -v "$ikos_pp" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_pp" >&2 exit 2 fi # Check ikos-import if ! command -v "$ikos_import" >/dev/null 2>&1; then echo "error: $progname: could not find $ikos_import" >&2 exit 2 fi # Check cc if ! command -v "$cc" >/dev/null 2>&1; then echo "error: $progname: could not find $cc" >&2 exit 2 fi # Clone sv-benchmarks if [[ ! -d sv-benchmarks ]] then echo "# Cloning sv-benchmarks" git clone "https://github.com/sosy-lab/sv-benchmarks.git" sv-benchmarks cd sv-benchmarks else echo "# Updating sv-benchmarks" cd sv-benchmarks git pull --rebase fi # Run the tests echo "# Running ikos-import over sv-comp with ikos-pp -opt=$opt_level" function test_dir { local dir=$1 pushd "$dir" >/dev/null echo "## $dir" # Find architecture in Makefile if grep -E "CC.Arch\s*:=\s*64" Makefile >/dev/null 2>/dev/null; then arch=64 else arch=32 fi for filename in *.c do if [[ "$filename" = "*.cp" ]]; then continue fi echo "### $PWD/$filename" "$cc" $cflags -m$arch "$filename" -o "$filename.bc" >/dev/null 2>/dev/null || { continue; } "$ikos_pp" -opt=$opt_level "$filename.bc" -o "$filename.pp.bc" || { continue; } "$ikos_import" $ikos_import_opts "$filename.pp.bc" done popd } for dir in $(find . -type d) do if [[ "$dir" = *"/.git"* ]] || [[ "$dir" = *"/eca-rers2012"* ]] || [[ "$dir" = *"/psyco"* ]]; then continue fi test_dir "$dir" done NASA-SW-VnV-ikos-1d98c65/script/000077500000000000000000000000001473507761200161225ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/script/bootstrap000077500000000000000000002300721473507761200200710ustar00rootroot00000000000000#!/bin/bash ################################################################################ # # Installation script that does not require root access. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2023 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ # # This script assumes the operating system provides: # bash, basename, dirname, mkdir, touch, sed, date # # Bash should provide the following builtins: # cd, pwd, exit, command, [[, ((, echo, set, unset, local, read, printf, # pushd, popd, return, shift # # Exit codes: # 0: success # 1: running as root # 2: bad argument # 3: assertion failed # 4: missing dependencies # 5: unable to detect version # 6: error while fetching a source code # 7: error while extracting an archive # 8: error while patching # 9: error while configuring # 10: error while building # 11: error while testing # 12: error while installing # ################################################################################ progname=$(basename "$0") # Version settings ikos_version="3.1" gcc_required_version="4.9.2" clang_required_version="3.4" apple_clang_required_version="3.4" gcc_install_version="9.2.0" gcc_gmp_install_version="6.1.0" gcc_mpfr_install_version="3.1.4" gcc_mpc_install_version="1.0.3" gcc_isl_install_version="0.18" cmake_required_version="3.4.3" cmake_install_version="3.15.2" zlib_install_version="1.2.11" ncurses_install_version="6.1" libedit_install_version="2.11" m4_install_version="1.4.18" gmp_required_version="5.0.0" gmp_install_version="6.1.2" mpfr_install_version="4.0.2" ppl_install_version="1.2" apron_install_version="0.9.10" sqlite_required_version="3.6.20" sqlite_install_version="3.29.0" boost_required_version="1.55.0" boost_install_version="1.70.0" tbb_required_version="2" tbb_install_version="11009" python3_required_version="3.3" python_install_version="3.3" llvm_required_version="9" llvm_install_version="9.0.0" # Default parameters install_dir="" src_dir="$(dirname "$0")/.." build_dir="/tmp/ikos-build" verbose=0 force=0 use_colors=1 check=1 if command -v nproc >/dev/null 2>&1; then njobs=$(nproc) else njobs=1 fi build_type="Release" ##################### # General functions # ##################### function init_colors() { if (( use_colors )); then coff="\033[0m" cbold="\033[1m" cred="\033[31m" cgreen="\033[32m" cyellow="\033[33m" cblue="\033[34m" cpurple="\033[35m" ccyan="\033[36m" cwhite="\033[37m" else coff="" cbold="" cred="" cgreen="" cyellow="" cblue="" cpurple="" ccyan="" cwhite="" fi } function usage() { echo "usage: $progname [options]" echo "" echo "Build and install IKOS on any UNIX environment without root access." echo "" echo "Defaults for the options are specified in brackets." echo "" echo "Configuration:" echo " --prefix=PREFIX Path to the installation directory" echo " --srcdir=SRC_DIR Path to the source directory [$src_dir]" echo " --builddir=BUILD_DIR Path to the build directory [$build_dir]" echo "" echo "Optional arguments:" echo " -h, --help Display this help and exit" echo " -V, --version Display version information and exit" echo " -v, --verbose Make this script more verbose" echo " -f, --force Force" echo " --no-colors Disable colors" echo " --no-check Do not run ikos tests" echo " --jobs=N Allow N jobs at once [$njobs]" echo " --build-type=TYPE Specify the build type {Release,Debug} [$build_type]" } function short_help() { echo "Try '$progname -h' for more information." >&2 } function version() { echo "ikos $ikos_version" echo "Copyright (c) 2011-2019 United States Government as represented by the" echo "Administrator of the National Aeronautics and Space Administration." echo "All Rights Reserved." } function error() { echo "$progname: error: $1" >&2 } # Split command line arguments, i.e: # -ab -> -a -b # --foo=bar -> --foo bar # # Split arguments are stored in the ARGS array # # Parameters: # $1,$2,$3,...,$n: arguments to split function explode_args() { unset ARGS local arg=$1 key value while [[ $arg ]]; do [[ $arg = "--" ]] && ARGS+=("$@") && break # Short options if [[ ${arg:0:1} = "-" && ${arg:1:1} != "-" ]]; then ARGS+=("-${arg:1:1}") (( ${#arg} > 2 )) && arg="-${arg:2}" || { shift; arg=$1; } # Long options elif [[ ${arg:0:2} = "--" ]]; then # Split argument at '=': # e.g --foo=bar -> key=--foo, value=bar key=${arg%%=*}; value=${arg#*=} ARGS+=("$key") [[ "$key" != "$value" ]] && ARGS+=("$value") shift; arg=$1 else ARGS+=("$arg"); shift; arg=$1 fi done } # Return a concatenation of strings separated by a given separator, i.e: # , a b c -> a,b,c # # Parameters: # $1: separator # $2,$2,$4,...,$n: arguments to join function join() { local sep=$1; shift echo -n "$1"; shift printf "%s" "${@/#/$sep}" } # Check if a command exists function command_exists() { command -v "$1" >/dev/null 2>&1 } # Return the absolute path of the given filename function abs_path() { local arg=${1/#\~/$HOME} local dirname=$(dirname "$arg") basename=$(basename "$arg") while [[ ! -d "$dirname" ]]; do basename="$(basename "$dirname")/$basename" dirname=$(dirname "$dirname") done pushd . >/dev/null cd "$dirname" dirname=$(pwd) popd >/dev/null if [[ "$dirname" = "/" ]]; then echo -n "/$basename" else echo -n "$dirname/$basename" fi } # Find a pattern within the standard input # # If found, return 0 and print the given captured group # Otherwise, return 1 # # Parameters: # $1: regular expression # $2: parenthesis group number to capture function match() { while read -r line; do if [[ "$line" =~ $1 ]]; then echo -n "${BASH_REMATCH[$2]}" return 0 fi done return 1 } # Return the name of all binaries in the PATH matching a regular expression function glob_binaries() { local IFS=: find $PATH \ -maxdepth 1 \ -regex ".*/$1" \ -exec basename {} \; 2>/dev/null | sort -u } ######################## # Download and extract # ######################## # Download a file from an URL. # # The file is stored under $download_dir and is named after the remote file function download() { local url=$1 filename=$(basename "$1") cd "$download_dir" if [[ -f "$filename" ]]; then progress "Using already downloaded $filename from $url" else progress "Downloading $url" # Note: do not try to capture curl/wget output because it contains # the progress bar $download_agent "$url" || { rm -f "$filename"; error "Error while fetching $filename"; exit 6; } fi } # Extract an archive and move the root directory # # Parameters: # $1: path to the archive # $2: destination path function extract() { local archive_path=$1 destination_path=$2 local archive_filename=$(basename "$archive_path") local archive_directory=$(dirname "$archive_path") progress "Extracting $archive_filename" cd "$archive_directory" run_log_debug tar xf "$archive_filename" || { error "Error while extracting $archive_filename"; exit 7; } root_directory=$archive_filename for ext in .gz .xz .bz2 .tar .tgz; do root_directory=${root_directory%$ext} done [[ -d "$root_directory" ]] || assert_failed "$root_directory does not exist" rm -rf "$destination_path" mv "$root_directory" "$destination_path" } # Download an archive from an URL and extract it at the given location # # Parameters: # $1: URL # $2: destination path function download_extract() { local url=$1 destination_path=$2 download "$url" extract "$download_dir/$(basename "$url")" "$destination_path" } ###################### # Version comparison # ###################### # Compare two version numbers # # Return 0 if $1 is equal to $2, # 1 if $1 is greater than $2 and # 2 if $1 is lower than $2 function version_compare() { [[ $1 == $2 ]] && return 0 local IFS=. local i ver1=($1) ver2=($2) # fill empty fields in ver1 with zeros for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)); do ver1[i]=0 done for ((i = 0; i < ${#ver1[@]}; i++)); do if [[ -z ${ver2[i]} ]]; then # fill empty fields in ver2 with zeros ver2[i]=0 fi if (( 10#${ver1[i]} > 10#${ver2[i]} )); then return 1 fi if (( 10#${ver1[i]} < 10#${ver2[i]} )); then return 2 fi done return 0 } # Compare two version numbers # # Return 0 iff $1 is greater or equal to $2 function version_ge() { version_compare "$1" "$2"; (( $? <= 1 )) } # Return 0 iif $1 major version number is $2 function major_version_eq() { [[ "$1" = "$2."* ]] } ##################### # Version detection # ##################### version_regex='[0-9]+(\.[0-9]+)*' # Parse and detect the version and compiler id of a C/C++ compiler, given the # command name # # Set the variable `result` to (cc_family cxx_family version) # # For example: # compiler_parse_version "gcc" -> result=("gcc" "g++" "6.1.0") # compiler_parse_version "clang++-3.7" -> result=("clang" clang++" "3.7.1") function compiler_parse_version() { unset result local ver local cmd_regex=$(basename "$1" | sed -E 's/(^|[^\])([\(\)\.\+\-])/\1\\\2/g') local version_output=$("$1" --version 2>&1) debug "'$1 --version':\n$version_output" ver=$(echo "$version_output" | match "^((gcc)|($cmd_regex)) \([^\)]+\) ($version_regex)( [0-9]+)?( \([^\)]+\))*$" 4) (( $? == 0 )) && result=("gcc" "g++" "$ver") && return 0 ver=$(echo "$version_output" | match "^clang version ($version_regex) \([^\)]+\)( \([^\)]+\))*$" 1) (( $? == 0 )) && result=("clang" "clang++" "$ver") && return 0 ver=$(echo "$version_output" | match "^((Apple LLVM)|(Apple clang)) version ($version_regex) \([^\)]+\)( \([^\)]+\))*$" 4) (( $? == 0 )) && result=("apple-clang" "apple-clang++" "$ver") && return 0 return 1 } # Check if a C/C++ compiler satisfies IKOS requirements # # Parameters: # $1: family (gcc, clang, apple-clang) # $2: version function compiler_satisfies_requirements() { local family=$1 version=$2 ([[ "$family" = "gcc" || "$family" = "g++" ]] && version_ge "$version" "$gcc_required_version") || ([[ "$family" = "clang" || "$family" = "clang++" ]] && version_ge "$version" "$clang_required_version") || ([[ "$family" = "apple-clang" || "$family" = "apple-clang++" ]] && version_ge "$version" "$apple_clang_required_version") } # Parse and detect the version of cmake, given the command name function cmake_parse_version() { local version_output=$("$1" --version 2>&1) debug "'$1 --version':\n$version_output" echo "$version_output" | match "^cmake version ($version_regex)$" 1 } # Parse the output of gcc -v to get the installation prefix function gcc_install_prefix() { local output=$("$1" -v 2>&1 | egrep -o -- '--prefix=([^-]|(-[^-]))+ --') echo -n "${output:9:${#output}-12}" } function cc_compile() { if (( verbose >= 1 )); then run_log_debug "$CC" $CPPFLAGS $CFLAGS $LDFLAGS -xc - "$@" else run_log_quiet "$CC" $CPPFLAGS $CFLAGS $LDFLAGS -xc - "$@" fi } function cxx_compile() { if (( verbose >= 1 )); then run_log_debug "$CXX" $CPPFLAGS $CXXFLAGS $LDFLAGS -xc++ - "$@" else run_log_quiet "$CXX" $CPPFLAGS $CXXFLAGS $LDFLAGS -xc++ - "$@" fi } # Compile a simple program using zlib function zlib_version_compile() { cc_compile -o "$tests_dir/zlib_version" -lz <<'EOF' #include #include #include #include int main() { assert(strcmp(ZLIB_VERSION, zlibVersion()) == 0); printf("%s", zlibVersion()); return 0; } EOF } # Detect the version of zlib function zlib_version() { zlib_version_compile && "$tests_dir/zlib_version" } # Compile a simple program using ncurses function ncurses_version_compile() { cc_compile -o "$tests_dir/ncurses_version" -lncurses <<'EOF' #include #include int main() { printf("%s", NCURSES_VERSION); return 0; } EOF } # Detect the version of ncurses function ncurses_version() { ncurses_version_compile && "$tests_dir/ncurses_version" } # Compile a simple program using libedit function libedit_version_compile() { cc_compile -o "$tests_dir/libedit_version" -ledit <<'EOF' #include #include #include int main(int argc, char** argv) { EditLine* el = el_init(argv[0], stdin, stdout, stderr); assert(el != NULL); printf("%d.%d", LIBEDIT_MAJOR, LIBEDIT_MINOR); return 0; } EOF } # Detect the version of libedit function libedit_version() { libedit_version_compile && "$tests_dir/libedit_version" } # Parse and detect the version of m4, given the command name function m4_parse_version() { local version_output=$("$1" --version 2>&1) debug "'$1 --version':\n$version_output" echo "$version_output" | match "^((GNU M4)|(m4 \(GNU M4\))) ($version_regex)$" 4 } # Compile a simple program using gmp function gmp_version_compile() { cc_compile -o "$tests_dir/gmp_version" -lgmp <<'EOF' #include #include #include int main() { mpz_t i, j, k; mpz_init_set_str(i, "1a", 16); mpz_init(j); mpz_init(k); mpz_sqrtrem(j, k, i); assert(mpz_get_si(j) == 5 && mpz_get_si(k) == 1); printf("%s", gmp_version); return 0; } EOF } # Detect the version of gmp function gmp_version() { gmp_version_compile && "$tests_dir/gmp_version" } # Compile a simple program using mpfr function mpfr_version_compile() { cc_compile -o "$tests_dir/mpfr_version" -lmpfr <<'EOF' #include #include int main() { mpfr_t x; mpfr_init_set_ui(x, 2, MPFR_RNDN); printf("%s", mpfr_get_version()); return 0; } EOF } # Detect the version of mpfr function mpfr_version() { mpfr_version_compile && "$tests_dir/mpfr_version" } # Compile a simple program using ppl function ppl_version_compile() { cc_compile -o "$tests_dir/ppl_version" -lppl_c <<'EOF' #include #include int main() { const char* version; ppl_initialize(); ppl_version(&version); printf("%s", version); return ppl_finalize(); } EOF } # Detect the version of ppl function ppl_version() { ppl_version_compile && "$tests_dir/ppl_version" } # Compile a simple program using apron function apron_compile() { cc_compile -o "$tests_dir/apron" -lapron -lboxMPQ <<'EOF' #include #include int main() { ap_manager_t* manbox = box_manager_alloc(); ap_abstract0_t* top = ap_abstract0_top(manbox, 0, 0); ap_abstract0_free(manbox, top); ap_manager_free(manbox); return 0; } EOF } # Check if apron is available function has_apron() { apron_compile && "$tests_dir/apron" } # Compile a simple program using sqlite function sqlite_version_compile() { cc_compile -o "$tests_dir/sqlite_version" -lsqlite3 <<'EOF' #include #include #include #include int main() { assert(strcmp(SQLITE_VERSION, sqlite3_libversion()) == 0); printf("%s", sqlite3_libversion()); return 0; } EOF } # Detect the version of sqlite function sqlite_version() { sqlite_version_compile && "$tests_dir/sqlite_version" } # Compile a simple program using boost function boost_version_compile() { cxx_compile -o "$tests_dir/boost_version" <<'EOF' #include #include int main() { std::cout << (BOOST_VERSION / 100000) << "." << (BOOST_VERSION / 100 % 1000) << "." << (BOOST_VERSION % 100); return 0; } EOF } # Detect the version of boost function boost_version() { boost_version_compile && "$tests_dir/boost_version" } # Compile a simple program using boost::system function boost_system_compile() { cxx_compile -o "$tests_dir/boost_system" -lboost_system <<'EOF' #include int main() { boost::system::error_code e; return 0; } EOF } # Check if boost::system is available function has_boost_system() { boost_system_compile && "$tests_dir/boost_system" } # Compile a simple program using boost::filesystem function boost_filesystem_compile() { cxx_compile -o "$tests_dir/boost_filesystem" -lboost_system -lboost_filesystem <<'EOF' #include int main() { boost::filesystem::path p; return 0; } EOF } # Check if boost::filesystem is available function has_boost_filesystem() { boost_filesystem_compile && "$tests_dir/boost_filesystem" } # Compile a simple program using boost::thread function boost_thread_compile() { for libname in "boost_thread" "boost_thread-mt"; do cxx_compile -o "$tests_dir/boost_thread" -l$libname <<'EOF' #include int main() { boost::mutex m; return 0; } EOF (( $? == 0 )) && return 0 done return 1 } # Check if boost::thread is available function has_boost_thread() { boost_thread_compile && "$tests_dir/boost_thread" } # Compile a simple program using boost::unit_test_framework function boost_unit_test_framework_compile() { cxx_compile -o "$tests_dir/boost_unit_test_framework" -lboost_unit_test_framework <<'EOF' #define BOOST_TEST_MODULE test #define BOOST_TEST_DYN_LINK #include BOOST_AUTO_TEST_CASE(test) { BOOST_CHECK(true); } EOF } # Check if boost::unit_test_framework is available function has_boost_unit_test_framework() { boost_unit_test_framework_compile && "$tests_dir/boost_unit_test_framework" >/dev/null 2>&1 } # Compile a simple program using tbb function tbb_version_compile() { cxx_compile -o "$tests_dir/tbb_version" -ltbb <<'EOF' #include #include #include int main() { tbb::mutex m; std::cout << tbb::TBB_runtime_interface_version(); return 0; } EOF } # Detect the version of tbb function tbb_version() { tbb_version_compile && "$tests_dir/tbb_version" } # Parse and detect the version of python, given the command name function python_parse_version() { local version_output=$("$1" --version 2>&1) debug "'$1 --version':\n$version_output" echo "$version_output" | match "^Python ($version_regex)(\+)?$" 1 } # Check if a python version satisfies IKOS requirements function python_satisfies_requirements() { local version=$1 ([[ ${version:0:1} = 3 ]] && version_ge "$version" "$python3_required_version") } # Parse and detect the version of llvm-config, given the command name function llvm_parse_version() { local version_output=$("$1" --version 2>&1) debug "'$1 --version':\n$version_output" echo "$version_output" | match "^($version_regex)$" 1 } # Parse and detect the version of ikos, given the command name function ikos_parse_version() { local version_output=$("$1" --version 2>&1) debug "'$1 --version':\n$version_output" echo "$version_output" | match "^ikos ($version_regex)(\.r[0-9a-zA-Z\.]+)?$" 1 } ################ # Main program # ################ # Parse options explode_args "$@" set -- "${ARGS[@]}" unset ARGS while [[ $1 ]]; do case "$1" in -h|--help) usage; exit 0;; -V|--version) version; exit 0;; -v|--verbose) (( verbose ++ ));; -f|--force) (( force ++ ));; --no-colors) use_colors=0;; --no-check) check=0;; --prefix) shift; install_dir=$1;; --srcdir) shift; src_dir=$1;; --builddir) shift; build_dir=$1;; --jobs) shift; njobs=$1;; --build-type) shift; build_type=$1;; *) error "unrecognized option: $1"; short_help; exit 2;; esac shift done # Check if running as root if (( ! force && UID == 0 )); then error "this script should NOT run as root" echo "Use --force to ignore this message." >&2 exit 1 fi # Check options if [[ -z "$install_dir" ]]; then error "missing argument --prefix"; short_help; exit 2 elif [[ -z "$src_dir" ]]; then error "missing argument --srcdir"; short_help; exit 2 elif [[ -z "$build_dir" ]]; then error "missing argument --builddir"; short_help; exit 2 elif [[ ! "$njobs" =~ ^[1-9][0-9]*$ ]]; then error "'$njobs' is not a positive number"; short_help; exit 2 fi install_dir_orig=$install_dir install_dir=$(abs_path "$install_dir") src_dir_orig=$src_dir src_dir=$(abs_path "$src_dir") build_dir_orig=$build_dir build_dir=$(abs_path "$build_dir") download_dir_orig="$build_dir_orig/downloads" download_dir="$build_dir/downloads" tests_dir_orig="$build_dir_orig/tests" tests_dir="$build_dir/tests" log_file_orig="$build_dir_orig/bootstrap.log" log_file="$build_dir/bootstrap.log" # Check that src_dir contains IKOS source code if [[ ! -e "$src_dir" ]]; then error "cannot access '$src_dir_orig': No such file or directory"; exit 2 elif [[ ! -d "$src_dir" ]]; then error "'$src_dir_orig' is not a directory"; exit 2 elif [[ ! -f "$src_dir/CMakeLists.txt" ]]; then error "'$src_dir_orig' does not contain ikos source code"; exit 2 fi # Initialize colors init_colors # Create directories mkdir -p "$install_dir" 2>/dev/null || { error "cannot create directory '$install_dir_orig'"; exit 2; } mkdir -p "$build_dir" 2>/dev/null || { error "cannot create directory '$build_dir_orig'"; exit 2; } mkdir -p "$download_dir" 2>/dev/null || { error "cannot create directory '$download_dir_orig'"; exit 2; } mkdir -p "$tests_dir" 2>/dev/null || { error "cannot create directory '$tests_dir_orig'"; exit 2; } touch "$log_file" 2>/dev/null || { error "cannot create '$log_file_orig'"; exit 2; } ###################### # Output and logging # ###################### function strip_colors() { echo -en "$1" | sed -E 's#'$(echo -en '\x1B')'\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]##g' } function log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$1] $(strip_colors "$2")" >> "$log_file" } function error() { echo -e "${cbold}${cred}$1${coff}" >&2 log error "$1" } function warning() { echo -e "${cbold}${cyellow}==> Warning: $1${coff}" log warning "$1" } function success() { echo -e "${cbold}${cgreen}==> ${coff}${cbold}$1${coff}" log success "$1" } function progress() { echo -e "${cbold}${cblue}==> ${coff}${cbold}$1${coff}" log progress "$1" } function info() { echo -e "$1${coff}" log info "$1" } function debug() { if (( verbose >= 1 )); then echo -e "$1${coff}" >&2 fi log debug "$1" } function assert_failed() { error "Assertion failed: $1"; exit 3; } function error_parse_version() { error "Unable to detect the version of '$1'"; exit 5; } function error_patch() { error "Error while patching $1. see $log_file_orig for more details." exit 8 } function error_configure() { if (( verbose == 0 )); then error "Error while configuring $1. see $log_file_orig for more details." else error "Error while configuring $1." fi exit 9 } function error_make() { if (( verbose == 0 )); then error "Error while building $1. see $log_file_orig for more details." else error "Error while building $1." fi exit 10 } function error_check() { if (( verbose == 0 )); then error "Error while testing $1. see $log_file_orig for more details." else error "Error while testing $1." fi exit 11 } function error_install() { if (( verbose == 0 )); then error "Error while installing $1. see $log_file_orig for more details." else error "Error while installing $1." fi exit 12 } # log everything, display everything function run_log_debug() { "$@" 2>&1 | tee -a "$log_file" >&2 return ${PIPESTATUS[0]} } # log everything, only display stderr function run_log_verbose() { { "$@" >> "$log_file" 2>&3; } 3>&1 | tee -a "$log_file" >&2 return ${PIPESTATUS[0]} } # log everything, do not display anything function run_log_quiet() { "$@" >> "$log_file" 2>&1 } function progress_run() { progress "$*" if (( verbose >= 2 )); then run_log_debug "$@" elif (( verbose == 1 )); then run_log_verbose "$@" else run_log_quiet "$@" fi } # Warning if the installation path contains a whitespace if [[ "$install_dir" = *\ * ]]; then warning "The installation path contains a whitespace. The script might fail." fi ################################ # Check required dependencies # ################################ progress "Checking required dependencies" if command_exists cc; then debug "Found cc at $(command -v cc)" elif command_exists gcc; then debug "Found gcc at $(command -v gcc)" elif command_exists clang; then debug "Found clang at $(command -v clang)" else error "Unable to find a C compiler" exit 4 fi if command_exists c++; then debug "Found c++ at $(command -v c++)" elif command_exists g++; then debug "Found g++ at $(command -v g++)" elif command_exists clang++; then debug "Found clang++ at $(command -v clang++)" else error "Unable to find a C++ compiler" exit 4 fi utils_deps=('uname' 'which' 'rm' 'mv' 'cp' 'ln' 'chmod' \ 'cat' 'tee' 'find' 'grep' 'egrep' 'sort' \ 'tar' 'gzip' 'gunzip' 'bzip2' 'bunzip2' 'xz' \ 'patch' 'make' 'install' 'ar' 'ranlib') unset missing_deps for cmd in "${utils_deps[@]}"; do if command_exists "$cmd"; then debug "Found $cmd at $(command -v "$cmd")" else missing_deps+=("$cmd") fi done if command_exists curl; then debug "Found curl at $(command -v curl)" download_agent='curl -OLfC - --progress-bar --ftp-pasv --retry 3 --retry-delay 3' elif command_exists wget; then debug "Found wget at $(command -v wget)" download_agent='wget -c -q --show-progress --tries=3 --waitretry=3' else missing_deps+=("curl") fi if (( ${#missing_deps[@]} > 0 )); then error "Missing required utilities: $(join ", " "${missing_deps[@]}")" exit 4 fi unset utils_deps missing_deps success "Found all required utilities" ############################# # Compiler and Linker flags # ############################# export CPPFLAGS export CFLAGS export CXXFLAGS export LDFLAGS export MAKEFLAGS="-j$njobs $MAKEFLAGS" ###################### # Activation scripts # ###################### # This script creates 2 bash scripts that can be source'd to enter an environment: # activate-minimal defines the required environment variables to use ikos # activate-full defines all environment variables to use any tools built with this script unset act_min_prepend_path act_full_prepend_path unset act_min_prepend_manpath act_full_prepend_manpath unset act_min_prepend_infopath act_full_prepend_infopath unset act_prepend_include_path unset act_prepend_library_path act_prepend_dyn_library_path function min_prepend_path() { PATH="$1:$PATH" act_min_prepend_path+=("$1") act_full_prepend_path+=("$1") } function full_prepend_path() { PATH="$1:$PATH" act_full_prepend_path+=("$1") } function min_prepend_manpath() { export MANPATH="$1${MANPATH:+:$MANPATH}" act_min_prepend_manpath+=("$1") act_full_prepend_manpath+=("$1") } function full_prepend_manpath() { export MANPATH="$1${MANPATH:+:$MANPATH}" act_full_prepend_manpath+=("$1") } function min_prepend_infopath() { export INFOPATH="$1${INFOPATH:+:$INFOPATH}" act_min_prepend_infopath+=("$1") act_full_prepend_infopath+=("$1") } function full_prepend_infopath() { export INFOPATH="$1${INFOPATH:+:$INFOPATH}" act_full_prepend_infopath+=("$1") } function prepend_include_path() { export CPPFLAGS="-I$1 $CPPFLAGS" act_prepend_include_path+=("$1") } if [[ "$(uname)" = "Darwin" ]]; then function prepend_dyn_library_path() { export DYLD_LIBRARY_PATH="$1${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}" act_prepend_dyn_library_path+=("$1") } else function prepend_dyn_library_path() { export LD_LIBRARY_PATH="$1${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" act_prepend_dyn_library_path+=("$1") } fi function prepend_library_path() { export LDFLAGS="-L$1 $LDFLAGS" act_prepend_library_path+=("$1") prepend_dyn_library_path "$1" } function generate_env_path_line() { local var_name=$1; shift if (( $# > 0 )); then echo "export ${var_name}=\"$(join ':' "$@")\${${var_name}:+:\$${var_name}}\"" fi } function generate_env_flag_line() { local var_name=$1; shift local flag_prefix=$1; shift if (( $# > 0 )); then local flag=() for e in "$@"; do flag+=("${flag_prefix}${e}") done echo "export ${var_name}=\"$(join ' ' "${flag[@]}") \$${var_name}\"" fi } ######################## # Check C/C++ compiler # ######################## progress "Checking for a C compiler" found_cc=0 for cmd in "$CC" \ $(glob_binaries "cc[0-9\.\-]*") \ $(glob_binaries "gcc[0-9\.\-]*") \ $(glob_binaries "clang[0-9\.\-]*"); do if command_exists "$cmd"; then compiler_parse_version "$cmd" || error_parse_version "$cmd" family=${result[0]} version=${result[2]} if compiler_satisfies_requirements "$family" "$version"; then found_cc=1 export CC=$(command -v "$cmd") success "Found $(basename "$cmd"): $family $version" break else progress "Found $(basename "$cmd"): $family $version, version too old, skipped" fi fi done progress "Checking for a C++ compiler" found_cxx=0 for cmd in "$CXX" \ $(glob_binaries "c\+\+[0-9\.\-]*") \ $(glob_binaries "g\+\+[0-9\.\-]*") \ $(glob_binaries "clang\+\+[0-9\.\-]*"); do if command_exists "$cmd"; then compiler_parse_version "$cmd" || error_parse_version "$cmd" family=${result[1]} version=${result[2]} if compiler_satisfies_requirements "$family" "$version"; then found_cxx=1 export CXX=$(command -v "$cmd") success "Found $(basename "$cmd"): $family $version" break else progress "Found $(basename "$cmd"): $family $version, version too old, skipped" fi fi done ############################ # Install gcc if necessary # ############################ if (( ! found_cc || ! found_cxx )); then progress "Could NOT find a C/C++ compiler that supports C++14" if [[ -x "$install_dir/gcc-$gcc_install_version/bin/gcc" ]]; then progress "Using already built ${cgreen}gcc $gcc_install_version" else progress "Installing ${cgreen}gcc $gcc_install_version" download_extract "ftp://gcc.gnu.org/pub/gcc/releases/gcc-$gcc_install_version/gcc-$gcc_install_version.tar.gz" \ "$build_dir/gcc-$gcc_install_version" download_extract "ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-$gcc_gmp_install_version.tar.bz2" \ "$build_dir/gcc-$gcc_install_version/gmp" download_extract "ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-$gcc_mpfr_install_version.tar.bz2" \ "$build_dir/gcc-$gcc_install_version/mpfr" download_extract "ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-$gcc_mpc_install_version.tar.gz" \ "$build_dir/gcc-$gcc_install_version/mpc" download_extract "ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-$gcc_isl_install_version.tar.bz2" \ "$build_dir/gcc-$gcc_install_version/isl" cd "$build_dir/gcc-$gcc_install_version" mkdir build cd build unset CC CXX progress_run ../configure \ --prefix="$install_dir/gcc-$gcc_install_version" \ --enable-languages=c,c++ \ --enable-threads=posix \ --enable-checking=release \ --enable-__cxa_atexit \ --disable-werror \ --disable-multilib \ --with-isl || error_configure gcc progress_run make || error_make gcc progress_run make install || error_install gcc fi export CC="$install_dir/gcc-$gcc_install_version/bin/gcc" export CXX="$install_dir/gcc-$gcc_install_version/bin/g++" full_prepend_path "$install_dir/gcc-$gcc_install_version/bin" full_prepend_manpath "$install_dir/gcc-$gcc_install_version/share/man" full_prepend_infopath "$install_dir/gcc-$gcc_install_version/share/info" if [[ -d "$install_dir/gcc-$gcc_install_version/lib64" ]]; then lib_dir="lib64" else lib_dir="lib" fi prepend_dyn_library_path "$install_dir/gcc-$gcc_install_version/$lib_dir" (command_exists "$CC" && compiler_parse_version "$CC" && [[ "${result[0]}" = "gcc" && "${result[2]}" = "$gcc_install_version" ]]) || assert_failed "$CC is not gcc $gcc_install_version" (command_exists "$CXX" && compiler_parse_version "$CXX" && [[ "${result[1]}" = "g++" && "${result[2]}" = "$gcc_install_version" ]]) || assert_failed "$CXX is not g++ $gcc_install_version" success "${cgreen}gcc $gcc_install_version${coff}${cbold} successfully installed" fi debug "CC=$CC" debug "CXX=$CXX" ############### # Check cmake # ############### progress "Checking for CMake" found_cmake=0 if command_exists cmake; then version=$(cmake_parse_version cmake) || error_parse_version cmake if version_ge "$version" "$cmake_required_version"; then found_cmake=1 success "Found CMake $version" else progress "Found CMake $version, version too old, skipped" fi fi ############################## # Install cmake if necessary # ############################## if (( ! found_cmake )); then progress "Could NOT find CMake >= $cmake_required_version" if [[ -x "$install_dir/cmake-$cmake_install_version/bin/cmake" ]]; then progress "Using already built ${cgreen}cmake $cmake_install_version" else progress "Installing ${cgreen}cmake $cmake_install_version" download_extract "https://cmake.org/files/v${cmake_install_version%.*}/cmake-$cmake_install_version.tar.gz" \ "$build_dir/cmake-$cmake_install_version" cd "$build_dir/cmake-$cmake_install_version" progress_run ./configure \ --prefix="$install_dir/cmake-$cmake_install_version" \ --no-system-libs || error_configure cmake progress_run make || error_make cmake progress_run make install || error_install cmake fi full_prepend_path "$install_dir/cmake-$cmake_install_version/bin" (command_exists cmake && version=$(cmake_parse_version cmake) && [[ "$version" = "$cmake_install_version" ]]) || assert_failed "cmake is not properly installed" success "${cgreen}cmake $cmake_install_version${coff}${cbold} successfully installed" fi ############## # Check zlib # ############## progress "Checking for zlib" found_zlib=0 if version=$(zlib_version); then found_zlib=1 success "Found zlib $version" fi ############################# # Install zlib if necessary # ############################# if (( ! found_zlib )); then progress "Could NOT find zlib" if [[ -f "$install_dir/zlib-$zlib_install_version/include/zlib.h" ]]; then progress "Using already built ${cgreen}zlib $zlib_install_version" else progress "Installing ${cgreen}zlib $zlib_install_version" download_extract "http://zlib.net/zlib-$zlib_install_version.tar.gz" \ "$build_dir/zlib-$zlib_install_version" cd "$build_dir/zlib-$zlib_install_version" progress_run ./configure \ --prefix="$install_dir/zlib-$zlib_install_version" || error_configure zlib progress_run make || error_make zlib progress_run make install || error_install zlib fi full_prepend_manpath "$install_dir/zlib-$zlib_install_version/share/man" prepend_include_path "$install_dir/zlib-$zlib_install_version/include" prepend_library_path "$install_dir/zlib-$zlib_install_version/lib" (version=$(zlib_version) && [[ "$version" = "$zlib_install_version" ]]) || assert_failed "zlib is not properly installed" success "${cgreen}zlib $zlib_install_version${coff}${cbold} successfully installed" fi ################# # Check ncurses # ################# progress "Checking for ncurses" found_ncurses=0 if version=$(ncurses_version); then found_ncurses=1 success "Found ncurses $version" fi ################################ # Install ncurses if necessary # ################################ if (( ! found_ncurses )); then progress "Could NOT find ncurses" if [[ -f "$install_dir/ncurses-$ncurses_install_version/include/ncursesw/curses.h" ]]; then progress "Using already built ${cgreen}ncurses $ncurses_install_version" else progress "Installing ${cgreen}ncurses $ncurses_install_version" download_extract "https://ftp.gnu.org/gnu/ncurses/ncurses-$ncurses_install_version.tar.gz" \ "$build_dir/ncurses-$ncurses_install_version" cd "$build_dir/ncurses-$ncurses_install_version" cat > mklib_gen-fix-mawk.patch <<'EOF' --- ncurses/base/MKlib_gen.sh +++ ncurses/base/MKlib_gen.sh @@ -72,7 +72,7 @@ # appears in gcc 5.0 and (with modification) in 5.1, making it necessary to # determine if we are using gcc, and if so, what version because the proposed # solution uses a nonstandard option. -PRG=`echo "$1" | $AWK '{ sub(/^[[:space:]]*/,""); sub(/[[:space:]].*$/, ""); print; }' || exit 0` +PRG=`echo "$1" | $AWK '{ sub(/^[ ]*/,""); sub(/[ ].*$/, ""); print; }' || exit 0` FSF=`"$PRG" --version 2>/dev/null || exit 0 | fgrep "Free Software Foundation" | head -n 1` ALL=`"$PRG" -dumpversion 2>/dev/null || exit 0` ONE=`echo "$ALL" | sed -e 's/\..*$//'` EOF progress "Applying patch mklib_gen-fix-mawk.patch" run_log_quiet patch -p0 < mklib_gen-fix-mawk.patch || error_patch ncurses progress_run ./configure \ --prefix="$install_dir/ncurses-$ncurses_install_version" \ --disable-pc-files \ --enable-sigwinch \ --enable-symlinks \ --enable-widec \ --with-manpage-format=normal \ --with-shared \ --with-gpm=no || error_configure ncurses progress_run make || error_make ncurses progress_run make install || error_install ncurses # Add symlinks # This is based on ncurses formula for homebrew: # https://github.com/Homebrew/homebrew-dupes/blob/master/ncurses.rb cd "$install_dir/ncurses-$ncurses_install_version" for name in form menu ncurses panel; do if [[ "$(uname)" = "Darwin" ]]; then ln -s "lib${name}w.${ncurses_install_version%.*}.dylib" \ "lib/lib${name}.dylib" ln -s "lib${name}w.${ncurses_install_version%.*}.dylib" \ "lib/lib${name}.${ncurses_install_version%.*}.dylib" else ln -s "lib${name}w.so.${ncurses_install_version}" \ "lib/lib${name}.so" ln -s "lib${name}w.so.${ncurses_install_version}" \ "lib/lib${name}.so.${ncurses_install_version%.*}" ln -s "lib${name}w.so.${ncurses_install_version}" \ "lib/lib${name}.so.${ncurses_install_version}" fi ln -s "lib${name}w.a" "lib/lib${name}.a" ln -s "lib${name}w_g.a" "lib/lib${name}_g.a" done ln -s "libncurses++w.a" "lib/libncurses++.a" ln -s "libncurses.a" "lib/libcurses.a" if [[ "$(uname)" = "Darwin" ]]; then ln -s "libncurses.dylib" "lib/libcurses.dylib" else ln -s "libncurses.so" "lib/libcurses.so" ln -s "libncurses.so" "lib/libtinfo.so" fi for name in curses.h form.h ncurses.h term.h termcap.h; do ln -s "ncursesw/${name}" "include/${name}" done fi full_prepend_path "$install_dir/ncurses-$ncurses_install_version/bin" full_prepend_manpath "$install_dir/ncurses-$ncurses_install_version/share/man" prepend_include_path "$install_dir/ncurses-$ncurses_install_version/include" prepend_library_path "$install_dir/ncurses-$ncurses_install_version/lib" (version=$(ncurses_version) && [[ "$version" = "$ncurses_install_version" ]]) || assert_failed "ncurses is not properly installed" success "${cgreen}ncurses $ncurses_install_version${coff}${cbold} successfully installed" fi ################# # Check libedit # ################# progress "Checking for libedit" found_libedit=0 if version=$(libedit_version); then found_libedit=1 success "Found libedit $version" fi ################################ # Install libedit if necessary # ################################ if (( ! found_libedit )); then progress "Could NOT find libedit" if [[ -f "$install_dir/libedit-$libedit_install_version/include/histedit.h" ]]; then progress "Using already built ${cgreen}libedit $libedit_install_version" else progress "Installing ${cgreen}libedit $libedit_install_version" download_extract "https://thrysoee.dk/editline/libedit-20190324-3.1.tar.gz" \ "$build_dir/libedit-$libedit_install_version" cd "$build_dir/libedit-$libedit_install_version" progress_run ./configure \ --prefix="$install_dir/libedit-$libedit_install_version" \ --disable-dependency-tracking \ --disable-silent-rules || error_configure libedit progress_run make || error_make libedit progress_run make install || error_install libedit fi full_prepend_manpath "$install_dir/libedit-$libedit_install_version/share/man" prepend_include_path "$install_dir/libedit-$libedit_install_version/include" prepend_library_path "$install_dir/libedit-$libedit_install_version/lib" (version=$(libedit_version) && [[ "$version" = "$libedit_install_version" ]]) || assert_failed "libedit is not properly installed" success "${cgreen}libedit $libedit_install_version${coff}${cbold} successfully installed" fi ############ # Check m4 # ############ progress "Checking for M4" found_m4=0 if command_exists m4; then version=$(m4_parse_version m4) || error_parse_version m4 success "Found M4 $version" found_m4=1 fi ########################### # Install m4 if necessary # ########################### if (( ! found_m4 )); then progress "Could NOT find M4" if [[ -x "$install_dir/m4-$m4_install_version/bin/m4" ]]; then progress "Using already built ${cgreen}m4 $m4_install_version" else progress "Installing ${cgreen}m4 $m4_install_version" download_extract "https://ftp.gnu.org/gnu/m4/m4-$m4_install_version.tar.xz" \ "$build_dir/m4-$m4_install_version" cd "$build_dir/m4-$m4_install_version" progress_run ./configure \ --prefix="$install_dir/m4-$m4_install_version" \ --disable-dependency-tracking || error_configure m4 progress_run make || error_make m4 progress_run make install || error_install m4 fi full_prepend_path "$install_dir/m4-$m4_install_version/bin" full_prepend_manpath "$install_dir/m4-$m4_install_version/share/man" full_prepend_infopath "$install_dir/m4-$m4_install_version/share/info" (command_exists m4 && version=$(m4_parse_version m4) && [[ "$version" = "$m4_install_version" ]]) || assert_failed "m4 is not properly installed" success "${cgreen}m4 $m4_install_version${coff}${cbold} successfully installed" fi ############# # Check gmp # ############# progress "Checking for GMP" found_gmp=0 if version=$(gmp_version); then if version_ge "$version" "$gmp_required_version"; then found_gmp=1 success "Found GMP $version" else progress "Found GMP $version, version too old, skipped" fi fi ############################ # Install gmp if necessary # ############################ if (( ! found_gmp )); then progress "Could NOT find GMP >= $gmp_required_version" if [[ -f "$install_dir/gmp-$gmp_install_version/include/gmp.h" ]]; then progress "Using already built ${cgreen}gmp $gmp_install_version" else progress "Installing ${cgreen}gmp $gmp_install_version" download_extract "https://gmplib.org/download/gmp/gmp-$gmp_install_version.tar.xz" \ "$build_dir/gmp-$gmp_install_version" cd "$build_dir/gmp-$gmp_install_version" progress_run ./configure \ --prefix="$install_dir/gmp-$gmp_install_version" \ --enable-cxx || error_configure gmp progress_run make || error_make gmp progress_run make install || error_install gmp fi custom_gmp_root="$install_dir/gmp-$gmp_install_version" full_prepend_infopath "$install_dir/gmp-$gmp_install_version/share/info" prepend_include_path "$install_dir/gmp-$gmp_install_version/include" prepend_library_path "$install_dir/gmp-$gmp_install_version/lib" (version=$(gmp_version) && [[ "$version" = "$gmp_install_version" ]]) || assert_failed "gmp is not properly installed" success "${cgreen}gmp $gmp_install_version${coff}${cbold} successfully installed" fi ############## # Check mpfr # ############## progress "Checking for MPFR" found_mpfr=0 if version=$(mpfr_version); then found_mpfr=1 success "Found MPFR $version" fi ############################# # Install mpfr if necessary # ############################# if (( ! found_mpfr )); then progress "Could NOT find MPFR" if [[ -f "$install_dir/mpfr-$mpfr_install_version/include/mpfr.h" ]]; then progress "Using already built ${cgreen}mpfr $mpfr_install_version" else progress "Installing ${cgreen}mpfr $mpfr_install_version" download_extract "https://ftp.gnu.org/gnu/mpfr/mpfr-$mpfr_install_version.tar.xz" \ "$build_dir/mpfr-$mpfr_install_version" cd "$build_dir/mpfr-$mpfr_install_version" progress_run ./configure \ --prefix="$install_dir/mpfr-$mpfr_install_version" \ --disable-dependency-tracking \ --disable-silent-rules || error_configure mpfr progress_run make || error_make mpfr progress_run make install || error_install mpfr fi custom_mpfr_root="$install_dir/mpfr-$mpfr_install_version" full_prepend_infopath "$install_dir/mpfr-$mpfr_install_version/share/info" prepend_include_path "$install_dir/mpfr-$mpfr_install_version/include" prepend_library_path "$install_dir/mpfr-$mpfr_install_version/lib" (version=$(mpfr_version) && [[ "$version" = "$mpfr_install_version" ]]) || assert_failed "mpfr is not properly installed" success "${cgreen}mpfr $mpfr_install_version${coff}${cbold} successfully installed" fi ############# # Check ppl # ############# progress "Checking for PPL" found_ppl=0 if version=$(ppl_version); then found_ppl=1 success "Found PPL $version" fi ############################ # Install ppl if necessary # ############################ if (( ! found_ppl )); then progress "Could NOT find PPL" if [[ -f "$install_dir/ppl-$ppl_install_version/include/ppl_c.h" ]]; then progress "Using already built ${cgreen}ppl $ppl_install_version" else progress "Installing ${cgreen}ppl $ppl_install_version" download_extract "https://www.bugseng.com/external/ppl/download/ftp/releases/$ppl_install_version/ppl-$ppl_install_version.tar.xz" \ "$build_dir/ppl-$ppl_install_version" cd "$build_dir/ppl-$ppl_install_version" cat > fix-missing-template-typename.patch <<'EOF' --- src/Determinate_inlines.hh +++ src/Determinate_inlines.hh @@ -289,8 +289,8 @@ operator()(Determinate& x, const Determinate& y) const { template template -inline -Determinate::Binary_Operator_Assign_Lifter +inline typename +Determinate::template Binary_Operator_Assign_Lifter Determinate::lift_op_assign(Binary_Operator_Assign op_assign) { return Binary_Operator_Assign_Lifter(op_assign); } --- src/OR_Matrix_inlines.hh +++ src/OR_Matrix_inlines.hh @@ -97,7 +97,7 @@ OR_Matrix::Pseudo_Row::Pseudo_Row(const Pseudo_Row& y) template template -inline OR_Matrix::Pseudo_Row& +inline typename OR_Matrix::template Pseudo_Row& OR_Matrix::Pseudo_Row::operator=(const Pseudo_Row& y) { first = y.first; #if PPL_OR_MATRIX_EXTRA_DEBUG EOF progress "Applying patch fix-missing-template-typename.patch" run_log_quiet patch -p0 < fix-missing-template-typename.patch || error_patch ppl progress_run ./configure \ --prefix="$install_dir/ppl-$ppl_install_version" \ --disable-dependency-tracking \ --disable-silent-rules || error_configure ppl progress_run make || error_make ppl progress_run make install || error_install ppl fi custom_ppl_root="$install_dir/ppl-$ppl_install_version" full_prepend_path "$install_dir/ppl-$ppl_install_version/bin" full_prepend_manpath "$install_dir/ppl-$ppl_install_version/share/man" prepend_include_path "$install_dir/ppl-$ppl_install_version/include" prepend_library_path "$install_dir/ppl-$ppl_install_version/lib" (version=$(ppl_version) && [[ "$version" = "$ppl_install_version" ]]) || assert_failed "ppl is not properly installed" success "${cgreen}ppl $ppl_install_version${coff}${cbold} successfully installed" fi ############### # Check apron # ############### progress "Checking for APRON" found_apron=0 if has_apron; then found_apron=1 success "Found APRON" fi ############################## # Install apron if necessary # ############################## if (( ! found_apron )); then progress "Could NOT find APRON" if [[ -f "$install_dir/apron-$apron_install_version/include/ap_abstract0.h" ]]; then progress "Using already built ${cgreen}apron $apron_install_version" else progress "Installing ${cgreen}apron $apron_install_version" download_extract "http://apron.cri.ensmp.fr/library/apron-$apron_install_version.tgz" \ "$build_dir/apron-$apron_install_version" cd "$build_dir/apron-$apron_install_version" cat > fix-invalid-operands-to-binary-expression.patch <<'EOF' --- ppl/ppl_user.cc +++ ppl/ppl_user.cc @@ -320,7 +320,12 @@ exact = false; } /* singleton */ - else r.insert(Constraint(Variable(i)==temp)); + else { + /* integerness check */ + mpz_class temp2 = mpz_class(temp); + if (temp==temp2) r.insert(Constraint(Variable(i)==temp2)); + else exact = false; + } } return exact; } EOF cat > fix-link-error.patch <<'EOF' --- products/Makefile +++ products/Makefile @@ -117,9 +117,9 @@ $(AR) rcs $@ $^ $(RANLIB) $@ libap_pkgrid.so: ap_pkgrid.o - $(CXX) $(CXXFLAGS) -shared -o $@ $^ $(LIBS) + $(CXX) $(CXXFLAGS) -shared -o $@ $^ -L../newpolka -lpolkaMPQ $(LIBS) libap_pkgrid_debug.so: ap_pkgrid_debug.o - $(CXX) $(CXXFLAGS_DEBUG) -shared -o $@ $^ $(LIBS_DEBUG) + $(CXX) $(CXXFLAGS_DEBUG) -shared -o $@ $^ -L../newpolka -lpolkaMPQ $(LIBS_DEBUG) #--------------------------------------- # C rules EOF cat > fix-missing-mpfr.patch <<'EOF' --- apron/Makefile +++ apron/Makefile @@ -191,7 +191,7 @@ ap_scalar.o: ap_scalar.c ap_scalar.h ap_config.h ap_interval.o: ap_interval.c ap_interval.h \ ap_config.h \ - ap_scalar.h $(MPFR_PREFIX)/include/mpfr.h + ap_scalar.h ap_coeff.o: ap_coeff.c ap_coeff.h \ ap_config.h \ ap_scalar.h \ @@ -287,7 +287,7 @@ ap_scalar_debug.o: ap_scalar.c ap_scalar.h ap_config.h ap_interval_debug.o: ap_interval.c ap_interval.h \ ap_config.h \ - ap_scalar.h $(MPFR_PREFIX)/include/mpfr.h + ap_scalar.h ap_coeff_debug.o: ap_coeff.c ap_coeff.h \ ap_config.h \ ap_scalar.h \ EOF cat > fix-static-decl-strdup.patch <<'EOF' --- apron/ap_config.h +++ apron/ap_config.h @@ -23,17 +23,6 @@ static const bool true = 1; #endif -#if !(defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __APPLE__ || defined __CYGWIN__) - -static inline char* strdup(const char* s){ - char* s2; - - s2 = malloc(strlen(s)+1); - strcpy(s2,s); - return s2; -} -#endif - #ifdef __cplusplus } #endif EOF progress "Applying patch fix-invalid-operands-to-binary-expression.patch" run_log_quiet patch -p0 < fix-invalid-operands-to-binary-expression.patch || error_patch apron progress "Applying patch fix-link-error.patch" run_log_quiet patch -p0 < fix-link-error.patch || error_patch apron progress "Applying patch fix-missing-mpfr.patch" run_log_quiet patch -p0 < fix-missing-mpfr.patch || error_patch apron progress "Applying patch fix-static-decl-strdup.patch" run_log_quiet patch -p0 < fix-static-decl-strdup.patch || error_patch apron run_log_quiet cp Makefile.config.model Makefile.config || error_configure apron progress_run make \ APRON_PREFIX="$install_dir/apron-$apron_install_version" \ GMP_PREFIX="$custom_gmp_root" \ MPFR_PREFIX="$custom_mpfr_root" \ PPL_PREFIX="$custom_ppl_root" \ HAS_OCAML= \ HAS_OCAMLOPT= \ HAS_JAVA= \ OCAMLFIND= \ HAS_PPL=1 \ all \ install \ -j1 || error_make apron fi custom_apron_root="$install_dir/apron-$apron_install_version" full_prepend_path "$install_dir/apron-$apron_install_version/bin" prepend_include_path "$install_dir/apron-$apron_install_version/include" prepend_library_path "$install_dir/apron-$apron_install_version/lib" has_apron || assert_failed "apron is not properly installed" success "${cgreen}apron $apron_install_version${coff}${cbold} successfully installed" fi ################ # Check sqlite # ################ progress "Checking for SQLite" found_sqlite=0 if version=$(sqlite_version); then if version_ge "$version" "$sqlite_required_version"; then found_sqlite=1 success "Found SQLite $version" else progress "Found SQLite $version, version too old, skipped" fi fi ############################### # Install sqlite if necessary # ############################### if (( ! found_sqlite )); then progress "Could NOT find SQLite >= $sqlite_required_version" if [[ -f "$install_dir/sqlite-$sqlite_install_version/include/sqlite3.h" ]]; then progress "Using already built ${cgreen}sqlite $sqlite_install_version" else progress "Installing ${cgreen}sqlite $sqlite_install_version" download_extract "https://sqlite.org/2019/sqlite-autoconf-3290000.tar.gz" \ "$build_dir/sqlite-$sqlite_install_version" cd "$build_dir/sqlite-$sqlite_install_version" CPPFLAGS="-DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_MAX_VARIABLE_NUMBER=250000 $CPPFLAGS" \ progress_run ./configure \ --prefix="$install_dir/sqlite-$sqlite_install_version" \ --disable-dependency-tracking \ --enable-dynamic-extensions || error_configure sqlite progress_run make || error_make sqlite progress_run make install || error_install sqlite fi custom_sqlite_root="$install_dir/sqlite-$sqlite_install_version" min_prepend_path "$install_dir/sqlite-$sqlite_install_version/bin" min_prepend_manpath "$install_dir/sqlite-$sqlite_install_version/share/man" prepend_include_path "$install_dir/sqlite-$sqlite_install_version/include" prepend_library_path "$install_dir/sqlite-$sqlite_install_version/lib" (version=$(sqlite_version) && [[ "$version" = "$sqlite_install_version" ]]) || assert_failed "sqlite is not properly installed" success "${cgreen}sqlite $sqlite_install_version${coff}${cbold} successfully installed" fi ############### # Check boost # ############### progress "Checking for Boost" found_boost=0 if version=$(boost_version); then if version_ge "$version" "$boost_required_version"; then success "Found Boost $version" if ! has_boost_system; then progress "Could NOT find boost_system" elif ! has_boost_filesystem; then progress "Could NOT find boost_filesystem" elif ! has_boost_thread; then progress "Could NOT find boost_thread" elif ! has_boost_unit_test_framework; then progress "Could NOT find boost_unit_test_framework" else success "Found Boost $version with libraries: system, filesystem, thread, unit_test_framework" found_boost=1 fi else progress "Found Boost $version, version too old, skipped" fi fi ############################## # Install boost if necessary # ############################## if (( ! found_boost )); then progress "Could NOT find Boost >= $boost_required_version with libraries: system, filesystem, thread, unit_test_framework" if [[ -d "$install_dir/boost-$boost_install_version/include/boost" ]]; then progress "Using already built ${cgreen}boost $boost_install_version" else progress "Installing ${cgreen}boost $boost_install_version" download_extract "https://dl.bintray.com/boostorg/release/$boost_install_version/source/boost_${boost_install_version//./_}.tar.bz2" \ "$build_dir/boost-$boost_install_version" cd "$build_dir/boost-$boost_install_version" progress_run ./bootstrap.sh \ --prefix="$install_dir/boost-$boost_install_version" \ --with-libraries=system \ --with-libraries=filesystem \ --with-libraries=thread \ --with-libraries=test || error_configure boost progress_run ./b2 "-j$njobs" || error_make boost progress_run ./b2 install || error_install boost fi custom_boost_root="$install_dir/boost-$boost_install_version" prepend_include_path "$install_dir/boost-$boost_install_version/include" prepend_library_path "$install_dir/boost-$boost_install_version/lib" (version=$(boost_version) && [[ "$version" = "$boost_install_version" ]]) || assert_failed "boost is not properly installed" success "${cgreen}boost $boost_install_version${coff}${cbold} successfully installed" fi ############# # Check tbb # ############# progress "Checking for TBB" found_tbb=0 if version=$(tbb_version); then if version_ge "$version" "$tbb_required_version"; then found_tbb=1 success "Found TBB $version" else progress "Found TBB $version, version too old, skipped" fi fi ############################ # Install tbb if necessary # ############################ if (( ! found_tbb )); then progress "Could NOT find TBB >= $tbb_required_version" if [[ -f "$install_dir/tbb-$tbb_install_version/include/tbb/tbb.h" ]]; then progress "Using already built ${cgreen}tbb $tbb_install_version" else progress "Installing ${cgreen}tbb $tbb_install_version" download "https://github.com/intel/tbb/archive/2019_U9.tar.gz" mv "$download_dir/2019_U9.tar.gz" "$download_dir/tbb-2019_U9.tar.gz" extract "$download_dir/tbb-2019_U9.tar.gz" "$build_dir/tbb-$tbb_install_version" cd "$build_dir/tbb-$tbb_install_version" progress_run make tbb_build_prefix= || error_make tbb progress_run install -d \ "$install_dir/tbb-$tbb_install_version/lib" || error_install tbb progress_run install \ build/_release/lib*.* \ "$install_dir/tbb-$tbb_install_version/lib" || error_install tbb progress_run install -d \ "$install_dir/tbb-$tbb_install_version/include" || error_install tbb progress_run cp -a \ include/tbb \ "$install_dir/tbb-$tbb_install_version/include" || error_install tbb progress_run cmake \ -DINSTALL_DIR="$install_dir/tbb-$tbb_install_version/lib/cmake/TBB" \ -DSYSTEM_NAME="$(uname)" \ -DTBB_VERSION_FILE="$install_dir/tbb-$tbb_install_version/include/tbb/tbb_stddef.h" \ -P cmake/tbb_config_installer.cmake || error_install tbb fi custom_tbb_root="$install_dir/tbb-$tbb_install_version" prepend_include_path "$install_dir/tbb-$tbb_install_version/include" prepend_library_path "$install_dir/tbb-$tbb_install_version/lib" (version=$(tbb_version) && [[ "$version" = "$tbb_install_version" ]]) || assert_failed "tbb is not properly installed" success "${cgreen}tbb $tbb_install_version${coff}${cbold} successfully installed" fi ################ # Check python # ################ progress "Checking for Python" found_python=0 # Check the default python if command_exists python; then version=$(python_parse_version python) || error_parse_version python if python_satisfies_requirements "$version"; then found_python=1 success "Found Python $version" else progress "Found Python $version, version too old, skipped" fi fi # Check all available versions of python if (( ! found_python )); then for cmd in $(glob_binaries "python[0-9\.\-][0-9\.\-]*"); do if command_exists "$cmd"; then version=$(python_parse_version "$cmd") || error_parse_version python if python_satisfies_requirements "$version"; then found_python=1 success "Found Python $version" # Create symbolic links progress "Using symbolic links to make it the default python" if [[ ! -d "$install_dir/python-$version" ]]; then mkdir -p "$install_dir/python-$version/bin" cd "$install_dir/python-$version/bin" ln -s "$(command -v "$cmd")" python ln -s "$(command -v "$cmd")-config" python-config fi min_prepend_path "$install_dir/python-$version/bin" break else progress "Found Python $version, version too old, skipped" fi fi done fi ############################### # Install python if necessary # ############################### if (( ! found_python )); then progress "Could NOT find Python >= $python3_required_version" if [[ -x "$install_dir/python-$python_install_version/bin/python" ]]; then progress "Using already built ${cgreen}python $python_install_version" else progress "Installing ${cgreen}python $python_install_version" download_extract "https://www.python.org/ftp/python/$python_install_version/Python-$python_install_version.tar.xz" \ "$build_dir/python-$python_install_version" cd "$build_dir/python-$python_install_version" if [[ -n "$custom_sqlite_root" ]]; then # We need to patch python to build _sqlite cat > setup-fix-custom-sqlite.patch <<'EOF' --- setup.py +++ setup.py @@ -1117,13 +1117,7 @@ # We hunt for #define SQLITE_VERSION "n.n.n" # We need to find >= sqlite version 3.0.8 sqlite_incdir = sqlite_libdir = None - sqlite_inc_paths = [ '/usr/include', - '/usr/include/sqlite', - '/usr/include/sqlite3', - '/usr/local/include', - '/usr/local/include/sqlite', - '/usr/local/include/sqlite3', - ] + sqlite_inc_paths = [ '$custom_sqlite_root/include' ] if cross_compiling: sqlite_inc_paths = [] MIN_SQLITE_VERSION_NUMBER = (3, 0, 8) EOF progress "Applying patch setup-fix-custom-sqlite.patch" run_log_quiet patch -p0 < setup-fix-custom-sqlite.patch || error_patch python fi progress_run ./configure \ --prefix="$install_dir/python-$python_install_version" || error_configure python progress_run make || error_make python progress_run make install || error_install python fi min_prepend_path "$install_dir/python-$python_install_version/bin" min_prepend_manpath "$install_dir/python-$python_install_version/share/man" prepend_include_path "$install_dir/python-$python_install_version/include" prepend_library_path "$install_dir/python-$python_install_version/lib" success "${cgreen}python $python_install_version${coff}${cbold} successfully installed" fi (command_exists python && version=$(python_parse_version python) && python_satisfies_requirements "$version") || assert_failed "python is not properly installed" ############## # Check llvm # ############## progress "Checking for LLVM" found_llvm=0 # Check the default llvm if command_exists llvm-config; then version=$(llvm_parse_version llvm-config) || error_parse_version llvm if major_version_eq "$version" "$llvm_required_version"; then found_llvm=1 success "Found LLVM $version" else progress "Found LLVM $version, skipped" fi fi if (( ! found_llvm )); then for cmd in $(glob_binaries "llvm\-config[0-9\.\-][0-9\.\-]*"); do if command_exists "$cmd"; then version=$(llvm_parse_version "$cmd") || error_parse_version llvm if major_version_eq "$version" "$llvm_required_version"; then found_llvm=1 success "Found LLVM $version" # Create symbolic links progress "Using symbolic links to make it the default llvm" if [[ ! -d "$install_dir/llvm-$version" ]]; then mkdir -p "$install_dir/llvm-$version/bin" bin_dir=$("$cmd" --bindir) cd "$bin_dir" if [[ -f "$cmd" ]]; then # binaries are suffixed suffix=${cmd:11} elif [[ -f llvm-config ]]; then # binaries are not suffixed suffix='' else assert_failed "could not find $cmd or llvm-config in $bin_dir" fi for bin in clang*$suffix lli*$suffix llvm*$suffix \ "FileCheck$suffix" "bugpoint$suffix" "c-index-test$suffix" \ "count$suffix" "llc$suffix" "macho-dump$suffix" "not$suffix" \ "obj2yaml$suffix" "opt$suffix" "pp-trace$suffix" \ "scan-build$suffix" "scan-view$suffix" \ "verify-uselistorder$suffix" "yaml2obj$suffix"; do if [[ -f "$bin" ]]; then ln -s "$bin_dir/$bin" "$install_dir/llvm-$version/bin" fi done fi min_prepend_path "$install_dir/llvm-$version/bin" break else progress "Found LLVM $version, skipped" fi fi done fi ############################# # Install llvm if necessary # ############################# if (( ! found_llvm )); then progress "Could NOT find LLVM $llvm_required_version" if [[ -x "$install_dir/llvm-$llvm_install_version/bin/llvm-config" ]]; then progress "Using already built ${cgreen}llvm $llvm_install_version" else progress "Installing ${cgreen}llvm $llvm_install_version" download_extract "https://releases.llvm.org/$llvm_install_version/llvm-$llvm_install_version.src.tar.xz" \ "$build_dir/llvm-$llvm_install_version" download_extract "https://releases.llvm.org/$llvm_install_version/cfe-$llvm_install_version.src.tar.xz" \ "$build_dir/llvm-$llvm_install_version/tools/clang" download_extract "https://releases.llvm.org/$llvm_install_version/clang-tools-extra-$llvm_install_version.src.tar.xz" \ "$build_dir/llvm-$llvm_install_version/tools/clang/tools/extra" download_extract "https://releases.llvm.org/$llvm_install_version/compiler-rt-$llvm_install_version.src.tar.xz" \ "$build_dir/llvm-$llvm_install_version/projects/compiler-rt" cd "$build_dir/llvm-$llvm_install_version" mkdir build cd build cmake_extra_args=() # If the compiler is gcc, tell clang to use the same SEARCH_PATH compiler_parse_version "$CXX" || error_parse_version "$CXX" if [[ "${result[1]}" = "g++" ]]; then gcc_install_dir=$(gcc_install_prefix "$CXX") if [[ -d "$gcc_install_dir" ]]; then cmake_extra_args+=("-DGCC_INSTALL_PREFIX=$gcc_install_dir") fi fi progress_run cmake \ -DCMAKE_INSTALL_PREFIX="$install_dir/llvm-$llvm_install_version" \ -DCMAKE_BUILD_TYPE=Release \ -DLLVM_TARGETS_TO_BUILD=all \ -DLLVM_INSTALL_UTILS=ON \ -DLLVM_ENABLE_RTTI=ON \ -DLLVM_ENABLE_EH=ON \ -DLLVM_ENABLE_CXX1Y=ON \ "${cmake_extra_args[@]}" \ .. || error_configure llvm progress_run make || error_make llvm progress_run make install || error_install llvm fi min_prepend_path "$install_dir/llvm-$llvm_install_version/bin" prepend_include_path "$install_dir/llvm-$llvm_install_version/include" prepend_library_path "$install_dir/llvm-$llvm_install_version/lib" success "${cgreen}llvm $llvm_install_version${coff}${cbold} successfully installed" fi (command_exists llvm-config && version=$(llvm_parse_version llvm-config) && major_version_eq "$version" "$llvm_required_version") || assert_failed "llvm is not properly installed" ################ # Install IKOS # ################ if [[ -x "$install_dir/ikos-$ikos_version/bin/ikos" ]]; then progress "Using already built ${cgreen}ikos $ikos_version" else progress "Installing ${cgreen}ikos $ikos_version" rm -rf "$build_dir/ikos-$ikos_version" mkdir -p "$build_dir/ikos-$ikos_version" cd "$build_dir/ikos-$ikos_version" cmake_extra_args=() if [[ -n "$custom_gmp_root" ]]; then cmake_extra_args+=("-DGMP_ROOT=$custom_gmp_root") fi if [[ -n "$custom_mpfr_root" ]]; then cmake_extra_args+=("-DMPFR_ROOT=$custom_mpfr_root") fi if [[ -n "$custom_ppl_root" ]]; then cmake_extra_args+=("-DPPL_ROOT=$custom_ppl_root") fi if [[ -n "$custom_apron_root" ]]; then cmake_extra_args+=("-DAPRON_ROOT=$custom_apron_root") fi if [[ -n "$custom_sqlite_root" ]]; then cmake_extra_args+=("-DSQLITE3_ROOT=$custom_sqlite_root") fi if [[ -n "$custom_boost_root" ]]; then cmake_extra_args+=("-DCUSTOM_BOOST_ROOT=$custom_boost_root") fi if [[ -n "$custom_tbb_root" ]]; then cmake_extra_args+=("-DTBB_ROOT=$custom_tbb_root") fi progress_run cmake \ -DCMAKE_INSTALL_PREFIX="$install_dir/ikos-$ikos_version" \ -DCMAKE_BUILD_TYPE="$build_type" \ "${cmake_extra_args[@]}" \ "$src_dir" || error_configure ikos progress_run make || error_make ikos progress_run make install || error_install ikos fi min_prepend_path "$install_dir/ikos-$ikos_version/bin" prepend_include_path "$install_dir/ikos-$ikos_version/include" prepend_library_path "$install_dir/ikos-$ikos_version/lib" (command_exists ikos && version=$(ikos_parse_version ikos) && [[ "$version" = "$ikos_version" ]]) || assert_failed "ikos is not properly installed" ################## # Run ikos tests # ################## if (( check )); then if [[ ! -d "$build_dir/ikos-$ikos_version" ]]; then progress "Could NOT run ikos tests because the build directory is missing" else cd "$build_dir/ikos-$ikos_version" progress_run make check || error_check ikos success "IKOS tests passed successfully" fi fi ################################### # Generate the Activation scripts # ################################### # activate-minimal echo '#!/bin/bash' > "$install_dir/activate-minimal" generate_env_path_line PATH "${act_min_prepend_path[@]}" >> "$install_dir/activate-minimal" generate_env_path_line MANPATH "${act_min_prepend_manpath[@]}" >> "$install_dir/activate-minimal" generate_env_path_line INFOPATH "${act_min_prepend_infopath[@]}" >> "$install_dir/activate-minimal" if [[ "$(uname)" = "Darwin" ]]; then generate_env_path_line DYLD_LIBRARY_PATH "${act_prepend_dyn_library_path[@]}" >> "$install_dir/activate-minimal" else generate_env_path_line LD_LIBRARY_PATH "${act_prepend_dyn_library_path[@]}" >> "$install_dir/activate-minimal" fi # activate-full echo '#!/bin/bash' > "$install_dir/activate-full" generate_env_path_line PATH "${act_full_prepend_path[@]}" >> "$install_dir/activate-full" generate_env_path_line MANPATH "${act_full_prepend_manpath[@]}" >> "$install_dir/activate-full" generate_env_path_line INFOPATH "${act_full_prepend_infopath[@]}" >> "$install_dir/activate-full" if [[ "$(uname)" = "Darwin" ]]; then generate_env_path_line DYLD_LIBRARY_PATH "${act_prepend_dyn_library_path[@]}" >> "$install_dir/activate-full" else generate_env_path_line LD_LIBRARY_PATH "${act_prepend_dyn_library_path[@]}" >> "$install_dir/activate-full" fi echo "export CC=\"$CC\"" >> "$install_dir/activate-full" echo "export CXX=\"$CXX\"" >> "$install_dir/activate-full" generate_env_flag_line CPPFLAGS "-I" "${act_prepend_include_path[@]}" >> "$install_dir/activate-full" generate_env_flag_line LDFLAGS "-L" "${act_prepend_library_path[@]}" >> "$install_dir/activate-full" if (( njobs > 1 )); then echo "export MAKEFLAGS=\"-j$njobs \$MAKEFLAGS\"" >> "$install_dir/activate-full" fi ########### # Success # ########### if command_exists source; then source_cmd="source" else source_cmd="." fi success "IKOS has been successfully installed" info "To use ikos, first run:" info "$ $source_cmd $install_dir_orig/activate-minimal" if (( ! check )); then info "" info "To run the tests:" info "$ $source_cmd $install_dir_orig/activate-full" info "$ cd $build_dir_orig/ikos-$ikos_version" info "$ make check" fi NASA-SW-VnV-ikos-1d98c65/script/run-clang-format000077500000000000000000000132371473507761200212320ustar00rootroot00000000000000#!/usr/bin/env python ############################################################################### # # Run clang-format on the whole repository # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import os import os.path import re import subprocess import sys # Expected clang-format version CLANG_FORMAT_VERSION = '14.0.6' # Extensions to format SOURCE_EXTENSIONS = ('.c', '.cpp', '.h', '.hpp') # Directories to ignore IGNORE_DIRECTORIES = ('.git', 'build', 'analyzer/test/regression') def printf(fmt, *args, **kwargs): file = kwargs.pop('file', sys.stdout) file.write(fmt % args if args else fmt) file.flush() def is_executable(fpath): return fpath and os.path.isfile(fpath) and os.access(fpath, os.X_OK) def which(program): ''' Try to find program in the PATH, otherwise return None. >>> which('cat') '/bin/cat' ''' fpath, fname = os.path.split(program) if fpath: if is_executable(program): return program else: for path in os.environ['PATH'].split(os.pathsep): exe_file = os.path.join(path, program) if is_executable(exe_file): return exe_file return None if __name__ == '__main__': progname = os.path.basename(sys.argv[0]) # Default source directory is the parent directory src_dir = os.path.join(os.path.dirname(sys.argv[0]), '..') src_dir = os.path.normpath(src_dir) # Parse arguments description = 'Run clang-format on the whole repository' parser = argparse.ArgumentParser(description=description) parser.add_argument('--srcdir', dest='src_dir', help='Path to the source directory [%s]' % src_dir, default=src_dir) parser.add_argument('--clang-format', dest='clang_format', help='Path to the clang-format binary', default='clang-format') opt = parser.parse_args() # Check source directory if not os.path.isdir(opt.src_dir): printf("%s: error: '%s' is not a directory\n", progname, opt.src_dir, file=sys.stderr) sys.exit(1) # Check clang-format clang_format = which(opt.clang_format) if not clang_format: printf('%s: error: %s: command not found\n', progname, opt.clang_format, file=sys.stderr) sys.exit(1) # Check clang-format version output = subprocess.check_output([clang_format, '--version']) output = output.decode('utf-8') r = re.match(r'^(Homebrew )?clang-format version ([0-9\.]+)( \(.*\))?\s*$', output) if not r: printf("%s: error: unexpected output of '%s --version'\n", progname, opt.clang_format, file=sys.stderr) sys.exit(1) version = r.group(2) if version != CLANG_FORMAT_VERSION: printf("%s: error: trying to use clang-format %s, expecting %s\n", progname, version, CLANG_FORMAT_VERSION, file=sys.stderr) sys.exit(1) os.chdir(opt.src_dir) for dirpath, _, filenames in os.walk('.'): if dirpath.startswith('./'): dirpath = dirpath[2:] if any(dirpath.startswith(n) for n in IGNORE_DIRECTORIES): continue for filename in filenames: _, ext = os.path.splitext(filename) if ext in SOURCE_EXTENSIONS: fullpath = os.path.join(dirpath, filename) printf("[*] Formatting %s\n", fullpath) subprocess.check_call([clang_format, '-i', '-style=file', fullpath]) NASA-SW-VnV-ikos-1d98c65/script/run-clang-tidy000077500000000000000000000257021473507761200207130ustar00rootroot00000000000000#!/usr/bin/env python ############################################################################### # # Run clang-tidy on the whole repository # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ############################################################################### import argparse import os.path import re import subprocess import sys import threading try: import Queue as queue # python 2 except ImportError: import queue as queue # python 3 # Extensions to analyze SOURCE_EXTENSIONS = ('.c', '.cpp', '.h', '.hpp') # Directories to ignore IGNORE_DIRECTORIES = ( '.git', 'build', 'analyzer/test/regression', 'frontend/llvm/test/regression/import', ) # Ignore checks for specific files FILE_IGNORE_CHECKS = { 'analyzer/include/ikos/analyzer/analysis/execution_engine/inliner.hpp': ('cppcoreguidelines-pro-bounds-pointer-arithmetic',), 'analyzer/include/ikos/analyzer/intrinsic.h': ('cppcoreguidelines-macro-usage', 'hicpp-deprecated-headers', 'modernize-deprecated-headers', 'readability-identifier-naming',), 'analyzer/include/ikos/analyzer/support/cast.hpp': ('misc-unused-using-decls',), 'analyzer/include/ikos/analyzer/support/number.hpp': ('misc-unused-using-decls',), 'analyzer/include/ikos/analyzer/support/string_ref.hpp': ('misc-unused-using-decls',), 'analyzer/include/ikos/analyzer/util/source_location.hpp': ('misc-unused-using-decls',), 'analyzer/src/ikos_analyzer.cpp': ('cert-err58-cpp', 'cppcoreguidelines-slicing',), 'ar/include/ikos/ar/support/cast.hpp': ('misc-unused-using-decls',), 'ar/include/ikos/ar/support/flags.hpp': ('clang-diagnostic-unused-macros',), 'ar/include/ikos/ar/support/number.hpp': ('misc-unused-using-decls',), 'core/include/ikos/core/domain/numeric/apron.hpp': ('cppcoreguidelines-pro-bounds-pointer-arithmetic', 'cppcoreguidelines-pro-type-union-access',), 'core/include/ikos/core/domain/numeric/octagon.hpp': ('readability-implicit-bool-conversion',), 'core/include/ikos/core/number/machine_int.hpp': ('cppcoreguidelines-owning-memory', 'cppcoreguidelines-pro-type-member-init', 'cppcoreguidelines-pro-type-union-access', 'hicpp-member-init',), 'core/include/ikos/core/number/supported_integral.hpp': ('google-runtime-int',), 'core/include/ikos/core/number/z_number.hpp': ('google-runtime-int',), 'core/include/ikos/core/support/assert.hpp': ('clang-diagnostic-unused-macros', 'cppcoreguidelines-macro-usage',), 'core/include/ikos/core/support/compiler.hpp': ('clang-diagnostic-unused-macros', 'cppcoreguidelines-macro-usage',), 'core/include/ikos/core/support/mpl.hpp': ('readability-identifier-naming',), 'frontend/llvm/include/ikos/frontend/llvm/pass.hpp': ('readability-identifier-naming',), 'frontend/llvm/src/ikos_import.cpp': ('cert-err58-cpp',), 'frontend/llvm/src/ikos_pp.cpp': ('cert-err58-cpp',), } def printf(fmt, *args, **kwargs): file = kwargs.pop('file', sys.stdout) file.write(fmt % args if args else fmt) file.flush() def is_executable(fpath): return fpath and os.path.isfile(fpath) and os.access(fpath, os.X_OK) def which(program): ''' Try to find program in the PATH, otherwise return None. >>> which('cat') '/bin/cat' ''' fpath, fname = os.path.split(program) if fpath: if is_executable(program): return program else: for path in os.environ['PATH'].split(os.pathsep): exe_file = os.path.join(path, program) if is_executable(exe_file): return exe_file return None def run_tidy(clang_tidy, build_dir, extra_checks, fix, task_queue, lock): while True: # Get the next task fullpath = task_queue.get() # Build the clang-tidy command # TODO: enable colors when clang-tidy supports it cmd = [clang_tidy] cmd.append('-quiet') cmd.append('-p=%s' % build_dir) checks = [] if fullpath in FILE_IGNORE_CHECKS: for check in FILE_IGNORE_CHECKS[fullpath]: checks.append('-%s' % check) if extra_checks: checks.append(extra_checks) if checks: cmd.append('-checks=%s' % ','.join(checks)) if fix: cmd.append('-fix') cmd.append(fullpath) # Run the clang-tidy command proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = proc.communicate() output = output.decode('utf-8') err = err.decode('utf-8') # Remove the line 'xxx warnings generated.' n = err.rfind('\n', 0, len(err) - 1) line = err[n + 1:] if re.match(r'^\d+ warnings? generated.\n$', line): err = err[:n + 1] with lock: printf('[*] %s\n', ' '.join(cmd)) sys.stdout.write(output) sys.stderr.write(err) task_queue.task_done() if __name__ == '__main__': progname = os.path.basename(sys.argv[0]) # Default source directory is '..' src_dir = os.path.join(os.path.dirname(sys.argv[0]), '..') src_dir = os.path.normpath(src_dir) # Default build directory is '../build' build_dir = os.path.join(os.path.dirname(sys.argv[0]), '..', 'build') build_dir = os.path.normpath(build_dir) # Parse arguments description = 'Run clang-tidy on the whole repository' parser = argparse.ArgumentParser(description=description) parser.add_argument('--srcdir', dest='src_dir', help='Path to the source directory [%s]' % src_dir, default=src_dir) parser.add_argument('--builddir', dest='build_dir', help='Path to the build directory [%s]' % build_dir, default=build_dir) parser.add_argument('--clang-tidy', dest='clang_tidy', help='Path to the clang-tidy binary', default='clang-tidy') parser.add_argument('--checks', dest='checks', help='Additional checks filters', default=None) parser.add_argument('--jobs', '-j', dest='jobs', metavar='N', type=int, help='Allow N jobs at once [1]', default=1) parser.add_argument('--fix', dest='fix', help='Apply suggested fixes', action='store_true', default=False) opt = parser.parse_args() # Check source directory if not os.path.isdir(opt.src_dir): printf("%s: error: '%s' is not a directory\n", progname, opt.src_dir, file=sys.stderr) sys.exit(1) # Check build directory if not os.path.isdir(opt.build_dir): printf("%s: error: '%s' is not a directory\n", progname, opt.build_dir, file=sys.stderr) sys.exit(1) build_dir = os.path.abspath(opt.build_dir) # Check clang-tidy clang_tidy = which(opt.clang_tidy) if not clang_tidy: printf('%s: error: %s: command not found\n', progname, opt.clang_tidy, file=sys.stderr) sys.exit(1) # Check jobs if opt.jobs < 1: printf('%s: error: invalid number of jobs\n', progname, file=sys.stderr) sys.exit(1) os.chdir(opt.src_dir) # Print the list of checks cmd = [clang_tidy] cmd.append('-p=%s' % build_dir) if opt.checks: cmd.append('-checks=%s' % opt.checks) cmd.append('-list-checks') cmd.append('-') subprocess.check_call(cmd) try: task_queue = queue.Queue(opt.jobs) lock = threading.Lock() # Start threads for _ in range(opt.jobs): t = threading.Thread(target=run_tidy, args=(clang_tidy, build_dir, opt.checks, opt.fix, task_queue, lock)) t.daemon = True t.start() # Fill the queue for dirpath, _, filenames in os.walk('.'): if dirpath.startswith('./'): dirpath = dirpath[2:] if any(dirpath.startswith(n) for n in IGNORE_DIRECTORIES): continue for filename in filenames: _, ext = os.path.splitext(filename) if ext in SOURCE_EXTENSIONS: fullpath = os.path.join(dirpath, filename) task_queue.put(fullpath) # Wait for all threads to be done task_queue.join() except KeyboardInterrupt: os.kill(0, 9) NASA-SW-VnV-ikos-1d98c65/test/000077500000000000000000000000001473507761200155755ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/000077500000000000000000000000001473507761200172435ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/archlinux/000077500000000000000000000000001473507761200212405ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/archlinux/Dockerfile000066400000000000000000000026051473507761200232350ustar00rootroot00000000000000FROM archlinux/base MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.16.0 # gmp 6.1.2 # mpfr 4.0.2 # ppl 1.2 # apron 0.9.10 # boost 1.71.0 # python 3.8 # sqlite 3.30.1 # tbb 11009 # llvm 9.0.0 # clang 9.0.0 # gcc 9.2.0 # Upgrade RUN pacman --noconfirm -Sy archlinux-keyring RUN pacman --noconfirm -Syu RUN pacman-db-upgrade # Install most dependencies RUN pacman -S --noconfirm base-devel git cmake gmp boost boost-libs python python-pygments sqlite intel-tbb llvm llvm-libs clang # Use -j$njobs when building packages RUN echo "MAKEFLAGS=\"-j$njobs\"" >> /etc/makepkg.conf # Create user 'makepkg' with sudo access RUN useradd -m makepkg RUN echo "makepkg ALL=(root) NOPASSWD: /usr/bin/pacman" >> /etc/sudoers # Install apron using AUR USER makepkg WORKDIR /home/makepkg RUN git clone https://aur.archlinux.org/apron.git WORKDIR /home/makepkg/apron RUN makepkg -si --noconfirm # Add ikos source code USER root ADD . /root/ikos # Build ikos RUN rm -rf /root/ikos/build && mkdir /root/ikos/build WORKDIR /root/ikos/build ENV MAKEFLAGS "-j$njobs" RUN cmake \ -DCMAKE_INSTALL_PREFIX="/opt/ikos" \ -DCMAKE_BUILD_TYPE="$build_type" \ .. RUN make RUN make install # Run the tests RUN make check # Add ikos to the path ENV PATH "/opt/ikos/bin:$PATH" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/centos-6/000077500000000000000000000000001473507761200207015ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/centos-6/Dockerfile000066400000000000000000000022341473507761200226740ustar00rootroot00000000000000FROM centos:6 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.15.2 # gmp 6.1.2 # mpfr 4.0.2 # ppl 1.2 # apron 0.9.10 # boost 1.70.0 # python 2.7.16 # sqlite 3.6.20 # tbb 4001 # llvm 9.0.0 # clang 9.0.0 # gcc 8.3.1 # Upgrade RUN yum -y update # Install dependencies using CentOS Sofware Collections Repository RUN yum -y install patch bzip2 xz zlib-devel libedit-devel make m4 sqlite-devel tbb-devel RUN yum -y install centos-release-scl RUN yum -y install devtoolset-8-gcc devtoolset-8-gcc-c++ python27 # Update env to use devtoolset-8 and python27 ENV PATH "/opt/rh/python27/root/usr/bin:/opt/rh/devtoolset-8/root/usr/bin:$PATH" ENV LD_LIBRARY_PATH "/opt/rh/python27/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib" # Add ikos source code ADD . /root/ikos # Use the bootstrap script to install ikos and run the tests WORKDIR /root/ikos/script RUN ./bootstrap -vvf \ --prefix="/opt/ikos" \ --builddir="/root/ikos-build" \ --build-type="$build_type" \ --jobs="$njobs" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/centos-7/000077500000000000000000000000001473507761200207025ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/centos-7/Dockerfile000066400000000000000000000021711473507761200226750ustar00rootroot00000000000000FROM centos:7 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.15.2 # gmp 6.0.0 # mpfr 3.1.1 # ppl 1.2 # apron 0.9.10 # boost 1.70.0 # python 2.7.5 # sqlite 3.7.17 # tbb 6103 # llvm 9.0.0 # clang 9.0.0 # gcc 8.3.1 # Upgrade RUN yum -y update # Install dependencies using CentOS Sofware Collections Repository RUN yum -y install which patch bzip2 xz zlib-devel libedit-devel make m4 gmp-devel mpfr-devel python python-pygments sqlite-devel tbb-devel RUN yum -y install centos-release-scl RUN yum -y install devtoolset-8-gcc devtoolset-8-gcc-c++ # Update env to use devtoolset-8 ENV PATH "/opt/rh/devtoolset-8/root/usr/bin:$PATH" ENV LD_LIBRARY_PATH "/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib" # Add ikos source code ADD . /root/ikos # Use the bootstrap script to install ikos and run the tests WORKDIR /root/ikos/script RUN ./bootstrap -vvf \ --prefix="/opt/ikos" \ --builddir="/root/ikos-build" \ --build-type="$build_type" \ --jobs="$njobs" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/debian-10/000077500000000000000000000000001473507761200207035ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/debian-10/Dockerfile000066400000000000000000000025731473507761200227040ustar00rootroot00000000000000FROM debian:10 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.13.4 # gmp 6.1.2 # boost 1.67.0 # python 2.7.16 # sqlite 3.27.2 # tbb 10006 # llvm 9.0.1 # clang 9.0.1 # gcc 8.3.0 # Upgrade RUN apt-get update RUN apt-get upgrade -y # Add ppa for llvm 9.0 RUN echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-9 main" >> /etc/apt/sources.list # Add llvm repository key RUN apt-get install -y wget gnupg RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - # Refresh cache RUN apt-get update # Install all dependencies RUN apt-get install -y gcc g++ cmake libgmp-dev libboost-dev \ libboost-filesystem-dev libboost-thread-dev libboost-test-dev python \ python-pygments libsqlite3-dev libtbb-dev libz-dev libedit-dev \ llvm-9 llvm-9-dev llvm-9-tools clang-9 # Add ikos source code ADD . /root/ikos # Build ikos RUN rm -rf /root/ikos/build && mkdir /root/ikos/build WORKDIR /root/ikos/build ENV MAKEFLAGS "-j$njobs" RUN cmake \ -DCMAKE_INSTALL_PREFIX="/opt/ikos" \ -DCMAKE_BUILD_TYPE="$build_type" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. RUN make RUN make install # Run the tests RUN make check # Add ikos to the path ENV PATH "/opt/ikos/bin:$PATH" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/debian-9/000077500000000000000000000000001473507761200206335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/debian-9/Dockerfile000066400000000000000000000025721473507761200226330ustar00rootroot00000000000000FROM debian:9 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.7.2 # gmp 6.1.2 # boost 1.62.0 # python 2.7.13 # sqlite 3.16.2 # tbb 8006 # llvm 9.0.1 # clang 9.0.1 # gcc 6.3.0 # Upgrade RUN apt-get update RUN apt-get upgrade -y # Add ppa for llvm 9.0 RUN echo "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-9 main" >> /etc/apt/sources.list # Add llvm repository key RUN apt-get install -y wget gnupg RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - # Refresh cache RUN apt-get update # Install all dependencies RUN apt-get install -y gcc g++ cmake libgmp-dev libboost-dev \ libboost-filesystem-dev libboost-thread-dev libboost-test-dev python \ python-pygments libsqlite3-dev libtbb-dev libz-dev libedit-dev \ llvm-9 llvm-9-dev llvm-9-tools clang-9 # Add ikos source code ADD . /root/ikos # Build ikos RUN rm -rf /root/ikos/build && mkdir /root/ikos/build WORKDIR /root/ikos/build ENV MAKEFLAGS "-j$njobs" RUN cmake \ -DCMAKE_INSTALL_PREFIX="/opt/ikos" \ -DCMAKE_BUILD_TYPE="$build_type" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. RUN make RUN make install # Run the tests RUN make check # Add ikos to the path ENV PATH "/opt/ikos/bin:$PATH" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/fedora-29/000077500000000000000000000000001473507761200207335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/fedora-29/Dockerfile000066400000000000000000000016121473507761200227250ustar00rootroot00000000000000FROM fedora:29 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.14.5 # gmp 6.1.2 # mpfr 3.1.6 # ppl 1.2 # apron 0.9.10 # boost 1.66.0 # python 2.7.17 # sqlite 3.26.0 # tbb 10005 # llvm 9.0.0 # clang 9.0.0 # gcc 8.3.1 # Upgrade RUN dnf -y update # Install all dependencies RUN dnf install -y which findutils patch bzip2 xz zlib-devel libedit-devel \ gcc gcc-c++ make cmake m4 gmp-devel mpfr-devel ppl-devel boost-devel \ python python-pygments sqlite-devel tbb-devel # Add ikos source code ADD . /root/ikos # Use the bootstrap script to install ikos and run the tests WORKDIR /root/ikos/script RUN ./bootstrap -vvf \ --prefix="/opt/ikos" \ --builddir="/root/ikos-build" \ --build-type="$build_type" \ --jobs="$njobs" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/fedora-30/000077500000000000000000000000001473507761200207235ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/fedora-30/Dockerfile000066400000000000000000000016121473507761200227150ustar00rootroot00000000000000FROM fedora:30 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.14.5 # gmp 6.1.2 # mpfr 3.1.6 # ppl 1.2 # apron 0.9.10 # boost 1.69.0 # python 2.7.17 # sqlite 3.26.0 # tbb 11008 # llvm 9.0.0 # clang 9.0.0 # gcc 9.2.1 # Upgrade RUN dnf -y update # Install all dependencies RUN dnf install -y which findutils patch bzip2 xz zlib-devel libedit-devel \ gcc gcc-c++ make cmake m4 gmp-devel mpfr-devel ppl-devel boost-devel \ python python-pygments sqlite-devel tbb-devel # Add ikos source code ADD . /root/ikos # Use the bootstrap script to install ikos and run the tests WORKDIR /root/ikos/script RUN ./bootstrap -vvf \ --prefix="/opt/ikos" \ --builddir="/root/ikos-build" \ --build-type="$build_type" \ --jobs="$njobs" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/logs/000077500000000000000000000000001473507761200202075ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/logs/.gitignore000066400000000000000000000000671473507761200222020ustar00rootroot00000000000000# ignore everything * # except .gitignore !.gitignore NASA-SW-VnV-ikos-1d98c65/test/install/rhel-6/000077500000000000000000000000001473507761200203405ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/rhel-6/Dockerfile000066400000000000000000000017451473507761200223410ustar00rootroot00000000000000FROM samdoran/rhel6-ansible MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release ARG rhel_username ARG rhel_password # Installs the following versions (note that it might be out of date): # cmake 3.15.2 # gmp 6.1.2 # mpfr 4.0.2 # ppl 1.2 # apron 0.9.10 # boost 1.70.0 # python 3.4.10 # sqlite 3.6.20 # tbb 4001 # llvm 9.0.0 # clang 9.0.0 # gcc 9.2.0 # Subscribe RUN subscription-manager register --username=$rhel_username --password=$rhel_password --auto-attach # Upgrade RUN yum -y update # Install dependencies RUN yum -y install which file patch tar bzip2 xz zlib-devel ncurses-devel gcc gcc-c++ make m4 python34 python34-pygments sqlite-devel tbb-devel # Add ikos source code ADD . /root/ikos # Use the bootstrap script to install ikos and run the tests WORKDIR /root/ikos/script RUN ./bootstrap -vvf \ --prefix="/opt/ikos" \ --builddir="/root/ikos-build" \ --build-type="$build_type" \ --jobs="$njobs" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/rhel-7/000077500000000000000000000000001473507761200203415ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/rhel-7/Dockerfile000066400000000000000000000017451473507761200223420ustar00rootroot00000000000000FROM samdoran/rhel7-ansible MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release ARG rhel_username ARG rhel_password # Installs the following versions (note that it might be out of date): # cmake 3.15.2 # gmp 6.0.0 # mpfr 3.1.1 # ppl 1.2 # apron 0.9.10 # boost 1.70.0 # python 2.7.5 # sqlite 3.7.17 # tbb 6103 # llvm 9.0.0 # clang 9.0.0 # gcc 9.2.0 # Subscribe RUN subscription-manager register --username=$rhel_username --password=$rhel_password --auto-attach # Upgrade RUN yum -y update # Install dependencies RUN yum -y install which file patch tar bzip2 xz zlib-devel ncurses-devel gcc gcc-c++ make m4 gmp-devel mpfr-devel python sqlite-devel tbb-devel # Add ikos source code ADD . /root/ikos # Use the bootstrap script to install ikos and run the tests WORKDIR /root/ikos/script RUN ./bootstrap -vvf \ --prefix="/opt/ikos" \ --builddir="/root/ikos-build" \ --build-type="$build_type" \ --jobs="$njobs" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/runtest000077500000000000000000000145361473507761200207060ustar00rootroot00000000000000#!/bin/bash ################################################################################ # Script for testing IKOS installation on different platforms # # These tests require Docker. # # Author: Maxime Arthaud # # Contact: ikos@lists.nasa.gov # # Notices: # # Copyright (c) 2011-2019 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Disclaimers: # # No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF # ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED # TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, # ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, # OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE # ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO # THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN # ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, # RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS # RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY # DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY SOFTWARE, # IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS." # # Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST # THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL # AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS # IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH # USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, # RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD # HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, # AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. # RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, # UNILATERAL TERMINATION OF THIS AGREEMENT. # ################################################################################ progname=$(basename "$0") root=$(dirname "$0") # Colors c0="\033[0m" cbold="\033[1m" cred="\033[31m" cgreen="\033[32m" cyellow="\033[33m" cblue="\033[34m" cwhite="\033[37m" function error() { echo -e "${cbold}${cred}==> ${cwhite}$1${c0}" >&2 } function warning() { echo -e "${cbold}${cyellow}==> ${cwhite}$1${c0}" >&2 } function success() { echo -e "${cbold}${cgreen}==> ${cwhite}$1${c0}" } function msg() { echo -e "${cbold}${cblue}==> ${cwhite}$1${c0}" } # Split command line arguments, i.e: # -ab -> -a -b # --foo=bar -> --foo bar # # Split arguments are stored in the ARGS array # # Parameters: # $1,$2,$3,...,$n: arguments to split function explode_args() { unset ARGS local arg=$1 key value while [[ $arg ]]; do [[ $arg = "--" ]] && ARGS+=("$@") && break # Short options if [[ ${arg:0:1} = "-" && ${arg:1:1} != "-" ]]; then ARGS+=("-${arg:1:1}") (( ${#arg} > 2 )) && arg="-${arg:2}" || { shift; arg=$1; } # Long options elif [[ ${arg:0:2} = "--" ]]; then # Split argument at '=': # e.g --foo=bar -> key=--foo, value=bar key=${arg%%=*}; value=${arg#*=} ARGS+=("$key") [[ "$key" != "$value" ]] && ARGS+=("$value") shift; arg=$1 else ARGS+=("$arg"); shift; arg=$1 fi done } function usage() { echo "usage: $progname [options] [OS ...]" echo "" echo "Try to build ikos and launch the tests on different operating systems" echo "" echo "Defaults for the options are specified in brackets." echo "" echo "positinal arguments:" echo " OS A list of operating systems" echo "" echo "optional arguments:" echo " -h, --help Show this help message and exit" echo " -a, --all Run the tests over all available operating systems" echo " --jobs=N Allow N jobs at once [$njobs]" echo " --build-type=TYPE Specify the build type {Release,Debug} [$build_type]" } # Default arguments cmd="" njobs=2 build_type="Release" # Parse arguments explode_args "$@" set -- "${ARGS[@]}" unset ARGS declare -a args while [[ $1 ]]; do case "$1" in -h|--help) cmd="help";; -a|--all) cmd="all";; --jobs) shift; njobs=$1;; --build-type) shift; build_type=$1;; *) args+=("$1");; esac shift done if [[ $cmd = "help" ]]; then usage exit 0 fi if [[ $cmd = "all" ]]; then # List of dockerfiles to try # Note that it does not include Red Hat Enterprise Linux because it needs a license args=("debian-9" "debian-10" \ "ubuntu-16.04" "ubuntu-18.04" "ubuntu-19.04" \ "archlinux" \ "centos-6" "centos-7" \ "fedora-29" "fedora-30") fi if (( ${#args[@]} == 0 )); then echo "$progname: error: too few arguments" >&2 exit 2 fi # Check that docker is available docker info >/dev/null || { exit 1; } cd "$root" root=$(pwd) # Check that we can find all the Dockerfiles for os in "${args[@]}"; do if [[ ! -f "$os/Dockerfile" ]]; then echo "$progname: error: could not find the Dockerfile for $os" exit 3 fi done # go into ikos root directory cd ../.. declare -a results declare -a logfiles for os in "${args[@]}"; do msg "Running tests on ${cgreen}${os}${cwhite}" logfile="logs/${os}-$(date +'%Y-%m-%d-%H:%M:%S')" logfiles+=("$logfile") rm -f "$root/$logfile" docker build \ -t "ikos-$os" \ -f "$root/$os/Dockerfile" \ --build-arg "njobs=$njobs" \ --build-arg "build_type=$build_type" \ --force-rm \ --no-cache \ . 2>&1 | tee "$root/$logfile" ret=${PIPESTATUS[0]} results+=("$ret") if (( $ret == 0 )); then success "${cgreen}Passed${cwhite} successfully" docker rmi "ikos-$os" >/dev/null else error "${cred}Failed${cwhite}. see $logfile" fi done if (( ${#args[@]} > 1 )); then msg "Summary:" for ((i = 0; i < ${#args[@]}; i++)); do if (( ${results[$i]} == 0 )); then success "${args[$i]}: ${cgreen}Passed${cwhite}" else error "${args[$i]}: ${cred}Failed${cwhite}. see ${logfiles[$i]}" fi done fi NASA-SW-VnV-ikos-1d98c65/test/install/ubuntu-16.04/000077500000000000000000000000001473507761200212335ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/ubuntu-16.04/Dockerfile000066400000000000000000000025741473507761200232350ustar00rootroot00000000000000FROM ubuntu:16.04 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.5.1 # gmp 6.1.0 # boost 1.58.0 # python 2.7.12 # sqlite 3.11.0 # tbb 9002 # llvm 9.0.1 # clang 9.0.1 # gcc 5.4.0 # Upgrade RUN apt-get update RUN apt-get upgrade -y # Add ppa for llvm 9.0 RUN echo "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" >> /etc/apt/sources.list # Add llvm repository key RUN apt-get install -y wget gnupg RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - # Refresh cache RUN apt-get update # Install all dependencies RUN apt-get install -y gcc g++ cmake libgmp-dev libboost-dev \ libboost-filesystem-dev libboost-thread-dev libboost-test-dev python \ python-pygments libsqlite3-dev libtbb-dev libz-dev libedit-dev \ llvm-9 llvm-9-dev llvm-9-tools clang-9 # Add ikos source code ADD . /root/ikos # Build ikos RUN rm -rf /root/ikos/build && mkdir /root/ikos/build WORKDIR /root/ikos/build ENV MAKEFLAGS "-j$njobs" RUN cmake \ -DCMAKE_INSTALL_PREFIX="/opt/ikos" \ -DCMAKE_BUILD_TYPE="$build_type" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. RUN make RUN make install # Run the tests RUN make check # Add ikos to the path ENV PATH "/opt/ikos/bin:$PATH" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/ubuntu-18.04/000077500000000000000000000000001473507761200212355ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/ubuntu-18.04/Dockerfile000066400000000000000000000025751473507761200232400ustar00rootroot00000000000000FROM ubuntu:18.04 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.10.2 # gmp 6.1.2 # boost 1.65.1 # python 2.7.15 # sqlite 3.22.0 # tbb 9107 # llvm 9.0.1 # clang 9.0.1 # gcc 7.4.0 # Upgrade RUN apt-get update RUN apt-get upgrade -y # Add ppa for llvm 9.0 RUN echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main" >> /etc/apt/sources.list # Add llvm repository key RUN apt-get install -y wget gnupg RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - # Refresh cache RUN apt-get update # Install all dependencies RUN apt-get install -y gcc g++ cmake libgmp-dev libboost-dev \ libboost-filesystem-dev libboost-thread-dev libboost-test-dev python \ python-pygments libsqlite3-dev libtbb-dev libz-dev libedit-dev \ llvm-9 llvm-9-dev llvm-9-tools clang-9 # Add ikos source code ADD . /root/ikos # Build ikos RUN rm -rf /root/ikos/build && mkdir /root/ikos/build WORKDIR /root/ikos/build ENV MAKEFLAGS "-j$njobs" RUN cmake \ -DCMAKE_INSTALL_PREFIX="/opt/ikos" \ -DCMAKE_BUILD_TYPE="$build_type" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. RUN make RUN make install # Run the tests RUN make check # Add ikos to the path ENV PATH "/opt/ikos/bin:$PATH" # Done WORKDIR / NASA-SW-VnV-ikos-1d98c65/test/install/ubuntu-19.04/000077500000000000000000000000001473507761200212365ustar00rootroot00000000000000NASA-SW-VnV-ikos-1d98c65/test/install/ubuntu-19.04/Dockerfile000066400000000000000000000025741473507761200232400ustar00rootroot00000000000000FROM ubuntu:19.04 MAINTAINER Maxime Arthaud ARG njobs=2 ARG build_type=Release # Installs the following versions (note that it might be out of date): # cmake 3.13.4 # gmp 6.1.2 # boost 1.67.0 # python 2.7.16 # sqlite 3.27.2 # tbb 10006 # llvm 9.0.1 # clang 9.0.1 # gcc 8.3.0 # Upgrade RUN apt-get update RUN apt-get upgrade -y # Add ppa for llvm 9.0 RUN echo "deb http://apt.llvm.org/disco/ llvm-toolchain-disco-9 main" >> /etc/apt/sources.list # Add llvm repository key RUN apt-get install -y wget gnupg RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - # Refresh cache RUN apt-get update # Install all dependencies RUN apt-get install -y gcc g++ cmake libgmp-dev libboost-dev \ libboost-filesystem-dev libboost-thread-dev libboost-test-dev python \ python-pygments libsqlite3-dev libtbb-dev libz-dev libedit-dev \ llvm-9 llvm-9-dev llvm-9-tools clang-9 # Add ikos source code ADD . /root/ikos # Build ikos RUN rm -rf /root/ikos/build && mkdir /root/ikos/build WORKDIR /root/ikos/build ENV MAKEFLAGS "-j$njobs" RUN cmake \ -DCMAKE_INSTALL_PREFIX="/opt/ikos" \ -DCMAKE_BUILD_TYPE="$build_type" \ -DLLVM_CONFIG_EXECUTABLE="/usr/lib/llvm-9/bin/llvm-config" \ .. RUN make RUN make install # Run the tests RUN make check # Add ikos to the path ENV PATH "/opt/ikos/bin:$PATH" # Done WORKDIR /
\n' line_num = 1 for i, line in source: statement_reports = lines_reports.get(line_num) t = '''
%d
%s
\n''' % (line_num, self._line_status(statement_reports), line_num, line_num, line.replace('\n', '')) if statement_reports: self.checks[line_num] = self._build_checks(statement_reports) yield i, t line_num += 1 yield 0, '