├── .gitignore ├── .vscode └── sftp.json ├── LICENSE ├── README.md ├── SECURITY.md ├── check_diff.py ├── inputs └── alive │ ├── instcombine │ ├── README.md │ ├── answ.txt │ ├── opt001 │ ├── opt002 │ ├── opt003 │ ├── opt004 │ ├── opt005 │ ├── opt006 │ ├── opt007 │ ├── opt008 │ ├── opt009 │ ├── opt010 │ ├── opt011 │ ├── opt012 │ ├── opt013 │ ├── opt014 │ ├── opt015 │ ├── opt016 │ ├── opt017 │ ├── opt018 │ ├── opt019 │ ├── opt020 │ ├── opt021 │ ├── opt022 │ ├── opt023 │ ├── opt024 │ ├── opt025 │ ├── opt026 │ ├── opt027 │ ├── opt028 │ ├── opt029 │ ├── opt030 │ ├── opt031 │ ├── opt032 │ ├── opt033 │ ├── opt034 │ ├── opt035 │ ├── opt036 │ ├── opt037 │ ├── opt038 │ ├── opt039 │ ├── opt040 │ ├── opt041 │ ├── opt042 │ ├── opt043 │ ├── opt044 │ ├── opt045 │ ├── opt046 │ ├── opt047 │ ├── opt048 │ ├── opt049 │ ├── opt050 │ ├── opt051 │ ├── opt052 │ ├── opt053 │ ├── opt054 │ ├── opt055 │ ├── opt056 │ ├── opt057 │ ├── opt058 │ ├── opt059 │ ├── opt060 │ ├── opt061 │ ├── opt062 │ ├── opt063 │ ├── opt064 │ ├── opt065 │ ├── opt066 │ ├── opt067 │ ├── opt068 │ ├── opt069 │ ├── opt070 │ ├── opt071 │ ├── opt072 │ ├── opt073 │ ├── opt074 │ ├── opt075 │ ├── opt076 │ ├── opt077 │ ├── opt078 │ ├── opt079 │ ├── opt080 │ ├── opt081 │ ├── opt082 │ ├── opt083 │ ├── opt084 │ ├── opt085 │ ├── opt086 │ ├── opt087 │ ├── opt088 │ ├── opt089 │ ├── opt090 │ ├── opt091 │ ├── opt092 │ ├── opt093 │ ├── opt094 │ ├── opt095 │ ├── opt096 │ ├── opt097 │ ├── opt098 │ ├── opt099 │ ├── opt100 │ ├── opt101 │ ├── opt102 │ ├── opt103 │ ├── opt104 │ ├── opt105 │ ├── opt106 │ ├── opt107 │ ├── opt108 │ ├── opt109 │ ├── opt110 │ ├── opt111 │ ├── opt112 │ ├── opt113 │ ├── opt114 │ ├── opt115 │ ├── opt116 │ ├── opt117 │ ├── opt118 │ ├── opt119 │ ├── opt120 │ ├── opt121 │ ├── opt122 │ ├── opt123 │ ├── opt124 │ ├── opt125 │ ├── opt126 │ ├── opt127 │ ├── opt128 │ ├── opt129 │ ├── opt130 │ ├── opt131 │ ├── opt132 │ └── opt133 │ └── unit │ ├── README.md │ ├── answ.txt │ ├── opt001 │ ├── opt002 │ ├── opt003 │ ├── opt004 │ ├── opt005 │ ├── opt006 │ ├── opt007 │ ├── opt008 │ ├── opt009 │ ├── opt010 │ ├── opt011 │ ├── opt012 │ ├── opt013 │ ├── opt014 │ ├── opt015 │ ├── opt016 │ ├── opt017 │ ├── opt018 │ └── opt019 ├── leanpkg.path ├── leanpkg.toml ├── run-alive.sh ├── run-irtest.sh ├── run-proptest.sh └── src ├── bitvector.lean ├── common.lean ├── freevar.lean ├── irsem.lean ├── irsem_exec.lean ├── irsem_smt.lean ├── irtest_run.lean ├── irtype.lean ├── lang.lean ├── lang_tostr.lean ├── langparser.lean ├── main.lean ├── ops.lean ├── proptest.lean ├── proptest_run.lean ├── smtcompile.lean ├── smtexpr.lean ├── spec ├── closed.lean ├── customlemmas.lean ├── equiv.lean ├── freevar.lean ├── initialstate.lean ├── irstate.lean ├── lemmas.lean ├── lemmas_basic.lean ├── openprog.lean ├── refinement.lean └── spec.lean ├── vcgen.lean └── verifyopt.lean /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | 290 | *.olean 291 | output.txt 292 | output_summarized.txt 293 | -------------------------------------------------------------------------------- /.vscode/sftp.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "localhost", 3 | "protocol": "sftp", 4 | "port": "22", 5 | "username": "username", 6 | "remotePath": "/" 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | AliveInLean 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AliveInLean 2 | 3 | ## Setup 4 | 5 | - Download Lean 3.4.2 from https://leanprover.github.io/download/ 6 | - Extract it, and update PATH environmental variable so command `lean` can be executed on the command prompt 7 | - Download & install z3 from https://github.com/Z3Prover/z3 and update PATH so `z3` can be executed as well 8 | - Run `leanpkg configure` to install SMT lib interface and mathlib 9 | 10 | 11 | ## Run 12 | 13 | ``` 14 | # Run selected tests from Alive's test suite (which contain 15 | # no precondition and do not require additional grammars) 16 | ./run-alive.sh 17 | ``` 18 | 19 | ``` 20 | # Run random tests for the specification of Z3 expression - 21 | # concrete value, as well as 4 admitted arithmetic lemmas. 22 | # Note that bv_equiv.zext/sext/trunc will have 'omitted' tests 23 | # because sometimes generated expressions try to compare 24 | # bitvectors with different bitwidths. 25 | ./run-proptest.sh 26 | ``` 27 | 28 | ``` 29 | # Run random tests for the specification of LLVM assembly language. 30 | # Set clang path to yours by modifying the script. 31 | ./run-irtest.sh 32 | ``` 33 | 34 | 35 | ## Theorems 36 | 37 | - Specification, as well as proof, is in `src/spec/`. 38 | 39 | 1. Execution of `bigstep` with two different value semantics (SMT expr / concrete value) 40 | has some good relations. 41 | 42 | ``` 43 | def encode (ss:irstate_smt) (se:irstate_exec) (η:freevar.env) := 44 | irstate_equiv (η⟦ss⟧) se 45 | 46 | def bigstep_both:= ∀ ss se (p:program) oss' ose' η 47 | (HENC:encode ss se η) 48 | (HOSS': oss' = bigstep irsem_smt ss p) 49 | (HOSE': ose' = bigstep irsem_exec se p), 50 | none_or_some oss' ose' (λ ss' se', encode ss' se' η) 51 | -- Its proof is at equiv.lean 52 | ``` 53 | 54 | 2. We can generate initial state correctly. 55 | 56 | ``` 57 | def init_state_encode:= ∀ (freevars:list (string × ty)) (sg sg':std_gen) ise iss 58 | (HUNQ: list.unique $ freevars.map prod.fst) 59 | (HIE:(ise, sg') = create_init_state_exec freevars sg) 60 | (HIS:iss = create_init_state_smt freevars), 61 | ∃ η, encode iss ise η 62 | -- Its proof is at initialstate.lean 63 | ``` 64 | 65 | 3. If refinement checking function `check_single_reg0` says it's true, refinement 66 | indeed holds. 67 | 68 | ``` 69 | def refines_single_reg_correct := ∀ (psrc ptgt:program) 70 | (root:string) (ss0:irstate_smt) sb 71 | (HSREF:some sb = check_single_reg0 irsem_smt psrc ptgt root ss0) 72 | (HEQ:∀ (η0:freevar.env) e, b_equiv (η0⟦sb⟧) e → e = tt), 73 | root_refines_smt psrc ptgt ss0 root 74 | -- Its proof is at refinement.lean 75 | ``` 76 | 77 | # Contributing 78 | 79 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 80 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 81 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 82 | 83 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 84 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 85 | provided by the bot. You will only need to do this once across all repos using our CLA. 86 | 87 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 88 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 89 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 90 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /check_diff.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import sys 3 | 4 | def matches(s1, s2): 5 | s1 = s1.strip() 6 | s2 = s2.strip() 7 | if s1 != "Correct" and s1 != "Incorrect": 8 | # Unknown output. 9 | return 0 10 | if (s1 == "Correct" and s2 == "Optimization is correct!") or \ 11 | (s1 == "Incorrect" and s2.startswith("ERROR:")): 12 | # Correct. 13 | return 1 14 | # Incorrect! 15 | return 2 16 | 17 | if len(sys.argv) != 3: 18 | print("check_diff.py ") 19 | exit(1) 20 | 21 | ls1 = open(sys.argv[1]).readlines() 22 | ls2 = open(sys.argv[2]).readlines() 23 | if len(ls1) != len(ls2): 24 | print("# of total lines of files differ..!") 25 | print("\t# of lines of " + sys.argv[1] + ": " + str(len(ls1))) 26 | print("\t# of lines of " + sys.argv[2] + ": " + str(len(ls2))) 27 | exit(1) 28 | 29 | correct = 0 30 | incorrect = 0 31 | strange = 0 32 | for i in range(0, len(ls1)): 33 | res = matches(ls1[i], ls2[i]) 34 | if res == 0: 35 | print(str(i+1) + ": Unknown output:") 36 | print("\t" + ls1[i].strip()) 37 | print("\t" + ls2[i].strip()) 38 | strange = strange + 1 39 | elif res == 1: 40 | correct = correct + 1 41 | elif res == 2: 42 | print(str(i+1) + ": Incorrect!") 43 | print("\t" + ls1[i].strip()) 44 | print("\t" + ls2[i].strip()) 45 | incorrect = incorrect + 1 46 | 47 | print("Total: " + str(correct) + " corrects, " + str(incorrect) + 48 | " incorrects, " + str(strange) + " strange outputs") 49 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/README.md: -------------------------------------------------------------------------------- 1 | From alive-newsema/tests/instcombine. 2 | 3 | answ.txt is the output of Alive (newsema branch). 4 | 5 | opt116, opt117, opt118,opt119, opt120, opt121, opt122, opt123 are not supported in currenct semantics because they are converting select into logical ops. 6 | Alive (with newsema branch) says they are incorrect as well. 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/answ.txt: -------------------------------------------------------------------------------- 1 | Optimization is correct! 2 | Optimization is correct! 3 | Optimization is correct! 4 | Optimization is correct! 5 | Optimization is correct! 6 | Optimization is correct! 7 | Optimization is correct! 8 | Optimization is correct! 9 | Optimization is correct! 10 | Optimization is correct! 11 | Optimization is correct! 12 | Optimization is correct! 13 | Optimization is correct! 14 | Optimization is correct! 15 | Optimization is correct! 16 | Optimization is correct! 17 | Optimization is correct! 18 | Optimization is correct! 19 | Optimization is correct! 20 | Optimization is correct! 21 | Optimization is correct! 22 | Optimization is correct! 23 | Optimization is correct! 24 | Optimization is correct! 25 | Optimization is correct! 26 | Optimization is correct! 27 | Optimization is correct! 28 | Optimization is correct! 29 | Optimization is correct! 30 | Optimization is correct! 31 | Optimization is correct! 32 | Optimization is correct! 33 | Optimization is correct! 34 | Optimization is correct! 35 | Optimization is correct! 36 | Optimization is correct! 37 | Optimization is correct! 38 | Optimization is correct! 39 | Optimization is correct! 40 | Optimization is correct! 41 | Optimization is correct! 42 | Optimization is correct! 43 | Optimization is correct! 44 | Optimization is correct! 45 | Optimization is correct! 46 | Optimization is correct! 47 | Optimization is correct! 48 | Optimization is correct! 49 | Optimization is correct! 50 | Optimization is correct! 51 | Optimization is correct! 52 | Optimization is correct! 53 | Optimization is correct! 54 | Optimization is correct! 55 | Optimization is correct! 56 | Optimization is correct! 57 | Optimization is correct! 58 | Optimization is correct! 59 | Optimization is correct! 60 | Optimization is correct! 61 | Optimization is correct! 62 | Optimization is correct! 63 | Optimization is correct! 64 | Optimization is correct! 65 | Optimization is correct! 66 | Optimization is correct! 67 | Optimization is correct! 68 | Optimization is correct! 69 | Optimization is correct! 70 | Optimization is correct! 71 | Optimization is correct! 72 | Optimization is correct! 73 | Optimization is correct! 74 | Optimization is correct! 75 | Optimization is correct! 76 | Optimization is correct! 77 | Optimization is correct! 78 | Optimization is correct! 79 | Optimization is correct! 80 | Optimization is correct! 81 | Optimization is correct! 82 | Optimization is correct! 83 | Optimization is correct! 84 | Optimization is correct! 85 | Optimization is correct! 86 | Optimization is correct! 87 | Optimization is correct! 88 | Optimization is correct! 89 | Optimization is correct! 90 | Optimization is correct! 91 | Optimization is correct! 92 | Optimization is correct! 93 | Optimization is correct! 94 | Optimization is correct! 95 | Optimization is correct! 96 | Optimization is correct! 97 | Optimization is correct! 98 | Optimization is correct! 99 | Optimization is correct! 100 | Optimization is correct! 101 | Optimization is correct! 102 | Optimization is correct! 103 | Optimization is correct! 104 | Optimization is correct! 105 | Optimization is correct! 106 | Optimization is correct! 107 | Optimization is correct! 108 | Optimization is correct! 109 | Optimization is correct! 110 | Optimization is correct! 111 | Optimization is correct! 112 | Optimization is correct! 113 | Optimization is correct! 114 | Optimization is correct! 115 | Optimization is correct! 116 | ERROR: Target is more poisonous than Source for i1 %A 117 | ERROR: Target is more poisonous than Source for i1 %A 118 | ERROR: Target is more poisonous than Source for i1 %A 119 | ERROR: Target is more poisonous than Source for i1 %A 120 | ERROR: Target is more poisonous than Source for i1 %r 121 | ERROR: Target is more poisonous than Source for i1 %r 122 | ERROR: Target is more poisonous than Source for i1 %r 123 | ERROR: Target is more poisonous than Source for i1 %r 124 | Optimization is correct! 125 | Optimization is correct! 126 | Optimization is correct! 127 | Optimization is correct! 128 | Optimization is correct! 129 | Optimization is correct! 130 | Optimization is correct! 131 | Optimization is correct! 132 | Optimization is correct! 133 | Optimization is correct! 134 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt001: -------------------------------------------------------------------------------- 1 | Name: AddSub:1098 2 | %ax = zext i1 %a to i4 3 | %c = add i4 %ax, %b 4 | => 5 | %b1 = add i4 %b, 1 6 | %c = select i1 %a, i4 %b1, i4 %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt002: -------------------------------------------------------------------------------- 1 | Name: AddSub:1152 2 | %r = add i1 %x, %y 3 | => 4 | %r = xor i1 %x, %y 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt003: -------------------------------------------------------------------------------- 1 | Name: AddSub:1164 2 | %na = sub i4 0, %a 3 | %c = add i4 %na, %b 4 | => 5 | %c = sub i4 %b, %a 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt004: -------------------------------------------------------------------------------- 1 | Name: AddSub:1165 2 | %na = sub i4 0, %a 3 | %nb = sub i4 0, %b 4 | %c = add i4 %na, %nb 5 | => 6 | %ab = add i4 %a, %b 7 | %c = sub i4 0, %ab 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt005: -------------------------------------------------------------------------------- 1 | Name: AddSub:1176 2 | %nb = sub i4 0, %b 3 | %c = add i4 %a, %nb 4 | => 5 | %c = sub i4 %a, %b 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt006: -------------------------------------------------------------------------------- 1 | Name: AddSub:1295 2 | %aab = and i4 %a, %b 3 | %aob = xor i4 %a, %b 4 | %c = add i4 %aab, %aob 5 | => 6 | %c = or i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt007: -------------------------------------------------------------------------------- 1 | Name: AddSub:1309 2 | %lhs = and i4 %a, %b 3 | %rhs = or i4 %a, %b 4 | %c = add i4 %lhs, %rhs 5 | => 6 | %c = add i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt008: -------------------------------------------------------------------------------- 1 | Name: AddSub:1309-2 2 | %lhs = and i4 %a, %b 3 | %rhs = or i4 %a, %b 4 | %c = add nsw i4 %lhs, %rhs 5 | => 6 | %c = add nsw i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt009: -------------------------------------------------------------------------------- 1 | Name: AddSub:1309-3 2 | %lhs = and i4 %a, %b 3 | %rhs = or i4 %a, %b 4 | %c = add nuw i4 %lhs, %rhs 5 | => 6 | %c = add nuw i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt010: -------------------------------------------------------------------------------- 1 | Name: AddSub:1539 2 | %na = sub i4 0, %a 3 | %r = sub i4 %x, %na 4 | => 5 | %r = add i4 %x, %a 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt011: -------------------------------------------------------------------------------- 1 | Name: AddSub:1546 2 | %na = sub nsw i4 0, %a 3 | %r = sub nsw i4 %x, %na 4 | => 5 | %r = add nsw i4 %x, %a 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt012: -------------------------------------------------------------------------------- 1 | Name: AddSub:1556 2 | %r = sub i1 %x, %y 3 | => 4 | %r = xor i1 %x, %y 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt013: -------------------------------------------------------------------------------- 1 | Name: AddSub:1560 2 | %r = sub i9 -1, %a 3 | => 4 | %r = xor i9 %a, -1 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt014: -------------------------------------------------------------------------------- 1 | Name: AddSub:1582 2 | %rhs = zext i1 %X to i9 3 | %r = sub i9 0, %rhs 4 | => 5 | %r = sext i1 %X to i9 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt015: -------------------------------------------------------------------------------- 1 | Name: AddSub:1587 2 | %rhs = sext i1 %X to i9 3 | %r = sub i9 0, %rhs 4 | => 5 | %r = zext i1 %X to i9 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt016: -------------------------------------------------------------------------------- 1 | Name: AddSub:1614 2 | %Op1 = add i4 %X, %Y 3 | %r = sub i4 %X, %Op1 4 | => 5 | %r = sub i4 0, %Y 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt017: -------------------------------------------------------------------------------- 1 | Name: AddSub:1619 2 | %Op0 = sub i4 %X, %Y 3 | %r = sub i4 %Op0, %X 4 | => 5 | %r = sub i4 0, %Y 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt018: -------------------------------------------------------------------------------- 1 | Name: AddSub:1624 2 | %Op0 = or i4 %A, %B 3 | %Op1 = xor i4 %A, %B 4 | %r = sub i4 %Op0, %Op1 5 | => 6 | %r = and i4 %A, %B 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt019: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:698 2 | %a1 = and i4 %a, %b 3 | %a2 = and i4 %a, %d 4 | %op0 = icmp eq i4 %a1, 0 5 | %op1 = icmp eq i4 %a2, 0 6 | %r = and i1 %op0, %op1 7 | => 8 | %or = or i4 %b, %d 9 | %a3 = and i4 %a, %or 10 | %r = icmp eq i4 %a3, 0 11 | 12 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt020: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:709 2 | %a1 = and i4 %a, %b 3 | %a2 = and i4 %a, %d 4 | %op0 = icmp eq i4 %a1, %b 5 | %op1 = icmp eq i4 %a2, %d 6 | %r = and i1 %op0, %op1 7 | => 8 | %or = or i4 %b, %d 9 | %a3 = and i4 %a, %or 10 | %r = icmp eq i4 %a3, %or 11 | 12 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt021: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:716 2 | %a1 = and i4 %a, %b 3 | %a2 = and i4 %a, %d 4 | %op0 = icmp eq i4 %a1, %a 5 | %op1 = icmp eq i4 %a2, %a 6 | %r = and i1 %op0, %op1 7 | => 8 | %a4 = and i4 %b, %d 9 | %a3 = and i4 %a, %a4 10 | %r = icmp eq i4 %a3, %a 11 | 12 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt022: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:794 2 | %op0 = icmp sgt i4 %a, %b 3 | %op1 = icmp ne i4 %a, %b 4 | %r = and i1 %op0, %op1 5 | => 6 | %r = icmp sgt i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt023: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:827 2 | %op0 = icmp eq i4 %a, 0 3 | %op1 = icmp eq i4 %b, 0 4 | %r = and i1 %op0, %op1 5 | => 6 | %o = or i4 %a, %b 7 | %r = icmp eq i4 %o, 0 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt024: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1191-1 2 | %op0 = shl i4 1, %op0RHS 3 | %r = and i4 %op0, 1 4 | => 5 | %newICMP = icmp eq i4 %op0RHS, 0 6 | %r = zext i1 %newICMP to i4 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt025: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1191-2 2 | %op0 = lshr i4 1, %op0RHS 3 | %r = and i4 %op0, 1 4 | => 5 | %newICMP = icmp eq i4 %op0RHS, 0 6 | %r = zext i1 %newICMP to i4 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt026: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1230 ~A & ~B -> ~(A | B) 2 | %op0 = xor i9 %notOp0, -1 3 | %op1 = xor i9 %notOp1, -1 4 | %r = and i9 %op0, %op1 5 | => 6 | %or = or i9 %notOp0, %notOp1 7 | %r = xor i9 %or, -1 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt027: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1241 (A|B) & ~(A&B) => A^B 2 | %op0 = or i9 %A, %B 3 | %notOp1 = and i9 %A, %B 4 | %op1 = xor i9 %notOp1, -1 5 | %r = and i9 %op0, %op1 6 | => 7 | %r = xor i9 %A, %B 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt028: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1247 ~(A&B) & (A|B) => A^B 2 | %notOp0 = and i9 %A, %B 3 | %op0 = xor i9 %notOp0, -1 4 | %op1 = or i9 %A, %B 5 | %r = and i9 %op0, %op1 6 | => 7 | %r = xor i9 %A, %B 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt029: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1253 A & (A^B) -> A & ~B 2 | %op0 = xor i9 %A, %B 3 | %r = and i9 %op0, %A 4 | => 5 | %notB = xor i9 %B, -1 6 | %r = and i9 %A, %notB 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt030: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1280 (~A|B)&A -> A&B 2 | %nA = xor i9 %A, -1 3 | %op0 = or i9 %nA, %B 4 | %r = and i9 %op0, %A 5 | => 6 | %r = and i9 %A, %B 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt031: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1288 (A ^ B) & ((B ^ C) ^ A) -> (A ^ B) & ~C 2 | %op0 = xor i9 %A, %B 3 | %x = xor i9 %B, %C 4 | %op1 = xor i9 %x, %A 5 | %r = and i9 %op0, %op1 6 | => 7 | %negC = xor i9 %C, -1 8 | %r = and i9 %op0, %negC 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt032: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1294 (A | B) & ((~A) ^ B) -> (A & B) 2 | %op0 = or i9 %A, %B 3 | %x = xor i9 %A, -1 4 | %op1 = xor i9 %x, %B 5 | %r = and i9 %op0, %op1 6 | => 7 | %r = and i9 %A, %B 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt033: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1346 (sext) 2 | %op0 = sext i3 %x to i9 3 | %op1 = sext i3 %y to i9 4 | %r = and i9 %op0, %op1 5 | => 6 | %0 = and i3 %x, %y 7 | %r = sext i3 %0 to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt034: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1346 (zext) 2 | %op0 = zext i3 %x to i9 3 | %op1 = zext i3 %y to i9 4 | %r = and i9 %op0, %op1 5 | => 6 | %0 = and i3 %x, %y 7 | %r = zext i3 %0 to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt035: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1346 (trunc) 2 | %op0 = trunc i10 %x to i9 3 | %op1 = trunc i10 %y to i9 4 | %r = and i9 %op0, %op1 5 | => 6 | %0 = and i10 %x, %y 7 | %r = trunc i10 %0 to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt036: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1388 2 | %op0 = sext i1 %a to i9 3 | %r = and i9 %op0, %b 4 | => 5 | %r = select i1 %a, i9 %b, i9 0 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt037: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1395 2 | %nop0 = sext i1 %a to i4 3 | %op0 = xor i4 %nop0, -1 4 | %r = and i4 %op0, %b 5 | => 6 | %r = select i1 %a, i4 0, i4 %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt038: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1574 2 | %A = sext i1 %Cond to i4 3 | %D = xor i4 %A, -1 4 | %a1 = and i4 %A, %C 5 | %a2 = and i4 %B, %D 6 | %r = or i4 %a1, %a2 7 | => 8 | %r = select i1 %Cond, i4 %C, i4 %B 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt039: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1577 2 | %A = sext i1 %Cond to i9 3 | %n = xor i1 %Cond, -1 4 | %D = sext i1 %n to i9 5 | %a1 = and i9 %A, %C 6 | %a2 = and i9 %B, %D 7 | %r = or i9 %a1, %a2 8 | => 9 | %r = select i1 %Cond, i9 %C, i9 %B 10 | 11 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt040: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1581 2 | %A = sext i1 %Cond to i4 3 | %B = xor i4 %A, -1 4 | %a1 = and i4 %A, %C 5 | %a2 = and i4 %B, %D 6 | %r = or i4 %a1, %a2 7 | => 8 | %r = select i1 %Cond, i4 %C, i4 %D 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt041: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1583 2 | %A = sext i1 %Cond to i9 3 | %n = xor i1 %Cond, -1 4 | %B = sext i1 %n to i9 5 | %a1 = and i9 %A, %C 6 | %a2 = and i9 %B, %D 7 | %r = or i9 %a1, %a2 8 | => 9 | %r = select i1 %Cond, i9 %C, i9 %D 10 | 11 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt042: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1683-1 2 | %op0 = icmp ugt i4 %a, %b 3 | %op1 = icmp eq i4 %a, %b 4 | %r = or i1 %op0, %op1 5 | => 6 | %r = icmp uge i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt043: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1704 2 | %cmp1 = icmp eq i9 %B, 0 3 | %cmp2 = icmp ult i9 %A, %B 4 | %r = or i1 %cmp1, %cmp2 5 | => 6 | %b1 = add i9 %B, -1 7 | %r = icmp uge i9 %b1, %A 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt044: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1705 2 | %cmp1 = icmp eq i9 %B, 0 3 | %cmp2 = icmp ugt i9 %B, %A 4 | %r = or i1 %cmp1, %cmp2 5 | => 6 | %b1 = add i9 %B, -1 7 | %r = icmp uge i9 %b1, %A 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt045: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:1733 2 | %cmp1 = icmp ne i4 %A, 0 3 | %cmp2 = icmp ne i4 %B, 0 4 | %r = or i1 %cmp1, %cmp2 5 | => 6 | %or = or i4 %A, %B 7 | %r = icmp ne i4 %or, 0 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt046: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2113 ((~A & B) | A) -> (A | B) 2 | %negA = xor i9 %A, -1 3 | %op0 = and i9 %negA, %B 4 | %r = or i9 %op0, %A 5 | => 6 | %r = or i9 %A, %B 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt047: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2118 ((A & B) | ~A) -> (~A | B) 2 | %negA = xor i9 %A, -1 3 | %op0 = and i9 %A, %B 4 | %r = or i9 %op0, %negA 5 | => 6 | %r = or i9 %negA, %B 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt048: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2123 (A & (~B)) | (A ^ B) -> (A ^ B) 2 | %negB = xor i9 %B, -1 3 | %op0 = and i9 %A, %negB 4 | %op1 = xor i9 %A, %B 5 | %r = or i9 %op0, %op1 6 | => 7 | %r = xor i9 %A, %B 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt049: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2188 2 | %C = xor i9 %D, -1 3 | %B = xor i9 %A, -1 4 | %op0 = and i9 %A, %C 5 | %op1 = and i9 %B, %D 6 | %r = or i9 %op0, %op1 7 | => 8 | %r = xor i9 %A, %D 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt050: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2231 (A ^ B) | ((B ^ C) ^ A) -> (A ^ B) | C 2 | %op0 = xor i4 %A, %B 3 | %x = xor i4 %B, %C 4 | %op1 = xor i4 %x, %A 5 | %r = or i4 %op0, %op1 6 | => 7 | %r = or i4 %op0, %C 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt051: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2243 ((B | C) & A) | B -> B | (A & C) 2 | %o = or i4 %B, %C 3 | %op0 = and i4 %o, %A 4 | %r = or i4 %op0, %B 5 | => 6 | %a = and i4 %A, %C 7 | %r = or i4 %B, %a 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt052: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2247 (~A | ~B) == (~(A & B)) 2 | %na = xor i9 %A, -1 3 | %nb = xor i9 %B, -1 4 | %r = or i9 %na, %nb 5 | => 6 | %a = and i9 %A, %B 7 | %r = xor i9 %a, -1 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt053: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2263 2 | %op1 = xor i4 %op0, %B 3 | %r = or i4 %op0, %op1 4 | => 5 | %r = or i4 %op0, %B 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt054: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2264 2 | %na = xor i9 %A, -1 3 | %op1 = xor i9 %na, %B 4 | %r = or i9 %A, %op1 5 | => 6 | %nb = xor i9 %B, -1 7 | %r = or i9 %A, %nb 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt055: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2265 2 | %op0 = and i4 %A, %B 3 | %op1 = xor i4 %A, %B 4 | %r = or i4 %op0, %op1 5 | => 6 | %r = or i4 %A, %B 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt056: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2284 2 | %o = or i9 %A, %B 3 | %op1 = xor i9 %o, -1 4 | %r = or i9 %A, %op1 5 | => 6 | %not = xor i9 %B, -1 7 | %r = or i9 %A, %not 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt057: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2285 2 | %o = xor i9 %A, %B 3 | %op1 = xor i9 %o, -1 4 | %r = or i9 %A, %op1 5 | => 6 | %not = xor i9 %B, -1 7 | %r = or i9 %A, %not 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt058: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2297 2 | %op0 = and i9 %A, %B 3 | %na = xor i9 %A, -1 4 | %op1 = xor i9 %na, %B 5 | %r = or i9 %op0, %op1 6 | => 7 | %r = xor i9 %na, %B 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt059: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2321-1 2 | %op0 = zext i3 %A to i9 3 | %op1 = zext i3 %B to i9 4 | %r = or i9 %op0, %op1 5 | => 6 | %or = or i3 %A, %B 7 | %r = zext i3 %or to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt060: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2321-2 2 | %op0 = sext i3 %A to i9 3 | %op1 = sext i3 %B to i9 4 | %r = or i9 %op0, %op1 5 | => 6 | %or = or i3 %A, %B 7 | %r = sext i3 %or to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt061: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2321-3 2 | %op0 = trunc i10 %A to i9 3 | %op1 = trunc i10 %B to i9 4 | %r = or i9 %op0, %op1 5 | => 6 | %or = or i10 %A, %B 7 | %r = trunc i10 %or to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt062: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2356 2 | %op0 = sext i1 %A to i4 3 | %r = or i4 %op0, %op1 4 | => 5 | %r = select i1 %A, i4 -1, i4 %op1 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt063: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2367 2 | %op0 = or i4 %A, %_C1 3 | %r = or i4 %op0, %op1 4 | => 5 | %i = or i4 %A, %op1 6 | %r = or i4 %i, %_C1 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt064: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2375 2 | %op0 = select i1 %x, i4 %A, i4 %B 3 | %op1 = select i1 %x, i4 %C, i4 %D 4 | %r = or i4 %op0, %op1 5 | => 6 | %t = or i4 %A, %C 7 | %f = or i4 %B, %D 8 | %r = select i1 %x, i4 %t, i4 %f 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt065: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2416 2 | %x = xor i9 %nx, -1 3 | %op0 = and i9 %x, %y 4 | %r = xor i9 %op0, -1 5 | => 6 | %ny = xor i9 %y, -1 7 | %r = or i9 %nx, %ny 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt066: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2417 2 | %x = xor i9 %nx, -1 3 | %op0 = or i9 %x, %y 4 | %r = xor i9 %op0, -1 5 | => 6 | %ny = xor i9 %y, -1 7 | %r = and i9 %nx, %ny 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt067: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2429 2 | %op0 = and i9 %x, %y 3 | %r = xor i9 %op0, -1 4 | => 5 | %nx = xor i9 %x, -1 6 | %ny = xor i9 %y, -1 7 | %r = or i9 %nx, %ny 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt068: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2430 2 | %op0 = or i9 %x, %y 3 | %r = xor i9 %op0, -1 4 | => 5 | %nx = xor i9 %x, -1 6 | %ny = xor i9 %y, -1 7 | %r = and i9 %nx, %ny 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt069: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2443 2 | %nx = xor i9 %x, -1 3 | %op0 = ashr i9 %nx, %y 4 | %r = xor i9 %op0, -1 5 | => 6 | %r = ashr i9 %x, %y 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt070: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2453 2 | %op0 = icmp slt i4 %x, %y 3 | %r = xor i1 %op0, -1 4 | => 5 | %r = icmp sge i4 %x, %y 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt071: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2459-1 2 | %cmp = icmp slt i4 %x, %y 3 | %op0 = zext i1 %cmp to i11 4 | %r = xor i11 %op0, 1 5 | => 6 | %ncmp = icmp sge i4 %x, %y 7 | %r = zext i1 %ncmp to i11 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt072: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2459-2 2 | %cmp = icmp slt i4 %x, %y 3 | %op0 = sext i1 %cmp to i11 4 | %r = xor i11 %op0, -1 5 | => 6 | %ncmp = icmp sge i4 %x, %y 7 | %r = sext i1 %ncmp to i11 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt073: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2581 (B|A)^B -> A & ~B 2 | %op0 = or i9 %a, %op1 3 | %r = xor i9 %op0, %op1 4 | => 5 | %nop1 = xor i9 %op1, -1 6 | %r = and i9 %a, %nop1 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt074: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2587 (B&A)^A -> ~B & A 2 | %op0 = and i9 %a, %op1 3 | %r = xor i9 %op0, %op1 4 | => 5 | %na = xor i9 %a, -1 6 | %r = and i9 %na, %op1 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt075: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2595 2 | %op0 = and i4 %a, %b 3 | %op1 = or i4 %a, %b 4 | %r = xor i4 %op0, %op1 5 | => 6 | %r = xor i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt076: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2607 2 | %na = xor i9 %a, -1 3 | %nb = xor i9 %b, -1 4 | %op0 = or i9 %a, %nb 5 | %op1 = or i9 %na, %b 6 | %r = xor i9 %op0, %op1 7 | => 8 | %r = xor i9 %a, %b 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt077: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2617 2 | %na = xor i9 %a, -1 3 | %nb = xor i9 %b, -1 4 | %op0 = and i9 %a, %nb 5 | %op1 = and i9 %na, %b 6 | %r = xor i9 %op0, %op1 7 | => 8 | %r = xor i9 %a, %b 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt078: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2627 2 | %op0 = xor i9 %a, %c 3 | %op1 = or i9 %a, %b 4 | %r = xor i9 %op0, %op1 5 | => 6 | %na = xor i9 %a, -1 7 | %and = and i9 %na, %b 8 | %r = xor i9 %and, %c 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt079: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2647 2 | %op0 = and i4 %a, %b 3 | %op1 = xor i4 %a, %b 4 | %r = xor i4 %op0, %op1 5 | => 6 | %r = or i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt080: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2658 2 | %nb = xor i9 %b, -1 3 | %op0 = and i9 %a, %nb 4 | %na = xor i9 %a, -1 5 | %r = xor i9 %op0, %na 6 | => 7 | %and = and i9 %a, %b 8 | %r = xor i9 %and, -1 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt081: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2663 2 | %op0 = icmp ule i4 %a, %b 3 | %op1 = icmp ne i4 %a, %b 4 | %r = xor i1 %op0, %op1 5 | => 6 | %r = icmp uge i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt082: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2681-1 2 | %op0 = zext i3 %a to i9 3 | %op1 = zext i3 %b to i9 4 | %r = xor i9 %op0, %op1 5 | => 6 | %0 = xor i3 %a, %b 7 | %r = zext i3 %0 to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt083: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2681-2 2 | %op0 = sext i3 %a to i9 3 | %op1 = sext i3 %b to i9 4 | %r = xor i9 %op0, %op1 5 | => 6 | %0 = xor i3 %a, %b 7 | %r = sext i3 %0 to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt084: -------------------------------------------------------------------------------- 1 | Name: AndOrXor:2681-3 2 | %op0 = trunc i10 %a to i9 3 | %op1 = trunc i10 %b to i9 4 | %r = xor i9 %op0, %op1 5 | => 6 | %0 = xor i10 %a, %b 7 | %r = trunc i10 %0 to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt085: -------------------------------------------------------------------------------- 1 | Name: 152 2 | %r = mul i9 %x, -1 3 | => 4 | %r = sub i9 0, %x 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt086: -------------------------------------------------------------------------------- 1 | Name: 229 2 | %Op0 = add i4 %X, %_C1 3 | %r = mul i4 %Op0, %Op1 4 | => 5 | %mul = mul i4 %_C1, %Op1 6 | %tmp = mul i4 %X, %Op1 7 | %r = add i4 %tmp, %mul 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt087: -------------------------------------------------------------------------------- 1 | Name: 239 2 | %a = sub i4 0, %X 3 | %b = sub i4 0, %Y 4 | %r = mul i4 %a, %b 5 | => 6 | %r = mul i4 %X, %Y 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt088: -------------------------------------------------------------------------------- 1 | Name: 266 2 | %div = udiv exact i4 %X, %Y 3 | %negY = sub i4 0, %Y 4 | %r = mul i4 %div, %negY 5 | => 6 | %r = sub i4 0, %X 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt089: -------------------------------------------------------------------------------- 1 | Name: 266-2 2 | %div = sdiv exact i4 %X, %Y 3 | %negY = sub i4 0, %Y 4 | %r = mul i4 %div, %negY 5 | => 6 | %r = sub i4 0, %X 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt090: -------------------------------------------------------------------------------- 1 | Name: 275 2 | %div = udiv i5 %X, %Y 3 | %r = mul i5 %div, %Y 4 | => 5 | %rem = urem i5 %X, %Y 6 | %r = sub i5 %X, %rem 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt091: -------------------------------------------------------------------------------- 1 | Name: 275-2 2 | %div = sdiv i5 %X, %Y 3 | %r = mul i5 %div, %Y 4 | => 5 | %rem = srem i5 %X, %Y 6 | %r = sub i5 %X, %rem 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt092: -------------------------------------------------------------------------------- 1 | Name: 276 2 | %div = sdiv i5 %X, %Y 3 | %negY = sub i5 0, %Y 4 | %r = mul i5 %div, %negY 5 | => 6 | %rem = srem i5 %X, %Y 7 | %r = sub i5 %rem, %X 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt093: -------------------------------------------------------------------------------- 1 | Name: 276-2 2 | %div = udiv i5 %X, %Y 3 | %negY = sub i5 0, %Y 4 | %r = mul i5 %div, %negY 5 | => 6 | %rem = urem i5 %X, %Y 7 | %r = sub i5 %rem, %X 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt094: -------------------------------------------------------------------------------- 1 | Name: 283 2 | %r = mul i1 %X, %Y 3 | => 4 | %r = and i1 %X, %Y 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt095: -------------------------------------------------------------------------------- 1 | Name: 290 & 292 2 | %Op0 = shl i9 1, %Y 3 | %r = mul i9 %Op0, %Op1 4 | => 5 | %r = shl i9 %Op1, %Y 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt096: -------------------------------------------------------------------------------- 1 | Name: SimplifyDivRemOfSelect 2 | %sel = select i1 %c, i4 %Y, i4 0 3 | %r = udiv i4 %X, %sel 4 | => 5 | %r = udiv i4 %X, %Y 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt097: -------------------------------------------------------------------------------- 1 | Name: 805 2 | %r = sdiv i4 1, %X 3 | => 4 | %inc = add i4 %X, 1 5 | %c = icmp ult i4 %inc, 3 6 | %r = select i1 %c, i4 %X, i4 0 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt098: -------------------------------------------------------------------------------- 1 | Name: 809 2 | %r = udiv i4 1, %X 3 | => 4 | %c = icmp eq i4 %X, 1 5 | %r = zext i1 %c to i4 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt099: -------------------------------------------------------------------------------- 1 | Name: 820 2 | %Z = srem i9 %X, %Op1 3 | %Op0 = sub i9 %X, %Z 4 | %r = sdiv i9 %Op0, %Op1 5 | => 6 | %r = sdiv i9 %X, %Op1 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt100: -------------------------------------------------------------------------------- 1 | Name: 820 2 | %Z = urem i9 %X, %Op1 3 | %Op0 = sub i9 %X, %Z 4 | %r = udiv i9 %Op0, %Op1 5 | => 6 | %r = udiv i9 %X, %Op1 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt101: -------------------------------------------------------------------------------- 1 | Name: 891 2 | %s = shl i13 1, %N 3 | %r = udiv i13 %x, %s 4 | => 5 | %r = lshr i13 %x, %N 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt102: -------------------------------------------------------------------------------- 1 | Name: 891-exact 2 | %s = shl i13 1, %N 3 | %r = udiv exact i13 %x, %s 4 | => 5 | %r = lshr exact i13 %x, %N 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt103: -------------------------------------------------------------------------------- 1 | Name: 976 2 | %Op0 = zext i3 %X to i9 3 | %Op1 = zext i3 %Y to i9 4 | %r = udiv i9 %Op0, %Op1 5 | => 6 | %d = udiv i3 %X, %Y 7 | %r = zext i3 %d to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt104: -------------------------------------------------------------------------------- 1 | Name: 976-exact 2 | %Op0 = zext i4 %X to i9 3 | %Op1 = zext i4 %Y to i9 4 | %r = udiv exact i9 %Op0, %Op1 5 | => 6 | %d = udiv exact i4 %X, %Y 7 | %r = zext i4 %d to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt105: -------------------------------------------------------------------------------- 1 | Name: 1030 2 | %r = sdiv i9 %X, -1 3 | => 4 | %r = sub i9 0, %X 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt106: -------------------------------------------------------------------------------- 1 | Name: 1285 2 | %Op0 = zext i3 %X to i9 3 | %Op1 = zext i3 %Y to i9 4 | %r = urem i9 %Op0, %Op1 5 | => 6 | %u = urem i3 %X, %Y 7 | %r = zext i3 %u to i9 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt107: -------------------------------------------------------------------------------- 1 | Name: 1298 2 | %r = urem i4 1, %Op1 3 | => 4 | %cmp = icmp ne i4 %Op1, 1 5 | %r = zext i1 %cmp to i4 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt108: -------------------------------------------------------------------------------- 1 | Name: Select:637 2 | %c = icmp eq i4 %X, %_C 3 | %r = select i1 %c, i4 %X, i4 %Y 4 | => 5 | %r = select i1 %c, i4 %_C, i4 %Y 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt109: -------------------------------------------------------------------------------- 1 | Name: Select:641 2 | %c = icmp ne i4 %X, %_C 3 | %r = select i1 %c, i4 %Y, i4 %X 4 | => 5 | %r = select i1 %c, i4 %Y, i4 %_C 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt110: -------------------------------------------------------------------------------- 1 | Name: Select:699 2 | %c = icmp uge i4 %A, %B 3 | %umax = select i1 %c, i4 %A, i4 %B 4 | %c2 = icmp uge i4 %umax, %B 5 | %umax2 = select i1 %c2, i4 %umax, i4 %B 6 | => 7 | %umax2 = select i1 %c, i4 %A, i4 %B 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt111: -------------------------------------------------------------------------------- 1 | Name: Select:700 2 | %c = icmp slt i4 %A, %B 3 | %smin = select i1 %c, i4 %A, i4 %B 4 | %c2 = icmp slt i4 %smin, %B 5 | %smin2 = select i1 %c2, i4 %smin, i4 %B 6 | => 7 | %smin2 = select i1 %c, i4 %A, i4 %B 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt112: -------------------------------------------------------------------------------- 1 | Name: Select:740 2 | %c = icmp sgt i9 %A, 0 3 | %minus = sub i9 0, %A 4 | %abs = select i1 %c, i9 %A, i9 %minus 5 | %c2 = icmp sgt i9 %abs, -1 6 | %minus2 = sub i9 0, %abs 7 | %abs2 = select i1 %c2, i9 %abs, i9 %minus2 8 | => 9 | %abs2 = select i1 %c, i9 %A, i9 %minus 10 | 11 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt113: -------------------------------------------------------------------------------- 1 | Name: Select:741 2 | %c = icmp sgt i9 %A, 0 3 | %minus = sub i9 0, %A 4 | %abs = select i1 %c, i9 %minus, i9 %A 5 | %c2 = icmp sgt i9 %abs, -1 6 | %minus2 = sub i9 0, %abs 7 | %abs2 = select i1 %c2, i9 %minus2, i9 %abs 8 | => 9 | %abs2 = select i1 %c, i9 %minus, i9 %A 10 | 11 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt114: -------------------------------------------------------------------------------- 1 | Name: Select:746 2 | %c = icmp slt i4 %A, 0 3 | %minus = sub i4 0, %A 4 | %abs = select i1 %c, i4 %A, i4 %minus 5 | %c2 = icmp sgt i4 %abs, 0 6 | %minus2 = sub i4 0, %abs 7 | %abs2 = select i1 %c2, i4 %abs, i4 %minus2 8 | => 9 | %c3 = icmp sgt i4 %A, 0 10 | %abs2 = select i1 %c3, i4 %A, i4 %minus 11 | 12 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt115: -------------------------------------------------------------------------------- 1 | Name: Select:747 2 | %c = icmp sgt i4 %A, 0 3 | %minus = sub i4 0, %A 4 | %abs = select i1 %c, i4 %A, i4 %minus 5 | %c2 = icmp slt i4 %abs, 0 6 | %minus2 = sub i4 0, %abs 7 | %abs2 = select i1 %c2, i4 %abs, i4 %minus2 8 | => 9 | %c3 = icmp slt i4 %A, 0 10 | %abs2 = select i1 %c3, i4 %A, i4 %minus 11 | 12 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt116: -------------------------------------------------------------------------------- 1 | Name: Select:846 2 | %A = select i1 %B, i1 true, i1 %C 3 | => 4 | %A = or i1 %B, %C 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt117: -------------------------------------------------------------------------------- 1 | Name: Select:850 2 | %A = select i1 %B, i1 false, i1 %C 3 | => 4 | %notb = xor i1 %B, true 5 | %A = and i1 %notb, %C 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt118: -------------------------------------------------------------------------------- 1 | Name: Select:855 2 | %A = select i1 %B, i1 %C, i1 false 3 | => 4 | %A = and i1 %B, %C 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt119: -------------------------------------------------------------------------------- 1 | Name: Select:859 2 | %A = select i1 %B, i1 %C, i1 true 3 | => 4 | %notb = xor i1 %B, true 5 | %A = or i1 %notb, %C 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt120: -------------------------------------------------------------------------------- 1 | Name: Select:851 2 | %r = select i1 %a, i1 %b, i1 %a 3 | => 4 | %r = and i1 %a, %b 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt121: -------------------------------------------------------------------------------- 1 | Name: Select:852 2 | %r = select i1 %a, i1 %a, i1 %b 3 | => 4 | %r = or i1 %a, %b 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt122: -------------------------------------------------------------------------------- 1 | Name: Select:858 2 | %nota = xor i1 %a, -1 3 | %r = select i1 %a, i1 %nota, i1 %b 4 | => 5 | %r = and i1 %nota, %b 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt123: -------------------------------------------------------------------------------- 1 | Name: Select:859 2 | %nota = xor i1 %a, -1 3 | %r = select i1 %a, i1 %b, i1 %nota 4 | => 5 | %r = or i1 %nota, %b 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt124: -------------------------------------------------------------------------------- 1 | Name: Select:869 2 | %r = select i1 %_C, i4 1, i4 0 3 | => 4 | %r = zext i1 %_C to i4 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt125: -------------------------------------------------------------------------------- 1 | Name: Select:873 2 | %r = select i1 %_C, i4 -1, i4 0 3 | => 4 | %r = sext i1 %_C to i4 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt126: -------------------------------------------------------------------------------- 1 | Name: Select:877 2 | %r = select i1 %c, i4 0, i4 1 3 | => 4 | %notc = xor i1 %c, -1 5 | %r = zext i1 %notc to i4 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt127: -------------------------------------------------------------------------------- 1 | Name: Select:883 2 | %r = select i1 %c, i4 0, i4 -1 3 | => 4 | %notc = xor i1 %c, -1 5 | %r = sext i1 %notc to i4 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt128: -------------------------------------------------------------------------------- 1 | Name: Select:962 2 | %s1 = add i4 %x, %y 3 | %s2 = add i4 %x, %z 4 | %r = select i1 %c, i4 %s1, i4 %s2 5 | => 6 | %yz = select i1 %c, i4 %y, i4 %z 7 | %r = add i4 %x, %yz 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt129: -------------------------------------------------------------------------------- 1 | Name: Select:967a 2 | %sum = add i9 %x, %y 3 | %dif = sub i9 %x, %y 4 | %r = select i1 %c, i9 %sum, i9 %dif 5 | => 6 | %neg = sub i9 0, %y 7 | %sel = select i1 %c, i9 %y, i9 %neg 8 | %r = add i9 %x, %sel 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt130: -------------------------------------------------------------------------------- 1 | Name: Select:967b 2 | %sum = sub i9 %x, %y 3 | %dif = add i9 %x, %y 4 | %r = select i1 %c, i9 %sum, i9 %dif 5 | => 6 | %neg = sub i9 0, %y 7 | %sel = select i1 %c, i9 %neg, i9 %y 8 | %r = add i9 %x, %sel 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt131: -------------------------------------------------------------------------------- 1 | Name: Select:1070 2 | %X = select i1 %c, i4 %W, i4 %Z 3 | %r = select i1 %c, i4 %X, i4 %Y 4 | => 5 | %r = select i1 %c, i4 %W, i4 %Y 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt132: -------------------------------------------------------------------------------- 1 | Name: Select:1078 2 | %Y = select i1 %c, i4 %W, i4 %Z 3 | %r = select i1 %c, i4 %X, i4 %Y 4 | => 5 | %r = select i1 %c, i4 %X, i4 %Z 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/instcombine/opt133: -------------------------------------------------------------------------------- 1 | Name: Select:1087 2 | %c = xor i1 %val, true 3 | %r = select i1 %c, i4 %X, i4 %Y 4 | => 5 | %r = select i1 %val, i4 %Y, i4 %X 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/unit/README.md: -------------------------------------------------------------------------------- 1 | From alive-newsema/tests/unit. 2 | 3 | answ.txt is the output of Alive (newsema branch) 4 | -------------------------------------------------------------------------------- /inputs/alive/unit/answ.txt: -------------------------------------------------------------------------------- 1 | ERROR: Target is more poisonous than Source for i4 %A 2 | Optimization is correct! 3 | Optimization is correct! 4 | Optimization is correct! 5 | Optimization is correct! 6 | Optimization is correct! 7 | Optimization is correct! 8 | ERROR: Target is more poisonous than Source for i4 %C 9 | ERROR: Domain of definedness of Target is smaller than Source's for i4 %r 10 | ERROR: Target is more poisonous than Source for i2 %r 11 | ERROR: Target is more poisonous than Source for i4 %r 12 | ERROR: Target is more poisonous than Source for i2 %15 13 | Optimization is correct! 14 | Optimization is correct! 15 | Optimization is correct! 16 | Optimization is correct! 17 | Optimization is correct! 18 | ERROR: Temporary register %cmp unused and does not overwrite any Source register 19 | ERROR: Temporary register %x unused and not overwritten 20 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt001: -------------------------------------------------------------------------------- 1 | Name: 1 2 | %A = add i4 %x, %y 3 | => 4 | %A = add nsw i4 %x, %y 5 | 6 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt002: -------------------------------------------------------------------------------- 1 | Name: 2 2 | %aab = and i4 %a, %b 3 | %aob = xor i4 %a, %b 4 | %c = add i4 %aab, %aob 5 | => 6 | %c = or i4 %a, %b 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt003: -------------------------------------------------------------------------------- 1 | Name: icmp + zext 2 | %1 = icmp ule i4 %n, %a 3 | %2 = zext i1 %1 to i32 4 | %3 = icmp eq i4 %n, %b 5 | %4 = zext i1 %3 to i32 6 | %5 = or i32 %2, %4 7 | %6 = icmp eq i32 %5, 0 8 | => 9 | %. = or i1 %1, %3 10 | %6 = icmp eq i1 %., 0 11 | 12 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt004: -------------------------------------------------------------------------------- 1 | Name: add1 2 | %neg = xor i9 %y, -1 3 | %sub = sub i9 %x, %neg 4 | %add = sub i9 %sub, 1 5 | => 6 | %add = add i9 %x, %y 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt005: -------------------------------------------------------------------------------- 1 | Name: add2 2 | %xor = xor i9 %y, %x 3 | %and = and i9 %y, %x 4 | %shl = shl i9 %and, 1 5 | %add = add i9 %shl, %xor 6 | => 7 | %add = add i9 %x, %y 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt006: -------------------------------------------------------------------------------- 1 | Name: add3 2 | %or = or i4 %y, %x 3 | %and = and i4 %y, %x 4 | %add = add i4 %or, %and 5 | => 6 | %add = add i4 %x, %y 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt007: -------------------------------------------------------------------------------- 1 | Name: add4 2 | %or = or i9 %y, %x 3 | %shl = shl i9 %or, 1 4 | %xor = xor i9 %y, %x 5 | %add = sub i9 %shl, %xor 6 | => 7 | %add = add i9 %x, %y 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt008: -------------------------------------------------------------------------------- 1 | Name: 34 2 | %B = sub i4 0, %A 3 | %C = sub nsw i4 %x, %B 4 | => 5 | %C = add nsw i4 %x, %A 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt009: -------------------------------------------------------------------------------- 1 | Name: 39 2 | %Op1 = sub i4 0, %X 3 | %r = srem i4 %Op0, %Op1 4 | => 5 | %r = srem i4 %Op0, %X 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt010: -------------------------------------------------------------------------------- 1 | Name: 41 2 | %13 = mul nsw i2 %0, %3 3 | %14 = mul nsw i2 %6, %0 4 | %r = sub nuw nsw i2 %13, %14 5 | => 6 | %p13 = sub i2 %3, %6 7 | %r = mul nsw i2 %p13, %0 8 | 9 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt011: -------------------------------------------------------------------------------- 1 | Name: 42 2 | %1 = mul nsw i4 -2, %2 3 | %r = add i4 %1, 3 4 | => 5 | %3 = mul nsw i4 %2, 2 6 | %r = sub i4 3, %3 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt012: -------------------------------------------------------------------------------- 1 | Name: 43 2 | %13 = sdiv exact i2 %0, -2 3 | %14 = sdiv i2 %0, -2 4 | %15 = select i1 %1, i2 %13, i2 %14 5 | => 6 | %15 = sdiv exact i2 %0, -2 7 | 8 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt013: -------------------------------------------------------------------------------- 1 | Name: shift 1 2 | %sh = shl nsw i17 1, %b 3 | %mul = mul nsw i17 %a, %sh 4 | => 5 | %mul = shl nsw i17 %a, %b 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt014: -------------------------------------------------------------------------------- 1 | Name: shift 2 2 | %A = shl nsw i4 %x, 1 3 | %B = ashr i4 %A, 3 4 | => 5 | %B = ashr i4 %x, 2 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt015: -------------------------------------------------------------------------------- 1 | Name: shift 3 2 | %A = shl nuw i4 %x, 1 3 | %B = lshr i4 %A, 3 4 | => 5 | %B = lshr i4 %x, 2 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt016: -------------------------------------------------------------------------------- 1 | Name: shift 4 2 | %A = shl nsw i4 %x, 3 3 | %B = ashr i4 %A, 1 4 | => 5 | %B = shl nsw i4 %x, 2 6 | 7 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt017: -------------------------------------------------------------------------------- 1 | Name: big shift 2 | %tmp4 = trunc i9 %a0 to i8 3 | %tmp5 = shl i8 %tmp4, 5 4 | %tmp48 = and i8 %tmp5, 32 5 | %tmp49 = lshr i8 %tmp48, 5 6 | %tmp50 = mul i8 %tmp49, 64 7 | %tmp51 = xor i8 %tmp50, %tmp5 8 | %tmp52 = and i8 %tmp51, -128 9 | %tmp53 = lshr i8 %tmp52, 7 10 | %tmp54 = mul i8 %tmp53, 16 11 | => 12 | %0 = shl i8 %tmp4, 2 13 | %tmp54 = and i8 %0, 16 14 | 15 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt018: -------------------------------------------------------------------------------- 1 | Name: 70 2 | %cmp1 = icmp sge i1 %V1, %_C 3 | %cmp2 = icmp sge i1 %V2, %_C 4 | %and = and i1 %cmp1, %cmp2 5 | => 6 | %or = or i1 %V1, %V2 7 | %and = icmp sge i1 %or, %_C 8 | %cmp = and i1 %and, %or 9 | 10 | -------------------------------------------------------------------------------- /inputs/alive/unit/opt019: -------------------------------------------------------------------------------- 1 | Name: 71 2 | %x = add i3 3, 4 3 | %y = add i4 0, 3 4 | => 5 | %y = add i4 1, 2 6 | 7 | -------------------------------------------------------------------------------- /leanpkg.path: -------------------------------------------------------------------------------- 1 | builtin_path 2 | path _target/deps/mathlib/. 3 | path _target/deps/smt2_interface/src 4 | path ./. 5 | -------------------------------------------------------------------------------- /leanpkg.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alive_in_lean" 3 | version = "0.1" 4 | lean_version = "3.4.2" 5 | 6 | [dependencies] 7 | smt2_interface = {git = "https://github.com/leanprover/smt2_interface.git", rev = "7ff0ce248b68ea4db2a2d4966a97b5786da05ed7"} 8 | mathlib = {git = "https://github.com/leanprover/mathlib.git", rev = "019b2364cadb1dd8b30c9f13c602d61c19d3b6ea"} 9 | -------------------------------------------------------------------------------- /run-alive.sh: -------------------------------------------------------------------------------- 1 | for i in "inputs/alive/instcombine" "inputs/alive/unit"; do 2 | echo "Running ${i}/*.opt .." 3 | find ${i} -name "opt*" -print0 | sort -z | xargs -0 cat > ${i}/all.opt 4 | lean -q --run src/main.lean -verifyopt ${i}/all.opt > output.txt 5 | python3 check_diff.py output.txt ${i}/answ.txt 6 | rm ${i}/all.opt 7 | echo 8 | done 9 | echo "NOTE: running inputs/alive/unit/all.opt should have two incorrect results because Alive does type checking on input which will fail but AliveInLean does not do type checking so it will say it's okay." 10 | -------------------------------------------------------------------------------- /run-irtest.sh: -------------------------------------------------------------------------------- 1 | if [ "$#" -ne 1 ] && [ "$#" -ne 0 ]; then 2 | echo "run-irtest.sh" 3 | echo "run-irtest.sh " 4 | exit 1 5 | fi 6 | 7 | # of testing 8 | n=5000 9 | # clang path 10 | clang=~/clang-7.0.1/bin/clang 11 | # verbosity, replace n with y if want the script to be verbose 12 | verbose=n 13 | # random seed 14 | if [ "$#" -eq 0 ]; then 15 | seed=0 16 | else 17 | seed=$1 18 | fi 19 | 20 | rm -rf tmp/ 21 | mkdir tmp 22 | 23 | echo "Generating & testing $n random programs.." 24 | time lean --run ./src/irtest_run.lean $n $clang $verbose $seed 25 | -------------------------------------------------------------------------------- /run-proptest.sh: -------------------------------------------------------------------------------- 1 | if [ "$#" -eq 0 ]; then 2 | lean --run src/proptest_run.lean arith all 30 3 | lean --run src/proptest_run.lean bv_equiv all 30 4 | lean --run src/proptest_run.lean b_equiv all 30 5 | lean --run src/proptest_run.lean overflow_chk all 30 6 | else 7 | lean --run src/proptest_run.lean $@ 8 | fi 9 | -------------------------------------------------------------------------------- /src/bitvector.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .common 5 | import .ops 6 | 7 | def bitvector (sz:size) := 8 | { x : nat // x < (2 ^ sz.val) } 9 | 10 | instance (sz:size) : has_to_string (bitvector sz) := 11 | ⟨λ s, to_string s.1⟩ 12 | 13 | instance (sz:size) : has_zero (bitvector sz) := 14 | ⟨⟨0, -- 0 < sz → 0 < sz^n 15 | nat.pos_pow_of_pos sz dec_trivial⟩⟩ 16 | 17 | instance (sz:size): has_coe (bitvector sz) nat := 18 | ⟨λ s, s.1⟩ 19 | 20 | 21 | namespace bitvector 22 | 23 | private lemma nat.ne_zero_of_pos {n:ℕ} : n > 0 → n ≠ 0 := 24 | λ h contr, by simp [contr] at h; cases h 25 | 26 | lemma bv_mod_lt (n : nat) (sz : nat) : n % (2^sz) < 2^sz := 27 | begin 28 | apply nat.mod_lt, 29 | apply nat.pos_pow_of_pos, 30 | tactic.comp_val 31 | end 32 | 33 | local notation `♯` := by apply bv_mod_lt 34 | 35 | 36 | def to_int {sz:size} (x:bitvector sz) : ℤ := 37 | if x.1 < (2 ^ (sz.val - 1)) then x.1 38 | else int.neg_succ_of_nat (2 ^ sz.val - x.1 - 1) 39 | 40 | def of_int (sz:size) : ℤ → bitvector sz 41 | | x@(int.of_nat q) := 42 | ⟨q % (2 ^ sz.val), ♯⟩ 43 | | x@(int.neg_succ_of_nat p) := 44 | ⟨(((2 ^ sz.val) - p - 1) % (2^sz.val)), ♯⟩ 45 | 46 | @[simp] 47 | def all_one (sz:size) : bitvector sz := of_int sz (all_one_nat sz) 48 | 49 | @[simp] 50 | def int_min (sz:size) : bitvector sz := of_int sz (int_min_nat sz) 51 | 52 | @[simp] 53 | def zero (sz:size) : bitvector sz := of_int sz 0 54 | 55 | def of_bool (b:bool) : bitvector (size.one) := of_int size.one (cond b 1 0) 56 | 57 | variable {sz:size} 58 | 59 | def signed_check (b1 b2:bitvector sz) (f:ℤ → ℤ → ℤ) : bool := 60 | let i1 := to_int b1, 61 | i2 := to_int b2, 62 | s := int.of_nat (2^(sz.val - 1)) in 63 | f i1 i2 < 0 - s ∨ s ≤ f i1 i2 64 | def unsigned_check (b1 b2:bitvector sz) (f:ℤ → ℤ → ℤ) : bool := 65 | let i1:ℤ := b1, 66 | i2:ℤ := b2, 67 | s := int.of_nat (2 ^ sz.val) in 68 | f i1 i2 < 0 ∨ s ≤ f i1 i2 69 | 70 | 71 | def add (b1 b2:bitvector sz) : bitvector sz := 72 | ⟨(b1 + b2) % (2 ^ sz.val), ♯⟩ 73 | 74 | def add_overflows (signed:bool) (b1 b2:bitvector sz) : bool := 75 | if signed then signed_check b1 b2 int.add 76 | else unsigned_check b1 b2 int.add 77 | 78 | def sub (b1 b2:bitvector sz) : bitvector sz := 79 | ⟨(b1 + (2 ^ sz.val) - b2) % (2 ^ sz.val), ♯⟩ 80 | 81 | def sub_overflows (signed:bool) (b1 b2:bitvector sz) : bool := 82 | if signed then signed_check b1 b2 (λ i1 i2, int.add i1 (0-i2)) 83 | else unsigned_check b1 b2 (λ i1 i2, int.add i1 (0-i2)) 84 | 85 | def mul (b1 b2:bitvector sz) : bitvector sz := 86 | ⟨(b1 * b2) % (2 ^ sz.val), ♯⟩ 87 | def mul_overflows (signed:bool) (b1 b2:bitvector sz) : bool := 88 | if signed then signed_check b1 b2 int.mul 89 | else unsigned_check b1 b2 int.mul 90 | 91 | -- Returns 0 in case of division by zero 92 | def udiv (b1 b2:bitvector sz) : bitvector sz := 93 | ⟨(b1 / b2) % (2 ^ sz.val), ♯⟩ 94 | 95 | -- Returns 0 in case of division by zero 96 | def urem (b1 b2:bitvector sz) : bitvector sz := 97 | ⟨(b1 % b2) % (2 ^ sz.val), ♯⟩ 98 | 99 | -- Returns 0 in case of division by zero. 100 | -- Returns 0 in case of INT_MIN / -1. 101 | def sdiv (b1 b2:bitvector sz) : bitvector sz := 102 | of_int sz (int.quot (to_int b1) (to_int b2)) 103 | 104 | -- Returns 0 in case of division by zero. 105 | def srem (b1 b2:bitvector sz) : bitvector sz := 106 | of_int sz (int.rem (to_int b1) (to_int b2)) 107 | 108 | -- Utility functions for bitwise operations. 109 | def bits_to_nat (v : list bool) : ℕ := 110 | list.foldr (λ (b:bool) (x:ℕ), 2 * x + cond b 1 0) 0 v 111 | 112 | def nat_to_bits : Π (sz:ℕ), ℕ → list bool 113 | | 0 n := [] 114 | | (nat.succ sz') n := to_bool (n % 2 = 1) :: (nat_to_bits sz' (n / 2)) 115 | 116 | def list_bitwise_op (f:bool → bool → bool) : ∀ (l1 l2: list bool), list bool 117 | | (h1::t1) (h2::t2) := ((f h1 h2)::(list_bitwise_op t1 t2)) 118 | | (list.nil) (list.nil) := [] 119 | | _ _ := [] 120 | 121 | -- bitwise operation template. 122 | def bitwise_op (f:bool → bool → bool) (b1 b2:bitvector sz) : bitvector sz := 123 | ⟨bits_to_nat (list_bitwise_op f (nat_to_bits sz b1) (nat_to_bits sz b2)) % (2^sz.val), ♯⟩ 124 | 125 | def bitwise_or := @bitwise_op sz bor 126 | def bitwise_and := @bitwise_op sz band 127 | def bitwise_xor := @bitwise_op sz (λ b1 b2, ¬(b1 = b2)) 128 | 129 | def shl (b1 b2:bitvector sz): bitvector sz := 130 | ⟨(b1 * (2^(if b2.val ≥ sz.val then sz.val else b2.val))) % 2^sz.val, ♯⟩ 131 | def shl_overflows (signed:bool) (b1 b2:bitvector sz) : bool := 132 | if signed then 133 | let i1 := to_int b1, sft := b2.1 % sz, s := int.of_nat (2^(sz.val - 1)) in 134 | let v := i1 * int.of_nat (2^sft) in 135 | v < 0 - s ∨ s ≤ v 136 | else 137 | let i1 := b1.1, sft := b2.1 % sz, s := (2 ^ sz.val) in 138 | let v := i1 * (2^sft) in 139 | s ≤ v 140 | 141 | def lshr (b1 b2:bitvector sz): bitvector sz := 142 | ⟨(b1 / (2^(b2.val % sz))) % (2 ^ sz.val), ♯⟩ 143 | def ashr (b1 b2:bitvector sz): bitvector sz := 144 | let n2 := b2.1 % sz, 145 | sgn := b1.1 / (2^(sz.val - 1)), 146 | mask := 2^sz.val - sgn * 2^(sz.val - n2) in 147 | ⟨((b1 / (2^(b2.val % sz.val))) + mask) % 2^sz.val, ♯⟩ 148 | 149 | def eq (b1 b2:bitvector sz) : bool := 150 | b1 = b2 151 | def ne (b1 b2:bitvector sz) : bool := 152 | b1 ≠ b2 153 | def sle (b1 b2:bitvector sz) : bool := 154 | to_int b1 ≤ to_int b2 155 | def slt (b1 b2:bitvector sz) : bool := 156 | to_int b1 < to_int b2 157 | def ule (b1 b2:bitvector sz) : bool := 158 | b1.1 ≤ b2.1 159 | def ult (b1 b2:bitvector sz) : bool := 160 | b1.1 < b2.1 161 | 162 | def zext (sz2:size) (b1:bitvector sz) : bitvector sz2 := 163 | ⟨b1.1 % (2^sz2.val), ♯⟩ 164 | def sext (sz2:size) (b1:bitvector sz) : bitvector sz2 := 165 | ⟨(of_int (sz.add sz2) (to_int b1)) % (2^sz2.val), ♯⟩ 166 | def trunc (sz2:size) (b1:bitvector sz) : bitvector sz2 := 167 | ⟨b1.1 % (2^sz2.val), ♯⟩ 168 | 169 | end bitvector 170 | 171 | 172 | instance bitvector_is_uint_like 173 | : uint_like bitvector := 174 | ⟨@bitvector.add, @bitvector.sub, @bitvector.mul, 175 | @bitvector.udiv, @bitvector.urem, @bitvector.sdiv, @bitvector.srem, 176 | @bitvector.bitwise_and, @bitvector.bitwise_or, @bitvector.bitwise_xor, 177 | @bitvector.shl, @bitvector.lshr, @bitvector.ashr, 178 | bitvector.zero, bitvector.all_one, bitvector.int_min, 179 | bitvector.of_int, @bitvector.zext, @bitvector.sext, @bitvector.trunc⟩ 180 | 181 | instance bool_bitvec_has_coe: has_coe bool (bitvector size.one) := 182 | ⟨bitvector.of_bool⟩ 183 | 184 | @[reducible] 185 | instance bitvector_has_comp 186 | : has_comp bitvector bool := 187 | ⟨@bitvector.eq, @bitvector.ne, @bitvector.sle, @bitvector.slt, 188 | @bitvector.ule, @bitvector.ult⟩ 189 | 190 | instance bitvector_has_overflow_check 191 | : has_overflow_check bitvector bool := 192 | ⟨@bitvector.add_overflows, @bitvector.sub_overflows, 193 | @bitvector.mul_overflows, @bitvector.shl_overflows⟩ 194 | -------------------------------------------------------------------------------- /src/common.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | def size := { n:nat // 0 < n } 5 | 6 | namespace size 7 | 8 | instance size_to_nat: has_coe size nat := 9 | ⟨λ s, s.1⟩ 10 | 11 | instance : has_to_string size := 12 | ⟨λ s, to_string s.1⟩ 13 | 14 | @[pattern, reducible] def one : size := ⟨1, dec_trivial⟩ 15 | 16 | @[reducible] def add (sz1:size) (sz2:size):size := 17 | ⟨sz1.1 + sz2.1, nat.lt_trans sz1.2 -- 0 < sz -> sz < sz+sz2 -> 0 < sz+sz2 18 | (nat.lt_add_of_pos_right sz2.2)⟩ 19 | instance : has_add size := ⟨add⟩ 20 | 21 | @[reducible] def incr (sz:size):size := sz.add size.one 22 | 23 | def incr_nat (sz:nat):size := ⟨nat.succ sz, dec_trivial⟩ 24 | 25 | @[reducible] def sub (sz1:size) (sz2:size) (prf:sz1.1 > sz2.1):size := 26 | ⟨sz1.1 - sz2.1, nat.sub_pos_of_lt prf⟩ 27 | 28 | 29 | theorem add_sub_eq (sz1 sz2:size) (prf:sz1.1 > sz2.1) : 30 | (sz2.add (sz1.sub sz2 prf)) = sz1 := 31 | begin 32 | apply subtype.eq, simp, 33 | rw nat.add_sub_of_le (nat.le_of_succ_le prf) 34 | end 35 | 36 | theorem add_sub_eq2 (sz1 sz2:size) (prf:(sz1.add sz2).val > sz2.val) : 37 | ((sz1.add sz2).sub sz2 prf) = sz1 := 38 | begin 39 | apply subtype.eq, simp, apply nat.add_sub_cancel 40 | end 41 | 42 | theorem add_gt (sz m:size): 43 | (sz.add m).val > sz.val := 44 | begin 45 | cases sz, 46 | cases m, 47 | simp, apply lt_add_of_pos_right, assumption 48 | end 49 | 50 | theorem add_gt2 (sz m:size): 51 | (sz.add m).val > m.val := 52 | begin 53 | cases sz, 54 | cases m, 55 | simp, rw nat.add_comm, apply lt_add_of_pos_right, assumption 56 | end 57 | 58 | theorem add_one_incr_eq (sz1:size) : 59 | (sz1.incr) = (sz1.add size.one) := 60 | begin apply subtype.eq, simp end 61 | 62 | end size 63 | 64 | @[reducible] def within_signed_range (sz:size) (x:ℤ) : Prop := 65 | (-int.of_nat (2 ^ (sz.val - 1)) ≤ x) ∧ (x < int.of_nat (2 ^ (sz.val - 1))) 66 | 67 | def all_one_nat (sz:size) : ℕ := (2 ^ sz.val) - 1 68 | def int_min_nat (sz:size) : ℕ := 2 ^ (sz.val - 1) 69 | -------------------------------------------------------------------------------- /src/freevar.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .lang 5 | import .irsem 6 | import .irsem_exec 7 | import .irsem_smt 8 | import smt2.syntax 9 | import smt2.builder 10 | 11 | namespace freevar 12 | 13 | open irsem 14 | open io 15 | 16 | def update (lhses:list string) (t:ty) (op:operand) (freevs:list (string × ty)) : list (string × ty) := 17 | match op with 18 | | operand.const _ := freevs 19 | | operand.reg (reg.r lname) := 20 | if bor (list.mem lname lhses) (list.mem (lname, t) freevs) 21 | then freevs else (lname, t)::freevs 22 | end 23 | 24 | -- Returns the list of free variables from the program 25 | def get (typed_prog:program): list (string × ty) := 26 | let res:(list string × list (string × ty)) := typed_prog.insts.foldl 27 | (λ res (inst:instruction), 28 | let update := update res.1 in 29 | match inst with 30 | | instruction.binop retty (reg.r lhsname) _ _ op1 op2 := 31 | (lhsname::(res.1), 32 | update retty op1 (update retty op2 res.2)) 33 | | instruction.unaryop (reg.r lhsname) _ fromty op toty := 34 | (lhsname::(res.1), update fromty op res.2) 35 | | instruction.selectop (reg.r lhsname) condty condop opty op1 op2 := 36 | (lhsname::(res.1), 37 | update condty condop 38 | (update opty op1 39 | (update opty op2 res.2))) 40 | | instruction.icmpop opty (reg.r lhsname) _ op1 op2 := 41 | (lhsname::(res.1), 42 | update opty op1 (update opty op2 res.2)) 43 | end) ([], []) in 44 | res.2 45 | 46 | 47 | def get_sz_from_ty (t:ty): size := 48 | let isz := (match t with | ty.int isz := isz | _ := 16 end) in 49 | if H:isz > 0 then subtype.mk isz H else ⟨1, dec_trivial⟩ 50 | 51 | def get_rand_bv (sz:size) (sg:std_gen): irsem_exec.intty sz × std_gen := 52 | let (n, sg) := std_next sg in 53 | (⟨n % 2^sz.val, by apply bitvector.bv_mod_lt⟩, sg) 54 | 55 | def get_rand_bool (sg:std_gen): bool × std_gen := 56 | let (n, sg) := std_next sg in 57 | (if n = 0 then ff else tt, sg) 58 | 59 | def get_free_sbitvec_name (name:string) := "v_" ++ name 60 | def get_free_sbitvec (name:string) (sz:size): sbitvec sz := 61 | sbitvec.var sz (get_free_sbitvec_name name) 62 | 63 | def get_free_sbool_name (name:string) := "b_" ++ name 64 | def get_free_sbool (name:string): sbool := 65 | sbool.var (get_free_sbool_name name) 66 | 67 | set_option eqn_compiler.zeta true 68 | def create_init_var_exec (name:string) (t:ty) (s:irstate irsem_exec × std_gen) 69 | : (irstate irsem_exec × std_gen) := 70 | let sz := get_sz_from_ty t in 71 | let (bv, sg) := get_rand_bv sz s.2 in 72 | let (b, sg) := get_rand_bool sg in 73 | (irstate.updatereg irsem_exec s.1 name 74 | (irsem.valty.ival sz bv b), sg) 75 | 76 | -- Creates a random initial state (of exec. sem) from given free variables 77 | def create_init_state_exec (freevars:list (string × ty)) (sg:std_gen) 78 | : (irstate irsem_exec × std_gen) := 79 | list.foldr (λ (n:string × ty) st, create_init_var_exec n.1 n.2 st) 80 | (irstate.empty irsem_exec, sg) 81 | freevars 82 | 83 | 84 | def create_init_var_smt (name:string) (t:ty) (s:irstate irsem_smt) 85 | : irstate irsem_smt := 86 | let sz := get_sz_from_ty t in 87 | let bv := get_free_sbitvec name sz in 88 | let p := get_free_sbool name in 89 | irstate.updatereg irsem_smt s name (irsem.valty.ival sz bv p) 90 | 91 | -- Creates an initial state (of smt. sem) from given free variables 92 | def create_init_state_smt (freevars:list (string × ty)): irstate irsem_smt := 93 | list.foldr (λ (n:string × ty) st, create_init_var_smt n.1 n.2 st) 94 | (irstate.empty irsem_smt) 95 | freevars 96 | 97 | 98 | -- env η is a mapping from SMT variables to their concrete values. 99 | -- It has two fields: one (bv) for bit-vector SMT variables, and another (b) for 100 | -- boolean SMT variables. 101 | structure env := 102 | (bv:string → option int) 103 | (b:string → option bool) 104 | 105 | namespace env 106 | -- An empty environment 107 | def empty : env := { bv := (λ n, none), b := λ n, none } 108 | 109 | -- Two functions for adding (name |-> v) to env. 110 | def add_bv (e:env) (name:string) (v:ℤ):env := 111 | {bv := (λ n, if n = name then some v else e.bv n), b := e.b} 112 | 113 | def add_b (e:env) (name:string) (b:bool):env := 114 | {bv := e.bv, b := (λ n, if n = name then some b else e.b n)} 115 | 116 | -- Given an SMT formula, replace all free variables with the concrete 117 | -- value assignments of the environment η. 118 | @[simp] 119 | mutual def replace_sbv, replace_sb 120 | with replace_sbv: Π (η:env) {sz:size}, sbitvec sz → sbitvec sz 121 | | η sz x@(sbitvec.var _ name) := 122 | match (η.bv name) with 123 | | some n := sbitvec.of_int sz n 124 | | none := x 125 | end 126 | | η sz (sbitvec.add x y) := 127 | sbitvec.add (replace_sbv η x) (replace_sbv η y) 128 | | η sz (sbitvec.sub x y) := 129 | sbitvec.sub (replace_sbv η x) (replace_sbv η y) 130 | | η sz (sbitvec.mul x y) := 131 | sbitvec.mul (replace_sbv η x) (replace_sbv η y) 132 | | η sz (sbitvec.udiv x y) := 133 | sbitvec.udiv (replace_sbv η x) (replace_sbv η y) 134 | | η sz (sbitvec.urem x y) := 135 | sbitvec.urem (replace_sbv η x) (replace_sbv η y) 136 | | η sz (sbitvec.sdiv x y) := 137 | sbitvec.sdiv (replace_sbv η x) (replace_sbv η y) 138 | | η sz (sbitvec.srem x y) := 139 | sbitvec.srem (replace_sbv η x) (replace_sbv η y) 140 | | η sz (sbitvec.and x y) := 141 | sbitvec.and (replace_sbv η x) (replace_sbv η y) 142 | | η sz (sbitvec.or x y) := 143 | sbitvec.or (replace_sbv η x) (replace_sbv η y) 144 | | η sz (sbitvec.xor x y) := 145 | sbitvec.xor (replace_sbv η x) (replace_sbv η y) 146 | | η sz (sbitvec.shl x y) := 147 | sbitvec.shl (replace_sbv η x) (replace_sbv η y) 148 | | η sz (sbitvec.lshr x y) := 149 | sbitvec.lshr (replace_sbv η x) (replace_sbv η y) 150 | | η sz (sbitvec.ashr x y) := 151 | sbitvec.ashr (replace_sbv η x) (replace_sbv η y) 152 | | η sz (sbitvec.zext sz' y) := 153 | sbitvec.zext sz' (replace_sbv η y) 154 | | η sz (sbitvec.sext sz' y) := 155 | sbitvec.sext sz' (replace_sbv η y) 156 | | η sz (sbitvec.trunc sz' y) := 157 | sbitvec.trunc sz' (replace_sbv η y) 158 | | η sz (sbitvec.extract hb lb H y) := 159 | sbitvec.extract hb lb H (replace_sbv η y) 160 | | η sz (sbitvec.ite c x y) := 161 | -- These conditions are necessary to guarantee that recursive functions 162 | -- replace_sbv, replace_sb are terminating. This is done by defining some 163 | -- measurement that is strictly decreasing after each recursive call. 164 | have 2 < (1 + (1 + (1 + (1 + (sbitvec.sizeof sz y + sbitvec.sizeof sz x))))), 165 | by repeat { rw nat.one_add }; exact dec_trivial, 166 | have 2 < (1 + (1 + (1 + (1 + (sbitvec.sizeof sz x + sbitvec.sizeof sz y))))), 167 | by repeat { rw nat.one_add }; exact dec_trivial, 168 | sbitvec.ite (replace_sb η c) (replace_sbv η x) (replace_sbv η y) 169 | | η sz c := c 170 | 171 | with replace_sb: Π (η:env) , sbool → sbool 172 | | η x@(sbool.var name) := 173 | match (η.b name) with 174 | | some b := sbool.of_bool b 175 | | none := x 176 | end 177 | | η (sbool.and x y) := 178 | sbool.and (replace_sb η x) (replace_sb η y) 179 | | η (sbool.or x y) := 180 | sbool.or (replace_sb η x) (replace_sb η y) 181 | | η (sbool.xor x y) := 182 | sbool.xor (replace_sb η x) (replace_sb η y) 183 | | η (sbool.eqb x y) := 184 | sbool.eqb (replace_sb η x) (replace_sb η y) 185 | | η (sbool.neb x y) := 186 | sbool.neb (replace_sb η x) (replace_sb η y) 187 | | η (sbool.ite c x y) := 188 | sbool.ite (replace_sb η c) (replace_sb η x) (replace_sb η y) 189 | | η (sbool.not y) := sbool.not (replace_sb η y) 190 | | η (@sbool.eqbv sz x y) := 191 | have 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 192 | have 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 193 | sbool.eqbv (replace_sbv η x) (replace_sbv η y) 194 | | η (@sbool.nebv sz x y) := 195 | have 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 196 | have 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 197 | sbool.nebv (replace_sbv η x) (replace_sbv η y) 198 | | η (@sbool.sle sz x y) := 199 | have 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 200 | have 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 201 | sbool.sle (replace_sbv η x) (replace_sbv η y) 202 | | η (@sbool.slt sz x y) := 203 | have 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 204 | have 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 205 | sbool.slt (replace_sbv η x) (replace_sbv η y) 206 | | η (@sbool.ule sz x y) := 207 | have 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 208 | have 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 209 | sbool.ule (replace_sbv η x) (replace_sbv η y) 210 | | η (@sbool.ult sz x y) := 211 | have 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 212 | have 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 213 | sbool.ult (replace_sbv η x) (replace_sbv η y) 214 | | η x := x 215 | 216 | @[simp, reducible] 217 | def replace_valty (η:env) (v:irsem.valty irsem_smt) := 218 | match v with 219 | | irsem.valty.ival sz i p := 220 | @irsem.valty.ival irsem_smt sz (η.replace_sbv i) (η.replace_sb p) 221 | end 222 | 223 | def replace (η:env) (ss:irstate irsem_smt): irstate irsem_smt := 224 | irstate.apply_to_values irsem_smt 225 | (irstate.setub irsem_smt ss (η.replace_sb (irstate.getub irsem_smt ss))) 226 | η.replace_valty 227 | 228 | notation η `⟦` s `⟧` := freevar.env.replace η s 229 | notation η `⟦` v `⟧` := freevar.env.replace_valty η v 230 | notation η `⟦` sbv `⟧` := freevar.env.replace_sbv η sbv 231 | notation η `⟦` sb `⟧` := freevar.env.replace_sb η sb 232 | instance env_has_mem: has_mem string freevar.env := 233 | ⟨λ s η, η.b s ≠ none ∨ η.bv s ≠ none⟩ 234 | instance has_mem_decidable (η:freevar.env) (n:string) 235 | : decidable (n ∈ η) := by apply_instance 236 | 237 | end env 238 | 239 | 240 | -- Creates smt declaration of free variables 241 | def create_smt_declares (freevars:list (string × ty)): smt2.builder unit := 242 | monad.foldl (λ (_:unit) (n:string × ty), do 243 | -- A variable representing concrete value 244 | smt2.builder.declare_fun (get_free_sbitvec_name n.1) [] (match n.2 with 245 | | ty.int isz := smt2.sort.apply "_" ["BitVec", to_string isz] 246 | | _ := smt2.sort.apply "_" ["BitVec", "16"] 247 | end), 248 | -- A variable representing poison value 249 | smt2.builder.declare_fun (get_free_sbool_name n.1) [] "Bool" 250 | ) () freevars 251 | 252 | end freevar 253 | -------------------------------------------------------------------------------- /src/irsem.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | /- 5 | Semantics of LLVM IR 6 | -/ 7 | import .lang 8 | import .common 9 | import .ops 10 | import system.io 11 | 12 | structure irsem := 13 | (intty:size → Type) 14 | (poisonty:Type) 15 | -- This is for UB as well 16 | (boolty:Type) 17 | 18 | namespace irsem 19 | section 20 | 21 | open io 22 | 23 | 24 | parameter (sem : irsem) 25 | 26 | -- uint_like types 27 | variable [ihc:has_comp sem.intty sem.boolty] 28 | variable [ioc:has_overflow_check sem.intty sem.boolty] 29 | variable [iul:uint_like sem.intty] 30 | -- poison types 31 | variable [pbl:bool_like sem.poisonty] 32 | variable [p2b:has_coe sem.poisonty sem.boolty] 33 | -- bool types 34 | variable [bbl:bool_like sem.boolty] 35 | variable [b2i:has_coe sem.boolty (sem.intty size.one)] 36 | variable [bhi:Π (sz:size), has_ite sem.boolty (sem.intty sz)] 37 | variable [bhi2:has_ite sem.boolty sem.poisonty] 38 | 39 | 40 | inductive valty 41 | | ival: Π (sz:size), sem.intty sz → sem.poisonty → valty 42 | 43 | -- A register file. 44 | def regfile := list (string × valty) 45 | def regfile.get (r:regfile) (s:string) : option valty := 46 | match (list.filter (λ (itm:string × valty), s = itm.fst) r) with 47 | | (name,val)::_ := some val 48 | | nil := none 49 | end 50 | 51 | def regfile.update (r:regfile) (s:string) (v:valty) := 52 | (s,v)::r 53 | 54 | def regfile.empty : regfile := 55 | [] 56 | 57 | def regfile.apply_to_values (r:regfile) (f:valty → valty): regfile := 58 | list.map (λ x:(string × valty), (x.1, f x.2)) r 59 | 60 | def regfile.regnames (r:regfile) : list string := 61 | list.map (λ x:(string × valty), x.1) r 62 | 63 | def regfile.to_string' [has_to_string valty] (rs:regfile) : string := 64 | list.foldr 65 | (λ (itm:string × valty) (befst:string), 66 | befst ++ (itm.1) ++ ":" ++ (to_string itm.2) ++ ",\n") 67 | "" rs 68 | 69 | include ihc 70 | include ioc 71 | include iul 72 | include bbl 73 | include pbl 74 | include p2b 75 | include b2i 76 | include bhi 77 | include bhi2 78 | 79 | -- Current state of execution. 80 | -- 'state' is already defined, Lean says. 81 | def irstate := sem.boolty × regfile 82 | 83 | def irstate.empty : irstate := 84 | (bbl.tt, regfile.empty) 85 | 86 | section 87 | variable (s:irstate) 88 | def irstate.getreg (name:string) : option valty := 89 | regfile.get s.2 name 90 | 91 | def irstate.regnames : list string := 92 | regfile.regnames s.2 93 | 94 | def irstate.updatereg (name:string) (v:valty) 95 | : irstate := 96 | (s.1, regfile.update s.2 name v) 97 | 98 | def irstate.updateub (u:sem.boolty) : irstate := 99 | (s.1 & u, s.2) 100 | 101 | def irstate.setub (u:sem.boolty) : irstate := 102 | (u, s.2) 103 | 104 | def irstate.getub : sem.boolty := 105 | s.1 106 | 107 | def irstate.apply_to_values (f:valty → valty): irstate := 108 | (s.1, regfile.apply_to_values s.2 f) 109 | 110 | def irstate.to_string' [has_to_string valty] [has_to_string sem.poisonty] [has_to_string sem.boolty] 111 | : string := 112 | "(Is not UB?: " ++ to_string(s.1) ++ ",\n" ++ regfile.to_string' s.2 ++ ")" 113 | end 114 | 115 | -- Get current value from syntactic val (either register or constant). 116 | -- For example, if val is a register "x", get_value loads "x" and returns 117 | -- the value. 118 | def get_value (s:irstate) (v:operand) (t:ty): option valty := 119 | match v with 120 | | operand.reg (reg.r name) := (irstate.getreg s name) 121 | | operand.const (const.int z) := 122 | match t with 123 | | ty.int bitsz := 124 | if h:(0 < bitsz) then 125 | let sz := (⟨bitsz, h⟩:size), 126 | intgen := @uint_like.from_z sem.intty iul sz, 127 | nopoison := pbl.tt in 128 | if h0:(within_signed_range sz z) then 129 | -- e.g. -128 ≤ z ≤ 127 (if bitsz is 8) 130 | some (valty.ival sz (intgen z) nopoison) 131 | else if h1:(↑(int_min_nat sz) ≤ z ∧ z ≤ (all_one_nat sz)) then 132 | -- e.g. 128 ≤ z ≤ 255 (if bitsz is 8) 133 | -- Convert into the corresponding negative number. 134 | some (valty.ival sz (intgen (z - int.of_nat (2 ^ bitsz))) nopoison) 135 | else 136 | none -- the constant does not fit in bitsize! 137 | else 138 | none -- bitsize should be always larger than 0! 139 | | ty.arbitrary_int := none -- arbitrary_int should not appear at execution time. 140 | end 141 | end 142 | 143 | -- Cast bool to poison 144 | @[reducible] 145 | def b2p (b:sem.boolty) : sem.poisonty := 146 | has_ite.ite b (pbl.tt) (pbl.ff) 147 | 148 | -- If v1 ≠ v2, yields poison 149 | @[reducible] 150 | def neq2p {sz:size} (v1 v2:sem.intty sz) : sem.poisonty := 151 | b2p (v1 =_{sem.boolty} v2) 152 | 153 | -- If v1 = v2, yields poison 154 | @[reducible] 155 | def eq2p {sz:size} (v1 v2:sem.intty sz) : sem.poisonty := 156 | b2p (v1 ≠_{sem.boolty} v2) 157 | 158 | -- Performs given binary operation. 159 | def bop_val (sz:size) : bopcode → sem.intty sz → sem.intty sz → sem.intty sz 160 | | bopcode.add n1 n2 := n1 + n2 161 | | bopcode.sub n1 n2 := n1 - n2 162 | | bopcode.mul n1 n2 := n1 * n2 163 | | bopcode.udiv n1 n2 := n1 /u n2 164 | | bopcode.urem n1 n2 := n1 %u n2 165 | | bopcode.sdiv n1 n2 := n1 / n2 166 | | bopcode.srem n1 n2 := n1 % n2 167 | | bopcode.and n1 n2 := n1 & n2 168 | | bopcode.or n1 n2 := n1 |b n2 169 | | bopcode.xor n1 n2 := n1 ^b n2 170 | | bopcode.shl n1 n2 := n1 << n2 171 | | bopcode.lshr n1 n2 := n1 >>l n2 172 | | bopcode.ashr n1 n2 := n1 >>a n2 173 | 174 | -- Returns true if it fits into the range of signed/unsigned integer 175 | def bop_overflow_check (nsw:bool) (sz:size) 176 | (bc:bopcode) (op1:sem.intty sz) (op2:sem.intty sz) 177 | : sem.poisonty := 178 | b2p (match bc with 179 | | bopcode.add := has_overflow_check.add_chk sem.boolty nsw op1 op2 180 | | bopcode.sub := has_overflow_check.sub_chk sem.boolty nsw op1 op2 181 | | bopcode.mul := has_overflow_check.mul_chk sem.boolty nsw op1 op2 182 | | bopcode.shl := has_overflow_check.shl_chk sem.boolty nsw op1 op2 183 | -- If the instruction is well-typed, it is unreachable here. 184 | | _ := has_overflow_check.mul_chk sem.boolty nsw op1 op2 185 | end) 186 | 187 | -- Returns true if it fits into the range of signed/unsigned integer 188 | def bop_exact_check (sz:size) (bc:bopcode) (op1:sem.intty sz) (op2:sem.intty sz) 189 | : sem.poisonty := 190 | let zero:sem.intty sz := uint_like.zero sz, 191 | sz':sem.intty sz := uint_like.from_z sz sz, 192 | op2' := op2 %u sz' in 193 | match bc with 194 | | bopcode.sdiv := eq2p (op1 % op2) zero 195 | | bopcode.srem := eq2p (op1 % op2) zero 196 | | bopcode.udiv := eq2p (op1 %u op2) zero 197 | | bopcode.urem := eq2p (op1 %u op2) zero 198 | | bopcode.ashr := eq2p ((op1 >>a op2') << op2') op1 199 | | bopcode.lshr := eq2p ((op1 >>l op2') << op2') op1 200 | | _ := eq2p op1 op2 -- Unreachable 201 | end 202 | 203 | -- Checks whether the binary operation returns poison. 204 | def bop_poison_flag (sz:size) (code:bopcode) (flag:bopflag) (v1:sem.intty sz) (v2:sem.intty sz) 205 | : sem.poisonty := 206 | ~ (match flag with 207 | | bopflag.nsw := bop_overflow_check tt sz code v1 v2 208 | | bopflag.nuw := bop_overflow_check ff sz code v1 v2 209 | | bopflag.exact := bop_exact_check sz code v1 v2 210 | end) 211 | 212 | def bop_poison (sz:size) (code:bopcode) (v1:sem.intty sz) (v2:sem.intty sz) 213 | : sem.poisonty := 214 | let sz':sem.intty sz := uint_like.from_z sz sz, 215 | res := match code with 216 | | bopcode.shl := v2 u_{sem.boolty} b 279 | | icmpcond.uge := a ≥u_{sem.boolty} b 280 | | icmpcond.ult := a _{sem.boolty} b 283 | | icmpcond.sge := a ≥_{sem.boolty} b 284 | | icmpcond.slt := a <_{sem.boolty} b 285 | | icmpcond.sle := a ≤_{sem.boolty} b 286 | end in 287 | (res, ap & bp) 288 | 289 | -- Semantics of select instruction. 290 | def selectop (cond:sem.intty size.one) (pcond:sem.poisonty) (sz:size) 291 | (a:sem.intty sz) (ap:sem.poisonty) (b:sem.intty sz) (bp:sem.poisonty) 292 | : (sem.intty sz × sem.poisonty) := 293 | let one:sem.intty _ := uint_like.from_z size.one 1, 294 | eqtest := cond =_{sem.boolty} one in 295 | let c := @has_ite.ite sem.boolty (sem.intty sz) (bhi sz) eqtest a b in 296 | let cp := has_ite.ite eqtest ap bp in 297 | (c, pcond & cp) 298 | 299 | 300 | /- 301 | - Execution of a single instruction 302 | -/ 303 | def to_ival {sz:size} (xp:sem.intty sz × sem.poisonty ) := 304 | valty.ival sz xp.1 xp.2 305 | 306 | -- Execution of bop, but it fails if type check fails 307 | def step_bop (v1 v2:valty) (code:bopcode) 308 | (bflags:list bopflag) (s1:irstate) (lhsn:string) : option irstate := 309 | match v1,v2 with 310 | | (valty.ival sz1 n1 p1), (valty.ival sz2 n2 p2) := 311 | if H:sz1 = sz2 then do 312 | let (u3, x) := (bop sz1 code bflags n1 p1 (cast (by rw H) n2) p2) in 313 | some (irstate.updatereg (irstate.updateub s1 u3) 314 | lhsn (to_ival x)) 315 | else none 316 | end 317 | 318 | -- Execution of unaryop, but it fails if type check fails 319 | def step_unaryop (v1:valty) (code:uopcode) 320 | (toisz:nat) (s1:irstate) (lhsn:string) : option irstate := 321 | match v1, code with 322 | | _, uopcode.freeze := none -- Not implemented yet 323 | | (valty.ival sz1 n1 p1), _ := 324 | if H:toisz > 0 then 325 | let tosz := subtype.mk toisz H in 326 | some (irstate.updatereg s1 lhsn (to_ival (castop sz1 code n1 p1 tosz))) 327 | else -- isz cannot be 0 size! 328 | none 329 | end 330 | 331 | -- Execution of bop, but it fails if type check fails 332 | def step_icmpop (v1 v2:valty) (cond:icmpcond) 333 | (s1:irstate) (lhsn:string) : option irstate := 334 | match v1,v2 with 335 | | (valty.ival sz1 n1 p1), (valty.ival sz2 n2 p2) := 336 | if H:sz1 = sz2 then 337 | some (irstate.updatereg s1 lhsn 338 | (to_ival (icmpop sz1 cond n1 p1 (cast (by rw H) n2) p2))) 339 | else 340 | none 341 | end 342 | 343 | -- Execution of bop, but it fails if type check fails 344 | def step_selectop (vcond v1 v2:valty) 345 | (s1:irstate) (lhsn:string) : option irstate := 346 | match vcond,v1,v2 with 347 | | (valty.ival szcond ncond pcond), 348 | (valty.ival sz1 n1 p1), (valty.ival sz2 n2 p2) := 349 | if Hc:szcond = size.one then 350 | if H:sz1 = sz2 then 351 | some (irstate.updatereg s1 lhsn (to_ival 352 | (selectop (cast (by rw Hc) ncond) pcond 353 | sz1 n1 p1 (cast (by rw H) n2) p2 ))) 354 | else none 355 | else none 356 | end 357 | 358 | def step (s1:irstate) (i:instruction) : option irstate := 359 | match i with 360 | | instruction.binop retty (reg.r lhsn) code bflags op1 op2 := 361 | do 362 | v1 ← get_value s1 op1 retty, 363 | v2 ← get_value s1 op2 retty, 364 | step_bop v1 v2 code bflags s1 lhsn 365 | | instruction.unaryop (reg.r lhsn) code fromty op1 toty@(ty.int toisz):= 366 | do 367 | v1 ← get_value s1 op1 fromty, 368 | step_unaryop v1 code toisz s1 lhsn 369 | | instruction.icmpop opty (reg.r lhsn) cond op1 op2 := 370 | do 371 | v1 ← get_value s1 op1 opty, 372 | v2 ← get_value s1 op2 opty, 373 | step_icmpop v1 v2 cond s1 lhsn 374 | | instruction.selectop (reg.r lhsn) condty cond vty op1 op2 := 375 | do 376 | vcond ← get_value s1 cond condty, 377 | v1 ← get_value s1 op1 vty, 378 | v2 ← get_value s1 op2 vty, 379 | step_selectop vcond v1 v2 s1 lhsn 380 | | _ := none -- Stuck! 381 | end 382 | 383 | -- Execution of a program 384 | def bigstep (inits:irstate) (p:program): option irstate := 385 | list.foldl (λ befst inst, 386 | match befst with 387 | | none := none -- Stuck! 388 | | some st := step st inst 389 | end) (some inits) (p.insts) 390 | 391 | end 392 | end irsem 393 | -------------------------------------------------------------------------------- /src/irsem_exec.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import system.io 5 | import smt2.syntax 6 | import .irsem 7 | import .lang 8 | import .common 9 | import .bitvector 10 | 11 | open io 12 | 13 | -- poisonty := bool -- If it is false, it is poison. 14 | -- boolty := bool -- If it is false, it is UB. 15 | def irsem_exec : irsem := { intty := bitvector, poisonty := bool, boolty := bool } 16 | 17 | namespace irsem_exec 18 | open irsem 19 | 20 | @[reducible] instance iul: uint_like irsem_exec.intty := bitvector_is_uint_like 21 | @[reducible] instance ihc: has_comp irsem_exec.intty irsem_exec.boolty := bitvector_has_comp 22 | @[reducible] instance ioc: has_overflow_check irsem_exec.intty irsem_exec.boolty := 23 | bitvector_has_overflow_check 24 | @[reducible] instance pbl: bool_like irsem_exec.poisonty := bool_is_bool_like 25 | @[reducible] instance p2b: has_coe irsem_exec.poisonty irsem_exec.boolty := ⟨@id bool⟩ 26 | @[reducible] instance bbl: bool_like irsem_exec.boolty := bool_is_bool_like 27 | @[reducible] instance b2i: has_coe irsem_exec.boolty (irsem_exec.intty size.one) := bool_bitvec_has_coe 28 | @[reducible] instance bhi (sz:size): has_ite irsem_exec.boolty (irsem_exec.intty sz) := bool_has_ite (bitvector sz) 29 | @[reducible] instance bhi2 : has_ite irsem_exec.boolty irsem_exec.poisonty := bool_has_ite irsem_exec.poisonty 30 | 31 | def give_poison: irsem.valty irsem_exec → irsem.valty irsem_exec 32 | | (valty.ival sz o b) := valty.ival sz o 33 | (@bool_like.ff irsem_exec.poisonty irsem_exec.pbl) 34 | 35 | instance poisonty_tostr: has_to_string irsem_exec.poisonty := 36 | ⟨λ b:bool, to_string b⟩ 37 | instance valty_tostr: has_to_string irsem_exec.valty := 38 | ⟨λ b, match b with 39 | | (irsem.valty.ival sz b p) := has_to_string.to_string (b.1) ++ 40 | ", poison:" ++ to_string (~p) 41 | end⟩ 42 | instance boolty_tostr: has_to_string irsem_exec.boolty := 43 | ⟨λ b:bool, to_string b⟩ 44 | 45 | instance tostr: has_to_string irsem_exec.irstate := 46 | ⟨λ st, irstate.to_string' irsem_exec st⟩ 47 | 48 | def int_to_smt (sz:size) : irsem_exec.intty sz → smt2.term 49 | | z := smt2.term.const (smt2.special_constant.bitvec sz z.1) 50 | def val_to_smt : irsem_exec.valty → smt2.term 51 | | (irsem.valty.ival sz i _) := int_to_smt sz i 52 | def poison_to_smt : irsem_exec.valty → smt2.term 53 | | (irsem.valty.ival _ _ p) := smt2.term.const (smt2.special_constant.bool p) 54 | def bool_to_smt : irsem_exec.boolty → smt2.term 55 | | p := smt2.term.const (smt2.special_constant.bool p) 56 | end irsem_exec 57 | -------------------------------------------------------------------------------- /src/irsem_smt.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import system.io 5 | import smt2.syntax 6 | import smt2.builder 7 | import .irsem 8 | import .lang 9 | import .common 10 | import .bitvector 11 | import .smtexpr 12 | import .smtcompile 13 | open io 14 | 15 | def irsem_smt : irsem := { intty := sbitvec, poisonty := sbool, boolty := sbool } 16 | 17 | namespace irsem_smt 18 | open irsem 19 | local attribute [reducible] irsem_smt 20 | 21 | @[reducible] instance iul: uint_like irsem_smt.intty := sbitvec_is_uint_like 22 | @[reducible] instance ihc: has_comp irsem_smt.intty irsem_smt.boolty := sbitvec_has_comp 23 | @[reducible] instance ioc: has_overflow_check irsem_smt.intty irsem_smt.boolty := 24 | sbitvec_has_overflow_check 25 | @[reducible] instance pbl: bool_like irsem_smt.poisonty := sbool_is_bool_like 26 | @[reducible] instance p2b: has_coe irsem_smt.poisonty irsem_smt.boolty := ⟨@id sbool⟩ 27 | @[reducible] instance bbl: bool_like irsem_smt.boolty := sbool_is_bool_like 28 | @[reducible] instance b2i: has_coe irsem_smt.boolty (irsem_smt.intty size.one) := sbool_sbitvec_has_coe 29 | @[reducible] instance bhi (sz:size): has_ite irsem_smt.boolty (irsem_smt.intty sz) := sbitvec_has_ite 30 | @[reducible] instance bhi2 : has_ite irsem_smt.boolty irsem_smt.poisonty := sbool_has_ite 31 | 32 | 33 | meta instance poisonty_tostr: has_to_string irsem_smt.poisonty := 34 | ⟨λ b:sbool, to_string b⟩ 35 | meta instance valty_tostr: has_to_string irsem_smt.valty := 36 | ⟨λ b, match b with 37 | | (irsem.valty.ival sz b p) := has_to_string.to_string b ++ 38 | ", IS_NOT_POISON:" ++ to_string p 39 | end⟩ 40 | meta instance boolty_tostr: has_to_string irsem_smt.boolty := 41 | ⟨λ b:sbool, to_string b⟩ 42 | 43 | meta instance tostr: has_to_string irsem_smt.irstate := 44 | ⟨λ st, irstate.to_string' irsem_smt st⟩ 45 | 46 | meta def int_to_smt (sz:size) : irsem_smt.intty sz → smt2.term 47 | | x := smt.compile_sbitvec x 48 | meta def val_to_smt : irsem_smt.valty → smt2.term 49 | | (irsem.valty.ival sz t _) := int_to_smt sz t 50 | meta def poison_to_smt : irsem_smt.valty → smt2.term 51 | | (irsem.valty.ival _ _ p) := smt.compile_sbool p 52 | meta def bool_to_smt : irsem_smt.boolty → smt2.term 53 | | u := smt.compile_sbool u 54 | end irsem_smt 55 | -------------------------------------------------------------------------------- /src/irtype.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .lang 5 | 6 | -- Returns true if program p contains uninstantiated type. 7 | def has_arbitrary_type (p:program): bool := 8 | list.foldl (λ (b:bool) inst, bor b 9 | (match inst with 10 | | instruction.binop t lhs bop nswnuw op1 op2 := 11 | t = ty.arbitrary_int 12 | | instruction.unaryop r uop t1 op t2 := 13 | t1 = ty.arbitrary_int ∨ t2 = ty.arbitrary_int 14 | | instruction.icmpop t r cond r1 r2 := 15 | t = ty.arbitrary_int 16 | | instruction.selectop r t1 cond t2 op1 op2 := 17 | t1 = ty.arbitrary_int ∨ t2 = ty.arbitrary_int 18 | end)) ff p.insts 19 | 20 | -- Returns a list of programs with concretized type 21 | def concretize_type (p:program) : list program := 22 | if ¬ (has_arbitrary_type p) then [p] 23 | else 24 | let create_one := fun (tysz:nat), program.mk 25 | ((list.map 26 | (λ inst, match inst with 27 | | instruction.binop t lhs bop nswnuw op1 op2 := 28 | (instruction.binop 29 | (match t with 30 | | ty.arbitrary_int := ty.int tysz 31 | | _ := t 32 | end) lhs bop nswnuw op1 op2) -- has type instantiation. 33 | | _ := inst -- no type instantiation. 34 | end) (p.insts)):list instruction) in 35 | [create_one 8, create_one 16] -------------------------------------------------------------------------------- /src/lang.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | -- constant value 5 | inductive const : Type 6 | | int : ℤ → const 7 | 8 | -- register 9 | -- Design choice: Let reg store its name, but not 10 | -- its type. Reason is that, if reg contains type, 11 | -- modifying register's type should track all 12 | -- def-use chains. 13 | inductive reg : Type 14 | | r : string → reg 15 | -- value 16 | inductive operand : Type 17 | | reg : reg → operand 18 | | const : const → operand 19 | 20 | -- type 21 | inductive ty : Type 22 | | int : ℕ → ty 23 | | arbitrary_int : ty 24 | 25 | -- for (t1:ty) (t2:ty), t1 = t2 is decidable. 26 | instance : decidable_eq ty := 27 | by tactic.mk_dec_eq_instance 28 | 29 | -- binary operation 30 | inductive bopcode : Type 31 | | add | sub | mul | udiv | urem | sdiv | srem | and | or | xor | shl | lshr | ashr 32 | 33 | instance : decidable_eq bopcode := 34 | by tactic.mk_dec_eq_instance 35 | -- Returns true if given bopcode is div or rem 36 | @[reducible, simp] 37 | def bop_isdiv : bopcode → bool 38 | | bopcode.udiv := tt 39 | | bopcode.urem := tt 40 | | bopcode.sdiv := tt 41 | | bopcode.srem := tt 42 | | _ := ff 43 | 44 | inductive bopflag : Type 45 | | nsw | nuw | exact 46 | 47 | @[reducible] 48 | def bop_availflags : bopcode → list bopflag 49 | | bopcode.add := [bopflag.nsw, bopflag.nuw] 50 | | bopcode.sub := [bopflag.nsw, bopflag.nuw] 51 | | bopcode.mul := [bopflag.nsw, bopflag.nuw] 52 | | bopcode.shl := [bopflag.nsw, bopflag.nuw] 53 | | bopcode.udiv := [bopflag.exact] 54 | | bopcode.sdiv := [bopflag.exact] 55 | | bopcode.urem := [] 56 | | bopcode.srem := [] 57 | | bopcode.lshr := [bopflag.exact] 58 | | bopcode.ashr := [bopflag.exact] 59 | | bopcode.and := [] 60 | | bopcode.or := [] 61 | | bopcode.xor := [] 62 | 63 | -- icmp operation 64 | inductive icmpcond : Type 65 | | eq | ne | ugt | uge | ult | ule | sgt | sge | slt | sle 66 | 67 | -- unary operation 68 | inductive uopcode : Type 69 | | freeze | zext | sext | trunc 70 | 71 | -- instruction 72 | -- TODO: the order of parameters should be consistent 73 | inductive instruction : Type 74 | -- binop: operations in https://github.com/nunoplopes/alive/blob/newsema/language.py#L278 75 | | binop : ty → reg → bopcode → list bopflag → 76 | operand → operand → instruction 77 | | icmpop : ty → reg → icmpcond → operand → -- opty, lhs, cond, op1, op2 78 | operand → instruction 79 | | selectop : reg → ty → operand → ty → operand → -- condty, opty 80 | operand → instruction 81 | | unaryop : reg → uopcode → 82 | ty → operand → ty → instruction -- fromty, toty 83 | 84 | -- program 85 | structure program : Type := 86 | (insts: list instruction) 87 | 88 | -- transformation 89 | structure transformation : Type := 90 | (name:string) 91 | (src:program) 92 | (tgt:program) 93 | 94 | -- precondition 95 | mutual inductive precond_fun, precond_exp 96 | with precond_fun : Type 97 | -- isPower2(x): returns true if x is guaranteed to 98 | -- be power of 2, returns false otherwise 99 | | is_power2 : precond_exp → precond_fun 100 | -- mayAlias(p, q): returns true if p and q may alias. 101 | -- If p and q are guaranteed not to alias, 102 | -- it returns false. 103 | | may_alias : precond_exp → precond_exp → precond_fun 104 | with precond_exp : Type 105 | -- E1 && E2, E1 & E2 106 | -- E1 and E2 may be either bool or int type. 107 | | and : precond_exp → precond_exp → precond_exp 108 | -- E1 || E2, E1 | E2 109 | -- E1 and E2 may be either bool or int type. 110 | | or : precond_exp → precond_exp → precond_exp 111 | -- ~E 112 | -- E may be either bool or int type. 113 | | not : precond_exp → precond_exp 114 | -- Value (register or constant) 115 | | v : operand → precond_exp 116 | -- Function call 117 | | fcall : precond_fun → precond_exp 118 | -------------------------------------------------------------------------------- /src/lang_tostr.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .lang 5 | 6 | namespace const 7 | instance: has_to_string const := 8 | ⟨λ a, match a with 9 | | (const.int n) := to_string n --"(int " ++ to_string n ++ ")" 10 | end⟩ 11 | end const 12 | 13 | namespace reg 14 | instance: has_to_string reg := 15 | ⟨λ r, match r with 16 | | (reg.r name) := name --"(reg " ++ name ++ ")" 17 | end⟩ 18 | end reg 19 | 20 | namespace operand 21 | instance: has_to_string operand := 22 | ⟨λ o, match o with 23 | | (operand.reg r) := to_string r 24 | | (operand.const c) := to_string c 25 | end⟩ 26 | end operand 27 | 28 | namespace ty 29 | instance: has_to_string ty := 30 | ⟨λ t, match t with 31 | | (ty.int n) := "i" ++ to_string n 32 | | (ty.arbitrary_int) := "iN" 33 | end⟩ 34 | end ty 35 | 36 | 37 | instance: has_to_string bopcode := 38 | ⟨(λ l:bopcode, bopcode.rec_on l "add" "sub" "mul" "udiv" "urem" "sdiv" "srem" 39 | "and" "or" "xor" "shl" "lshr" "ashr")⟩ 40 | 41 | instance: has_to_string uopcode := 42 | ⟨(λ u:uopcode, uopcode.rec_on u "freeze" "zext" "sext" "trunc")⟩ 43 | 44 | instance: has_to_string icmpcond := 45 | ⟨(λ u:icmpcond, icmpcond.rec_on u "eq" "ne" "ugt" "uge" "ult" "ule" "sgt" "sge" "slt" "sle")⟩ 46 | 47 | instance: has_to_string bopflag := 48 | ⟨(λ u:bopflag, bopflag.rec_on u "nsw" "nuw" "exact")⟩ 49 | 50 | 51 | namespace instruction 52 | instance: has_to_string instruction := 53 | ⟨λ i, match i with 54 | | (instruction.binop lhsty lhs bop flags op1 op2) := 55 | (to_string lhs) ++ " = " ++ 56 | (to_string bop) ++ 57 | (list.foldl (λ s1 f, s1 ++ " " ++ to_string f) "" flags) ++ " " ++ 58 | (to_string lhsty) ++ " " ++ 59 | (to_string op1) ++ ", " ++ (to_string op2) 60 | | (instruction.unaryop lhs uop fromty op toty) := 61 | (to_string lhs) ++ " = " ++ (to_string uop) ++ " " ++ 62 | (match uop with 63 | | uopcode.freeze := (to_string op) 64 | | _ := (to_string fromty) ++ " " ++ (to_string op) ++ 65 | " to " ++ (to_string toty) 66 | end) 67 | | (instruction.icmpop opty lhs cond op1 op2) := 68 | (to_string lhs) ++ " = icmp " ++ (to_string cond) ++ " " ++ 69 | (to_string opty) ++ " " ++ (to_string op1) ++ ", " ++ (to_string op2) 70 | | (instruction.selectop lhs condty cond opty op1 op2) := 71 | (to_string lhs) ++ " = select " ++ (to_string condty) ++ " " ++ 72 | (to_string cond) ++ ", " ++ (to_string opty) ++ " " ++ (to_string op1) ++ 73 | ", " ++ (to_string opty) ++ " " ++ (to_string op2) 74 | end⟩ 75 | end instruction 76 | 77 | namespace program 78 | instance: has_to_string program := 79 | ⟨λ p, list.foldr (λ a b, to_string a ++ "\n" ++ b) "" (p.insts)⟩ 80 | end program 81 | 82 | namespace transformation 83 | instance: has_to_string transformation := 84 | ⟨λ t, "Name: " ++ t.name ++ "\n" ++ (to_string t.src) ++ "=>\n" ++ (to_string t.tgt)⟩ 85 | end transformation -------------------------------------------------------------------------------- /src/langparser.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .lang 5 | import .lang_tostr 6 | import data.buffer.parser 7 | 8 | open parser 9 | 10 | -- ReadLinebreaks reads zero or more '\n's. 11 | def ReadLinebreaks: parser unit := 12 | many' (ch '\n') 13 | 14 | -- ReadLine reads a line. 15 | def ReadLine: parser string := 16 | many_char1 $ sat $ λ c, c ≠ '\n' 17 | 18 | -- ReadWhitespaces reads zero or more whitespaces. 19 | def ReadWhitespaces: parser unit := 20 | decorate_error "Whitespace expected" $ many' $ sat $ λ c, c.is_whitespace 21 | 22 | -- Reads a register. 23 | def ReadReg: parser reg := 24 | do 25 | ch '%', 26 | cs ← many_char1 $ sat $ λ c, c.is_alpha ∨ c.is_digit ∨ c = '_' ∨ c = '.', 27 | return (reg.r ("%" ++ cs)) 28 | 29 | -- Reads one constant. 30 | -- Only positive number is supported currently. 31 | def ReadIntConst: parser const := 32 | do 33 | is_neg ← ((do ch '-', return tt) <|> return ff), 34 | cs ← many_char1 $ sat $ λ c, c.is_digit, 35 | -- coercion from nat to int 36 | return (const.int (if is_neg then -1 * (cs.to_nat) else cs.to_nat)) 37 | 38 | -- Reads a value. 39 | -- Either ReadReg or ReadConst. 40 | def ReadVal: parser operand := 41 | (do r ← ReadReg, return (operand.reg r)) <|> 42 | (do str "true", return (operand.const (const.int (-1)))) <|> 43 | (do str "false", return (operand.const (const.int 0))) <|> 44 | (do c ← ReadIntConst, return (operand.const c)) <|> 45 | failure 46 | 47 | def ReadBinaryInstFlag: parser bopflag := 48 | (do str "nsw", ReadWhitespaces, return bopflag.nsw) <|> 49 | (do str "nuw", ReadWhitespaces, return bopflag.nuw) <|> 50 | (do str "exact", ReadWhitespaces, return bopflag.exact) 51 | 52 | def ReadType: parser ty := 53 | do 54 | ch 'i', 55 | sz ← many_char1 $ sat $ λ c, c.is_digit, 56 | return (ty.int sz.to_nat) 57 | 58 | -- Reads a binary instruction. 59 | def ReadBinaryInst (lhs:reg) (opname:string) (bopc:bopcode) : parser instruction := 60 | do 61 | str opname, 62 | ReadWhitespaces, 63 | flags ← many ReadBinaryInstFlag, 64 | ReadWhitespaces, 65 | retty ← (ReadType <|> return (ty.arbitrary_int)), 66 | ReadWhitespaces, 67 | v1 ← ReadVal, 68 | ReadWhitespaces, 69 | ch ',', 70 | ReadWhitespaces, 71 | v2 ← ReadVal, 72 | ReadWhitespaces, 73 | ReadLinebreaks, 74 | return (instruction.binop retty lhs bopc flags v1 v2) 75 | 76 | -- Reads "cast" instructions. 77 | def ReadCastInst (lhs:reg) (opname:string) (uopc:uopcode): parser instruction := 78 | do 79 | str opname, 80 | ReadWhitespaces, 81 | fromty ← (ReadType <|> return (ty.arbitrary_int)), 82 | ReadWhitespaces, 83 | v ← ReadVal, 84 | ReadWhitespaces, 85 | str "to", 86 | ReadWhitespaces, 87 | toty ← ReadType, 88 | ReadLinebreaks, 89 | return (instruction.unaryop lhs uopc fromty v toty) 90 | 91 | def ReadICmpCond: parser icmpcond := 92 | let ls := [icmpcond.eq, icmpcond.ne, icmpcond.ugt, icmpcond.uge, 93 | icmpcond.ult, icmpcond.ule, icmpcond.sgt, icmpcond.sge, 94 | icmpcond.slt, icmpcond.sle] in 95 | let fs := ls.map (λ (cond:icmpcond), do str (to_string cond), return cond) in 96 | list.foldl (λ a b, a <|> b) fs.head fs.tail 97 | 98 | -- Reads "icmp" instruction. 99 | def ReadSelectInst (lhs:reg): parser instruction := 100 | do 101 | str "select", 102 | ReadWhitespaces, 103 | condty ← (ReadType <|> return (ty.arbitrary_int)), 104 | ReadWhitespaces, 105 | cond ← ReadVal, 106 | ReadWhitespaces, 107 | ch ',', 108 | ReadWhitespaces, 109 | valty ← (ReadType <|> return (ty.arbitrary_int)), 110 | ReadWhitespaces, 111 | v1 ← ReadVal, 112 | ReadWhitespaces, 113 | ch ',', 114 | ReadWhitespaces, 115 | valty ← (ReadType <|> return (ty.arbitrary_int)), 116 | ReadWhitespaces, 117 | v2 ← ReadVal, 118 | ReadWhitespaces, 119 | ReadLinebreaks, 120 | return (instruction.selectop lhs condty cond valty v1 v2) 121 | 122 | -- Reads "icmp" instruction. 123 | def ReadICmpInst (lhs:reg): parser instruction := 124 | do 125 | str "icmp", 126 | ReadWhitespaces, 127 | cond ← ReadICmpCond, 128 | ReadWhitespaces, 129 | thety ← (ReadType <|> return (ty.arbitrary_int)), 130 | ReadWhitespaces, 131 | v1 ← ReadVal, 132 | ReadWhitespaces, 133 | ch ',', 134 | ReadWhitespaces, 135 | v2 ← ReadVal, 136 | ReadWhitespaces, 137 | ReadLinebreaks, 138 | return (instruction.icmpop thety lhs cond v1 v2) 139 | 140 | -- Reads "freeze" instruction. 141 | def ReadFreezeInst (lhs:reg): parser instruction := 142 | do 143 | str "freeze", 144 | ReadWhitespaces, 145 | v ← ReadVal, 146 | ReadWhitespaces, 147 | ReadLinebreaks, 148 | return (instruction.unaryop lhs uopcode.freeze (ty.arbitrary_int) v (ty.arbitrary_int)) 149 | 150 | -- Reads an instruction. 151 | def ReadInstruction: parser instruction := 152 | do 153 | ReadWhitespaces, 154 | lhs ← ReadReg, 155 | ReadWhitespaces, 156 | str "=", 157 | ReadWhitespaces, 158 | (ReadBinaryInst lhs "add" bopcode.add) <|> 159 | (ReadBinaryInst lhs "sub" bopcode.sub) <|> 160 | (ReadBinaryInst lhs "mul" bopcode.mul) <|> 161 | (ReadBinaryInst lhs "udiv" bopcode.udiv) <|> 162 | (ReadBinaryInst lhs "urem" bopcode.urem) <|> 163 | (ReadBinaryInst lhs "sdiv" bopcode.sdiv) <|> 164 | (ReadBinaryInst lhs "srem" bopcode.srem) <|> 165 | (ReadBinaryInst lhs "shl" bopcode.shl) <|> 166 | (ReadBinaryInst lhs "ashr" bopcode.ashr) <|> 167 | (ReadBinaryInst lhs "lshr" bopcode.lshr) <|> 168 | (ReadBinaryInst lhs "and" bopcode.and) <|> 169 | (ReadBinaryInst lhs "or" bopcode.or) <|> 170 | (ReadBinaryInst lhs "xor" bopcode.xor) <|> 171 | (ReadCastInst lhs "zext" uopcode.zext) <|> 172 | (ReadCastInst lhs "sext" uopcode.sext) <|> 173 | (ReadCastInst lhs "trunc" uopcode.trunc) <|> 174 | (ReadSelectInst lhs) <|> 175 | (ReadICmpInst lhs) <|> 176 | (ReadFreezeInst lhs) <|> 177 | failure 178 | 179 | -- Reads a program. 180 | def ReadProgram: parser program := 181 | do 182 | ReadWhitespaces, 183 | insts ← many ReadInstruction, 184 | return (program.mk insts) 185 | 186 | def ReadTransformation: parser transformation := 187 | do 188 | ReadWhitespaces, str "Name:", 189 | name ← ReadLine, 190 | p1 ← ReadProgram, 191 | str "=>", 192 | p2 ← ReadProgram, 193 | return (transformation.mk name p1 p2) 194 | 195 | def ReadTransformations: parser (list transformation) := 196 | do 197 | tfs ← many ReadTransformation, 198 | return tfs -------------------------------------------------------------------------------- /src/main.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import system.io 5 | import system.random 6 | import .freevar 7 | import .langparser 8 | import .lang 9 | import .lang_tostr 10 | import .irsem 11 | import .irsem_smt 12 | import .irsem_exec 13 | import .irtype 14 | import .vcgen 15 | import .verifyopt 16 | import smt2.solvers.z3 17 | 18 | open io 19 | open parser 20 | open irsem 21 | 22 | 23 | def string.starts_with (s1:string) (sprefix:string): bool := 24 | list.is_prefix_of (sprefix.to_list) (s1.to_list) 25 | 26 | 27 | 28 | def exec_emitter:vcgen.emitter irsem_exec := 29 | ⟨irsem_exec.val_to_smt, 30 | irsem_exec.poison_to_smt, irsem_exec.bool_to_smt⟩ 31 | 32 | meta def smt_emitter:vcgen.emitter irsem_smt := 33 | ⟨irsem_smt.val_to_smt, 34 | irsem_smt.poison_to_smt, irsem_smt.bool_to_smt⟩ 35 | 36 | -- Runs a single program. 37 | namespace singleprog 38 | 39 | meta def print_result {α:Type} [has_to_string α] (result_state:option α) 40 | : io (option α) := 41 | match result_state with 42 | | none := do 43 | io.print_ln "Stuck", 44 | return none 45 | | some finalresult := do 46 | io.print_ln (finalresult), 47 | return (some finalresult) 48 | end 49 | 50 | -- Executes a program and check whether SMT formula generated 51 | -- from the program encodes the final state. 52 | meta def run_and_emit_smt2 (typedp:program) : io unit := 53 | do 54 | let gen := mk_std_gen, 55 | print_ln "=== Free Variables ===", 56 | let freevars := freevar.get typedp, 57 | print_ln $ "free vars:" ++ to_string freevars, 58 | print_ln "=== Run-EXE ===", 59 | let (init_st, gen) := freevar.create_init_state_exec freevars gen, 60 | final_st ← print_result (bigstep irsem_exec init_st typedp), 61 | print_ln "=== Run-SMT ===", 62 | let init_st' := freevar.create_init_state_smt freevars, 63 | final_st' ← print_result (bigstep irsem_smt init_st' typedp), 64 | 65 | match final_st, final_st' with 66 | | (some final_st), (some final_st') := 67 | do 68 | print_ln "=== SMT Code Gen ===", 69 | let smtcode := vcgen.emit_smt typedp 70 | freevars init_st' final_st final_st' 71 | exec_emitter smt_emitter, 72 | print_ln smtcode, 73 | print_ln "=== Z3 Result ===", 74 | z3i ← z3_instance.start, 75 | smtres ← z3_instance.raw z3i smtcode.to_string, 76 | print_ln smtres, 77 | return () 78 | | _, _ := return () 79 | end 80 | 81 | 82 | -- Reads an input, concretizes its type, emit SMT code, and run it 83 | meta def check (filename:string) (encode_poison:bool): io unit := do 84 | hl ← mk_file_handle filename (io.mode.read) ff, 85 | charbuf ← io.fs.read_to_end hl, 86 | -- Parse the input. 87 | match (run ReadProgram charbuf) with 88 | | sum.inl errmsg := put_str errmsg -- Parsing failed. 89 | | sum.inr prog := 90 | let runf := λ p (encode_poison:bool), run_and_emit_smt2 p in 91 | do 92 | _ ← put_str (to_string prog), 93 | match (concretize_type prog) with 94 | | list.nil := put_str "Cannot find well-typed program with given input." 95 | | x := -- Just run one among them. 96 | monad.foldl (λ a typed_prog, do 97 | print_ln "-------- Next Example ----------", 98 | print_ln "=== After type concretization ===", 99 | print_ln typed_prog, 100 | runf typed_prog encode_poison) 101 | () x 102 | end 103 | end 104 | 105 | end singleprog 106 | 107 | 108 | 109 | -- Verifies optimizations. 110 | namespace verifyopt 111 | 112 | def root_name (p:program): string := 113 | match p.insts.reverse with 114 | | [] := "" 115 | | (instruction.binop _ (reg.r r) _ _ _ _)::_ := r 116 | | (instruction.icmpop _ (reg.r r) _ _ _)::_ := r 117 | | (instruction.selectop (reg.r r) _ _ _ _ _)::_ := r 118 | | (instruction.unaryop (reg.r r) _ _ _ _)::_ := r 119 | end 120 | 121 | meta def check_one (t:transformation) (n:nat) (verbose:bool): io unit := do 122 | let debug_ln (str:format) := 123 | if verbose then print_ln str else return (), 124 | debug_ln format!"--------{t.name}-------{n}--", 125 | let (lp1, lp2) := (concretize_type t.src, concretize_type t.tgt), 126 | let gen := mk_std_gen, 127 | match lp1, lp2 with 128 | | p1::_, p2::_ := do 129 | let freevars := freevar.get p1, 130 | let (init_st, gen) := freevar.create_init_state_exec freevars gen, 131 | let init_st' := freevar.create_init_state_smt freevars, 132 | let r := root_name p1, 133 | 134 | debug_ln (format!"Root variable:{r}"), 135 | debug_ln "=== Does it refine? (EXE) ===", 136 | let ob_exec := opt.check_single_reg irsem_exec p1 p2 r init_st, 137 | debug_ln (to_string ob_exec), 138 | 139 | debug_ln "=== Does it refine? (SMT) ===", 140 | let ob_smt := opt.check_single_reg irsem_smt p1 p2 r init_st', 141 | debug_ln (to_string ob_smt), 142 | 143 | match ob_smt with 144 | | some smtobj := do 145 | debug_ln "=== Z3 Result ===", 146 | let smtcode := vcgen.emit_refine_smt p1 p2 147 | freevars smtobj smt_emitter, 148 | debug_ln smtcode, 149 | z3i ← z3_instance.start, 150 | smtres ← z3_instance.raw z3i smtcode.to_string, 151 | debug_ln (smtres ++ "(Unsat means the opt. is correct)"), 152 | debug_ln "", 153 | if smtres = "unsat\n" then 154 | print_ln "Correct" 155 | else 156 | print_ln "Incorrect" 157 | | none := return () 158 | end 159 | | _, _ := return () 160 | end 161 | 162 | -- Reads transformations and checks them. 163 | meta def check (filename:string) (parseonly:bool) (verbose:bool): io unit := do 164 | hl ← mk_file_handle filename (io.mode.read) ff, 165 | charbuf ← io.fs.read_to_end hl, 166 | 167 | match (run ReadTransformations charbuf) with 168 | | sum.inl errmsg := put_str errmsg 169 | | sum.inr tfs := 170 | if parseonly then do 171 | print_ln "Parsing done.", 172 | _ ← monad.foldl (λ n tf, do 173 | print_ln (to_string tf), print_ln "", return (n+1)) 1 tfs, 174 | return () 175 | 176 | else do 177 | _ ← monad.foldl (λ n tf, do 178 | check_one tf n verbose, return (n+1)) 1 tfs, 179 | return () 180 | end 181 | 182 | end verifyopt 183 | 184 | 185 | 186 | 187 | meta def main : io unit := 188 | do args ← io.cmdline_args, 189 | let cmd := list.head args in 190 | let args := list.tail args in 191 | let get_verbose (l:list string): bool := 192 | match l with | [] := ff | l := 193 | if list.head (list.reverse l) = "-verbose" then tt else ff end in 194 | match cmd with 195 | | "-input" := singleprog.check (list.head args) ff 196 | | "-input2" := singleprog.check (list.head args) tt 197 | | "-parseopt" := verifyopt.check (list.head args) tt 198 | (get_verbose (list.tail args)) 199 | | "-verifyopt" := verifyopt.check (list.head args) ff 200 | (get_verbose (list.tail args)) 201 | | _ := print_ln ("Unknown argument: " ++ cmd) 202 | end -------------------------------------------------------------------------------- /src/ops.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .common 5 | 6 | universes u v 7 | 8 | class has_udiv (α : Type u) := (udiv : α → α → α) 9 | class has_umod (α : Type u) := (umod : α → α → α) 10 | class has_and (α : Type u) := (and : α → α → α) 11 | class has_or (α : Type u) := (or : α → α → α) 12 | class has_xor (α : Type u) := (xor : α → α → α) 13 | class has_shl (α : Type u) := (shl : α → α → α) 14 | class has_lshr (α : Type u) := (lshr : α → α → α) 15 | class has_ashr (α : Type u) := (ashr : α → α → α) 16 | class has_not (α : Type u) := (not : α → α) 17 | infix `/u`:70 := has_udiv.udiv 18 | infix `%u`:70 := has_umod.umod 19 | infix `&`:70 := has_and.and 20 | infix `|b`:70 := has_or.or 21 | infix `^b`:70 := has_xor.xor 22 | infix `<<`:70 := has_shl.shl 23 | infix `>>l`:70 := has_lshr.lshr 24 | infix `>>a`:70 := has_ashr.ashr 25 | prefix `~` := has_not.not 26 | 27 | class has_eq (β: Type v) (α: Type u) := (eq : α → α → β) 28 | class has_ne (β: Type v) (α: Type u) := (ne : α → α → β) 29 | class has_slt (β: Type v) (α: Type u) := (slt : α → α → β) 30 | class has_sle (β: Type v) (α: Type u) := (sle : α → α → β) 31 | class has_ult (β: Type v) (α: Type u) := (ult : α → α → β) 32 | class has_ule (β: Type v) (α: Type u) := (ule : α → α → β) 33 | class has_sgt (β: Type v) (α: Type u) := (sgt : α → α → β) 34 | class has_sge (β: Type v) (α: Type u) := (sge : α → α → β) 35 | class has_ugt (β: Type v) (α: Type u) := (ugt : α → α → β) 36 | class has_uge (β: Type v) (α: Type u) := (uge : α → α → β) 37 | 38 | notation a `=_{` ty `}` b : 50 := has_eq.eq ty a b 39 | notation a `≠_{` ty `}` b : 50 := has_ne.ne ty a b 40 | notation a `<_{` ty `}` b : 50 := has_slt.slt ty a b 41 | notation a `≤_{` ty `}` b : 50 := has_sle.sle ty a b 42 | notation a `>_{` ty `}` b : 50 := has_sgt.sgt ty a b 43 | notation a `≥_{` ty `}` b : 50 := has_sge.sge ty a b 44 | notation a `u_{` ty `}` b : 50 := has_ugt.ugt ty a b 47 | notation a `≥u_{` ty `}` b : 50 := has_uge.uge ty a b 48 | 49 | class bool_like (α: Type u) := 50 | (tt ff:α) 51 | (and or xor:α → α → α) 52 | (not:α → α) 53 | 54 | instance bool_like_has_and (α : Type u) [s:bool_like α] 55 | : has_and α := ⟨s.and⟩ 56 | instance bool_like_has_or (α : Type u) [s:bool_like α] 57 | : has_or α := ⟨s.or⟩ 58 | instance bool_like_has_xor (α : Type u) [s:bool_like α] 59 | : has_xor α := ⟨s.xor⟩ 60 | instance bool_like_has_not (α : Type u) [s:bool_like α] 61 | : has_not α := ⟨s.not⟩ 62 | 63 | instance bool_is_bool_like : bool_like bool := 64 | ⟨tt, ff, band, bor, bxor, bnot⟩ 65 | 66 | 67 | class uint_like (α: Π (v:size), Type v) := 68 | (add sub mul udiv urem sdiv srem and or xor shl lshr ashr: 69 | Π {sz:size}, α sz → α sz → α sz) 70 | (zero {} :Π (sz:size), α sz) 71 | (allone {} :Π (sz:size), α sz) 72 | (signonly {} :Π (sz:size), α sz) 73 | (from_z {} :Π (sz:size) (z:ℤ), α sz) 74 | (zext sext:Π (sz1 sz2:size), α sz1 → α sz2) 75 | (trunc:Π (sz1 sz2:size), α sz1 → α sz2) 76 | 77 | instance uint_like_has_add (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 78 | : has_add (α sz) := ⟨uint_like.add⟩ 79 | instance uint_like_has_sub (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 80 | : has_sub (α sz) := ⟨uint_like.sub⟩ 81 | instance uint_like_has_mul (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 82 | : has_mul (α sz) := ⟨uint_like.mul⟩ 83 | instance uint_like_has_udiv (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 84 | : has_udiv (α sz) := ⟨uint_like.udiv⟩ 85 | instance uint_like_has_urem (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 86 | : has_umod (α sz) := 87 | ⟨uint_like.urem⟩ -- Even if rem and mod are different, we define this way 88 | -- because this helps us use '%u' operator 89 | instance uint_like_has_sdiv (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 90 | : has_div (α sz) := ⟨uint_like.sdiv⟩ 91 | instance uint_like_has_srem (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 92 | : has_mod (α sz) := ⟨uint_like.srem⟩ 93 | instance uint_like_has_and (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 94 | : has_and (α sz) := ⟨uint_like.and⟩ 95 | instance uint_like_has_or (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 96 | : has_or (α sz) := ⟨uint_like.or⟩ 97 | instance uint_like_has_xor (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 98 | : has_xor (α sz) := ⟨uint_like.xor⟩ 99 | instance uint_like_has_shl (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 100 | : has_shl (α sz) := ⟨uint_like.shl⟩ 101 | instance uint_like_has_lshr (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 102 | : has_lshr (α sz) := ⟨uint_like.lshr⟩ 103 | instance uint_like_has_ashr (α:Π (v:size), Type v) [s:uint_like α] {sz:size} 104 | : has_ashr (α sz) := ⟨uint_like.ashr⟩ 105 | 106 | 107 | class has_ite (α :Type v) (β:Type u) := 108 | (ite:α → β → β → β) 109 | 110 | @[reducible] 111 | instance bool_has_ite (β:Type u) : has_ite bool β := 112 | ⟨cond⟩ 113 | 114 | class has_comp (α:Π (v:size), Type u) (β:Type v) := 115 | (eq ne sle slt ule ult:Π {sz:size}, α sz → α sz → β) 116 | 117 | instance has_comp_has_eq (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 118 | : has_eq β (α sz) := ⟨@has_comp.eq α β s sz⟩ 119 | instance has_comp_has_ne (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 120 | : has_ne β (α sz) := ⟨@has_comp.ne α β s sz⟩ 121 | instance has_comp_has_slt (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 122 | : has_slt β (α sz) := ⟨@has_comp.slt α β s sz⟩ 123 | instance has_comp_has_sle (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 124 | : has_sle β (α sz) := ⟨@has_comp.sle α β s sz⟩ 125 | instance has_comp_has_sgt (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 126 | : has_sgt β (α sz) := ⟨λ x y, has_comp.slt β y x⟩ 127 | instance has_comp_has_sge (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 128 | : has_sge β (α sz) := ⟨λ x y, has_comp.sle β y x⟩ 129 | instance has_comp_has_ult (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 130 | : has_ult β (α sz) := ⟨@has_comp.ult α β s sz⟩ 131 | instance has_comp_has_ule (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 132 | : has_ule β (α sz) := ⟨@has_comp.ule α β s sz⟩ 133 | instance has_comp_has_ugt (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 134 | : has_ugt β (α sz) := ⟨λ x y, has_comp.ult β y x⟩ 135 | instance has_comp_has_uge (α:Π (v:size), Type u) (β:Type v) [s:has_comp α β] {sz:size} 136 | : has_uge β (α sz) := ⟨λ x y, has_comp.ule β y x⟩ 137 | 138 | 139 | class has_overflow_check (α:Π (v:size), Type u) (β:Type v):= 140 | (add_chk sub_chk mul_chk shl_chk:Π {sz:size}, bool → α sz → α sz → β) -- is_sign? → op1 → op2 141 | -------------------------------------------------------------------------------- /src/proptest_run.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import system.io 5 | import .smtexpr 6 | import .smtcompile 7 | import .spec.spec 8 | import .proptest 9 | import .spec.lemmas 10 | 11 | open tactic 12 | open spec 13 | 14 | axiom inteq: (3:int) = 3 15 | axiom inteq2: (3:int) = 1+2 16 | axiom forall1 : ∀ (x:int), x = x 17 | axiom forall2_unsat : ∀ (x y:int), x = y 18 | axiom forall3 : ∀ (x:int), x + 2 = x + 1 + 1 19 | axiom forall4 : ∀ (x y:int), x + 2 = x + 1 + 1 20 | axiom intlt: (3:int) < 4 21 | 22 | def stat := list (proptest.test_result × nat) 23 | 24 | namespace stat 25 | def new:stat := [] 26 | 27 | def incr (s:stat) (r:proptest.test_result) := 28 | if s.any (λ l, l.1 = r) then 29 | s.map (λ c, if c.1 = r then (c.1, c.2 + 1) else c) 30 | else 31 | (r, 1)::s 32 | 33 | def to_string (s:stat) := 34 | s.foldl (λ s itm, 35 | s ++ 36 | (to_string itm.1) ++ " : " ++ (to_string itm.2) ++ "\n" 37 | ) "" 38 | end stat 39 | 40 | meta def test_n_loop (e:expr) : nat → std_gen → stat → tactic (stat × std_gen) 41 | | n g s := 42 | if n = 0 then return (s, g) 43 | else do 44 | if n % 1000 = 0 then do 45 | trace n 46 | else skip, 47 | (smtcode, r, g) ← proptest.test e g, 48 | let s := s.incr r, 49 | match r with 50 | | proptest.test_result.error errmsg := do 51 | trace "SMT error!", 52 | trace errmsg, 53 | fail "SMT error!" 54 | | proptest.test_result.fail := do 55 | trace "Counter example:", 56 | trace smtcode, 57 | test_n_loop (n - 1) g s 58 | | _ := 59 | test_n_loop (n - 1) g s 60 | end 61 | 62 | meta def test_n (e:expr) (g:std_gen) (n:nat) : tactic std_gen := 63 | do 64 | trace format!"--------- test_n: total {n} times", 65 | trace e, 66 | ety ← infer_type e, 67 | trace ety, 68 | (s, g) ← test_n_loop e n g stat.new, 69 | trace (s.to_string), 70 | return g 71 | 72 | 73 | meta def arith: list expr := 74 | [ `(inteq), 75 | `(inteq2), 76 | `(forall1), 77 | `(forall2_unsat), 78 | `(forall3), 79 | `(forall4), 80 | `(intlt) ] 81 | 82 | meta def bv_equiv_cons: list expr := 83 | [ `(@spec.bv_equiv.add), 84 | `(@spec.bv_equiv.sub), 85 | `(@spec.bv_equiv.mul), 86 | `(@spec.bv_equiv.and), 87 | `(@spec.bv_equiv.or), 88 | `(@spec.bv_equiv.xor), 89 | `(@spec.bv_equiv.shl), 90 | `(@spec.bv_equiv.lshr), 91 | `(@spec.bv_equiv.ashr), 92 | `(@spec.bv_equiv.udiv), 93 | `(@spec.bv_equiv.urem), 94 | `(@spec.bv_equiv.sdiv), 95 | `(@spec.bv_equiv.srem), 96 | `(@spec.bv_equiv.ite), 97 | `(@spec.bv_equiv.of_bool), 98 | `(@spec.bv_equiv.trunc), 99 | `(@spec.bv_equiv.zext), 100 | `(@spec.bv_equiv.sext) ] 101 | 102 | meta def b_equiv_cons: list expr := 103 | [ `(@spec.b_equiv.tt), 104 | `(@spec.b_equiv.ff), 105 | `(@spec.b_equiv.and1), 106 | -- ∀ (s1 s2:sbool) (b1 b2:bool), 107 | -- b_equiv s1 b1 → (b1 = tt → b_equiv s2 b2) → b_equiv (s1.and s2) (band b1 b2) 108 | -- => 109 | -- (assume that we randomly assigned b1 := tt, b2 := ff) 110 | -- ∀ (s1 s2:sbool), 111 | -- b_equiv s1 tt → (tt = tt → b_equiv s2 ff) → b_equiv (s1.and s2) (ff) 112 | -- .. then this is turned into SMT formula & checked by Z3 113 | `(@spec.b_equiv.and2), 114 | `(@spec.b_equiv.or1), 115 | `(@spec.b_equiv.or2), 116 | `(@spec.b_equiv.xor), 117 | `(@spec.b_equiv.not), 118 | `(@spec.b_equiv.ite), 119 | `(@spec.b_equiv.eq), 120 | `(@spec.b_equiv.ne), 121 | `(@spec.b_equiv.ult), 122 | `(@spec.b_equiv.ule), 123 | `(@spec.b_equiv.slt), 124 | `(@spec.b_equiv.sle)] 125 | 126 | meta def overflow_chks: list expr := 127 | [ `(@spec.add_overflow_chk), 128 | `(@spec.sub_overflow_chk), 129 | `(@spec.mul_overflow_chk), 130 | `(@spec.shl_overflow_chk) ] 131 | 132 | open io 133 | 134 | meta def main:io unit := 135 | let failmsg:io unit := do 136 | print_ln "proptest_run.lean ", 137 | print_ln ":", 138 | print_ln format!"\tarith: 0 ~ 6", 139 | print_ln format!"\tbv_equiv: 0 ~ {bv_equiv_cons.length}", 140 | print_ln format!"\tb_equiv: 0 ~ {b_equiv_cons.length}", 141 | print_ln format!"\toverflow_chk: 0 ~ {overflow_chks.length}", 142 | return () in do 143 | args ← io.cmdline_args, 144 | match args with 145 | | testset::id::cnt::_ := 146 | let exprs := match testset with 147 | | "arith" := arith | "bv_equiv" := bv_equiv_cons 148 | | "b_equiv" := b_equiv_cons | "overflow_chk" := overflow_chks 149 | | _ := [] end in 150 | if exprs.length = 0 then 151 | failmsg 152 | else 153 | let n := cnt.to_nat in 154 | let gen := mk_std_gen in do 155 | exprs ← (if id = "all" then return exprs else 156 | match exprs.nth (id.to_nat) with 157 | | some e := return [e] 158 | | none := do failmsg, io.fail "" 159 | end), 160 | gen' ← monad.foldl (λ gen e, 161 | run_tactic (test_n e gen n)) gen exprs, 162 | return () 163 | | _ := failmsg 164 | end 165 | -------------------------------------------------------------------------------- /src/smtcompile.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .smtexpr 5 | import smt2.syntax 6 | import smt2.builder 7 | 8 | namespace smt 9 | 10 | -- A sample optimizing function. 11 | @[reducible] def optimize_add_zero {sz:size} : sbitvec sz → sbitvec sz 12 | | (sbitvec.add (sbitvec.const _ 0) y) := y 13 | | s := s 14 | 15 | open sbitvec 16 | open sbool 17 | open smt2.builder 18 | 19 | mutual def compile_sbitvec, compile_sbool 20 | with compile_sbitvec : Π {sz:size}, sbitvec sz → smt2.term 21 | | _ (const sz n) := smt2.term.const (smt2.special_constant.bitvec sz (n)) 22 | | _ (var sz x) := smt2.term.qual_id x 23 | | _ (add x y) := bv_add (compile_sbitvec x) (compile_sbitvec y) 24 | | _ (sub x y) := bv_sub (compile_sbitvec x) (compile_sbitvec y) 25 | | _ (mul x y) := bv_mul (compile_sbitvec x) (compile_sbitvec y) 26 | | _ (udiv x y) := bv_udiv (compile_sbitvec x) (compile_sbitvec y) 27 | | _ (urem x y) := bv_urem (compile_sbitvec x) (compile_sbitvec y) 28 | | _ (sdiv x y) := bv_sdiv (compile_sbitvec x) (compile_sbitvec y) 29 | | _ (srem x y) := bv_srem (compile_sbitvec x) (compile_sbitvec y) 30 | | _ (and x y) := bv_and (compile_sbitvec x) (compile_sbitvec y) 31 | | _ (or x y) := bv_or (compile_sbitvec x) (compile_sbitvec y) 32 | | _ (xor x y) := bv_xor (compile_sbitvec x) (compile_sbitvec y) 33 | | _ (shl x y) := bv_shl (compile_sbitvec x) (compile_sbitvec y) 34 | | _ (lshr x y) := bv_lshr (compile_sbitvec x) (compile_sbitvec y) 35 | | _ (ashr x y) := bv_ashr (compile_sbitvec x) (compile_sbitvec y) 36 | | _ (@zext sz sz' x) := bv_zext (sz'- sz) (@compile_sbitvec sz x) 37 | | _ (@sext sz sz' x) := bv_sext (sz'- sz) (@compile_sbitvec sz x) 38 | | _ (@trunc sz sz' x) := bv_extract (sz'-1) 0 (@compile_sbitvec sz x) 39 | | _ (@extract sz sz' hb lb H x) := bv_extract hb lb (@compile_sbitvec sz x) 40 | | _ (@sbitvec.ite sz cond x y) := ite (compile_sbool cond) (compile_sbitvec x) (compile_sbitvec y) 41 | with compile_sbool: sbool → smt2.term 42 | | tt := smt2.term.const (smt2.special_constant.bool tt) 43 | | ff := smt2.term.const (smt2.special_constant.bool ff) 44 | | (var x) := smt2.term.qual_id x 45 | | (and x y) := and2 (compile_sbool x) (compile_sbool y) 46 | | (or x y) := or2 (compile_sbool x) (compile_sbool y) 47 | | (xor x y) := xor2 (compile_sbool x) (compile_sbool y) 48 | | (eqb x y) := equals (compile_sbool x) (compile_sbool y) 49 | | (neb x y) := equals (compile_sbool x) (compile_sbool y) 50 | | (ite c x y) := ite (compile_sbool c) (compile_sbool x) (compile_sbool y) 51 | | (not x) := not (compile_sbool x) 52 | | (@eqbv sz x y) := 53 | have Hx: 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 54 | have Hy: 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 55 | equals (compile_sbitvec x) (compile_sbitvec y) 56 | | (@nebv sz x y) := 57 | have Hx: 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 58 | have Hy: 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 59 | not (equals (compile_sbitvec x) (compile_sbitvec y)) 60 | | (@sle sz x y) := 61 | have Hx: 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 62 | have Hy: 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 63 | bv_sle (compile_sbitvec x) (compile_sbitvec y) 64 | | (@slt sz x y) := 65 | have Hx: 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 66 | have Hy: 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 67 | bv_slt (compile_sbitvec x) (compile_sbitvec y) 68 | | (@ule sz x y) := 69 | have Hx: 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 70 | have Hy: 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 71 | bv_ule (compile_sbitvec x) (compile_sbitvec y) 72 | | (@ult sz x y) := 73 | have Hx: 0 < sbitvec.sizeof sz x, by apply sbitvec.decr_sbitvec, 74 | have Hy: 0 < sbitvec.sizeof sz y, by apply sbitvec.decr_sbitvec, 75 | bv_ult (compile_sbitvec x) (compile_sbitvec y) 76 | 77 | 78 | meta instance sbool_has_to_string : has_to_string sbool := 79 | ⟨λ b, to_string ((compile_sbool b).to_format) ⟩ 80 | meta instance sbitvec_has_to_string {sz:size} : has_to_string (sbitvec sz) := 81 | ⟨λ b, to_string ((compile_sbitvec b).to_format) ⟩ 82 | 83 | end smt -------------------------------------------------------------------------------- /src/smtexpr.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .common 5 | import .ops 6 | import .bitvector 7 | import smt2.syntax 8 | import smt2.builder 9 | 10 | universes u 11 | 12 | -- sbool: Boolean SMT formula 13 | -- sbitvec: Bit-vector SMT formula (takes its bitwidth) 14 | mutual inductive sbool, sbitvec 15 | with sbool : Type 16 | | tt: sbool | ff:sbool 17 | | var: string → sbool -- SMT variable 18 | | and: sbool → sbool → sbool 19 | | or: sbool → sbool → sbool 20 | | xor: sbool → sbool → sbool 21 | | eqb: sbool → sbool → sbool 22 | | neb: sbool → sbool → sbool 23 | | ite: sbool → sbool → sbool → sbool 24 | | not: sbool → sbool 25 | | eqbv: Π {sz:size}, sbitvec sz → sbitvec sz → sbool 26 | | nebv: Π {sz:size}, sbitvec sz → sbitvec sz → sbool 27 | | sle: Π {sz:size}, sbitvec sz → sbitvec sz → sbool 28 | | slt: Π {sz:size}, sbitvec sz → sbitvec sz → sbool 29 | | ule: Π {sz:size}, sbitvec sz → sbitvec sz → sbool 30 | | ult: Π {sz:size}, sbitvec sz → sbitvec sz → sbool 31 | with sbitvec : size → Type 32 | | const: Π (sz:size) (n:nat), sbitvec sz 33 | | var: Π (sz:size), string → sbitvec sz -- SMT variable 34 | | add: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 35 | | sub: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 36 | | mul: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 37 | | udiv: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 38 | | urem: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 39 | | sdiv: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 40 | | srem: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 41 | | and: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 42 | | or: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 43 | | xor: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 44 | | shl: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 45 | | lshr: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 46 | | ashr: Π {sz:size}, sbitvec sz → sbitvec sz → sbitvec sz 47 | | zext: Π {sz:size} (sz':size), sbitvec sz → sbitvec sz' 48 | | sext: Π {sz:size} (sz':size), sbitvec sz → sbitvec sz' 49 | | trunc: Π {sz:size} (sz':size), sbitvec sz → sbitvec sz' 50 | | extract: Π {sz sz':size} (highbit lowbit:nat) 51 | (H:sz'.val = highbit - lowbit + 1), sbitvec sz → sbitvec sz' 52 | | ite: Π {sz:size}, sbool → sbitvec sz → sbitvec sz → sbitvec sz 53 | 54 | 55 | namespace sbool 56 | 57 | open smt2.term 58 | open smt2.builder 59 | 60 | def of_bool (b:bool):sbool := 61 | cond b sbool.tt sbool.ff 62 | 63 | def and_simpl (t1 t2:sbool):sbool := 64 | match t1 with 65 | | sbool.tt := t2 66 | | sbool.ff := sbool.ff 67 | | _ := 68 | match t2 with 69 | | sbool.tt := t1 70 | | sbool.ff := sbool.ff 71 | | _ := sbool.and t1 t2 72 | end 73 | end 74 | 75 | end sbool 76 | 77 | instance sbool_is_bool_like : bool_like sbool := 78 | ⟨sbool.tt, sbool.ff, sbool.and, sbool.or, sbool.xor, sbool.not⟩ 79 | 80 | instance sbool_has_ite : has_ite sbool sbool := 81 | ⟨sbool.ite⟩ 82 | 83 | 84 | 85 | namespace sbitvec 86 | 87 | open smt2.term 88 | open smt2.builder 89 | 90 | def of_int (sz:size) : ℤ → sbitvec sz 91 | | x@(int.of_nat q) := sbitvec.const sz (q % (2^sz.val)) 92 | | x@(int.neg_succ_of_nat p) := 93 | sbitvec.const sz (((2 ^ sz.val) - p - 1) % (2^sz.val)) 94 | 95 | @[simp] 96 | def one (sz:size) : sbitvec sz := of_int sz 1 97 | 98 | @[simp] 99 | def zero (sz:size) : sbitvec sz := of_int sz 0 100 | 101 | @[simp] 102 | def intmin (sz:size) : sbitvec sz := of_int sz (int_min_nat sz) 103 | 104 | @[simp] 105 | def intmax (sz:size) : sbitvec sz := of_int sz (int.of_nat ((2^(sz.val-1))-1)) 106 | 107 | @[simp] 108 | def uintmax (sz:size) : sbitvec sz := of_int sz (all_one_nat sz) 109 | 110 | def of_bool (b:sbool) : sbitvec (size.one) := 111 | sbitvec.ite b (sbitvec.one size.one) (sbitvec.zero size.one) 112 | 113 | def of_bv {sz:size} (b:bitvector sz) : sbitvec sz := of_int sz b.1 114 | 115 | private theorem add_size_eq (n m:size): 116 | subtype.mk ((n.1 + m.1 - 1) - n.1 + 1) dec_trivial = m := 117 | begin apply subtype.eq, simp, 118 | rewrite nat.add_sub_assoc, 119 | { -- 1 + (n.val + (m.val - 1) - n.val) = m.val 120 | rewrite nat.add_sub_cancel_left, -- 1 + (m.val - 1) = m.val 121 | rewrite ← nat.add_sub_assoc, -- 1 + m.val - 1 = m.val 122 | rewrite nat.add_sub_cancel_left, -- 1 ≤ m.val 123 | apply m.2 124 | }, 125 | { -- 1 ≤ m.val 126 | apply m.2 } 127 | end 128 | 129 | theorem decr_sbitvec: ∀ (sz:size) (v:sbitvec sz), 0 < sbitvec.sizeof sz v 130 | := begin 131 | intros, induction v, 132 | any_goals { unfold sbitvec.sizeof }, 133 | any_goals { try {simp}, rw nat.one_add, exact dec_trivial } 134 | end 135 | 136 | variable {sz:size} 137 | 138 | @[simp] 139 | def mk_zext (m:size) (a:sbitvec sz): sbitvec (sz.add m) := 140 | sbitvec.zext (sz.add m) a 141 | 142 | @[simp] 143 | def mk_sext (m:size) (a:sbitvec sz): sbitvec (sz.add m) := 144 | sbitvec.sext (sz.add m) a 145 | 146 | -- Returns false if it overflows. 147 | def overflow_chk (f:Π {sz':size}, sbitvec sz' → sbitvec sz' → sbitvec sz') 148 | (m:size) (signed:bool) 149 | (a b:sbitvec sz):sbool := 150 | if signed then 151 | let a' := sbitvec.mk_sext m a, 152 | b' := sbitvec.mk_sext m b, 153 | r' := f a' b', 154 | r := f a b, 155 | r'' := sbitvec.mk_sext m r in 156 | sbool.nebv r' r'' 157 | else 158 | let a' := sbitvec.mk_zext m a, 159 | b' := sbitvec.mk_zext m b, 160 | r' := f a' b' in 161 | let H:(m.val = (sz.val + m.val - 1) - sz.val + 1) := begin 162 | rw nat.add_comm sz.val m.val, 163 | rw nat.sub.right_comm, 164 | rw nat.add_sub_cancel, 165 | rw nat.sub_add_cancel, 166 | cases m, assumption 167 | end in 168 | let padding := sbitvec.extract (sz+m-1) sz H r' in 169 | sbool.nebv padding (sbitvec.zero m) 170 | 171 | def shl_overflow_chk (m:size) (signed:bool) (a b:sbitvec sz):sbool := 172 | overflow_chk (@sbitvec.shl) sz signed a (sbitvec.urem b (sbitvec.of_int sz sz.val)) 173 | end sbitvec 174 | 175 | 176 | instance sbitvec_is_uint_like 177 | : uint_like (sbitvec) := 178 | ⟨@sbitvec.add, @sbitvec.sub, @sbitvec.mul, 179 | @sbitvec.udiv, @sbitvec.urem, @sbitvec.sdiv, @sbitvec.srem, 180 | @sbitvec.and, @sbitvec.or, @sbitvec.xor, 181 | @sbitvec.shl, @sbitvec.lshr, @sbitvec.ashr, 182 | sbitvec.zero, sbitvec.uintmax, sbitvec.intmin, 183 | sbitvec.of_int, @sbitvec.zext, @sbitvec.sext, @sbitvec.trunc⟩ 184 | 185 | instance sbool_sbitvec_has_coe: has_coe sbool (sbitvec size.one) := 186 | ⟨sbitvec.of_bool⟩ 187 | 188 | @[reducible] 189 | instance sbitvec_has_comp 190 | : has_comp sbitvec sbool := 191 | ⟨@sbool.eqbv, @sbool.nebv, @sbool.sle, @sbool.slt, @sbool.ule, @sbool.ult⟩ 192 | 193 | instance sbitvec_has_ite {sz:size} : has_ite sbool (sbitvec sz) := 194 | ⟨sbitvec.ite⟩ 195 | 196 | instance sbitvec_has_overflow_check 197 | : has_overflow_check sbitvec sbool := 198 | ⟨(λ {sz:size}, @sbitvec.overflow_chk sz @sbitvec.add size.one), 199 | (λ {sz:size}, @sbitvec.overflow_chk sz @sbitvec.sub size.one), 200 | (λ {sz:size}, @sbitvec.overflow_chk sz @sbitvec.mul sz), 201 | (λ {sz:size}, @sbitvec.shl_overflow_chk sz sz)⟩ 202 | -------------------------------------------------------------------------------- /src/spec/customlemmas.lean: -------------------------------------------------------------------------------- 1 | import ..lang 2 | import ..irsem 3 | import ..irsem_exec 4 | import .lemmas_basic 5 | import .lemmas 6 | 7 | open irsem_exec 8 | 9 | -- a single small-step function 10 | @[simp] 11 | def step := irsem.step irsem_exec 12 | 13 | -- a new udiv instruction 14 | @[simp] 15 | def udiv (isz:nat) (name:string) (op1 op2:operand): instruction 16 | := instruction.binop (ty.int isz) (reg.r name) (bopcode.udiv) [] op1 op2 17 | 18 | -- ub check 19 | @[simp] 20 | def has_ub (st:irsem.irstate irsem_exec):Prop := 21 | irsem.irstate.getub irsem_exec st = ff 22 | 23 | -- get value 24 | @[simp] 25 | def get_value (st:irsem.irstate irsem_exec) (op:operand) (opty:ty) := 26 | irsem.get_value irsem_exec st op opty 27 | 28 | -- is poison? 29 | @[simp] 30 | def is_poison: irsem.valty irsem_exec → Prop 31 | | (irsem.valty.ival sz o b) := 32 | b = (@bool_like.ff irsem_exec.poisonty irsem_exec.pbl) 33 | 34 | set_option eqn_compiler.zeta true 35 | set_option pp.proofs true 36 | 37 | local attribute [simp] option.bind irsem.step irsem.step_bop 38 | irsem.bop irsem.bop_ub irsem.irstate.updateub irsem.irstate.updatereg 39 | 40 | lemma never_poison: 41 | ∀ isz name op1 op2 st st' val 42 | (HSTEP:step st (udiv isz name op1 op2) = some st') 43 | (HNOUB:¬ has_ub st') 44 | (HVAL:some val = get_value st op2 (ty.int isz)), 45 | ¬ is_poison val 46 | := begin 47 | intros, 48 | cases st with ub regs, cases st' with ub' regs', 49 | cases ub'; simp at HNOUB; unfold irsem.irstate.getub at HNOUB, 50 | injection HNOUB, clear HNOUB, 51 | cases op2, simp at *, 52 | { 53 | cases (irsem.get_value irsem_exec (ub, regs) op1 (ty.int isz)) with val1; 54 | unfold has_bind.bind at *; unfold option.bind at *, 55 | injection HSTEP, 56 | rw ← HVAL at HSTEP, simp at HSTEP, 57 | cases val1 with isz1 ii1 ip1, 58 | cases val with isz2 ii2 ip2, 59 | simp at HSTEP, 60 | have HISZDEC:decidable (isz1 = isz2), apply_instance, 61 | cases HISZDEC; unfold irsem.bop_val at HSTEP, 62 | { rw dif_neg at HSTEP, injection HSTEP }, 63 | { rw (dif_pos HISZDEC) at HSTEP, 64 | injection HSTEP with HSTEP', clear HSTEP, 65 | cases ub; cases ip2, 66 | any_goals { 67 | -- if dividend was poison or previous state was ub.. 68 | unfold_coes at HSTEP', unfold has_and.and at HSTEP', 69 | unfold bool_like.and at HSTEP', simp at HSTEP', cases HSTEP' with HH _ }, 70 | { simp } 71 | } 72 | }, 73 | { 74 | simp at HVAL, 75 | cases op2, 76 | unfold irsem.get_value at HVAL, 77 | have HSZDEC1: decidable (0 < isz), apply_instance, 78 | cases HSZDEC1, 79 | { rw (dif_neg HSZDEC1) at HVAL, injection HVAL }, 80 | { rw (dif_pos HSZDEC1) at HVAL, 81 | simp at HVAL, 82 | have HVAL2 := ite_or _ HVAL, 83 | cases HVAL2, 84 | { injection HVAL2, rw h_1, simp }, 85 | { have HVAL3 := ite_or _ HVAL2, 86 | cases HVAL3, 87 | { injection HVAL3, rw h_1, simp }, 88 | { injection HVAL3 } 89 | } 90 | } 91 | } 92 | end -------------------------------------------------------------------------------- /src/spec/initialstate.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import ..smtexpr 5 | import ..smtcompile 6 | import ..bitvector 7 | import .spec 8 | import .lemmas 9 | import .lemmas_basic 10 | import .irstate 11 | import .freevar 12 | import .equiv 13 | import .closed 14 | import smt2.syntax 15 | import system.io 16 | import init.meta.tactic 17 | import init.meta.interactive 18 | 19 | namespace spec 20 | 21 | open irsem 22 | open freevar 23 | 24 | -- get_free_*_name 25 | 26 | lemma get_free_name_diff: ∀ n, 27 | get_free_sbitvec_name n ≠ get_free_sbool_name n 28 | := begin 29 | intros, 30 | intros H, 31 | unfold get_free_sbitvec_name at H, 32 | unfold get_free_sbool_name at H, 33 | rw string.eq_list at H, 34 | rw string.append_to_list at H, 35 | rw string.append_to_list at H, 36 | have H' := list.append_eq2 H, 37 | cases H' 38 | end 39 | 40 | 41 | lemma closed_regfile_apply_add_b_bv: ∀ (rf:regfile irsem_smt) (η:freevar.env) 42 | vname vz bname vb 43 | (HC:closed_regfile (rf.apply_to_values irsem_smt (env.replace_valty η))), 44 | closed_regfile (rf.apply_to_values irsem_smt 45 | (env.replace_valty ((η.add_bv vname vz).add_b bname vb))) 46 | := begin 47 | intros, 48 | revert HC, 49 | apply regfile.induction rf, 50 | { 51 | unfold closed_regfile, 52 | intros, 53 | rw regfile.empty_apply_empty, 54 | apply closed_regfile_empty 55 | }, 56 | { 57 | intros rf IH, 58 | intros, 59 | unfold closed_regfile, 60 | intros, 61 | rw regfile.apply_update_comm at HC, 62 | rw regfile.apply_update_comm, 63 | unfold closed_regfile at IH, 64 | rw closed_regfile_update_split at HC, 65 | cases HC with HC HCval, 66 | have HC := IH HC, 67 | rw closed_regfile_update_split, 68 | split, 69 | { 70 | assumption 71 | }, 72 | { 73 | cases v, 74 | unfold freevar.env.replace_valty at HCval, 75 | rw closed_ival_split at HCval, 76 | cases HCval with HCval1 HCval2, 77 | unfold freevar.env.replace_valty, 78 | rw closed_ival_split, 79 | split, 80 | { 81 | have H := closed_b_add_bv vname vz HCval1, 82 | have H := closed_b_add_b bname vb H, 83 | assumption 84 | }, 85 | { 86 | have H := closed_bv_add_bv vname vz HCval2, 87 | have H := closed_bv_add_b bname vb H, 88 | assumption 89 | } 90 | } 91 | } 92 | end 93 | 94 | lemma regfile_update_ival_closed: ∀ rf rf' (η:freevar.env) regn sz 95 | vn pn bvn p 96 | (HCRF: closed_regfile (regfile.apply_to_values irsem_smt rf 97 | (env.replace_valty η))) 98 | (HRF': rf' = regfile.update irsem_smt rf regn 99 | (valty.ival sz (sbitvec.var sz vn) (sbool.var pn))), 100 | closed_regfile (regfile.apply_to_values irsem_smt rf' 101 | (env.replace_valty (env.add_b (env.add_bv η vn bvn) pn p))) 102 | := begin 103 | intros, 104 | have H1 : closed_regfile (regfile.apply_to_values irsem_smt 105 | rf (env.replace_valty (env.add_b (env.add_bv η vn bvn) pn p))), 106 | { 107 | apply closed_regfile_apply_add_b_bv, 108 | assumption 109 | }, 110 | have H2 : closed_valty 111 | ((env.add_b (env.add_bv η vn bvn) pn p) 112 | ⟦valty.ival sz (sbitvec.var sz vn) (sbool.var pn)⟧), 113 | { apply ival_closed }, 114 | rw HRF', 115 | rw regfile.apply_update_comm, 116 | rw closed_regfile_update_split, 117 | split, assumption, assumption 118 | end 119 | 120 | lemma updatereg_closed: ∀ (ss ss':irstate_smt) (η:freevar.env) 121 | regn sz vn pn bvn p 122 | (HC:closed_irstate (η⟦ss⟧)) 123 | (HNOTIN1: vn ∉ η) 124 | (HNOTIN2: pn ∉ η) 125 | (HNOTEQ: vn ≠ pn) 126 | (HS:ss' = irstate.updatereg irsem_smt ss regn 127 | (irsem.valty.ival sz (sbitvec.var sz vn) (sbool.var pn))), 128 | closed_irstate (((η.add_bv vn bvn).add_b pn p)⟦ss'⟧) 129 | := begin 130 | intros, 131 | cases ss with sub srf, 132 | cases ss' with sub' srf', 133 | unfold freevar.env.replace at *, 134 | rw ← irstate.setub_apply_to_values at *, 135 | unfold irstate.getub at *, 136 | simp at *, 137 | unfold irstate.setub at *, 138 | unfold irstate.apply_to_values at *, 139 | rw closed_irstate_split, 140 | rw closed_irstate_split at HC, 141 | cases HC with HCUB HCRF, 142 | unfold irstate.updatereg at HS, 143 | simp at *, 144 | cases HS with h_1 h_2, 145 | subst h_1, 146 | split, 147 | { 148 | have H0: closed_b ((env.add_bv η vn bvn)⟦sub'⟧), 149 | { 150 | apply closed_b_add_bv, 151 | apply HCUB 152 | }, 153 | apply closed_b_add_b, 154 | { assumption } 155 | }, 156 | { 157 | apply regfile_update_ival_closed, assumption, assumption 158 | } 159 | end 160 | 161 | -- encode 162 | 163 | 164 | -- Note that `irstate_equiv η⟦iss⟧ ise` does not imply 165 | -- closed_irstate η⟦iss⟧. It is because, for example, 166 | -- `b_equiv (sbool.and (sbool.var _) (sbool.ff)) ff` holds. 167 | -- Then why `encode iss ise` is needed? -> encode is 168 | -- the only way to relate ise and iss. 169 | lemma init_var_encode_intty: ∀ ise iss ise' iss' (sg sg':std_gen) η n t 170 | (HENC: encode iss ise η) (HCLOSED: closed_irstate (η⟦iss⟧)) 171 | (HNOTIN1: get_free_sbitvec_name n ∉ η) 172 | (HNOTIN2: get_free_sbool_name n ∉ η) 173 | (HIE:(ise', sg') = create_init_var_exec n t (ise, sg)) 174 | (HIS:iss' = create_init_var_smt n t iss), 175 | ∃ η', (encode iss' ise' η' ∧ closed_irstate (η'⟦iss'⟧) ∧ 176 | env.added2 η (get_free_sbitvec_name n) 177 | (get_free_sbool_name n) η') 178 | := begin 179 | intros, 180 | 181 | unfold create_init_var_smt at HIS, 182 | simp at HIS, 183 | 184 | unfold create_init_var_exec at HIE, 185 | simp at HIE, 186 | generalize Hrbv':(get_rand_bv (get_sz_from_ty t) sg) = rbv', 187 | cases rbv' with rbv' sg'', 188 | rw Hrbv' at *, 189 | unfold create_init_var_exec._match_2 at HIE, 190 | generalize Hrb':(get_rand_bool sg'') = rb', 191 | cases rb' with rb' sg''', 192 | rw Hrb' at *, 193 | unfold create_init_var_exec._match_1 at HIE, 194 | injection HIE with HIE HIE_sg, 195 | simp at HIE, 196 | 197 | existsi ((η.add_b (get_free_sbool_name n) rb') 198 | .add_bv (get_free_sbitvec_name n) rbv'.to_int), 199 | split, 200 | { 201 | unfold encode, 202 | rw HIS, 203 | rw replace_updatereg, 204 | rw HIE, 205 | rw env.not_in_add_bv_irstate_comm, 206 | rw env.not_in_add_b_irstate_comm, 207 | rw HCLOSED, rw HCLOSED, 208 | rw env.not_in_add_bv_valty_comm, 209 | rw env.not_in_add_b_valty_comm, 210 | 211 | unfold freevar.env.replace_valty, 212 | -- making value.. 213 | unfold get_free_sbitvec, 214 | rw env.not_in_replace_sbv, 215 | rw env.add_b_replace_sbv, 216 | rw env.empty_replace_sbv, 217 | rw env.add_bv_replace_match, 218 | -- making poison.. 219 | unfold get_free_sbool, 220 | rw env.not_in_replace_sb, 221 | rw env.add_b_replace_match, 222 | rw env.replace_sb_of_bool, 223 | apply irstate.updatereg_equiv, 224 | { 225 | intros, 226 | cases rb', 227 | { -- poison 228 | apply val_equiv.poison_intty, 229 | { constructor, constructor }, 230 | { refl }, 231 | { refl } 232 | }, 233 | { 234 | apply val_equiv.concrete_intty, 235 | { constructor, constructor }, 236 | { 237 | cases rbv', 238 | rw sbitvec_of_int_const, 239 | constructor 240 | }, 241 | { refl } 242 | } 243 | }, 244 | { rw sbitvec_of_int_const, unfold equals_size, simp }, 245 | { apply HENC }, 246 | any_goals { assumption }, 247 | any_goals { 248 | apply env.not_in_add_b, 249 | apply get_free_name_diff, 250 | assumption 251 | }, 252 | }, 253 | split, 254 | { 255 | unfold closed_irstate, 256 | intros, 257 | rw HIS, 258 | rw replace_updatereg, 259 | rw env.not_in_add_bv_irstate_comm, 260 | rw env.not_in_add_b_irstate_comm, 261 | rw HCLOSED, rw HCLOSED, 262 | rw env.not_in_add_bv_valty_comm, 263 | rw env.not_in_add_b_valty_comm, 264 | 265 | unfold freevar.env.replace_valty, 266 | -- making value.. 267 | unfold get_free_sbitvec, 268 | rw env.not_in_replace_sbv, 269 | rw env.add_b_replace_sbv, 270 | rw env.empty_replace_sbv, 271 | rw env.add_bv_replace_match, 272 | -- making poison.. 273 | unfold get_free_sbool, 274 | rw env.not_in_replace_sb, 275 | rw env.add_b_replace_match, 276 | rw env.replace_sb_of_bool, 277 | 278 | rw replace_updatereg, 279 | unfold freevar.env.replace_valty, 280 | rw env.replace_sbv_of_int, 281 | rw env.replace_sb_of_bool, 282 | rw HCLOSED, 283 | any_goals { assumption }, 284 | apply env.not_in_add_b, apply get_free_name_diff, assumption, 285 | apply env.not_in_add_b, apply get_free_name_diff, assumption 286 | }, 287 | { 288 | unfold env.added2, 289 | split, { 290 | intros n_1 H1 H2, 291 | cases H2, 292 | apply env.not_in_add_bv, 293 | assumption, 294 | apply env.not_in_add_b, 295 | assumption, 296 | rw env.not_in_split at H1, 297 | rw env.not_in_split, 298 | assumption 299 | }, 300 | { 301 | intros n_1 H, 302 | unfold env.add_b, 303 | unfold env.add_bv, 304 | unfold has_mem.mem, simp, 305 | cases H, 306 | { 307 | rw if_neg, rw if_neg, unfold has_mem.mem at H, 308 | cases H, left, assumption, right, assumption, 309 | intros H', rw H' at H, apply HNOTIN1, assumption, 310 | intros H', rw H' at H, apply HNOTIN2, assumption, 311 | }, 312 | { 313 | cases H, 314 | { right, rw if_pos, intros H0, cases H0, assumption }, 315 | { left, rw if_pos, intros H0, cases H0, assumption } 316 | } 317 | } 318 | } 319 | end 320 | 321 | def fv_smt_names (fvnames:list string) := 322 | fvnames.map get_free_sbitvec_name ++ 323 | fvnames.map get_free_sbool_name 324 | 325 | lemma init_state_encode_strong: ∀ (freevars:list (string × ty)) (sg sg':std_gen) ise iss 326 | (HUNQ: list.unique $ freevars.map prod.fst) 327 | (HIE:(ise, sg') = create_init_state_exec freevars sg) 328 | (HIS:iss = create_init_state_smt freevars), 329 | ∃ η, (encode iss ise η ∧ closed_irstate (η⟦iss⟧) 330 | ∧ env.has_only η (fv_smt_names $ freevars.map prod.fst)) 331 | := begin 332 | intros, 333 | revert ise iss sg sg', 334 | induction freevars, 335 | { 336 | intros, 337 | unfold create_init_state_exec at HIE, 338 | unfold create_init_state_smt at HIS, 339 | simp at HIE,simp at HIS, 340 | cases HIE with HIE _, 341 | rw [HIS, HIE], 342 | existsi (freevar.env.empty), 343 | unfold encode, rw empty_replace_st, 344 | constructor, constructor, constructor, 345 | any_goals { constructor }, 346 | { 347 | apply closed_irstate_empty 348 | }, 349 | { 350 | unfold fv_smt_names, simp, 351 | unfold env.has_only, intros, split, 352 | { intros H, cases H }, 353 | { intros H, have H := (env.not_in_empty name) H, cases H } 354 | } 355 | }, 356 | { 357 | intros, 358 | rename freevars_tl tl, 359 | cases freevars_hd with vname vty, 360 | have HEtmp: ∀ h t, create_init_state_exec (h::t) sg 361 | = create_init_var_exec h.1 h.2 (create_init_state_exec t sg), 362 | { intros, refl }, 363 | rw HEtmp at HIE, 364 | clear HEtmp, 365 | have HStmp: ∀ h t, create_init_state_smt (h::t) 366 | = create_init_var_smt h.1 h.2 (create_init_state_smt t), 367 | { intros, refl }, 368 | rw HStmp at HIS, 369 | clear HStmp, 370 | generalize HE0: create_init_state_exec tl sg = ise_sg0, 371 | generalize HS0: create_init_state_smt tl = iss0, 372 | rw HE0 at *, 373 | rw HS0 at *, 374 | cases ise_sg0 with ise0 sg0, 375 | simp at HIE HIS, 376 | have HEX: (∃ (η0 : env), encode iss0 ise0 η0 ∧ closed_irstate (η0⟦iss0⟧) 377 | ∧ env.has_only η0 (fv_smt_names $ tl.map prod.fst)), 378 | { 379 | apply freevars_ih, 380 | { 381 | simp at HUNQ, cases HUNQ, assumption 382 | }, apply (eq.symm HE0), refl 383 | }, 384 | cases HEX with η0 HEX, 385 | cases HEX with HEX1 HEX2, 386 | cases HEX2 with HEX2 HEX3, 387 | -- Now add a new variable to each irstate 388 | have HUPDATED: ∃ η', (encode iss ise η' ∧ closed_irstate (η'⟦iss⟧) ∧ 389 | env.added2 η0 (get_free_sbitvec_name vname) 390 | (get_free_sbool_name vname) η'), 391 | { 392 | apply init_var_encode_intty, 393 | apply HEX1, 394 | apply HEX2, 395 | { -- get_free_sbitvec_name vname ∉ η0 396 | simp at HUNQ, cases HUNQ, 397 | apply env.has_only_not_in, 398 | { apply HEX3 }, 399 | { unfold fv_smt_names, 400 | unfold get_free_sbitvec_name, 401 | apply list.not_mem_append, 402 | apply slist_prefix_notin, assumption, 403 | apply slist_prefix_notin2 "v_" "b_" 'v' 'b', assumption, 404 | { intros H0, cases H0 }, refl, refl 405 | } 406 | }, 407 | { -- get_free_sbool_name vname ∉ η0 408 | simp at HUNQ, cases HUNQ, 409 | apply env.has_only_not_in, 410 | { apply HEX3 }, 411 | { unfold fv_smt_names, 412 | unfold get_free_sbool_name, 413 | apply list.not_mem_append, 414 | apply slist_prefix_notin2 "b_" "v_" 'b' 'v', assumption, 415 | { intros H0, cases H0 }, refl, refl, 416 | apply slist_prefix_notin, assumption, 417 | } 418 | }, 419 | assumption, assumption 420 | }, 421 | cases HUPDATED with η HUPDATED, 422 | cases HUPDATED with HUPDATED Htmp, -- env.has_only_added2 (Honly) (Hadd2) 423 | cases Htmp with HUPDATED2 HUPDATED3, 424 | have Hη := env.has_only_added2 HEX3 HUPDATED3, 425 | existsi η, 426 | split, assumption, split, assumption, 427 | { 428 | unfold fv_smt_names, simp, 429 | unfold fv_smt_names at Hη, simp at Hη, 430 | rw ← list.cons_append, 431 | rw ← env.has_only_shuffle (get_free_sbool_name vname), 432 | simp, 433 | rw env.has_only_shuffle2, 434 | apply Hη 435 | } 436 | } 437 | end 438 | 439 | theorem init_state_encode_prf: init_state_encode 440 | := begin 441 | unfold init_state_encode, 442 | intros, 443 | have H := init_state_encode_strong freevars sg sg' ise iss HUNQ 444 | HIE HIS, 445 | cases H with η H, 446 | cases H, existsi η, assumption 447 | end 448 | 449 | -- Future work: theorem that `freevars.get` correctly returns all 450 | -- free variables. 451 | 452 | end spec -------------------------------------------------------------------------------- /src/spec/irstate.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .spec 5 | import .lemmas 6 | import ..irsem 7 | 8 | 9 | namespace spec 10 | 11 | open irsem 12 | /- 13 | - Lemmas about regfile. 14 | -/ 15 | 16 | -- Induction principle of regfile. 17 | lemma regfile.induction: ∀ {sem} {P: regfile sem → Prop} 18 | {HP0: P (@regfile.empty sem)} 19 | {HPU: ∀ rf, P rf → ∀ n v, P (regfile.update sem rf n v)}, 20 | ∀ rf, P rf 21 | := begin 22 | intros, 23 | induction rf, 24 | { apply HP0 }, 25 | { 26 | cases rf_hd, 27 | unfold regfile.update at HPU, 28 | apply HPU, assumption 29 | } 30 | end 31 | 32 | -- regfile.get returns none on regfile.empty 33 | lemma regfile.empty_get_none: ∀ {sem} rname, 34 | regfile.get sem (regfile.empty sem) rname = none 35 | := begin 36 | intros, 37 | unfold regfile.empty, 38 | unfold regfile.get, 39 | simp, 40 | unfold regfile.get._match_1 41 | end 42 | 43 | lemma regfile.empty_apply_empty: ∀ {sem} f, 44 | regfile.apply_to_values sem (regfile.empty sem) f = regfile.empty sem 45 | := begin 46 | intros, 47 | unfold regfile.empty, 48 | refl 49 | end 50 | 51 | -- regfile.get returns the value which is updated just before 52 | -- if rname = rname2 53 | lemma regfile.update_get_match: ∀ {sem} (rname rname2:string) vp rf 54 | (Hnameeq: rname2 = rname), 55 | regfile.get sem (regfile.update sem rf rname vp) rname2 = some vp 56 | := begin 57 | intros, 58 | unfold regfile.get, 59 | unfold regfile.update, 60 | rw list.filter_cons_of_pos, 61 | { unfold regfile.get._match_1 }, 62 | { simp, assumption } 63 | end 64 | 65 | -- Updating a register file does not affect the result 66 | -- of regfile.get if rname ≠ rname2 67 | lemma regfile.update_get_nomatch: ∀ {sem} (rname rname2:string) vp rf 68 | (Hnameeq: rname2 ≠ rname), 69 | regfile.get sem (regfile.update sem rf rname vp) rname2 = 70 | regfile.get sem rf rname2 71 | := begin 72 | intros, 73 | unfold regfile.get, 74 | unfold regfile.update, 75 | rw list.filter_cons_of_neg, 76 | { simp, assumption }, 77 | end 78 | 79 | lemma regfile.regnames_empty: ∀ {sem} n, 80 | n ∉ regfile.regnames sem (regfile.empty sem) 81 | := begin 82 | intros, 83 | unfold regfile.regnames, 84 | unfold regfile.empty, 85 | simp 86 | end 87 | 88 | lemma regfile.reg_in_regnames_update: ∀ {sem} rf n n' v 89 | (H: n ∈ regfile.regnames sem rf), 90 | n ∈ regfile.regnames sem (regfile.update sem rf n' v) 91 | := begin 92 | intros, 93 | unfold regfile.update, 94 | unfold regfile.regnames at *, 95 | simp, 96 | right, apply H 97 | end 98 | 99 | lemma regfile.reg_in_regnames_update2: ∀ {sem} rf n v, 100 | n ∈ regfile.regnames sem (regfile.update sem rf n v) 101 | := begin 102 | intros, 103 | unfold regfile.update, 104 | unfold regfile.regnames at *, 105 | simp 106 | end 107 | 108 | lemma regfile.reg_in_regnames_update3: ∀ {sem} rf n n' v 109 | (H: n ∈ regfile.regnames sem (regfile.update sem rf n' v)) 110 | (HNEQ: n ≠ n'), 111 | n ∈ regfile.regnames sem rf 112 | := begin 113 | intros, 114 | unfold regfile.update at H, 115 | unfold regfile.regnames at *, 116 | simp at *, 117 | cases H, 118 | { exfalso, apply HNEQ, assumption }, 119 | assumption 120 | end 121 | 122 | lemma regfile.reg_notin_regnames_get_none: ∀ {sem} (rname:string) (f:regfile sem), 123 | regfile.get sem f rname = none ↔ rname ∉ regfile.regnames sem f 124 | := begin 125 | intros, 126 | split, 127 | { 128 | intros H, 129 | induction f, 130 | { unfold regfile.regnames, simp }, 131 | { 132 | unfold regfile.get at H, 133 | unfold regfile.regnames, 134 | cases f_hd with n1 v1, unfold list.filter at H, 135 | simp, 136 | have H0: decidable (n1 = rname), apply_instance, 137 | cases H0, 138 | { 139 | rw if_neg at H, 140 | { intros H1, 141 | cases H1, 142 | { rw H1 at H0, apply H0, refl }, 143 | { apply f_ih, apply H, apply H1 } 144 | }, 145 | { 146 | simp, apply neq_symm, apply H0 147 | } 148 | }, 149 | { 150 | rw if_pos at H, 151 | unfold regfile.get._match_1 at H, cases H, 152 | simp, rw H0 153 | } 154 | } 155 | }, 156 | { 157 | intros H, 158 | induction f, 159 | { 160 | unfold regfile.get, 161 | simp, unfold regfile.get._match_1 162 | }, 163 | { 164 | unfold regfile.regnames at H, 165 | simp at H, 166 | rw ← list.mem_cons_iff at H, 167 | rw list.notmem_and at H, 168 | unfold regfile.get, 169 | have H: decidable (f_hd.fst = rname), apply_instance, 170 | cases H, 171 | { -- first element is not rname 172 | unfold list.filter, 173 | rw if_neg, apply f_ih, 174 | cases H, apply H_right, 175 | intros H', rw H' at H_1, apply H_1, refl 176 | }, 177 | { 178 | cases H, rw H_1 at H_left, exfalso, apply H_left, refl 179 | } 180 | } 181 | } 182 | end 183 | 184 | lemma regfile.reg_in_regnames_get_some: ∀ {sem} (rname:string) (f:regfile sem), 185 | (∃ v, regfile.get sem f rname = some v) ↔ rname ∈ regfile.regnames sem f 186 | := begin 187 | intros, 188 | split, 189 | { 190 | apply regfile.induction f, 191 | { 192 | intros H, cases H, 193 | rw regfile.empty_get_none at H_h, 194 | cases H_h 195 | }, 196 | { 197 | intros s Hind n v H, 198 | have HN:decidable (n = rname), apply_instance, 199 | cases HN, 200 | { 201 | rw regfile.update_get_nomatch at H, 202 | have H := Hind H, 203 | apply regfile.reg_in_regnames_update, assumption, 204 | apply neq_symm, assumption 205 | }, 206 | { 207 | rw HN, 208 | apply regfile.reg_in_regnames_update2 209 | } 210 | } 211 | }, 212 | { 213 | apply regfile.induction f, 214 | { intros H, cases H }, 215 | { 216 | intros rf Hind n v H, 217 | have HN:decidable (n = rname), apply_instance, 218 | cases HN, 219 | { 220 | rw regfile.update_get_nomatch, 221 | apply Hind, 222 | apply regfile.reg_in_regnames_update3, 223 | { apply H }, 224 | any_goals { apply neq_symm, assumption }, 225 | }, 226 | { 227 | rw HN, 228 | apply exists.intro v, 229 | apply regfile.update_get_match, refl 230 | } 231 | } 232 | } 233 | end 234 | 235 | lemma regfile.apply_update_comm: ∀ {sem} f n v rf, 236 | regfile.apply_to_values sem (regfile.update sem rf n v) f = 237 | regfile.update sem (regfile.apply_to_values sem rf f) n (f v) 238 | := begin 239 | intros, unfold regfile.apply_to_values, unfold regfile.update, refl 240 | end 241 | 242 | -- Note: reverse direction does not hold! 243 | lemma regfile.reg_apply_some: ∀ {sem} (rf:regfile sem) (f:valty sem → valty sem) v n 244 | (H:regfile.get sem rf n = some v), 245 | regfile.get sem (regfile.apply_to_values sem rf f) n = some (f v) 246 | := begin 247 | intros, 248 | revert H, 249 | apply regfile.induction rf, 250 | { intros H, rw regfile.empty_get_none at H, cases H }, 251 | { 252 | intros rf Hind n1 v1 H, 253 | have HNAME: decidable(n1 = n), apply_instance, 254 | cases HNAME, 255 | { 256 | rw regfile.update_get_nomatch at H, 257 | have H' := Hind H, 258 | rw regfile.apply_update_comm, 259 | rw regfile.update_get_nomatch, assumption, 260 | any_goals { apply neq_symm, assumption } 261 | }, 262 | { 263 | rw regfile.update_get_match at H, 264 | injection H, subst h_1, 265 | rw regfile.apply_update_comm, 266 | rw regfile.update_get_match, 267 | any_goals { rw HNAME } 268 | } 269 | } 270 | end 271 | 272 | lemma regfile.reg_apply_none: ∀ {sem} (rf:regfile sem) (f:valty sem → valty sem) n, 273 | regfile.get sem rf n = none ↔ regfile.get sem (regfile.apply_to_values sem rf f) n = none 274 | := begin 275 | intros, 276 | split, 277 | { 278 | apply regfile.induction rf, 279 | { 280 | intros H, rw regfile.empty_apply_empty, assumption 281 | }, 282 | { 283 | intros rf Hind n1 v1 H, 284 | have HNAME: decidable(n1 = n), apply_instance, 285 | cases HNAME, 286 | { 287 | rw regfile.update_get_nomatch at H, 288 | have H' := Hind H, 289 | rw regfile.apply_update_comm, 290 | rw regfile.update_get_nomatch, assumption, 291 | any_goals { apply neq_symm, assumption } 292 | }, 293 | { 294 | rw regfile.update_get_match at H, 295 | injection H, rw HNAME 296 | } 297 | } 298 | }, 299 | { 300 | apply regfile.induction rf, 301 | { 302 | intros H, rw regfile.empty_apply_empty at H, assumption 303 | }, 304 | { 305 | intros rf Hind n1 v1 H, 306 | have HNAME: decidable(n1 = n), apply_instance, 307 | cases HNAME, 308 | { 309 | rw regfile.apply_update_comm at H, 310 | rw regfile.update_get_nomatch at H, 311 | have H' := Hind H, 312 | rw regfile.update_get_nomatch, assumption, 313 | any_goals { apply neq_symm, assumption } 314 | }, 315 | { 316 | rw regfile.apply_update_comm at H, 317 | rw regfile.update_get_match at H, 318 | injection H, rw HNAME 319 | } 320 | } 321 | } 322 | end 323 | 324 | lemma irstate.updatereg_getreg_match_smt: ∀ (rname rname2:string) v st 325 | (Hnameeq: rname2 = rname), 326 | irstate.getreg irsem_smt (irstate.updatereg irsem_smt st rname v) rname2 = some v 327 | := begin 328 | intros, 329 | unfold irstate.getreg, 330 | unfold irstate.updatereg, 331 | simp, 332 | apply regfile.update_get_match, assumption 333 | end 334 | 335 | lemma irstate.notin_regnames_getreg_smt: ∀ (rname:string) (s:irstate irsem_smt) 336 | (H:rname ∉ irstate.regnames irsem_smt s), 337 | irstate.getreg irsem_smt s rname = none 338 | := begin 339 | intros, 340 | unfold irstate.getreg, 341 | unfold irstate.regnames at *, 342 | cases s, 343 | simp, 344 | rw regfile.reg_notin_regnames_get_none, 345 | apply H 346 | end 347 | 348 | lemma irstate.getreg_diff_smt: ∀ ss (n1 n2:string) v 349 | (H1: irstate.getreg irsem_smt ss n1 = none) 350 | (H2: irstate.getreg irsem_smt ss n2 = some v), 351 | n1 ≠ n2 352 | := begin 353 | intros, 354 | intros HEQ, 355 | rw HEQ at H1, 356 | rw H1 at H2, 357 | cases H2 358 | end 359 | 360 | lemma irstate.updatereg_getreg_nomatch_smt: ∀ ss ss' (n1 n2:string) v v' 361 | (H1: irstate.getreg irsem_smt ss n1 = v) 362 | (H2: ss' = irstate.updatereg irsem_smt ss n2 v') 363 | (HDIFF:n1 ≠ n2), 364 | irstate.getreg irsem_smt ss' n1 = v 365 | := begin 366 | intros, 367 | rw H2, 368 | unfold irstate.getreg at *, 369 | unfold irstate.updatereg at *, 370 | simp, 371 | rw regfile.update_get_nomatch, assumption, assumption 372 | end 373 | 374 | lemma irstate.updatereg_getreg_nomatch_inv_smt: ∀ ss ss' (n1 n2:string) v v' 375 | (H1: irstate.getreg irsem_smt ss' n1 = v) 376 | (H2: ss' = irstate.updatereg irsem_smt ss n2 v') 377 | (HDIFF:n1 ≠ n2), 378 | irstate.getreg irsem_smt ss n1 = v 379 | := begin 380 | intros, 381 | rw H2 at H1, 382 | unfold irstate.getreg at *, 383 | unfold irstate.updatereg at *, 384 | simp at H1, 385 | rw regfile.update_get_nomatch at H1, assumption, assumption 386 | end 387 | 388 | lemma irstate.getreg_empty_none_smt: ∀ s n 389 | (H:irstate.regnames irsem_smt s = []), 390 | irstate.getreg irsem_smt s n = none 391 | := begin 392 | intros, 393 | cases s with ub rf, 394 | unfold irstate.regnames at H, 395 | unfold regfile.regnames at H, 396 | simp at H, 397 | have H' : rf = [], 398 | { apply list.map_nil, apply H }, 399 | rw H', unfold irstate.getreg, unfold regfile.get, simp, 400 | delta regfile.get._match_1, simp 401 | end 402 | 403 | lemma irstate.getub_equiv: ∀ {ss:irstate_smt} {se:irstate_exec} 404 | {sret} {eret} (HSTEQ:irstate_equiv ss se) 405 | (HSSRET: sret = ss.getub irsem_smt) 406 | (HSERET: eret = se.getub irsem_exec), 407 | b_equiv sret eret 408 | := begin 409 | intros, 410 | cases HSTEQ, 411 | any_goals { -- irstate_equiv.noub 412 | unfold irstate.getub at HSSRET, 413 | unfold irstate.getub at HSERET, 414 | simp at HSSRET, simp at HSERET, 415 | subst HSSRET, subst HSERET, assumption 416 | } 417 | end 418 | 419 | lemma irstate.getub_updatereg_smt: ∀ (s:irstate irsem_smt) n v, 420 | irstate.getub irsem_smt (irstate.updatereg irsem_smt s n v) = irstate.getub irsem_smt s 421 | := begin 422 | intros, 423 | unfold irstate.updatereg, 424 | refl 425 | end 426 | 427 | lemma irstate.getreg_apply_some_smt: ∀ (s:irstate irsem_smt) (f:valty_smt → valty_smt) v n 428 | (H: irstate.getreg irsem_smt s n = some v), 429 | irstate.getreg irsem_smt (irstate.apply_to_values irsem_smt s f) n = some (f v) 430 | := begin 431 | intros, 432 | cases s, 433 | unfold irstate.apply_to_values, 434 | unfold irstate.getreg, 435 | apply regfile.reg_apply_some, 436 | apply H 437 | end 438 | 439 | lemma irstate.getreg_apply_none_smt: ∀ (s:irstate irsem_smt) (f:valty_smt → valty_smt) n, 440 | irstate.getreg irsem_smt s n = none ↔ 441 | irstate.getreg irsem_smt (irstate.apply_to_values irsem_smt s f) n = none 442 | := begin 443 | intros, 444 | split, 445 | { 446 | intros H, cases s, 447 | unfold irstate.apply_to_values, 448 | unfold irstate.getreg, 449 | rw ← regfile.reg_apply_none, 450 | apply H 451 | }, 452 | { 453 | intros H, cases s, 454 | unfold irstate.apply_to_values at H, 455 | unfold irstate.getreg, 456 | rw regfile.reg_apply_none, 457 | apply H 458 | } 459 | end 460 | 461 | lemma irstate.empty_apply_empty_smt: ∀ f, 462 | irstate.apply_to_values irsem_smt (irstate.empty irsem_smt) f = irstate.empty irsem_smt 463 | := begin 464 | intros, 465 | unfold irstate.empty, 466 | refl 467 | end 468 | 469 | lemma irstate.getub_apply_to_values: ∀ (s:irstate irsem_smt) f, 470 | irstate.getub irsem_smt (irstate.apply_to_values irsem_smt s f) = 471 | irstate.getub irsem_smt s 472 | := begin 473 | intros, 474 | unfold irstate.getub, 475 | unfold irstate.apply_to_values 476 | end 477 | 478 | lemma irstate.setub_apply_to_values: ∀ (s:irstate irsem_smt) f b, 479 | irstate.setub irsem_smt (irstate.apply_to_values irsem_smt s f) b = 480 | irstate.apply_to_values irsem_smt (irstate.setub irsem_smt s b) f 481 | := begin 482 | intros, 483 | unfold irstate.setub, 484 | unfold irstate.apply_to_values 485 | end 486 | 487 | 488 | end spec -------------------------------------------------------------------------------- /src/spec/lemmas_basic.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | universes u v 5 | -- Basic 6 | lemma prod_inj: ∀ {α:Type u} {β:Type v} (p q:α × β), 7 | p = q ↔ p.fst = q.fst ∧ p.snd = q.snd 8 | := begin 9 | intros, 10 | split, 11 | { intros H, rw H, split; refl }, 12 | { intros H, cases p, cases q, simp at H, 13 | cases H with H1 H2, rw [H1, H2] } 14 | end 15 | 16 | lemma ite_or: 17 | ∀ {α:Type} {c} {x y z:α} (HDEC:decidable c) 18 | (HITE:x = @ite c HDEC α y z), 19 | x = y ∨ x = z 20 | := begin 21 | intros, 22 | cases HDEC, 23 | { rw if_neg at HITE, right, assumption, assumption }, 24 | { rw if_pos at HITE, left, assumption, assumption } 25 | end 26 | 27 | 28 | -- Arithmetic operations 29 | 30 | lemma nat.pow_mul_pow: ∀ (m n:ℕ), 31 | m * m^n = m^(n+1) 32 | := begin 33 | intros, apply nat.mul_comm 34 | end 35 | 36 | lemma nat.lt_pow2: ∀ (n:ℕ), 37 | n < 2^n 38 | := begin 39 | intros, 40 | induction n, 41 | { simp, constructor }, 42 | { 43 | have n_ih := nat.succ_lt_succ n_ih, 44 | apply lt_of_lt_of_le, 45 | { apply n_ih }, 46 | { unfold has_pow.pow, rw nat.pow, rw nat.mul_comm, rw nat.succ_mul, 47 | simp, rw ← nat.add_one, 48 | apply nat.add_le_add_left, 49 | apply nat.pos_pow_of_pos, constructor, constructor 50 | } 51 | } 52 | end 53 | 54 | lemma nat.mod_pow2: ∀ (x:ℕ), 55 | x % 2^x = x 56 | := begin 57 | intros, apply nat.mod_eq_of_lt, apply nat.lt_pow2 58 | end 59 | 60 | lemma neq_symm: ∀ {α:Type u} (x y:α), 61 | x ≠ y → y ≠ x 62 | := begin 63 | intros, intros H, rw H at a, apply a, refl 64 | end 65 | 66 | lemma nat.not_gt_not_eq_implies_lt: ∀ (x y:ℕ), 67 | ¬(x > y) → (x ≠ y) → x < y 68 | := begin 69 | intros x y H1 H2, 70 | have H3 := nat.lt_or_ge x y, 71 | apply or.resolve_right, 72 | apply H3, 73 | intros H0, apply H1, apply nat.lt_of_le_and_ne, apply H0, apply neq_symm, assumption 74 | end 75 | 76 | -- list 77 | 78 | lemma list.foldl_unroll: ∀ {α:Type u} {β:Type v} {f:α → β → α} a (l:list β) x, 79 | list.foldl f a (l++[x]) = f (list.foldl f a l) x 80 | := begin 81 | intros, 82 | revert a, 83 | induction l, 84 | { simp }, 85 | { intros, simp, rw l_ih } 86 | end 87 | 88 | lemma list.notmem_and {α:Type u} [decidable_eq α] : ∀ (l:list α) h a, 89 | (a ∉ h::l) ↔ (a ≠ h ∧ a ∉ l) 90 | := begin 91 | intros, 92 | have HD:decidable (a ∈ l), 93 | { apply (list.decidable_mem a l)}, 94 | simp, rw decidable.not_or_iff_and_not 95 | end 96 | 97 | lemma list.cases_back: ∀ {α:Type u} (l:list α), 98 | l = [] ∨ ∃ a l', l = l' ++ [a] 99 | := begin 100 | intros, 101 | induction l, 102 | { left, refl }, 103 | { 104 | cases l_ih, 105 | { 106 | right, 107 | rw l_ih, 108 | apply exists.intro l_hd, 109 | apply exists.intro [], refl 110 | }, 111 | { 112 | cases l_ih, 113 | cases l_ih_h, 114 | right, 115 | rw l_ih_h_h, 116 | apply exists.intro l_ih_w, 117 | apply exists.intro (l_hd :: l_ih_h_w), 118 | refl 119 | } 120 | } 121 | end 122 | 123 | lemma list.map_nil: ∀ {α:Type u} {β:Type v} (l:list α) (f:α → β) 124 | (H:list.map f l = []), l = [] 125 | := begin 126 | intros, 127 | induction l, 128 | simp, simp at H, cases H 129 | end 130 | 131 | lemma list.map_eq: ∀ {α:Type u} {β:Type v} (l:list α) (f g:α → β) 132 | (H:∀ x, f x = g x), 133 | l.map f = l.map g 134 | := begin 135 | intros, induction l; simp [*] 136 | end 137 | 138 | lemma list.foldr_inv: ∀ {α:Type u} {β:Type v} (la:list α) (b:β) (f:α → β → β) 139 | (P:β → Prop) 140 | (HINV:∀ b', P b' → ∀ a', P (f a' b')) 141 | (H0:P b), 142 | P (list.foldr f b la) 143 | := begin 144 | intros, 145 | induction la, 146 | { simp, assumption }, 147 | { simp, apply HINV, assumption } 148 | end 149 | 150 | lemma list.foldr_eq: ∀ {α:Type u} {β:Type v} (la1 la2:list α) 151 | (b1 b2:β) (f1 f2:α → β → β) 152 | (HF: ∀ a b, f1 a b = f2 a b) 153 | (HLA:la1 = la2) 154 | (HB: b1 = b2), 155 | list.foldr f1 b1 la1 = list.foldr f2 b2 la2 156 | := begin 157 | intros, 158 | revert la1, 159 | induction la2, 160 | { intros, subst HLA, simp, assumption }, 161 | { intros, 162 | subst HLA, 163 | simp, 164 | rw la2_ih, 165 | apply HF, refl 166 | } 167 | end 168 | 169 | lemma list.append_eq: ∀ {α:Type u} {l l21 l22:list α}, 170 | l ++ l21 = l ++ l22 → l21 = l22 171 | := begin 172 | intros, 173 | induction l, simp at a, assumption, 174 | apply l_ih, simp at a, assumption 175 | end 176 | 177 | lemma list.append_nil_eq: ∀ {α:Type u} {l l2:list α}, 178 | l = l2 ++ l → l2 = [] 179 | := begin 180 | intros, induction l with h t, simp at a, rw a, 181 | cases l2, refl, 182 | have a' : (h :: t).length = (l2_hd :: l2_tl ++ h :: t).length, rw ← a, 183 | simp at a', 184 | have a' := nat.add_left_cancel a', 185 | rw ← nat.add_assoc at a', 186 | rw nat.add_comm 1 at a', 187 | rw nat.add_assoc at a', 188 | rw ← nat.add_zero (list.length t) at a', 189 | have a' := nat.add_left_cancel a', 190 | rw nat.one_add at a', cases a' 191 | end 192 | 193 | lemma list.append_eq2: ∀ {α:Type u} {l l1 l2:list α}, 194 | l1 ++ l = l2 ++ l → l1 = l2 195 | := begin 196 | intros, 197 | revert l2, 198 | induction l1, intros, simp at a, rw list.append_nil_eq a, 199 | intros, cases l2, 200 | rw list.nil_append at a, have a' := list.append_nil_eq (eq.symm a), assumption, 201 | injection a, rw h_1, rw l1_ih, apply h_2 202 | end 203 | 204 | 205 | inductive list.unique {α:Type u}: list α → Prop 206 | | nil: list.unique [] 207 | | cons: ∀ a l (H:list.unique l) (H2:a ∉ l), list.unique (a::l) 208 | 209 | 210 | lemma list.not_mem_append: ∀ {α:Type u} {a} {l1 l2:list α} 211 | (H1: a ∉ l1) (H2: a ∉ l2), a ∉ (l1 ++ l2) 212 | := begin 213 | intros, intros H0, rw list.mem_append at H0, 214 | cases H0, apply H1, assumption, apply H2, assumption 215 | end 216 | 217 | -- if two lists are different, appended lists are always different 218 | lemma list.append_ne {α:Type u}: 219 | ∀ {s1 s2:list α} {a1 a2:α} (H:a1 ≠ a2), 220 | s1 ++ [a1] ≠ s2 ++ [a2] 221 | := begin 222 | intros, revert s2, 223 | induction s1, 224 | { 225 | intros, cases s2, simp, assumption, 226 | simp, intros H, cases H, cases s2_tl, 227 | simp at H_right, assumption, cases H_right 228 | }, 229 | { 230 | intros, intros H, cases s2, simp at H, 231 | cases H, cases s1_tl, simp at H_right, assumption, 232 | simp at H_right, assumption, 233 | apply s1_ih, simp at H, cases H, assumption 234 | } 235 | end 236 | 237 | -- strings 238 | 239 | def string.reverse (s:string):string := s.to_list.reverse.as_string 240 | 241 | lemma string.append_to_list: ∀ {s1 s2:string}, 242 | (s1 ++ s2).to_list = s1.to_list ++ s2.to_list 243 | := begin 244 | intros, 245 | cases s1, cases s2, 246 | unfold string.to_list, 247 | refl 248 | end 249 | 250 | lemma string.eq_list: ∀ {s1 s2:string}, 251 | s1 = s2 ↔ s1.to_list = s2.to_list 252 | := begin 253 | intros, 254 | split, 255 | intros, 256 | cases s1, cases s2, 257 | injection a, 258 | intros, cases s1, cases s2, unfold string.to_list at a, rw a 259 | end 260 | 261 | lemma string.eq_suffix: ∀ {s1 s2 suffix:string} 262 | (H:s1 ++ suffix = s2 ++ suffix), s1 = s2 263 | := begin 264 | intros, 265 | rw string.eq_list at H, 266 | rw string.append_to_list at H, 267 | rw string.append_to_list at H, 268 | have H := list.append_eq2 H, 269 | rw string.eq_list, 270 | assumption 271 | end 272 | 273 | lemma string.eq_prefix: ∀ {s1 s2 pref:string} 274 | (H:pref++s1 = pref++s2), s1 = s2 275 | := begin 276 | intros, 277 | rw string.eq_list at H, 278 | rw string.append_to_list at H, 279 | rw string.append_to_list at H, 280 | have H := list.append_eq H, 281 | rw string.eq_list, 282 | assumption 283 | end 284 | 285 | lemma slist_prefix_notin: ∀ {l: list string} {a} (pref: string) 286 | (H:a ∉ l), pref ++ a ∉ l.map (λs, pref ++ s) 287 | := begin 288 | intros, 289 | intros H', 290 | apply H, clear H, 291 | induction l with h t, simp at H', cases H', 292 | simp at *, 293 | cases H', left, apply string.eq_prefix, assumption, 294 | right, apply l_ih, assumption 295 | end 296 | 297 | -- Just a special case - if first characters of two prefixes are 298 | -- different, ∉ holds. 299 | lemma slist_prefix_notin2: ∀ {l: list string} {a} 300 | (pfx1 pfx2: string) {pfx1_t pfx2_t: list char} (pfx1_h pfx2_h : char) 301 | (H:a ∉ l) (HNE:pfx1_h ≠ pfx2_h) 302 | (H1:pfx1 = (pfx1_h::pfx1_t).as_string) 303 | (H1:pfx2 = (pfx2_h::pfx2_t).as_string), 304 | pfx1 ++ a ∉ l.map (λs, pfx2 ++ s) 305 | := begin 306 | intros, 307 | induction l with h t, 308 | { simp }, 309 | rw list.map, 310 | intros H0, apply l_ih, 311 | { intros H', apply H, simp, right, assumption }, 312 | simp at H0, 313 | cases H0, 314 | { 315 | rw string.eq_list at H0, 316 | rw string.append_to_list at H0, 317 | rw string.append_to_list at H0, 318 | rw [H1, H1_1] at H0, 319 | unfold list.as_string at H0, 320 | unfold string.to_list at H0, 321 | simp at H0, cases H0, exfalso, apply HNE, assumption 322 | }, apply H0 323 | end 324 | 325 | lemma slist_prefix_unique: ∀ (l: list string) (pref: string) 326 | (H:list.unique l), list.unique (l.map (λs, pref ++ s)) 327 | := begin 328 | intros, 329 | induction l with h t, 330 | { apply H }, 331 | { 332 | cases H, have H := l_ih H_H, 333 | apply list.unique.cons, assumption, 334 | simp, apply slist_prefix_notin, assumption 335 | } 336 | end -------------------------------------------------------------------------------- /src/spec/spec.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import ..smtexpr 5 | import ..bitvector 6 | import ..irsem 7 | import ..irsem_exec 8 | import ..irsem_smt 9 | import ..freevar 10 | import ..verifyopt 11 | import .lemmas_basic 12 | import smt2.syntax 13 | import smt2.solvers.z3 14 | import system.io 15 | 16 | 17 | namespace spec 18 | 19 | -- This inductive predicate formally defines the equality relation between 20 | -- SMT expressions and LEAN values. 21 | -- bool is LEAN's datatype, and sbool is the SMT boolean expression defined in AliveInLean. 22 | -- bool.tt is LEAN's true, bool.ff is LEAN's false. 23 | mutual inductive b_equiv, bv_equiv 24 | with b_equiv : sbool → bool → Prop 25 | 26 | -- SMT's true constant is equivalent to LEAN's true. 27 | | tt: b_equiv sbool.tt bool.tt 28 | 29 | | ff: b_equiv sbool.ff bool.ff 30 | 31 | -- In the semantics of 'and', short-circuiting was necessary because 32 | -- the former version (2.5) of SMT-LIB defined x / 0 as "undefined". 33 | -- This short-circuiting enables defining this expression as 'false': 34 | -- (and ff (= (bvudiv 1 0) ...)) must be false 35 | | and1: ∀ (s1 s2:sbool) (b1 b2:bool), 36 | b_equiv s1 b1 → (b1 = tt → b_equiv s2 b2) → b_equiv (s1.and s2) (band b1 b2) 37 | 38 | | and2: ∀ (s1 s2:sbool) (b1 b2:bool), 39 | b_equiv s2 b2 → (b2 = tt → b_equiv s1 b1) → b_equiv (s1.and s2) (band b1 b2) 40 | 41 | | or1: ∀ (s1 s2:sbool) (b1 b2:bool), 42 | b_equiv s1 b1 → (b1 = ff → b_equiv s2 b2) → b_equiv (s1.or s2) (bor b1 b2) 43 | 44 | | or2: ∀ (s1 s2:sbool) (b1 b2:bool), 45 | b_equiv s2 b2 → (b2 = ff → b_equiv s1 b1) → b_equiv (s1.or s2) (bor b1 b2) 46 | 47 | | xor: ∀ (s1 s2:sbool) (b1 b2:bool), 48 | b_equiv s1 b1 → b_equiv s2 b2 → b_equiv (s1.xor s2) (bxor b1 b2) 49 | 50 | | not: ∀ (s:sbool) (b:bool), 51 | b_equiv s b → b_equiv (s.not) (bnot b) 52 | 53 | | ite: ∀ (sc s1 s2: sbool) (bc b1 b2:bool), 54 | b_equiv sc bc → b_equiv s1 b1 → b_equiv s2 b2 → 55 | b_equiv (sbool.ite sc s1 s2) (cond bc b1 b2) 56 | 57 | | eq: ∀ (sz:size) (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 58 | bv_equiv s1 b1 → bv_equiv s2 b2 → b_equiv (sbool.eqbv s1 s2) (bitvector.eq b1 b2) 59 | 60 | | ne: ∀ (sz:size) (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 61 | bv_equiv s1 b1 → bv_equiv s2 b2 → b_equiv (sbool.nebv s1 s2) (bitvector.ne b1 b2) 62 | 63 | | ult: ∀ (sz:size) (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 64 | bv_equiv s1 b1 → bv_equiv s2 b2 → b_equiv (sbool.ult s1 s2) (bitvector.ult b1 b2) 65 | 66 | | ule: ∀ (sz:size) (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 67 | bv_equiv s1 b1 → bv_equiv s2 b2 → b_equiv (sbool.ule s1 s2) (bitvector.ule b1 b2) 68 | 69 | | slt: ∀ (sz:size) (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 70 | bv_equiv s1 b1 → bv_equiv s2 b2 → b_equiv (sbool.slt s1 s2) (bitvector.slt b1 b2) 71 | 72 | | sle: ∀ (sz:size) (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 73 | bv_equiv s1 b1 → bv_equiv s2 b2 → b_equiv (sbool.sle s1 s2) (bitvector.sle b1 b2) 74 | 75 | 76 | -- Relates sbitvec and bitvector where bitvector is a LEAN value. 77 | with bv_equiv : Π {sz:size}, sbitvec sz → bitvector sz → Prop 78 | | const: ∀ {sz:size} (n:nat) (H:n < 2^sz.val), bv_equiv 79 | (sbitvec.const sz n) ⟨n, H⟩ 80 | 81 | | add: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 82 | bv_equiv s1 b1 → bv_equiv s2 b2 → bv_equiv (s1.add s2) (b1.add b2) 83 | 84 | | sub: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 85 | bv_equiv s1 b1 → bv_equiv s2 b2 → bv_equiv (s1.sub s2) (b1.sub b2) 86 | 87 | | mul: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 88 | bv_equiv s1 b1 → bv_equiv s2 b2 → bv_equiv (s1.mul s2) (b1.mul b2) 89 | 90 | | and: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 91 | bv_equiv s1 b1 → bv_equiv s2 b2 → bv_equiv (s1.and s2) (b1.bitwise_and b2) 92 | 93 | | or: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 94 | bv_equiv s1 b1 → bv_equiv s2 b2 → bv_equiv (s1.or s2) (b1.bitwise_or b2) 95 | 96 | | xor: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 97 | bv_equiv s1 b1 → bv_equiv s2 b2 → bv_equiv (s1.xor s2) (b1.bitwise_xor b2) 98 | 99 | | shl: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 100 | bv_equiv s1 b1 → bv_equiv s2 b2 → 101 | (bitvector.ult b2 (bitvector.of_int sz (int.of_nat sz.val)) = tt) → 102 | bv_equiv (s1.shl s2) (b1.shl b2) 103 | 104 | | lshr: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 105 | bv_equiv s1 b1 → bv_equiv s2 b2 → 106 | (bitvector.ult b2 (bitvector.of_int sz (int.of_nat sz.val)) = tt) → 107 | bv_equiv (s1.lshr s2) (b1.lshr b2) 108 | 109 | | ashr: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 110 | bv_equiv s1 b1 → bv_equiv s2 b2 → 111 | (bitvector.ult b2 (bitvector.of_int sz (int.of_nat sz.val)) = tt) → 112 | bv_equiv (s1.ashr s2) (b1.ashr b2) 113 | 114 | | udiv: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 115 | bv_equiv s1 b1 → bv_equiv s2 b2 → 116 | (bitvector.ne b2 (bitvector.zero sz) = tt) → -- Div by 0 is UB 117 | bv_equiv (s1.udiv s2) (b1.udiv b2) 118 | 119 | | urem: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 120 | bv_equiv s1 b1 → bv_equiv s2 b2 → 121 | (bitvector.ne b2 (bitvector.zero sz) = tt) → -- Div by 0 is UB 122 | bv_equiv (s1.urem s2) (b1.urem b2) 123 | 124 | | sdiv: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 125 | bv_equiv s1 b1 → bv_equiv s2 b2 → 126 | (bitvector.ne b2 (bitvector.zero sz) = tt) → -- Div by 0 is UB 127 | (bitvector.ne b1 (bitvector.int_min sz) = tt) 128 | ∨ (bitvector.ne b2 (bitvector.all_one sz) = tt) → -- (INT_MIN / -1 is UB) 129 | bv_equiv (s1.sdiv s2) (b1.sdiv b2) 130 | 131 | | srem: ∀ {sz:size} (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 132 | bv_equiv s1 b1 → bv_equiv s2 b2 → 133 | (bitvector.ne b2 (bitvector.zero sz) = tt) → -- Div by 0 is UB 134 | (bitvector.ne b1 (bitvector.int_min sz) = tt) 135 | ∨ (bitvector.ne b2 (bitvector.all_one sz) = tt) → -- (INT_MIN / -1 is UB) 136 | bv_equiv (s1.srem s2) (b1.srem b2) 137 | 138 | | ite: ∀ {sz:size} (sc: sbool) (bc:bool) (s1 s2:sbitvec sz) (b1 b2:bitvector sz), 139 | b_equiv sc bc → (bc = tt → bv_equiv s1 b1) → (bc = ff → bv_equiv s2 b2) → 140 | bv_equiv (sbitvec.ite sc s1 s2) (cond bc b1 b2) 141 | 142 | | of_bool: ∀ (s:sbool) (b:bool), 143 | b_equiv s b → bv_equiv (sbitvec.of_bool s) (bitvector.of_bool b) 144 | 145 | | trunc: ∀ (fromsz tosz:size) (H:tosz.val < fromsz.val) (s:sbitvec fromsz) (b:bitvector fromsz), 146 | bv_equiv s b → bv_equiv (sbitvec.trunc tosz s) (bitvector.trunc tosz b) 147 | 148 | | zext: ∀ (fromsz tosz:size) (H:tosz.val > fromsz.val) 149 | (s:sbitvec fromsz) (b:bitvector fromsz), 150 | bv_equiv s b → bv_equiv (sbitvec.zext tosz s) (bitvector.zext tosz b) 151 | 152 | | sext: ∀ (fromsz tosz:size) (H:tosz.val > fromsz.val) 153 | (s:sbitvec fromsz) (b:bitvector fromsz), 154 | bv_equiv s b → bv_equiv (sbitvec.sext tosz s) (bitvector.sext tosz b) 155 | 156 | 157 | open irsem 158 | open freevar 159 | open opt 160 | 161 | @[reducible] 162 | def intty_smt := irsem_smt.intty 163 | @[reducible] 164 | def intty_exec := irsem_exec.intty 165 | 166 | @[reducible] 167 | def valty_smt := irsem_smt.valty 168 | @[reducible] 169 | def valty_exec := irsem_exec.valty 170 | 171 | @[reducible] 172 | def equals_size : valty_smt → valty_exec → bool 173 | | (irsem.valty.ival sz1 v1 p1) (irsem.valty.ival sz2 v2 p2) := sz1 = sz2 174 | 175 | @[reducible] 176 | def poisonty_smt := irsem_smt.poisonty 177 | @[reducible] 178 | def poisonty_exec := irsem_exec.poisonty 179 | 180 | -- Equivalence of two poison values. 181 | inductive poison_equiv: 182 | irsem_smt.poisonty → irsem_exec.poisonty → Prop 183 | | intro: Π (ps:poisonty_smt) (pe:poisonty_exec), 184 | b_equiv ps pe → poison_equiv ps pe 185 | 186 | -- Equivalence of (concrete-value, poison) 187 | inductive val_equiv: valty_smt → valty_exec → Prop 188 | | poison_intty: Π (szs:size) (vs:intty_smt szs) (ps:poisonty_smt) 189 | (sze:size) (ve:intty_exec sze) (pe:poisonty_exec), 190 | poison_equiv ps pe → 191 | szs = sze → 192 | pe = irsem_exec.pbl.ff → 193 | val_equiv (irsem.valty.ival szs vs ps) (irsem.valty.ival sze ve pe) 194 | | concrete_intty: Π (sz:size) (vs:intty_smt sz) (ps:poisonty_smt) 195 | (ve:intty_exec sz) (pe:poisonty_exec), 196 | poison_equiv ps pe → 197 | bv_equiv vs ve → 198 | pe = irsem_exec.pbl.tt → 199 | val_equiv (irsem.valty.ival sz vs ps) (irsem.valty.ival sz ve pe) 200 | 201 | @[reducible] 202 | def regfile_smt := irsem_smt.regfile 203 | @[reducible] 204 | def regfile_exec := irsem_exec.regfile 205 | 206 | -- Equivalence of two Register files. 207 | inductive regfile_equiv: regfile_smt → regfile_exec → Prop 208 | | empty: ∀ rs re, 209 | rs = regfile.empty irsem_smt → 210 | re = regfile.empty irsem_exec → 211 | regfile_equiv rs re 212 | | update: ∀ rs re vs ve rname rs' re', 213 | regfile_equiv rs re → 214 | val_equiv vs ve → 215 | rs' = regfile.update irsem_smt rs rname vs → 216 | re' = regfile.update irsem_exec re rname ve → 217 | regfile_equiv rs' re' 218 | 219 | @[reducible] 220 | def none_or_some {α β:Type} (os: option α) (oe:option β) (P:α → β → Prop) := 221 | (os = none ∧ oe = none) ∨ 222 | (∃ s e, os = some s ∧ oe = some e ∧ (P s e)) 223 | 224 | def regfile_sametypes (rs:regfile_smt) (re:regfile_exec) := 225 | ∀ (rname:string) os oe, 226 | os = regfile.get irsem_smt rs rname ∧ 227 | oe = regfile.get irsem_exec re rname → 228 | none_or_some os oe (λ vs ve, equals_size vs ve = tt) 229 | 230 | def irstate_smt := irsem_smt.irstate 231 | def irstate_exec := irsem_exec.irstate 232 | 233 | @[reducible] 234 | def has_no_ub: irstate_exec → bool 235 | | (ubs, rs) := ubs 236 | 237 | -- Equivalence of two IR states. 238 | inductive irstate_equiv: irstate_smt → irstate_exec → Prop 239 | | noub: ∀ ubs ube rs re, 240 | regfile_equiv rs re → 241 | b_equiv ubs ube → 242 | ube = irsem_exec.bbl.tt → 243 | irstate_equiv (ubs, rs) (ube, re) 244 | | ub: ∀ ubs ube rs re, -- if UB, register files may differ. 245 | b_equiv ubs ube → 246 | ube = irsem_exec.bbl.ff → 247 | regfile_sametypes rs re → -- but they should have same type! 248 | irstate_equiv (ubs, rs) (ube, re) 249 | 250 | 251 | -- Smallstep preserves equivalence between two states. 252 | def step_both := ∀ {ss:irstate_smt} {se:irstate_exec} {i:instruction} 253 | {oss':option irstate_smt} {ose':option irstate_exec} 254 | (HSTEQ: irstate_equiv ss se) 255 | (HOSS': oss' = step irsem_smt ss i) 256 | (HOSE': ose' = step irsem_exec se i), 257 | none_or_some oss' ose' (λ ss' se', irstate_equiv ss' se') 258 | 259 | 260 | -- Bigstep on an open program 261 | def encode (ss:irstate_smt) (se:irstate_exec) (η:freevar.env) := 262 | irstate_equiv (η⟦ss⟧) se 263 | 264 | def bigstep_both:= ∀ ss se p oss' ose' η 265 | (HENC:encode ss se η) 266 | (HOSS': oss' = bigstep irsem_smt ss p) 267 | (HOSE': ose' = bigstep irsem_exec se p), 268 | none_or_some oss' ose' (λ ss' se', encode ss' se' η) 269 | 270 | def init_state_encode:= ∀ (freevars:list (string × ty)) (sg sg':std_gen) ise iss 271 | (HUNQ: list.unique $ freevars.map prod.fst) 272 | (HIE:(ise, sg') = create_init_state_exec freevars sg) 273 | (HIS:iss = create_init_state_smt freevars), 274 | ∃ η, encode iss ise η 275 | 276 | 277 | -- Correctness of freevar.get is not necessary because an SMT solver 278 | -- will fail if a variable is missing. If it returns a redundant variable, 279 | -- it does not participate in the execution of a program, so it's still okay. 280 | 281 | 282 | -- Refinement 283 | inductive val_refines : valty_exec → valty_exec → Prop 284 | | poison_intty: ∀ sz (isrc:intty_exec sz) psrc (itgt:intty_exec sz) ptgt, 285 | psrc = irsem_exec.pbl.ff → 286 | val_refines (valty.ival sz isrc psrc) (valty.ival sz itgt ptgt) 287 | | concrete_intty: ∀ sz (isrc:intty_exec sz) psrc (itgt:intty_exec sz) ptgt, 288 | psrc = irsem_exec.pbl.tt → 289 | ptgt = irsem_exec.pbl.tt → 290 | isrc = itgt → 291 | val_refines (valty.ival sz isrc psrc) (valty.ival sz itgt ptgt) 292 | 293 | def check_val_exec_spec:= 294 | ∀ vsrc vtgt (H:opt.check_val irsem_exec vsrc vtgt = some tt), 295 | val_refines vsrc vtgt 296 | 297 | 298 | inductive ub_refines: irstate_exec → irstate_exec → Prop 299 | | noub: ∀ src tgt, 300 | irstate.getub irsem_exec src = irsem_exec.bbl.tt → 301 | irstate.getub irsem_exec tgt = irsem_exec.bbl.tt → 302 | ub_refines src tgt 303 | | ub: ∀ src tgt, 304 | irstate.getub irsem_exec src = irsem_exec.bbl.ff → 305 | ub_refines src tgt 306 | 307 | def irstate_refines (se:irstate_exec) (se':irstate_exec): Prop := 308 | ub_refines se se' ∧ 309 | ∀ r, none_or_some (irstate.getreg irsem_exec se r) 310 | (irstate.getreg irsem_exec se' r) 311 | (λ v1 v2, val_refines v1 v2) 312 | 313 | def root_refines (ssrc:irstate_exec) (stgt:irstate_exec) (root:string): Prop := 314 | ub_refines ssrc stgt ∧ 315 | (irstate.getub irsem_exec ssrc = irsem_exec.bbl.tt → 316 | ∃ v1 v2, some v1 = irstate.getreg irsem_exec ssrc root ∧ 317 | some v2 = irstate.getreg irsem_exec stgt root ∧ 318 | val_refines v1 v2) 319 | 320 | def refines_finalstate (psrc ptgt:program) (se0:irstate_exec) := 321 | ∀ se se', 322 | some se = bigstep irsem_exec se0 psrc → 323 | some se' = bigstep irsem_exec se0 ptgt → 324 | irstate_refines se se' 325 | 326 | def root_refines_finalstate (psrc ptgt:program) (se0:irstate_exec) (root:string):= 327 | ∀ se se', 328 | some se = bigstep irsem_exec se0 psrc → 329 | some se' = bigstep irsem_exec se0 ptgt → 330 | root_refines se se' root 331 | 332 | def refines_smt (psrc ptgt:program) := ∀ (η:freevar.env) ss0 se0, 333 | encode ss0 se0 η → refines_finalstate psrc ptgt se0 334 | 335 | def root_refines_smt (psrc ptgt:program) (ss0:irstate_smt) (root:string) := 336 | ∀ (η:freevar.env) se0, 337 | encode ss0 se0 η → root_refines_finalstate psrc ptgt se0 root 338 | 339 | def refines_single_reg_correct := ∀ (psrc ptgt:program) 340 | (root:string) (ss0:irstate_smt) sb 341 | (HSREF:some sb = check_single_reg0 irsem_smt psrc ptgt root ss0) 342 | (HEQ:∀ (η0:freevar.env) e, b_equiv (η0⟦sb⟧) e → e = tt), 343 | root_refines_smt psrc ptgt ss0 root 344 | 345 | end spec 346 | -------------------------------------------------------------------------------- /src/vcgen.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .lang 5 | import .irsem 6 | import .irsem_exec 7 | import .irsem_smt 8 | import .freevar 9 | import smt2.syntax 10 | import smt2.builder 11 | 12 | namespace vcgen 13 | 14 | open irsem 15 | open smt2 16 | open smt2.builder 17 | 18 | -- An emitter that translates value, poison, ub into SMT terms. 19 | structure emitter (sem:irsem) := 20 | (val_f: sem.valty → term) 21 | (poison_f: sem.valty → term) 22 | (bool_f: sem.boolty → term) 23 | 24 | meta def emit_smt (p:program) 25 | (freevars:list (string × ty)) (init_smt_st: irstate irsem_smt) 26 | (final_exec_st:irstate irsem_exec) 27 | (final_smt_st:irstate irsem_smt) 28 | (exec_emit:emitter irsem_exec) (smt_emit:emitter irsem_smt) 29 | : format := 30 | let b:builder unit := 31 | -- Let's show that Behavior(EXEC) ∈ Behavior(SMT)! 32 | -- In nondeterministic semantics, SMT may encode 33 | -- many possible choices, but exec will only have one execution result. 34 | -- First of all, (ub ∈ UB_smt) must hold. 35 | -- ub is a single bool that says whether UB happened in the execution. 36 | -- UB_smt is a SMT term, and it will encode a subset of {tt, ff}. 37 | -- Second, for all register r, poison(r) ∈ POISON_smt(r) must hold. 38 | -- poison(r) is a bool that says whether register r is poison 39 | -- or not. POISON_smt(r) is a SMT term. 40 | -- Third, if ub_yes ∉ UB_smt ∧ poison_yes ∉ POISON_smt(r), 41 | -- val(r) ∈ VAL_smt(r) must hold! ub_yes and poison_yes are 42 | -- constants saying that UB and poison are created. 43 | -- val(r) is a value after execution of the program. 44 | -- VAL_smt(r) is a SMT term that encodes a set of values that r may have 45 | -- in an execution. 46 | 47 | let reglist := irstate.regnames irsem_exec final_exec_st in 48 | -- Did execution raise UB? 49 | let ub_exec := exec_emit.bool_f (irstate.getub irsem_exec final_exec_st) in 50 | let ub_smt := smt_emit.bool_f (irstate.getub irsem_smt final_smt_st) in 51 | -- 'UB happened' constant 52 | let ub_yes := exec_emit.bool_f (irsem_exec.bbl.ff) in 53 | do 54 | -- First of all, declare freevars 55 | freevar.create_smt_declares freevars, 56 | -- Now generate assertions 57 | list.foldl (λ (bldr:builder unit) rdef:string, 58 | match (irstate.getreg irsem_exec final_exec_st rdef, 59 | irstate.getreg irsem_smt final_smt_st rdef) with 60 | | ((some val_exec), (some val_smt)) := 61 | -- Prepare SMT terms 62 | let poison_exec := exec_emit.poison_f val_exec, 63 | poison_smt := smt_emit.poison_f val_smt, 64 | exval := exec_emit.val_f val_exec, 65 | smtval := smt_emit.val_f val_smt in 66 | let poison_yes := exec_emit.poison_f (irsem_exec.give_poison val_exec) in 67 | do bldr, 68 | -- Checks poison_exec(r) ∈ POISON_smt(r) 69 | assert (equals poison_exec poison_smt), 70 | -- Checks ub_yes ∉ UB_smt ∧ poison_yes(r) ∉ POISON_smt(r) → 71 | -- val(r) ∈ VAL_smt(r) 72 | assert (implies 73 | (and2 (not (equals ub_yes ub_smt)) 74 | (not (equals poison_yes poison_smt))) 75 | (equals exval smtval)) 76 | | (_, _) := fail ("Fail to make assertion on register " ++ rdef) 77 | end) 78 | (assert (equals ub_exec ub_smt)) -- Checks ub_exec ∈ UB_smt first 79 | reglist, 80 | -- Add (check-sat)! 81 | check_sat in 82 | builder.to_format b 83 | 84 | 85 | meta def emit_refine_smt (p1 p2:program) (freevars:list (string × ty)) 86 | (refines:sbool) (smt_emit:emitter irsem_smt) 87 | : format := 88 | let b:builder unit := 89 | do 90 | -- First of all, declare freevars 91 | freevar.create_smt_declares freevars, 92 | -- Emit the refinement condition. 93 | assert (not (smt_emit.bool_f refines)), 94 | -- Add (check-sat)! 95 | check_sat in 96 | builder.to_format b 97 | 98 | end vcgen -------------------------------------------------------------------------------- /src/verifyopt.lean: -------------------------------------------------------------------------------- 1 | -- Copyright (c) Microsoft Corporation. All rights reserved. 2 | -- Licensed under the MIT license. 3 | 4 | import .ops 5 | import .lang 6 | import .irsem 7 | 8 | namespace opt 9 | section 10 | 11 | open irsem 12 | 13 | parameter (sem : irsem) 14 | 15 | -- uint_like types 16 | variable [ihc:has_comp sem.intty sem.boolty] 17 | variable [ioc:has_overflow_check sem.intty sem.boolty] 18 | variable [iul:uint_like sem.intty] 19 | -- poison types 20 | variable [pbl:bool_like sem.poisonty] 21 | variable [p2b:has_coe sem.poisonty sem.boolty] 22 | -- bool types 23 | variable [bbl:bool_like sem.boolty] 24 | variable [b2i:has_coe sem.boolty (sem.intty size.one)] 25 | variable [bhi:Π (sz:size), has_ite sem.boolty (sem.intty sz)] 26 | variable [bhi2:has_ite sem.boolty sem.poisonty] 27 | 28 | include ihc 29 | include ioc 30 | include iul 31 | include bbl 32 | include pbl 33 | include p2b 34 | include b2i 35 | include bhi 36 | include bhi2 37 | 38 | def check_val (vsrc vtgt:irsem.valty sem) : option sem.boolty := 39 | match vsrc, vtgt with 40 | | irsem.valty.ival sz1 v1 p1, irsem.valty.ival sz2 v2 p2 := 41 | if H:sz1 = sz2 then 42 | some ((~ p1) |b (p2 & (v1 =_{sem.boolty} (cast (by rw H) v2)))) 43 | else none 44 | end 45 | 46 | def check_single_reg0 (psrc ptgt:program) (r:string) (initst:irstate sem) : option sem.boolty := 47 | do 48 | s1 ← irsem.bigstep sem initst psrc, 49 | s2 ← irsem.bigstep sem initst ptgt, 50 | v1 ← irsem.irstate.getreg sem s1 r, 51 | v2 ← irsem.irstate.getreg sem s2 r, 52 | ref ← check_val v1 v2, 53 | return ((~ irstate.getub sem s1) |b (irstate.getub sem s2 & ref)) 54 | 55 | -- This is another version of check_single_reg0 that allows using variables 56 | -- in the source instructions. 57 | -- Currently, proof in AliveInLean does not exploit SSA property of a program, so this is 58 | -- okay. regfile.update_get_match at spec/irstate.lean states that 59 | -- the latest update to a variable has the latest value. 60 | def check_single_reg (psrc ptgt:program) (r:string) (initst:irstate sem) : option sem.boolty := 61 | do 62 | s1 ← irsem.bigstep sem initst psrc, 63 | s2 ← irsem.bigstep sem initst { insts := psrc.insts ++ ptgt.insts }, 64 | v1 ← irsem.irstate.getreg sem s1 r, 65 | v2 ← irsem.irstate.getreg sem s2 r, 66 | ref ← check_val v1 v2, 67 | return ((~ irstate.getub sem s1) |b (irstate.getub sem s2 & ref)) 68 | 69 | end 70 | end opt 71 | --------------------------------------------------------------------------------