| author | |
| committer | |
| log | 7f7d58ee895d0e29850ed1823ba91e672edc03a6 |
| tree | 7bd7515a24e5eafa8c4a95332908e6e5e41ffa47 |
| parent | 5929da37a117dfe67983155b39d4ee39e11f7ebc |
| parent | b3922289be1ffaf194b55face332892280981356 |
| signature |
100 files changed, 2632 insertions(+), 1056 deletions(-)
ci/azure/pipelines.yml+27-1| ... | @@ -27,7 +27,7 @@ jobs: | ... | @@ -27,7 +27,7 @@ jobs: |
| 27 | vmImage: 'windows-2019' | 27 | vmImage: 'windows-2019' |
| 28 | variables: | 28 | variables: |
| 29 | TARGET: 'x86_64-windows-gnu' | 29 | TARGET: 'x86_64-windows-gnu' |
| 30 | ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.2931+bdf3fa12f' | 30 | ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.3524+74673b7f6' |
| 31 | ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip' | 31 | ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip' |
| 32 | steps: | 32 | steps: |
| 33 | - pwsh: | | 33 | - pwsh: | |
| ... | @@ -41,6 +41,13 @@ jobs: | ... | @@ -41,6 +41,13 @@ jobs: |
| 41 | Set-Variable -Name ZIGINSTALLDIR -Value "${ZIGBUILDDIR}\dist" | 41 | Set-Variable -Name ZIGINSTALLDIR -Value "${ZIGBUILDDIR}\dist" |
| 42 | Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$(ZIG_LLVM_CLANG_LLD_NAME)" | 42 | Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$(ZIG_LLVM_CLANG_LLD_NAME)" |
| 43 | 43 | ||
| 44 | function CheckLastExitCode { | ||
| 45 | if (!$?) { | ||
| 46 | exit 1 | ||
| 47 | } | ||
| 48 | return 0 | ||
| 49 | } | ||
| 50 | |||
| 44 | # Make the `zig version` number consistent. | 51 | # Make the `zig version` number consistent. |
| 45 | # This will affect the `zig build` command below which uses `git describe`. | 52 | # This will affect the `zig build` command below which uses `git describe`. |
| 46 | git config core.abbrev 9 | 53 | git config core.abbrev 9 |
| ... | @@ -69,6 +76,7 @@ jobs: | ... | @@ -69,6 +76,7 @@ jobs: |
| 69 | -Dstrip ` | 76 | -Dstrip ` |
| 70 | -Duse-zig-libcxx ` | 77 | -Duse-zig-libcxx ` |
| 71 | -Dtarget=$(TARGET) | 78 | -Dtarget=$(TARGET) |
| 79 | CheckLastExitCode | ||
| 72 | 80 | ||
| 73 | cd - | 81 | cd - |
| 74 | 82 | ||
| ... | @@ -83,19 +91,37 @@ jobs: | ... | @@ -83,19 +91,37 @@ jobs: |
| 83 | - pwsh: | | 91 | - pwsh: | |
| 84 | Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist" | 92 | Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist" |
| 85 | 93 | ||
| 94 | function CheckLastExitCode { | ||
| 95 | if (!$?) { | ||
| 96 | exit 1 | ||
| 97 | } | ||
| 98 | return 0 | ||
| 99 | } | ||
| 100 | |||
| 86 | # Sadly, stage2 is omitted from this build to save memory on the CI server. Once self-hosted is | 101 | # Sadly, stage2 is omitted from this build to save memory on the CI server. Once self-hosted is |
| 87 | # built with itself and does not gobble as much memory, we can enable these tests. | 102 | # built with itself and does not gobble as much memory, we can enable these tests. |
| 88 | #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1 | 103 | #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1 |
| 104 | #CheckLastExitCode | ||
| 89 | 105 | ||
| 90 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1 | 106 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1 |
| 107 | CheckLastExitCode | ||
| 91 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1 | 108 | & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1 |
| 109 | CheckLastExitCode | ||
| 92 | name: test | 110 | name: test |
| 93 | displayName: 'Test' | 111 | displayName: 'Test' |
| 94 | 112 | ||
| 95 | - pwsh: | | 113 | - pwsh: | |
| 96 | Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist" | 114 | Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist" |
| 97 | 115 | ||
| 116 | function CheckLastExitCode { | ||
| 117 | if (!$?) { | ||
| 118 | exit 1 | ||
| 119 | } | ||
| 120 | return 0 | ||
| 121 | } | ||
| 122 | |||
| 98 | & "$ZIGINSTALLDIR\bin\zig.exe" build docs | 123 | & "$ZIGINSTALLDIR\bin\zig.exe" build docs |
| 124 | CheckLastExitCode | ||
| 99 | timeoutInMinutes: 60 | 125 | timeoutInMinutes: 60 |
| 100 | name: doc | 126 | name: doc |
| 101 | displayName: 'Documentation' | 127 | displayName: 'Documentation' |
ci/srht/update_download_page+13-5| ... | @@ -103,11 +103,19 @@ cd "$HOME" | ... | @@ -103,11 +103,19 @@ cd "$HOME" |
| 103 | 103 | ||
| 104 | # Upload new stdlib autodocs | 104 | # Upload new stdlib autodocs |
| 105 | mkdir -p docs_to_upload/documentation/master/std/ | 105 | mkdir -p docs_to_upload/documentation/master/std/ |
| 106 | cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html | 106 | |
| 107 | cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js | 107 | gzip -c -9 "$ZIGDIR/docs/std/index.html" > docs_to_upload/documentation/master/std/index.html |
| 108 | cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js | 108 | gzip -c -9 "$ZIGDIR/docs/std/data.js" > docs_to_upload/documentation/master/std/data.js |
| 109 | cp "$LANGREF" docs_to_upload/documentation/master/index.html | 109 | gzip -c -9 "$ZIGDIR/docs/std/main.js" > docs_to_upload/documentation/master/std/main.js |
| 110 | $S3CMD put -P --no-mime-magic --recursive --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/ | 110 | gzip -c -9 "$LANGREF" > docs_to_upload/documentation/master/index.html |
| 111 | $S3CMD put -P --no-mime-magic --recursive --add-header="Content-Encoding:gzip" --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/ | ||
| 112 | |||
| 113 | ## Copy without compression: | ||
| 114 | # cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html | ||
| 115 | # cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js | ||
| 116 | # cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js | ||
| 117 | # cp "$LANGREF" docs_to_upload/documentation/master/index.html | ||
| 118 | # $S3CMD put -P --no-mime-magic --recursive --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/ | ||
| 111 | 119 | ||
| 112 | git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git | 120 | git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git |
| 113 | cd www.ziglang.org | 121 | cd www.ziglang.org |
lib/docs/index.html+17-9| ... | @@ -169,8 +169,8 @@ | ... | @@ -169,8 +169,8 @@ |
| 169 | width: 100%; | 169 | width: 100%; |
| 170 | margin-bottom: 0.8rem; | 170 | margin-bottom: 0.8rem; |
| 171 | padding: 0.5rem; | 171 | padding: 0.5rem; |
| 172 | font-size: 1rem; | ||
| 173 | font-family: var(--ui); | 172 | font-family: var(--ui); |
| 173 | font-size: 1rem; | ||
| 174 | color: var(--tx-color); | 174 | color: var(--tx-color); |
| 175 | background-color: var(--search-bg-color); | 175 | background-color: var(--search-bg-color); |
| 176 | border-top: 0; | 176 | border-top: 0; |
| ... | @@ -339,8 +339,8 @@ | ... | @@ -339,8 +339,8 @@ |
| 339 | kbd { | 339 | kbd { |
| 340 | display: inline-block; | 340 | display: inline-block; |
| 341 | padding: 0.3em 0.2em; | 341 | padding: 0.3em 0.2em; |
| 342 | font-size: 1.2em; | 342 | font-family: var(--mono); |
| 343 | font-size: var(--mono); | 343 | font-size: 1em; |
| 344 | line-height: 0.8em; | 344 | line-height: 0.8em; |
| 345 | vertical-align: middle; | 345 | vertical-align: middle; |
| 346 | color: #000; | 346 | color: #000; |
| ... | @@ -612,7 +612,7 @@ | ... | @@ -612,7 +612,7 @@ |
| 612 | </div> | 612 | </div> |
| 613 | </nav> | 613 | </nav> |
| 614 | </div> | 614 | </div> |
| 615 | <div class="flex-right"> | 615 | <div id="docs" class="flex-right"> |
| 616 | <div class="wrap"> | 616 | <div class="wrap"> |
| 617 | <section class="docs"> | 617 | <section class="docs"> |
| 618 | <div style="position: relative"> | 618 | <div style="position: relative"> |
| ... | @@ -654,7 +654,13 @@ | ... | @@ -654,7 +654,13 @@ |
| 654 | </div> | 654 | </div> |
| 655 | <div id="sectSearchNoResults" class="hidden"> | 655 | <div id="sectSearchNoResults" class="hidden"> |
| 656 | <h2>No Results Found</h2> | 656 | <h2>No Results Found</h2> |
| 657 | <p>Press escape to exit search and then '?' to see more options.</p> | 657 | <p>Here are some things you can try:</p> |
| 658 | <ul> | ||
| 659 | <li>Check out the <a id="langRefLink">Language Reference</a> for the language itself.</li> | ||
| 660 | <li>Check out the <a href="https://ziglang.org/learn/">Learn page</a> for other helpful resources for learning Zig.</li> | ||
| 661 | <li>Use your search engine.</li> | ||
| 662 | </ul> | ||
| 663 | <p>Press <kbd>?</kbd> to see keyboard shortcuts and <kbd>Esc</kbd> to return.</p> | ||
| 658 | </div> | 664 | </div> |
| 659 | <div id="sectFields" class="hidden"> | 665 | <div id="sectFields" class="hidden"> |
| 660 | <h2>Fields</h2> | 666 | <h2>Fields</h2> |
| ... | @@ -716,11 +722,13 @@ | ... | @@ -716,11 +722,13 @@ |
| 716 | <div class="modal"> | 722 | <div class="modal"> |
| 717 | <h1>Keyboard Shortcuts</h1> | 723 | <h1>Keyboard Shortcuts</h1> |
| 718 | <dl><dt><kbd>?</kbd></dt><dd>Show this help modal</dd></dl> | 724 | <dl><dt><kbd>?</kbd></dt><dd>Show this help modal</dd></dl> |
| 719 | <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this modal</dd></dl> | ||
| 720 | <dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl> | 725 | <dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl> |
| 721 | <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl> | 726 | <div style="margin-left: 1em"> |
| 722 | <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl> | 727 | <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl> |
| 723 | <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl> | 728 | <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl> |
| 729 | <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl> | ||
| 730 | </div> | ||
| 731 | <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this modal</dd></dl> | ||
| 724 | </div> | 732 | </div> |
| 725 | </div> | 733 | </div> |
| 726 | </div> | 734 | </div> |
lib/docs/main.js+45-24| ... | @@ -41,7 +41,7 @@ var zigAnalysis; | ... | @@ -41,7 +41,7 @@ var zigAnalysis; |
| 41 | const domSearch = document.getElementById("search"); | 41 | const domSearch = document.getElementById("search"); |
| 42 | const domSectSearchResults = document.getElementById("sectSearchResults"); | 42 | const domSectSearchResults = document.getElementById("sectSearchResults"); |
| 43 | const domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink"); | 43 | const domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink"); |
| 44 | 44 | const domDocs = document.getElementById("docs"); | |
| 45 | const domListSearchResults = document.getElementById("listSearchResults"); | 45 | const domListSearchResults = document.getElementById("listSearchResults"); |
| 46 | const domSectSearchNoResults = document.getElementById("sectSearchNoResults"); | 46 | const domSectSearchNoResults = document.getElementById("sectSearchNoResults"); |
| 47 | const domSectInfo = document.getElementById("sectInfo"); | 47 | const domSectInfo = document.getElementById("sectInfo"); |
| ... | @@ -52,6 +52,7 @@ var zigAnalysis; | ... | @@ -52,6 +52,7 @@ var zigAnalysis; |
| 52 | const domHelpModal = document.getElementById("helpModal"); | 52 | const domHelpModal = document.getElementById("helpModal"); |
| 53 | const domSearchPlaceholder = document.getElementById("searchPlaceholder"); | 53 | const domSearchPlaceholder = document.getElementById("searchPlaceholder"); |
| 54 | const sourceFileUrlTemplate = "/src-viewer/{{file}}#L{{line}}" | 54 | const sourceFileUrlTemplate = "/src-viewer/{{file}}#L{{line}}" |
| 55 | const domLangRefLink = document.getElementById("langRefLink"); | ||
| 55 | 56 | ||
| 56 | let lineCounter = 1; | 57 | let lineCounter = 1; |
| 57 | let searchTimer = null; | 58 | let searchTimer = null; |
| ... | @@ -118,10 +119,10 @@ var zigAnalysis; | ... | @@ -118,10 +119,10 @@ var zigAnalysis; |
| 118 | }); | 119 | }); |
| 119 | domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false); | 120 | domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false); |
| 120 | function onClickSearchShowAllResults(ev) { | 121 | function onClickSearchShowAllResults(ev) { |
| 121 | ev.preventDefault(); | 122 | ev.preventDefault(); |
| 122 | ev.stopPropagation(); | 123 | ev.stopPropagation(); |
| 123 | searchTrimResults = false; | 124 | searchTrimResults = false; |
| 124 | onHashChange(); | 125 | onHashChange(); |
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | domPrivDeclsBox.addEventListener( | 128 | domPrivDeclsBox.addEventListener( |
| ... | @@ -163,6 +164,13 @@ var zigAnalysis; | ... | @@ -163,6 +164,13 @@ var zigAnalysis; |
| 163 | window.addEventListener("keydown", onWindowKeyDown, false); | 164 | window.addEventListener("keydown", onWindowKeyDown, false); |
| 164 | onHashChange(); | 165 | onHashChange(); |
| 165 | 166 | ||
| 167 | let langRefVersion = zigAnalysis.params.zigVersion; | ||
| 168 | if (!/^\d+\.\d+\.\d+$/.test(langRefVersion)) { | ||
| 169 | // the version is probably not released yet | ||
| 170 | langRefVersion = "master"; | ||
| 171 | } | ||
| 172 | domLangRefLink.href = `https://ziglang.org/documentation/${langRefVersion}/`; | ||
| 173 | |||
| 166 | function renderTitle() { | 174 | function renderTitle() { |
| 167 | let list = curNav.pkgNames.concat(curNav.declNames); | 175 | let list = curNav.pkgNames.concat(curNav.declNames); |
| 168 | let suffix = " - Zig"; | 176 | let suffix = " - Zig"; |
| ... | @@ -3154,6 +3162,23 @@ var zigAnalysis; | ... | @@ -3154,6 +3162,23 @@ var zigAnalysis; |
| 3154 | domSearch.blur(); | 3162 | domSearch.blur(); |
| 3155 | } | 3163 | } |
| 3156 | 3164 | ||
| 3165 | // hide the modal if it's visible or return to the previous result page and unfocus the search | ||
| 3166 | function onEscape(ev) { | ||
| 3167 | if (!domHelpModal.classList.contains("hidden")) { | ||
| 3168 | domHelpModal.classList.add("hidden"); | ||
| 3169 | ev.preventDefault(); | ||
| 3170 | ev.stopPropagation(); | ||
| 3171 | } else { | ||
| 3172 | domSearch.value = ""; | ||
| 3173 | domSearch.blur(); | ||
| 3174 | domSearchPlaceholder.classList.remove("hidden"); | ||
| 3175 | curSearchIndex = -1; | ||
| 3176 | ev.preventDefault(); | ||
| 3177 | ev.stopPropagation(); | ||
| 3178 | startSearch(); | ||
| 3179 | } | ||
| 3180 | } | ||
| 3181 | |||
| 3157 | function onSearchKeyDown(ev) { | 3182 | function onSearchKeyDown(ev) { |
| 3158 | switch (getKeyString(ev)) { | 3183 | switch (getKeyString(ev)) { |
| 3159 | case "Enter": | 3184 | case "Enter": |
| ... | @@ -3170,19 +3195,15 @@ var zigAnalysis; | ... | @@ -3170,19 +3195,15 @@ var zigAnalysis; |
| 3170 | ev.stopPropagation(); | 3195 | ev.stopPropagation(); |
| 3171 | return; | 3196 | return; |
| 3172 | case "Esc": | 3197 | case "Esc": |
| 3173 | domSearch.value = ""; | 3198 | onEscape(ev); |
| 3174 | domSearch.blur(); | 3199 | return |
| 3175 | curSearchIndex = -1; | ||
| 3176 | ev.preventDefault(); | ||
| 3177 | ev.stopPropagation(); | ||
| 3178 | startSearch(); | ||
| 3179 | return; | ||
| 3180 | case "Up": | 3200 | case "Up": |
| 3181 | moveSearchCursor(-1); | 3201 | moveSearchCursor(-1); |
| 3182 | ev.preventDefault(); | 3202 | ev.preventDefault(); |
| 3183 | ev.stopPropagation(); | 3203 | ev.stopPropagation(); |
| 3184 | return; | 3204 | return; |
| 3185 | case "Down": | 3205 | case "Down": |
| 3206 | // TODO: make the page scroll down if the search cursor is out of the screen | ||
| 3186 | moveSearchCursor(1); | 3207 | moveSearchCursor(1); |
| 3187 | ev.preventDefault(); | 3208 | ev.preventDefault(); |
| 3188 | ev.stopPropagation(); | 3209 | ev.stopPropagation(); |
| ... | @@ -3251,19 +3272,18 @@ var zigAnalysis; | ... | @@ -3251,19 +3272,18 @@ var zigAnalysis; |
| 3251 | function onWindowKeyDown(ev) { | 3272 | function onWindowKeyDown(ev) { |
| 3252 | switch (getKeyString(ev)) { | 3273 | switch (getKeyString(ev)) { |
| 3253 | case "Esc": | 3274 | case "Esc": |
| 3254 | if (!domHelpModal.classList.contains("hidden")) { | 3275 | onEscape(ev); |
| 3255 | domHelpModal.classList.add("hidden"); | 3276 | break; |
| 3277 | case "s": | ||
| 3278 | if (domHelpModal.classList.contains("hidden")) { | ||
| 3279 | domSearch.focus(); | ||
| 3280 | domSearch.select(); | ||
| 3281 | domDocs.scrollTo(0, 0); | ||
| 3256 | ev.preventDefault(); | 3282 | ev.preventDefault(); |
| 3257 | ev.stopPropagation(); | 3283 | ev.stopPropagation(); |
| 3284 | startAsyncSearch(); | ||
| 3258 | } | 3285 | } |
| 3259 | break; | 3286 | break; |
| 3260 | case "s": | ||
| 3261 | domSearch.focus(); | ||
| 3262 | domSearch.select(); | ||
| 3263 | ev.preventDefault(); | ||
| 3264 | ev.stopPropagation(); | ||
| 3265 | startAsyncSearch(); | ||
| 3266 | break; | ||
| 3267 | case "?": | 3287 | case "?": |
| 3268 | ev.preventDefault(); | 3288 | ev.preventDefault(); |
| 3269 | ev.stopPropagation(); | 3289 | ev.stopPropagation(); |
| ... | @@ -3279,6 +3299,7 @@ var zigAnalysis; | ... | @@ -3279,6 +3299,7 @@ var zigAnalysis; |
| 3279 | domHelpModal.style.top = | 3299 | domHelpModal.style.top = |
| 3280 | window.innerHeight / 2 - domHelpModal.clientHeight / 2 + "px"; | 3300 | window.innerHeight / 2 - domHelpModal.clientHeight / 2 + "px"; |
| 3281 | domHelpModal.focus(); | 3301 | domHelpModal.focus(); |
| 3302 | domSearch.blur(); | ||
| 3282 | } | 3303 | } |
| 3283 | 3304 | ||
| 3284 | function clearAsyncSearch() { | 3305 | function clearAsyncSearch() { |
| ... | @@ -3304,7 +3325,7 @@ var zigAnalysis; | ... | @@ -3304,7 +3325,7 @@ var zigAnalysis; |
| 3304 | list.sort(); | 3325 | list.sort(); |
| 3305 | return list; | 3326 | return list; |
| 3306 | } | 3327 | } |
| 3307 | 3328 | ||
| 3308 | function renderSearch() { | 3329 | function renderSearch() { |
| 3309 | let matchedItems = []; | 3330 | let matchedItems = []; |
| 3310 | let ignoreCase = curNavSearch.toLowerCase() === curNavSearch; | 3331 | let ignoreCase = curNavSearch.toLowerCase() === curNavSearch; |
| ... | @@ -3393,13 +3414,13 @@ var zigAnalysis; | ... | @@ -3393,13 +3414,13 @@ var zigAnalysis; |
| 3393 | const text = lastPkgName + "." + match.path.declNames.join("."); | 3414 | const text = lastPkgName + "." + match.path.declNames.join("."); |
| 3394 | const href = navLink(match.path.pkgNames, match.path.declNames); | 3415 | const href = navLink(match.path.pkgNames, match.path.declNames); |
| 3395 | 3416 | ||
| 3396 | matchedItemsHTML += "<li><a href=\""+ href +"\">"+ text + "</a></li>"; | 3417 | matchedItemsHTML += "<li><a href=\"" + href + "\">" + text + "</a></li>"; |
| 3397 | } | 3418 | } |
| 3398 | 3419 | ||
| 3399 | // Replace the search results using our newly constructed HTML string | 3420 | // Replace the search results using our newly constructed HTML string |
| 3400 | domListSearchResults.innerHTML = matchedItemsHTML; | 3421 | domListSearchResults.innerHTML = matchedItemsHTML; |
| 3401 | if (searchTrimmed) { | 3422 | if (searchTrimmed) { |
| 3402 | domSectSearchAllResultsLink.classList.remove("hidden"); | 3423 | domSectSearchAllResultsLink.classList.remove("hidden"); |
| 3403 | } | 3424 | } |
| 3404 | renderSearchCursor(); | 3425 | renderSearchCursor(); |
| 3405 | 3426 |
lib/std/array_list.zig+63| ... | @@ -221,6 +221,30 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -221,6 +221,30 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 221 | mem.copy(T, self.items[old_len..], items); | 221 | mem.copy(T, self.items[old_len..], items); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | /// Append an unaligned slice of items to the list. Allocates more | ||
| 225 | /// memory as necessary. Only call this function if calling | ||
| 226 | /// `appendSlice` instead would be a compile error. | ||
| 227 | pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void { | ||
| 228 | try self.ensureUnusedCapacity(items.len); | ||
| 229 | self.appendUnalignedSliceAssumeCapacity(items); | ||
| 230 | } | ||
| 231 | |||
| 232 | /// Append the slice of items to the list, asserting the capacity is already | ||
| 233 | /// enough to store the new items. **Does not** invalidate pointers. | ||
| 234 | /// Only call this function if calling `appendSliceAssumeCapacity` instead | ||
| 235 | /// would be a compile error. | ||
| 236 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { | ||
| 237 | const old_len = self.items.len; | ||
| 238 | const new_len = old_len + items.len; | ||
| 239 | assert(new_len <= self.capacity); | ||
| 240 | self.items.len = new_len; | ||
| 241 | @memcpy( | ||
| 242 | @ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len), | ||
| 243 | @ptrCast([*]const u8, items.ptr), | ||
| 244 | items.len * @sizeOf(T), | ||
| 245 | ); | ||
| 246 | } | ||
| 247 | |||
| 224 | pub const Writer = if (T != u8) | 248 | pub const Writer = if (T != u8) |
| 225 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ | 249 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ |
| 226 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") | 250 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") |
| ... | @@ -592,6 +616,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -592,6 +616,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 592 | mem.copy(T, self.items[old_len..], items); | 616 | mem.copy(T, self.items[old_len..], items); |
| 593 | } | 617 | } |
| 594 | 618 | ||
| 619 | /// Append the slice of items to the list. Allocates more | ||
| 620 | /// memory as necessary. Only call this function if a call to `appendSlice` instead would | ||
| 621 | /// be a compile error. | ||
| 622 | pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void { | ||
| 623 | try self.ensureUnusedCapacity(allocator, items.len); | ||
| 624 | self.appendUnalignedSliceAssumeCapacity(items); | ||
| 625 | } | ||
| 626 | |||
| 627 | /// Append an unaligned slice of items to the list, asserting the capacity is enough | ||
| 628 | /// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity` | ||
| 629 | /// instead would be a compile error. | ||
| 630 | pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void { | ||
| 631 | const old_len = self.items.len; | ||
| 632 | const new_len = old_len + items.len; | ||
| 633 | assert(new_len <= self.capacity); | ||
| 634 | self.items.len = new_len; | ||
| 635 | @memcpy( | ||
| 636 | @ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len), | ||
| 637 | @ptrCast([*]const u8, items.ptr), | ||
| 638 | items.len * @sizeOf(T), | ||
| 639 | ); | ||
| 640 | } | ||
| 641 | |||
| 595 | pub const WriterContext = struct { | 642 | pub const WriterContext = struct { |
| 596 | self: *Self, | 643 | self: *Self, |
| 597 | allocator: Allocator, | 644 | allocator: Allocator, |
| ... | @@ -899,6 +946,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" { | ... | @@ -899,6 +946,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" { |
| 899 | try testing.expect(list.pop() == 1); | 946 | try testing.expect(list.pop() == 1); |
| 900 | try testing.expect(list.items.len == 9); | 947 | try testing.expect(list.items.len == 9); |
| 901 | 948 | ||
| 949 | var unaligned: [3]i32 align(1) = [_]i32{ 4, 5, 6 }; | ||
| 950 | list.appendUnalignedSlice(&unaligned) catch unreachable; | ||
| 951 | try testing.expect(list.items.len == 12); | ||
| 952 | try testing.expect(list.pop() == 6); | ||
| 953 | try testing.expect(list.pop() == 5); | ||
| 954 | try testing.expect(list.pop() == 4); | ||
| 955 | try testing.expect(list.items.len == 9); | ||
| 956 | |||
| 902 | list.appendSlice(&[_]i32{}) catch unreachable; | 957 | list.appendSlice(&[_]i32{}) catch unreachable; |
| 903 | try testing.expect(list.items.len == 9); | 958 | try testing.expect(list.items.len == 9); |
| 904 | 959 | ||
| ... | @@ -941,6 +996,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" { | ... | @@ -941,6 +996,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" { |
| 941 | try testing.expect(list.pop() == 1); | 996 | try testing.expect(list.pop() == 1); |
| 942 | try testing.expect(list.items.len == 9); | 997 | try testing.expect(list.items.len == 9); |
| 943 | 998 | ||
| 999 | var unaligned: [3]i32 align(1) = [_]i32{ 4, 5, 6 }; | ||
| 1000 | list.appendUnalignedSlice(a, &unaligned) catch unreachable; | ||
| 1001 | try testing.expect(list.items.len == 12); | ||
| 1002 | try testing.expect(list.pop() == 6); | ||
| 1003 | try testing.expect(list.pop() == 5); | ||
| 1004 | try testing.expect(list.pop() == 4); | ||
| 1005 | try testing.expect(list.items.len == 9); | ||
| 1006 | |||
| 944 | list.appendSlice(a, &[_]i32{}) catch unreachable; | 1007 | list.appendSlice(a, &[_]i32{}) catch unreachable; |
| 945 | try testing.expect(list.items.len == 9); | 1008 | try testing.expect(list.items.len == 9); |
| 946 | 1009 |
lib/std/bounded_array.zig+1-1| ... | @@ -275,7 +275,7 @@ test "BoundedArray" { | ... | @@ -275,7 +275,7 @@ test "BoundedArray" { |
| 275 | try testing.expectEqualSlices(u8, &x, a.constSlice()); | 275 | try testing.expectEqualSlices(u8, &x, a.constSlice()); |
| 276 | 276 | ||
| 277 | var a2 = a; | 277 | var a2 = a; |
| 278 | try testing.expectEqualSlices(u8, a.constSlice(), a.constSlice()); | 278 | try testing.expectEqualSlices(u8, a.constSlice(), a2.constSlice()); |
| 279 | a2.set(0, 0); | 279 | a2.set(0, 0); |
| 280 | try testing.expect(a.get(0) != a2.get(0)); | 280 | try testing.expect(a.get(0) != a2.get(0)); |
| 281 | 281 |
lib/std/builtin.zig+3-2| ... | @@ -294,6 +294,8 @@ pub const Type = union(enum) { | ... | @@ -294,6 +294,8 @@ pub const Type = union(enum) { |
| 294 | /// therefore must be kept in sync with the compiler implementation. | 294 | /// therefore must be kept in sync with the compiler implementation. |
| 295 | pub const Struct = struct { | 295 | pub const Struct = struct { |
| 296 | layout: ContainerLayout, | 296 | layout: ContainerLayout, |
| 297 | /// Only valid if layout is .Packed | ||
| 298 | backing_integer: ?type = null, | ||
| 297 | fields: []const StructField, | 299 | fields: []const StructField, |
| 298 | decls: []const Declaration, | 300 | decls: []const Declaration, |
| 299 | is_tuple: bool, | 301 | is_tuple: bool, |
| ... | @@ -867,10 +869,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn { | ... | @@ -867,10 +869,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn { |
| 867 | std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len }); | 869 | std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len }); |
| 868 | } | 870 | } |
| 869 | 871 | ||
| 870 | pub noinline fn returnError(maybe_st: ?*StackTrace) void { | 872 | pub noinline fn returnError(st: *StackTrace) void { |
| 871 | @setCold(true); | 873 | @setCold(true); |
| 872 | @setRuntimeSafety(false); | 874 | @setRuntimeSafety(false); |
| 873 | const st = maybe_st orelse return; | ||
| 874 | addErrRetTraceAddr(st, @returnAddress()); | 875 | addErrRetTraceAddr(st, @returnAddress()); |
| 875 | } | 876 | } |
| 876 | 877 |
lib/std/c/darwin.zig+4-4| ... | @@ -814,10 +814,10 @@ pub const sigset_t = u32; | ... | @@ -814,10 +814,10 @@ pub const sigset_t = u32; |
| 814 | pub const empty_sigset: sigset_t = 0; | 814 | pub const empty_sigset: sigset_t = 0; |
| 815 | 815 | ||
| 816 | pub const SIG = struct { | 816 | pub const SIG = struct { |
| 817 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 817 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 818 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 818 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 819 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 819 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 820 | pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 5); | 820 | pub const HOLD = @intToPtr(?Sigaction.handler_fn, 5); |
| 821 | 821 | ||
| 822 | /// block specified signal set | 822 | /// block specified signal set |
| 823 | pub const _BLOCK = 1; | 823 | pub const _BLOCK = 1; |
lib/std/c/dragonfly.zig+3-3| ... | @@ -609,9 +609,9 @@ pub const S = struct { | ... | @@ -609,9 +609,9 @@ pub const S = struct { |
| 609 | pub const BADSIG = SIG.ERR; | 609 | pub const BADSIG = SIG.ERR; |
| 610 | 610 | ||
| 611 | pub const SIG = struct { | 611 | pub const SIG = struct { |
| 612 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 612 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 613 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 613 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 614 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 614 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 615 | 615 | ||
| 616 | pub const BLOCK = 1; | 616 | pub const BLOCK = 1; |
| 617 | pub const UNBLOCK = 2; | 617 | pub const UNBLOCK = 2; |
lib/std/c/freebsd.zig+3-3| ... | @@ -670,9 +670,9 @@ pub const SIG = struct { | ... | @@ -670,9 +670,9 @@ pub const SIG = struct { |
| 670 | pub const UNBLOCK = 2; | 670 | pub const UNBLOCK = 2; |
| 671 | pub const SETMASK = 3; | 671 | pub const SETMASK = 3; |
| 672 | 672 | ||
| 673 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 673 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 674 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 674 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 675 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 675 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 676 | 676 | ||
| 677 | pub const WORDS = 4; | 677 | pub const WORDS = 4; |
| 678 | pub const MAXSIG = 128; | 678 | pub const MAXSIG = 128; |
lib/std/c/netbsd.zig+3-3| ... | @@ -910,9 +910,9 @@ pub const winsize = extern struct { | ... | @@ -910,9 +910,9 @@ pub const winsize = extern struct { |
| 910 | const NSIG = 32; | 910 | const NSIG = 32; |
| 911 | 911 | ||
| 912 | pub const SIG = struct { | 912 | pub const SIG = struct { |
| 913 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 913 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 914 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 914 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 915 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 915 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 916 | 916 | ||
| 917 | pub const WORDS = 4; | 917 | pub const WORDS = 4; |
| 918 | pub const MAXSIG = 128; | 918 | pub const MAXSIG = 128; |
lib/std/c/openbsd.zig+5-5| ... | @@ -982,11 +982,11 @@ pub const winsize = extern struct { | ... | @@ -982,11 +982,11 @@ pub const winsize = extern struct { |
| 982 | const NSIG = 33; | 982 | const NSIG = 33; |
| 983 | 983 | ||
| 984 | pub const SIG = struct { | 984 | pub const SIG = struct { |
| 985 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 985 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 986 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 986 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 987 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 987 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 988 | pub const CATCH = @intToPtr(?Sigaction.sigaction_fn, 2); | 988 | pub const CATCH = @intToPtr(?Sigaction.handler_fn, 2); |
| 989 | pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 3); | 989 | pub const HOLD = @intToPtr(?Sigaction.handler_fn, 3); |
| 990 | 990 | ||
| 991 | pub const HUP = 1; | 991 | pub const HUP = 1; |
| 992 | pub const INT = 2; | 992 | pub const INT = 2; |
lib/std/c/solaris.zig+4-4| ... | @@ -879,10 +879,10 @@ pub const winsize = extern struct { | ... | @@ -879,10 +879,10 @@ pub const winsize = extern struct { |
| 879 | const NSIG = 75; | 879 | const NSIG = 75; |
| 880 | 880 | ||
| 881 | pub const SIG = struct { | 881 | pub const SIG = struct { |
| 882 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 882 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 883 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 883 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 884 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 884 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 885 | pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 2); | 885 | pub const HOLD = @intToPtr(?Sigaction.handler_fn, 2); |
| 886 | 886 | ||
| 887 | pub const WORDS = 4; | 887 | pub const WORDS = 4; |
| 888 | pub const MAXSIG = 75; | 888 | pub const MAXSIG = 75; |
lib/std/crypto/25519/ed25519.zig+3-1| ... | @@ -355,7 +355,9 @@ test "ed25519 batch verification" { | ... | @@ -355,7 +355,9 @@ test "ed25519 batch verification" { |
| 355 | try Ed25519.verifyBatch(2, signature_batch); | 355 | try Ed25519.verifyBatch(2, signature_batch); |
| 356 | 356 | ||
| 357 | signature_batch[1].sig = sig1; | 357 | signature_batch[1].sig = sig1; |
| 358 | try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(signature_batch.len, signature_batch)); | 358 | // TODO https://github.com/ziglang/zig/issues/12240 |
| 359 | const sig_len = signature_batch.len; | ||
| 360 | try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(sig_len, signature_batch)); | ||
| 359 | } | 361 | } |
| 360 | } | 362 | } |
| 361 | 363 |
lib/std/debug.zig+1-1| ... | @@ -1787,7 +1787,7 @@ fn resetSegfaultHandler() void { | ... | @@ -1787,7 +1787,7 @@ fn resetSegfaultHandler() void { |
| 1787 | return; | 1787 | return; |
| 1788 | } | 1788 | } |
| 1789 | var act = os.Sigaction{ | 1789 | var act = os.Sigaction{ |
| 1790 | .handler = .{ .sigaction = os.SIG.DFL }, | 1790 | .handler = .{ .handler = os.SIG.DFL }, |
| 1791 | .mask = os.empty_sigset, | 1791 | .mask = os.empty_sigset, |
| 1792 | .flags = 0, | 1792 | .flags = 0, |
| 1793 | }; | 1793 | }; |
lib/std/fs.zig+4-2| ... | @@ -877,8 +877,9 @@ pub const IterableDir = struct { | ... | @@ -877,8 +877,9 @@ pub const IterableDir = struct { |
| 877 | /// a reference to the path. | 877 | /// a reference to the path. |
| 878 | pub fn next(self: *Walker) !?WalkerEntry { | 878 | pub fn next(self: *Walker) !?WalkerEntry { |
| 879 | while (self.stack.items.len != 0) { | 879 | while (self.stack.items.len != 0) { |
| 880 | // `top` becomes invalid after appending to `self.stack` | 880 | // `top` and `containing` become invalid after appending to `self.stack` |
| 881 | var top = &self.stack.items[self.stack.items.len - 1]; | 881 | var top = &self.stack.items[self.stack.items.len - 1]; |
| 882 | var containing = top; | ||
| 882 | var dirname_len = top.dirname_len; | 883 | var dirname_len = top.dirname_len; |
| 883 | if (try top.iter.next()) |base| { | 884 | if (try top.iter.next()) |base| { |
| 884 | self.name_buffer.shrinkRetainingCapacity(dirname_len); | 885 | self.name_buffer.shrinkRetainingCapacity(dirname_len); |
| ... | @@ -899,10 +900,11 @@ pub const IterableDir = struct { | ... | @@ -899,10 +900,11 @@ pub const IterableDir = struct { |
| 899 | .dirname_len = self.name_buffer.items.len, | 900 | .dirname_len = self.name_buffer.items.len, |
| 900 | }); | 901 | }); |
| 901 | top = &self.stack.items[self.stack.items.len - 1]; | 902 | top = &self.stack.items[self.stack.items.len - 1]; |
| 903 | containing = &self.stack.items[self.stack.items.len - 2]; | ||
| 902 | } | 904 | } |
| 903 | } | 905 | } |
| 904 | return WalkerEntry{ | 906 | return WalkerEntry{ |
| 905 | .dir = top.iter.dir, | 907 | .dir = containing.iter.dir, |
| 906 | .basename = self.name_buffer.items[dirname_len..], | 908 | .basename = self.name_buffer.items[dirname_len..], |
| 907 | .path = self.name_buffer.items, | 909 | .path = self.name_buffer.items, |
| 908 | .kind = base.kind, | 910 | .kind = base.kind, |
lib/std/fs/test.zig+3| ... | @@ -1058,6 +1058,9 @@ test "walker" { | ... | @@ -1058,6 +1058,9 @@ test "walker" { |
| 1058 | std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)}); | 1058 | std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)}); |
| 1059 | return err; | 1059 | return err; |
| 1060 | }; | 1060 | }; |
| 1061 | // make sure that the entry.dir is the containing dir | ||
| 1062 | var entry_dir = try entry.dir.openDir(entry.basename, .{}); | ||
| 1063 | defer entry_dir.close(); | ||
| 1061 | num_walked += 1; | 1064 | num_walked += 1; |
| 1062 | } | 1065 | } |
| 1063 | try testing.expectEqual(expected_paths.kvs.len, num_walked); | 1066 | try testing.expectEqual(expected_paths.kvs.len, num_walked); |
lib/std/hash/auto_hash.zig+19-20| ... | @@ -30,13 +30,15 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy) | ... | @@ -30,13 +30,15 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy) |
| 30 | .DeepRecursive => hash(hasher, key.*, .DeepRecursive), | 30 | .DeepRecursive => hash(hasher, key.*, .DeepRecursive), |
| 31 | }, | 31 | }, |
| 32 | 32 | ||
| 33 | .Slice => switch (strat) { | 33 | .Slice => { |
| 34 | .Shallow => { | 34 | switch (strat) { |
| 35 | hashPointer(hasher, key.ptr, .Shallow); | 35 | .Shallow => { |
| 36 | hash(hasher, key.len, .Shallow); | 36 | hashPointer(hasher, key.ptr, .Shallow); |
| 37 | }, | 37 | }, |
| 38 | .Deep => hashArray(hasher, key, .Shallow), | 38 | .Deep => hashArray(hasher, key, .Shallow), |
| 39 | .DeepRecursive => hashArray(hasher, key, .DeepRecursive), | 39 | .DeepRecursive => hashArray(hasher, key, .DeepRecursive), |
| 40 | } | ||
| 41 | hash(hasher, key.len, .Shallow); | ||
| 40 | }, | 42 | }, |
| 41 | 43 | ||
| 42 | .Many, | 44 | .Many, |
| ... | @@ -53,17 +55,8 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy) | ... | @@ -53,17 +55,8 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy) |
| 53 | 55 | ||
| 54 | /// Helper function to hash a set of contiguous objects, from an array or slice. | 56 | /// Helper function to hash a set of contiguous objects, from an array or slice. |
| 55 | pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | 57 | pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 56 | switch (strat) { | 58 | for (key) |element| { |
| 57 | .Shallow => { | 59 | hash(hasher, element, strat); |
| 58 | for (key) |element| { | ||
| 59 | hash(hasher, element, .Shallow); | ||
| 60 | } | ||
| 61 | }, | ||
| 62 | else => { | ||
| 63 | for (key) |element| { | ||
| 64 | hash(hasher, element, strat); | ||
| 65 | } | ||
| 66 | }, | ||
| 67 | } | 60 | } |
| 68 | } | 61 | } |
| 69 | 62 | ||
| ... | @@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool { | ... | @@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool { |
| 193 | pub fn autoHash(hasher: anytype, key: anytype) void { | 186 | pub fn autoHash(hasher: anytype, key: anytype) void { |
| 194 | const Key = @TypeOf(key); | 187 | const Key = @TypeOf(key); |
| 195 | if (comptime typeContainsSlice(Key)) { | 188 | if (comptime typeContainsSlice(Key)) { |
| 196 | @compileError("std.auto_hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++ | 189 | @compileError("std.hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++ |
| 197 | ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead."); | 190 | ") because the intent is unclear. Consider using std.hash.autoHashStrat or providing your own hash function instead."); |
| 198 | } | 191 | } |
| 199 | 192 | ||
| 200 | hash(hasher, key, .Shallow); | 193 | hash(hasher, key, .Shallow); |
| ... | @@ -359,6 +352,12 @@ test "testHash array" { | ... | @@ -359,6 +352,12 @@ test "testHash array" { |
| 359 | try testing.expectEqual(h, hasher.final()); | 352 | try testing.expectEqual(h, hasher.final()); |
| 360 | } | 353 | } |
| 361 | 354 | ||
| 355 | test "testHash multi-dimensional array" { | ||
| 356 | const a = [_][]const u32{ &.{ 1, 2, 3 }, &.{ 4, 5 } }; | ||
| 357 | const b = [_][]const u32{ &.{ 1, 2 }, &.{ 3, 4, 5 } }; | ||
| 358 | try testing.expect(testHash(a) != testHash(b)); | ||
| 359 | } | ||
| 360 | |||
| 362 | test "testHash struct" { | 361 | test "testHash struct" { |
| 363 | const Foo = struct { | 362 | const Foo = struct { |
| 364 | a: u32 = 1, | 363 | a: u32 = 1, |
lib/std/os.zig+7-4| ... | @@ -475,10 +475,9 @@ pub fn abort() noreturn { | ... | @@ -475,10 +475,9 @@ pub fn abort() noreturn { |
| 475 | 475 | ||
| 476 | // Install default handler so that the tkill below will terminate. | 476 | // Install default handler so that the tkill below will terminate. |
| 477 | const sigact = Sigaction{ | 477 | const sigact = Sigaction{ |
| 478 | .handler = .{ .sigaction = SIG.DFL }, | 478 | .handler = .{ .handler = SIG.DFL }, |
| 479 | .mask = undefined, | 479 | .mask = empty_sigset, |
| 480 | .flags = undefined, | 480 | .flags = 0, |
| 481 | .restorer = undefined, | ||
| 482 | }; | 481 | }; |
| 483 | sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) { | 482 | sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) { |
| 484 | error.OperationNotSupported => unreachable, | 483 | error.OperationNotSupported => unreachable, |
| ... | @@ -953,6 +952,10 @@ pub const WriteError = error{ | ... | @@ -953,6 +952,10 @@ pub const WriteError = error{ |
| 953 | OperationAborted, | 952 | OperationAborted, |
| 954 | NotOpenForWriting, | 953 | NotOpenForWriting, |
| 955 | 954 | ||
| 955 | /// The process cannot access the file because another process has locked | ||
| 956 | /// a portion of the file. Windows-only. | ||
| 957 | LockViolation, | ||
| 958 | |||
| 956 | /// This error occurs when no global event loop is configured, | 959 | /// This error occurs when no global event loop is configured, |
| 957 | /// and reading from the file descriptor would block. | 960 | /// and reading from the file descriptor would block. |
| 958 | WouldBlock, | 961 | WouldBlock, |
lib/std/os/linux.zig+9-9| ... | @@ -1945,9 +1945,9 @@ pub const SIG = if (is_mips) struct { | ... | @@ -1945,9 +1945,9 @@ pub const SIG = if (is_mips) struct { |
| 1945 | pub const SYS = 31; | 1945 | pub const SYS = 31; |
| 1946 | pub const UNUSED = SIG.SYS; | 1946 | pub const UNUSED = SIG.SYS; |
| 1947 | 1947 | ||
| 1948 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 1948 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 1949 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 1949 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 1950 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 1950 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 1951 | } else if (is_sparc) struct { | 1951 | } else if (is_sparc) struct { |
| 1952 | pub const BLOCK = 1; | 1952 | pub const BLOCK = 1; |
| 1953 | pub const UNBLOCK = 2; | 1953 | pub const UNBLOCK = 2; |
| ... | @@ -1989,9 +1989,9 @@ pub const SIG = if (is_mips) struct { | ... | @@ -1989,9 +1989,9 @@ pub const SIG = if (is_mips) struct { |
| 1989 | pub const PWR = LOST; | 1989 | pub const PWR = LOST; |
| 1990 | pub const IO = SIG.POLL; | 1990 | pub const IO = SIG.POLL; |
| 1991 | 1991 | ||
| 1992 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 1992 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 1993 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 1993 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 1994 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 1994 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 1995 | } else struct { | 1995 | } else struct { |
| 1996 | pub const BLOCK = 0; | 1996 | pub const BLOCK = 0; |
| 1997 | pub const UNBLOCK = 1; | 1997 | pub const UNBLOCK = 1; |
| ... | @@ -2032,9 +2032,9 @@ pub const SIG = if (is_mips) struct { | ... | @@ -2032,9 +2032,9 @@ pub const SIG = if (is_mips) struct { |
| 2032 | pub const SYS = 31; | 2032 | pub const SYS = 31; |
| 2033 | pub const UNUSED = SIG.SYS; | 2033 | pub const UNUSED = SIG.SYS; |
| 2034 | 2034 | ||
| 2035 | pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | 2035 | pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize)); |
| 2036 | pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 2036 | pub const DFL = @intToPtr(?Sigaction.handler_fn, 0); |
| 2037 | pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 2037 | pub const IGN = @intToPtr(?Sigaction.handler_fn, 1); |
| 2038 | }; | 2038 | }; |
| 2039 | 2039 | ||
| 2040 | pub const kernel_rwf = u32; | 2040 | pub const kernel_rwf = u32; |
lib/std/os/test.zig+1-1| ... | @@ -785,7 +785,7 @@ test "sigaction" { | ... | @@ -785,7 +785,7 @@ test "sigaction" { |
| 785 | try testing.expect(signal_test_failed == false); | 785 | try testing.expect(signal_test_failed == false); |
| 786 | // Check if the handler has been correctly reset to SIG_DFL | 786 | // Check if the handler has been correctly reset to SIG_DFL |
| 787 | try os.sigaction(os.SIG.USR1, null, &old_sa); | 787 | try os.sigaction(os.SIG.USR1, null, &old_sa); |
| 788 | try testing.expectEqual(os.SIG.DFL, old_sa.handler.sigaction); | 788 | try testing.expectEqual(os.SIG.DFL, old_sa.handler.handler); |
| 789 | } | 789 | } |
| 790 | 790 | ||
| 791 | test "dup & dup2" { | 791 | test "dup & dup2" { |
lib/std/os/windows.zig+4| ... | @@ -517,6 +517,9 @@ pub const WriteFileError = error{ | ... | @@ -517,6 +517,9 @@ pub const WriteFileError = error{ |
| 517 | OperationAborted, | 517 | OperationAborted, |
| 518 | BrokenPipe, | 518 | BrokenPipe, |
| 519 | NotOpenForWriting, | 519 | NotOpenForWriting, |
| 520 | /// The process cannot access the file because another process has locked | ||
| 521 | /// a portion of the file. | ||
| 522 | LockViolation, | ||
| 520 | Unexpected, | 523 | Unexpected, |
| 521 | }; | 524 | }; |
| 522 | 525 | ||
| ... | @@ -597,6 +600,7 @@ pub fn WriteFile( | ... | @@ -597,6 +600,7 @@ pub fn WriteFile( |
| 597 | .IO_PENDING => unreachable, | 600 | .IO_PENDING => unreachable, |
| 598 | .BROKEN_PIPE => return error.BrokenPipe, | 601 | .BROKEN_PIPE => return error.BrokenPipe, |
| 599 | .INVALID_HANDLE => return error.NotOpenForWriting, | 602 | .INVALID_HANDLE => return error.NotOpenForWriting, |
| 603 | .LOCK_VIOLATION => return error.LockViolation, | ||
| 600 | else => |err| return unexpectedError(err), | 604 | else => |err| return unexpectedError(err), |
| 601 | } | 605 | } |
| 602 | } | 606 | } |
lib/std/zig/Ast.zig+1-1| ... | @@ -2967,7 +2967,7 @@ pub const Node = struct { | ... | @@ -2967,7 +2967,7 @@ pub const Node = struct { |
| 2967 | /// Same as ContainerDeclTwo except there is known to be a trailing comma | 2967 | /// Same as ContainerDeclTwo except there is known to be a trailing comma |
| 2968 | /// or semicolon before the rbrace. | 2968 | /// or semicolon before the rbrace. |
| 2969 | container_decl_two_trailing, | 2969 | container_decl_two_trailing, |
| 2970 | /// `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`. | 2970 | /// `struct(lhs)` / `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`. |
| 2971 | container_decl_arg, | 2971 | container_decl_arg, |
| 2972 | /// Same as container_decl_arg but there is known to be a trailing | 2972 | /// Same as container_decl_arg but there is known to be a trailing |
| 2973 | /// comma or semicolon before the rbrace. | 2973 | /// comma or semicolon before the rbrace. |
lib/std/zig/parse.zig+6-4| ... | @@ -3356,16 +3356,18 @@ const Parser = struct { | ... | @@ -3356,16 +3356,18 @@ const Parser = struct { |
| 3356 | } | 3356 | } |
| 3357 | 3357 | ||
| 3358 | /// Caller must have already verified the first token. | 3358 | /// Caller must have already verified the first token. |
| 3359 | /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE | ||
| 3360 | /// | ||
| 3359 | /// ContainerDeclType | 3361 | /// ContainerDeclType |
| 3360 | /// <- KEYWORD_struct | 3362 | /// <- KEYWORD_struct (LPAREN Expr RPAREN)? |
| 3363 | /// / KEYWORD_opaque | ||
| 3361 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? | 3364 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? |
| 3362 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? | 3365 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? |
| 3363 | /// / KEYWORD_opaque | ||
| 3364 | fn parseContainerDeclAuto(p: *Parser) !Node.Index { | 3366 | fn parseContainerDeclAuto(p: *Parser) !Node.Index { |
| 3365 | const main_token = p.nextToken(); | 3367 | const main_token = p.nextToken(); |
| 3366 | const arg_expr = switch (p.token_tags[main_token]) { | 3368 | const arg_expr = switch (p.token_tags[main_token]) { |
| 3367 | .keyword_struct, .keyword_opaque => null_node, | 3369 | .keyword_opaque => null_node, |
| 3368 | .keyword_enum => blk: { | 3370 | .keyword_struct, .keyword_enum => blk: { |
| 3369 | if (p.eatToken(.l_paren)) |_| { | 3371 | if (p.eatToken(.l_paren)) |_| { |
| 3370 | const expr = try p.expectExpr(); | 3372 | const expr = try p.expectExpr(); |
| 3371 | _ = try p.expectToken(.r_paren); | 3373 | _ = try p.expectToken(.r_paren); |
lib/std/zig/parser_test.zig+7| ... | @@ -3064,6 +3064,13 @@ test "zig fmt: struct declaration" { | ... | @@ -3064,6 +3064,13 @@ test "zig fmt: struct declaration" { |
| 3064 | \\ c: u8, | 3064 | \\ c: u8, |
| 3065 | \\}; | 3065 | \\}; |
| 3066 | \\ | 3066 | \\ |
| 3067 | \\const Ps = packed struct(u32) { | ||
| 3068 | \\ a: u1, | ||
| 3069 | \\ b: u2, | ||
| 3070 | \\ | ||
| 3071 | \\ c: u29, | ||
| 3072 | \\}; | ||
| 3073 | \\ | ||
| 3067 | \\const Es = extern struct { | 3074 | \\const Es = extern struct { |
| 3068 | \\ a: u8, | 3075 | \\ a: u8, |
| 3069 | \\ b: u8, | 3076 | \\ b: u8, |
lib/std/zig/tokenizer.zig+18| ... | @@ -797,6 +797,10 @@ pub const Tokenizer = struct { | ... | @@ -797,6 +797,10 @@ pub const Tokenizer = struct { |
| 797 | remaining_code_units = 3; | 797 | remaining_code_units = 3; |
| 798 | state = .char_literal_unicode; | 798 | state = .char_literal_unicode; |
| 799 | }, | 799 | }, |
| 800 | '\n' => { | ||
| 801 | result.tag = .invalid; | ||
| 802 | break; | ||
| 803 | }, | ||
| 800 | else => { | 804 | else => { |
| 801 | state = .char_literal_end; | 805 | state = .char_literal_end; |
| 802 | }, | 806 | }, |
| ... | @@ -1507,6 +1511,20 @@ test "tokenizer - code point literal with hex escape" { | ... | @@ -1507,6 +1511,20 @@ test "tokenizer - code point literal with hex escape" { |
| 1507 | , &.{ .invalid, .invalid }); | 1511 | , &.{ .invalid, .invalid }); |
| 1508 | } | 1512 | } |
| 1509 | 1513 | ||
| 1514 | test "tokenizer - newline in char literal" { | ||
| 1515 | try testTokenize( | ||
| 1516 | \\' | ||
| 1517 | \\' | ||
| 1518 | , &.{ .invalid, .invalid }); | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | test "tokenizer - newline in string literal" { | ||
| 1522 | try testTokenize( | ||
| 1523 | \\" | ||
| 1524 | \\" | ||
| 1525 | , &.{ .invalid, .string_literal }); | ||
| 1526 | } | ||
| 1527 | |||
| 1510 | test "tokenizer - code point literal with unicode escapes" { | 1528 | test "tokenizer - code point literal with unicode escapes" { |
| 1511 | // Valid unicode escapes | 1529 | // Valid unicode escapes |
| 1512 | try testTokenize( | 1530 | try testTokenize( |
src/Air.zig+5| ... | @@ -673,6 +673,10 @@ pub const Inst = struct { | ... | @@ -673,6 +673,10 @@ pub const Inst = struct { |
| 673 | /// Uses the `un_op` field. | 673 | /// Uses the `un_op` field. |
| 674 | error_name, | 674 | error_name, |
| 675 | 675 | ||
| 676 | /// Returns true if error set has error with value. | ||
| 677 | /// Uses the `ty_op` field. | ||
| 678 | error_set_has_value, | ||
| 679 | |||
| 676 | /// Constructs a vector, tuple, struct, or array value out of runtime-known elements. | 680 | /// Constructs a vector, tuple, struct, or array value out of runtime-known elements. |
| 677 | /// Some of the elements may be comptime-known. | 681 | /// Some of the elements may be comptime-known. |
| 678 | /// Uses the `ty_pl` field, payload is index of an array of elements, each of which | 682 | /// Uses the `ty_pl` field, payload is index of an array of elements, each of which |
| ... | @@ -1062,6 +1066,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1062,6 +1066,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1062 | .is_err_ptr, | 1066 | .is_err_ptr, |
| 1063 | .is_non_err_ptr, | 1067 | .is_non_err_ptr, |
| 1064 | .is_named_enum_value, | 1068 | .is_named_enum_value, |
| 1069 | .error_set_has_value, | ||
| 1065 | => return Type.bool, | 1070 | => return Type.bool, |
| 1066 | 1071 | ||
| 1067 | .const_ty => return Type.type, | 1072 | .const_ty => return Type.type, |
src/AstGen.zig+180-28| ... | @@ -152,6 +152,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { | ... | @@ -152,6 +152,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { |
| 152 | 0, | 152 | 0, |
| 153 | tree.containerDeclRoot(), | 153 | tree.containerDeclRoot(), |
| 154 | .Auto, | 154 | .Auto, |
| 155 | 0, | ||
| 155 | )) |struct_decl_ref| { | 156 | )) |struct_decl_ref| { |
| 156 | assert(refToIndex(struct_decl_ref).? == 0); | 157 | assert(refToIndex(struct_decl_ref).? == 0); |
| 157 | } else |err| switch (err) { | 158 | } else |err| switch (err) { |
| ... | @@ -2454,7 +2455,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2454,7 +2455,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2454 | .trunc, | 2455 | .trunc, |
| 2455 | .round, | 2456 | .round, |
| 2456 | .tag_name, | 2457 | .tag_name, |
| 2457 | .reify, | ||
| 2458 | .type_name, | 2458 | .type_name, |
| 2459 | .frame_type, | 2459 | .frame_type, |
| 2460 | .frame_size, | 2460 | .frame_size, |
| ... | @@ -2501,7 +2501,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2501,7 +2501,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2501 | .closure_get, | 2501 | .closure_get, |
| 2502 | .array_base_ptr, | 2502 | .array_base_ptr, |
| 2503 | .field_base_ptr, | 2503 | .field_base_ptr, |
| 2504 | .param_type, | ||
| 2505 | .ret_ptr, | 2504 | .ret_ptr, |
| 2506 | .ret_type, | 2505 | .ret_type, |
| 2507 | .@"try", | 2506 | .@"try", |
| ... | @@ -3071,6 +3070,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void { | ... | @@ -3071,6 +3070,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void { |
| 3071 | const line = astgen.source_line - gz.decl_line; | 3070 | const line = astgen.source_line - gz.decl_line; |
| 3072 | const column = astgen.source_column; | 3071 | const column = astgen.source_column; |
| 3073 | 3072 | ||
| 3073 | if (gz.instructions.items.len > 0) { | ||
| 3074 | const last = gz.instructions.items[gz.instructions.items.len - 1]; | ||
| 3075 | const zir_tags = astgen.instructions.items(.tag); | ||
| 3076 | if (zir_tags[last] == .dbg_stmt) { | ||
| 3077 | const zir_datas = astgen.instructions.items(.data); | ||
| 3078 | zir_datas[last].dbg_stmt = .{ | ||
| 3079 | .line = line, | ||
| 3080 | .column = column, | ||
| 3081 | }; | ||
| 3082 | return; | ||
| 3083 | } | ||
| 3084 | } | ||
| 3085 | |||
| 3074 | _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ | 3086 | _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ |
| 3075 | .dbg_stmt = .{ | 3087 | .dbg_stmt = .{ |
| 3076 | .line = line, | 3088 | .line = line, |
| ... | @@ -4212,15 +4224,18 @@ fn structDeclInner( | ... | @@ -4212,15 +4224,18 @@ fn structDeclInner( |
| 4212 | node: Ast.Node.Index, | 4224 | node: Ast.Node.Index, |
| 4213 | container_decl: Ast.full.ContainerDecl, | 4225 | container_decl: Ast.full.ContainerDecl, |
| 4214 | layout: std.builtin.Type.ContainerLayout, | 4226 | layout: std.builtin.Type.ContainerLayout, |
| 4227 | backing_int_node: Ast.Node.Index, | ||
| 4215 | ) InnerError!Zir.Inst.Ref { | 4228 | ) InnerError!Zir.Inst.Ref { |
| 4216 | const decl_inst = try gz.reserveInstructionIndex(); | 4229 | const decl_inst = try gz.reserveInstructionIndex(); |
| 4217 | 4230 | ||
| 4218 | if (container_decl.ast.members.len == 0) { | 4231 | if (container_decl.ast.members.len == 0 and backing_int_node == 0) { |
| 4219 | try gz.setStruct(decl_inst, .{ | 4232 | try gz.setStruct(decl_inst, .{ |
| 4220 | .src_node = node, | 4233 | .src_node = node, |
| 4221 | .layout = layout, | 4234 | .layout = layout, |
| 4222 | .fields_len = 0, | 4235 | .fields_len = 0, |
| 4223 | .decls_len = 0, | 4236 | .decls_len = 0, |
| 4237 | .backing_int_ref = .none, | ||
| 4238 | .backing_int_body_len = 0, | ||
| 4224 | .known_non_opv = false, | 4239 | .known_non_opv = false, |
| 4225 | .known_comptime_only = false, | 4240 | .known_comptime_only = false, |
| 4226 | }); | 4241 | }); |
| ... | @@ -4255,6 +4270,35 @@ fn structDeclInner( | ... | @@ -4255,6 +4270,35 @@ fn structDeclInner( |
| 4255 | }; | 4270 | }; |
| 4256 | defer block_scope.unstack(); | 4271 | defer block_scope.unstack(); |
| 4257 | 4272 | ||
| 4273 | const scratch_top = astgen.scratch.items.len; | ||
| 4274 | defer astgen.scratch.items.len = scratch_top; | ||
| 4275 | |||
| 4276 | var backing_int_body_len: usize = 0; | ||
| 4277 | const backing_int_ref: Zir.Inst.Ref = blk: { | ||
| 4278 | if (backing_int_node != 0) { | ||
| 4279 | if (layout != .Packed) { | ||
| 4280 | return astgen.failNode(backing_int_node, "non-packed struct does not support backing integer type", .{}); | ||
| 4281 | } else { | ||
| 4282 | const backing_int_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node); | ||
| 4283 | if (!block_scope.isEmpty()) { | ||
| 4284 | if (!block_scope.endsWithNoReturn()) { | ||
| 4285 | _ = try block_scope.addBreak(.break_inline, decl_inst, backing_int_ref); | ||
| 4286 | } | ||
| 4287 | |||
| 4288 | const body = block_scope.instructionsSlice(); | ||
| 4289 | const old_scratch_len = astgen.scratch.items.len; | ||
| 4290 | try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); | ||
| 4291 | appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); | ||
| 4292 | backing_int_body_len = astgen.scratch.items.len - old_scratch_len; | ||
| 4293 | block_scope.instructions.items.len = block_scope.instructions_top; | ||
| 4294 | } | ||
| 4295 | break :blk backing_int_ref; | ||
| 4296 | } | ||
| 4297 | } else { | ||
| 4298 | break :blk .none; | ||
| 4299 | } | ||
| 4300 | }; | ||
| 4301 | |||
| 4258 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); | 4302 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 4259 | const field_count = @intCast(u32, container_decl.ast.members.len - decl_count); | 4303 | const field_count = @intCast(u32, container_decl.ast.members.len - decl_count); |
| 4260 | 4304 | ||
| ... | @@ -4279,7 +4323,7 @@ fn structDeclInner( | ... | @@ -4279,7 +4323,7 @@ fn structDeclInner( |
| 4279 | var known_non_opv = false; | 4323 | var known_non_opv = false; |
| 4280 | var known_comptime_only = false; | 4324 | var known_comptime_only = false; |
| 4281 | for (container_decl.ast.members) |member_node| { | 4325 | for (container_decl.ast.members) |member_node| { |
| 4282 | const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { | 4326 | const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 4283 | .decl => continue, | 4327 | .decl => continue, |
| 4284 | .field => |field| field, | 4328 | .field => |field| field, |
| 4285 | }; | 4329 | }; |
| ... | @@ -4367,6 +4411,8 @@ fn structDeclInner( | ... | @@ -4367,6 +4411,8 @@ fn structDeclInner( |
| 4367 | .layout = layout, | 4411 | .layout = layout, |
| 4368 | .fields_len = field_count, | 4412 | .fields_len = field_count, |
| 4369 | .decls_len = decl_count, | 4413 | .decls_len = decl_count, |
| 4414 | .backing_int_ref = backing_int_ref, | ||
| 4415 | .backing_int_body_len = @intCast(u32, backing_int_body_len), | ||
| 4370 | .known_non_opv = known_non_opv, | 4416 | .known_non_opv = known_non_opv, |
| 4371 | .known_comptime_only = known_comptime_only, | 4417 | .known_comptime_only = known_comptime_only, |
| 4372 | }); | 4418 | }); |
| ... | @@ -4375,7 +4421,9 @@ fn structDeclInner( | ... | @@ -4375,7 +4421,9 @@ fn structDeclInner( |
| 4375 | const decls_slice = wip_members.declsSlice(); | 4421 | const decls_slice = wip_members.declsSlice(); |
| 4376 | const fields_slice = wip_members.fieldsSlice(); | 4422 | const fields_slice = wip_members.fieldsSlice(); |
| 4377 | const bodies_slice = astgen.scratch.items[bodies_start..]; | 4423 | const bodies_slice = astgen.scratch.items[bodies_start..]; |
| 4378 | try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + fields_slice.len + bodies_slice.len); | 4424 | try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + |
| 4425 | decls_slice.len + fields_slice.len + bodies_slice.len); | ||
| 4426 | astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]); | ||
| 4379 | astgen.extra.appendSliceAssumeCapacity(decls_slice); | 4427 | astgen.extra.appendSliceAssumeCapacity(decls_slice); |
| 4380 | astgen.extra.appendSliceAssumeCapacity(fields_slice); | 4428 | astgen.extra.appendSliceAssumeCapacity(fields_slice); |
| 4381 | astgen.extra.appendSliceAssumeCapacity(bodies_slice); | 4429 | astgen.extra.appendSliceAssumeCapacity(bodies_slice); |
| ... | @@ -4446,7 +4494,7 @@ fn unionDeclInner( | ... | @@ -4446,7 +4494,7 @@ fn unionDeclInner( |
| 4446 | defer wip_members.deinit(); | 4494 | defer wip_members.deinit(); |
| 4447 | 4495 | ||
| 4448 | for (members) |member_node| { | 4496 | for (members) |member_node| { |
| 4449 | const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { | 4497 | const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 4450 | .decl => continue, | 4498 | .decl => continue, |
| 4451 | .field => |field| field, | 4499 | .field => |field| field, |
| 4452 | }; | 4500 | }; |
| ... | @@ -4571,9 +4619,7 @@ fn containerDecl( | ... | @@ -4571,9 +4619,7 @@ fn containerDecl( |
| 4571 | else => unreachable, | 4619 | else => unreachable, |
| 4572 | } else std.builtin.Type.ContainerLayout.Auto; | 4620 | } else std.builtin.Type.ContainerLayout.Auto; |
| 4573 | 4621 | ||
| 4574 | assert(container_decl.ast.arg == 0); | 4622 | const result = try structDeclInner(gz, scope, node, container_decl, layout, container_decl.ast.arg); |
| 4575 | |||
| 4576 | const result = try structDeclInner(gz, scope, node, container_decl, layout); | ||
| 4577 | return rvalue(gz, rl, result, node); | 4623 | return rvalue(gz, rl, result, node); |
| 4578 | }, | 4624 | }, |
| 4579 | .keyword_union => { | 4625 | .keyword_union => { |
| ... | @@ -4733,7 +4779,7 @@ fn containerDecl( | ... | @@ -4733,7 +4779,7 @@ fn containerDecl( |
| 4733 | for (container_decl.ast.members) |member_node| { | 4779 | for (container_decl.ast.members) |member_node| { |
| 4734 | if (member_node == counts.nonexhaustive_node) | 4780 | if (member_node == counts.nonexhaustive_node) |
| 4735 | continue; | 4781 | continue; |
| 4736 | const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { | 4782 | const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 4737 | .decl => continue, | 4783 | .decl => continue, |
| 4738 | .field => |field| field, | 4784 | .field => |field| field, |
| 4739 | }; | 4785 | }; |
| ... | @@ -4811,13 +4857,26 @@ fn containerDecl( | ... | @@ -4811,13 +4857,26 @@ fn containerDecl( |
| 4811 | }; | 4857 | }; |
| 4812 | defer namespace.deinit(gpa); | 4858 | defer namespace.deinit(gpa); |
| 4813 | 4859 | ||
| 4860 | astgen.advanceSourceCursorToNode(node); | ||
| 4861 | var block_scope: GenZir = .{ | ||
| 4862 | .parent = &namespace.base, | ||
| 4863 | .decl_node_index = node, | ||
| 4864 | .decl_line = astgen.source_line, | ||
| 4865 | .astgen = astgen, | ||
| 4866 | .force_comptime = true, | ||
| 4867 | .in_defer = false, | ||
| 4868 | .instructions = gz.instructions, | ||
| 4869 | .instructions_top = gz.instructions.items.len, | ||
| 4870 | }; | ||
| 4871 | defer block_scope.unstack(); | ||
| 4872 | |||
| 4814 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); | 4873 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 4815 | 4874 | ||
| 4816 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); | 4875 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); |
| 4817 | defer wip_members.deinit(); | 4876 | defer wip_members.deinit(); |
| 4818 | 4877 | ||
| 4819 | for (container_decl.ast.members) |member_node| { | 4878 | for (container_decl.ast.members) |member_node| { |
| 4820 | const res = try containerMember(gz, &namespace.base, &wip_members, member_node); | 4879 | const res = try containerMember(&block_scope, &namespace.base, &wip_members, member_node); |
| 4821 | if (res == .field) { | 4880 | if (res == .field) { |
| 4822 | return astgen.failNode(member_node, "opaque types cannot have fields", .{}); | 4881 | return astgen.failNode(member_node, "opaque types cannot have fields", .{}); |
| 4823 | } | 4882 | } |
| ... | @@ -5038,6 +5097,16 @@ fn tryExpr( | ... | @@ -5038,6 +5097,16 @@ fn tryExpr( |
| 5038 | 5097 | ||
| 5039 | if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{}); | 5098 | if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{}); |
| 5040 | 5099 | ||
| 5100 | // Ensure debug line/column information is emitted for this try expression. | ||
| 5101 | // Then we will save the line/column so that we can emit another one that goes | ||
| 5102 | // "backwards" because we want to evaluate the operand, but then put the debug | ||
| 5103 | // info back at the try keyword for error return tracing. | ||
| 5104 | if (!parent_gz.force_comptime) { | ||
| 5105 | try emitDbgNode(parent_gz, node); | ||
| 5106 | } | ||
| 5107 | const try_line = astgen.source_line - parent_gz.decl_line; | ||
| 5108 | const try_column = astgen.source_column; | ||
| 5109 | |||
| 5041 | const operand_rl: ResultLoc = switch (rl) { | 5110 | const operand_rl: ResultLoc = switch (rl) { |
| 5042 | .ref => .ref, | 5111 | .ref => .ref, |
| 5043 | else => .none, | 5112 | else => .none, |
| ... | @@ -5067,6 +5136,7 @@ fn tryExpr( | ... | @@ -5067,6 +5136,7 @@ fn tryExpr( |
| 5067 | }; | 5136 | }; |
| 5068 | const err_code = try else_scope.addUnNode(err_tag, operand, node); | 5137 | const err_code = try else_scope.addUnNode(err_tag, operand, node); |
| 5069 | try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); | 5138 | try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); |
| 5139 | try emitDbgStmt(&else_scope, try_line, try_column); | ||
| 5070 | _ = try else_scope.addUnNode(.ret_node, err_code, node); | 5140 | _ = try else_scope.addUnNode(.ret_node, err_code, node); |
| 5071 | 5141 | ||
| 5072 | try else_scope.setTryBody(try_inst, operand); | 5142 | try else_scope.setTryBody(try_inst, operand); |
| ... | @@ -6573,6 +6643,16 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6573,6 +6643,16 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6573 | 6643 | ||
| 6574 | if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{}); | 6644 | if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{}); |
| 6575 | 6645 | ||
| 6646 | // Ensure debug line/column information is emitted for this return expression. | ||
| 6647 | // Then we will save the line/column so that we can emit another one that goes | ||
| 6648 | // "backwards" because we want to evaluate the operand, but then put the debug | ||
| 6649 | // info back at the return keyword for error return tracing. | ||
| 6650 | if (!gz.force_comptime) { | ||
| 6651 | try emitDbgNode(gz, node); | ||
| 6652 | } | ||
| 6653 | const ret_line = astgen.source_line - gz.decl_line; | ||
| 6654 | const ret_column = astgen.source_column; | ||
| 6655 | |||
| 6576 | const defer_outer = &astgen.fn_block.?.base; | 6656 | const defer_outer = &astgen.fn_block.?.base; |
| 6577 | 6657 | ||
| 6578 | const operand_node = node_datas[node].lhs; | 6658 | const operand_node = node_datas[node].lhs; |
| ... | @@ -6591,11 +6671,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6591,11 +6671,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6591 | const defer_counts = countDefers(astgen, defer_outer, scope); | 6671 | const defer_counts = countDefers(astgen, defer_outer, scope); |
| 6592 | if (!defer_counts.need_err_code) { | 6672 | if (!defer_counts.need_err_code) { |
| 6593 | try genDefers(gz, defer_outer, scope, .both_sans_err); | 6673 | try genDefers(gz, defer_outer, scope, .both_sans_err); |
| 6674 | try emitDbgStmt(gz, ret_line, ret_column); | ||
| 6594 | _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token); | 6675 | _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token); |
| 6595 | return Zir.Inst.Ref.unreachable_value; | 6676 | return Zir.Inst.Ref.unreachable_value; |
| 6596 | } | 6677 | } |
| 6597 | const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token); | 6678 | const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token); |
| 6598 | try genDefers(gz, defer_outer, scope, .{ .both = err_code }); | 6679 | try genDefers(gz, defer_outer, scope, .{ .both = err_code }); |
| 6680 | try emitDbgStmt(gz, ret_line, ret_column); | ||
| 6599 | _ = try gz.addUnNode(.ret_node, err_code, node); | 6681 | _ = try gz.addUnNode(.ret_node, err_code, node); |
| 6600 | return Zir.Inst.Ref.unreachable_value; | 6682 | return Zir.Inst.Ref.unreachable_value; |
| 6601 | } | 6683 | } |
| ... | @@ -6614,6 +6696,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6614,6 +6696,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6614 | .never => { | 6696 | .never => { |
| 6615 | // Returning a value that cannot be an error; skip error defers. | 6697 | // Returning a value that cannot be an error; skip error defers. |
| 6616 | try genDefers(gz, defer_outer, scope, .normal_only); | 6698 | try genDefers(gz, defer_outer, scope, .normal_only); |
| 6699 | try emitDbgStmt(gz, ret_line, ret_column); | ||
| 6617 | try gz.addRet(rl, operand, node); | 6700 | try gz.addRet(rl, operand, node); |
| 6618 | return Zir.Inst.Ref.unreachable_value; | 6701 | return Zir.Inst.Ref.unreachable_value; |
| 6619 | }, | 6702 | }, |
| ... | @@ -6621,6 +6704,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6621,6 +6704,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6621 | // Value is always an error. Emit both error defers and regular defers. | 6704 | // Value is always an error. Emit both error defers and regular defers. |
| 6622 | const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; | 6705 | const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; |
| 6623 | try genDefers(gz, defer_outer, scope, .{ .both = err_code }); | 6706 | try genDefers(gz, defer_outer, scope, .{ .both = err_code }); |
| 6707 | try emitDbgStmt(gz, ret_line, ret_column); | ||
| 6624 | try gz.addRet(rl, operand, node); | 6708 | try gz.addRet(rl, operand, node); |
| 6625 | return Zir.Inst.Ref.unreachable_value; | 6709 | return Zir.Inst.Ref.unreachable_value; |
| 6626 | }, | 6710 | }, |
| ... | @@ -6629,6 +6713,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6629,6 +6713,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6629 | if (!defer_counts.have_err) { | 6713 | if (!defer_counts.have_err) { |
| 6630 | // Only regular defers; no branch needed. | 6714 | // Only regular defers; no branch needed. |
| 6631 | try genDefers(gz, defer_outer, scope, .normal_only); | 6715 | try genDefers(gz, defer_outer, scope, .normal_only); |
| 6716 | try emitDbgStmt(gz, ret_line, ret_column); | ||
| 6632 | try gz.addRet(rl, operand, node); | 6717 | try gz.addRet(rl, operand, node); |
| 6633 | return Zir.Inst.Ref.unreachable_value; | 6718 | return Zir.Inst.Ref.unreachable_value; |
| 6634 | } | 6719 | } |
| ... | @@ -6642,6 +6727,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6642,6 +6727,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6642 | defer then_scope.unstack(); | 6727 | defer then_scope.unstack(); |
| 6643 | 6728 | ||
| 6644 | try genDefers(&then_scope, defer_outer, scope, .normal_only); | 6729 | try genDefers(&then_scope, defer_outer, scope, .normal_only); |
| 6730 | try emitDbgStmt(&then_scope, ret_line, ret_column); | ||
| 6645 | try then_scope.addRet(rl, operand, node); | 6731 | try then_scope.addRet(rl, operand, node); |
| 6646 | 6732 | ||
| 6647 | var else_scope = gz.makeSubBlock(scope); | 6733 | var else_scope = gz.makeSubBlock(scope); |
| ... | @@ -6651,6 +6737,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6651,6 +6737,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6651 | .both = try else_scope.addUnNode(.err_union_code, result, node), | 6737 | .both = try else_scope.addUnNode(.err_union_code, result, node), |
| 6652 | }; | 6738 | }; |
| 6653 | try genDefers(&else_scope, defer_outer, scope, which_ones); | 6739 | try genDefers(&else_scope, defer_outer, scope, which_ones); |
| 6740 | try emitDbgStmt(&else_scope, ret_line, ret_column); | ||
| 6654 | try else_scope.addRet(rl, operand, node); | 6741 | try else_scope.addRet(rl, operand, node); |
| 6655 | 6742 | ||
| 6656 | try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); | 6743 | try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); |
| ... | @@ -7553,7 +7640,6 @@ fn builtinCall( | ... | @@ -7553,7 +7640,6 @@ fn builtinCall( |
| 7553 | .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc), | 7640 | .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc), |
| 7554 | .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round), | 7641 | .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round), |
| 7555 | .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name), | 7642 | .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name), |
| 7556 | .Type => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .type_info_type }, params[0], .reify), | ||
| 7557 | .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name), | 7643 | .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name), |
| 7558 | .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type), | 7644 | .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type), |
| 7559 | .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size), | 7645 | .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size), |
| ... | @@ -7568,6 +7654,31 @@ fn builtinCall( | ... | @@ -7568,6 +7654,31 @@ fn builtinCall( |
| 7568 | .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), | 7654 | .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), |
| 7569 | // zig fmt: on | 7655 | // zig fmt: on |
| 7570 | 7656 | ||
| 7657 | .Type => { | ||
| 7658 | const operand = try expr(gz, scope, .{ .coerced_ty = .type_info_type }, params[0]); | ||
| 7659 | |||
| 7660 | const gpa = gz.astgen.gpa; | ||
| 7661 | |||
| 7662 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 7663 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | ||
| 7664 | |||
| 7665 | const payload_index = try gz.astgen.addExtra(Zir.Inst.UnNode{ | ||
| 7666 | .node = gz.nodeIndexToRelative(node), | ||
| 7667 | .operand = operand, | ||
| 7668 | }); | ||
| 7669 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | ||
| 7670 | gz.astgen.instructions.appendAssumeCapacity(.{ | ||
| 7671 | .tag = .extended, | ||
| 7672 | .data = .{ .extended = .{ | ||
| 7673 | .opcode = .reify, | ||
| 7674 | .small = @enumToInt(gz.anon_name_strategy), | ||
| 7675 | .operand = payload_index, | ||
| 7676 | } }, | ||
| 7677 | }); | ||
| 7678 | gz.instructions.appendAssumeCapacity(new_index); | ||
| 7679 | const result = indexToRef(new_index); | ||
| 7680 | return rvalue(gz, rl, result, node); | ||
| 7681 | }, | ||
| 7571 | .panic => { | 7682 | .panic => { |
| 7572 | try emitDbgNode(gz, node); | 7683 | try emitDbgNode(gz, node); |
| 7573 | return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], if (gz.force_comptime) .panic_comptime else .panic); | 7684 | return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], if (gz.force_comptime) .panic_comptime else .panic); |
| ... | @@ -8152,6 +8263,33 @@ fn callExpr( | ... | @@ -8152,6 +8263,33 @@ fn callExpr( |
| 8152 | assert(callee != .none); | 8263 | assert(callee != .none); |
| 8153 | assert(node != 0); | 8264 | assert(node != 0); |
| 8154 | 8265 | ||
| 8266 | const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | ||
| 8267 | const call_inst = Zir.indexToRef(call_index); | ||
| 8268 | try gz.astgen.instructions.append(astgen.gpa, undefined); | ||
| 8269 | try gz.instructions.append(astgen.gpa, call_index); | ||
| 8270 | |||
| 8271 | const scratch_top = astgen.scratch.items.len; | ||
| 8272 | defer astgen.scratch.items.len = scratch_top; | ||
| 8273 | |||
| 8274 | var scratch_index = scratch_top; | ||
| 8275 | try astgen.scratch.resize(astgen.gpa, scratch_top + call.ast.params.len); | ||
| 8276 | |||
| 8277 | for (call.ast.params) |param_node| { | ||
| 8278 | var arg_block = gz.makeSubBlock(scope); | ||
| 8279 | defer arg_block.unstack(); | ||
| 8280 | |||
| 8281 | // `call_inst` is reused to provide the param type. | ||
| 8282 | const arg_ref = try expr(&arg_block, &arg_block.base, .{ .coerced_ty = call_inst }, param_node); | ||
| 8283 | _ = try arg_block.addBreak(.break_inline, call_index, arg_ref); | ||
| 8284 | |||
| 8285 | const body = arg_block.instructionsSlice(); | ||
| 8286 | try astgen.scratch.ensureUnusedCapacity(astgen.gpa, countBodyLenAfterFixups(astgen, body)); | ||
| 8287 | appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); | ||
| 8288 | |||
| 8289 | astgen.scratch.items[scratch_index] = @intCast(u32, astgen.scratch.items.len - scratch_top); | ||
| 8290 | scratch_index += 1; | ||
| 8291 | } | ||
| 8292 | |||
| 8155 | const payload_index = try addExtra(astgen, Zir.Inst.Call{ | 8293 | const payload_index = try addExtra(astgen, Zir.Inst.Call{ |
| 8156 | .callee = callee, | 8294 | .callee = callee, |
| 8157 | .flags = .{ | 8295 | .flags = .{ |
| ... | @@ -8159,22 +8297,16 @@ fn callExpr( | ... | @@ -8159,22 +8297,16 @@ fn callExpr( |
| 8159 | .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), | 8297 | .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), |
| 8160 | }, | 8298 | }, |
| 8161 | }); | 8299 | }); |
| 8162 | var extra_index = try reserveExtra(astgen, call.ast.params.len); | 8300 | if (call.ast.params.len != 0) { |
| 8163 | 8301 | try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]); | |
| 8164 | for (call.ast.params) |param_node, i| { | ||
| 8165 | const param_type = try gz.add(.{ | ||
| 8166 | .tag = .param_type, | ||
| 8167 | .data = .{ .param_type = .{ | ||
| 8168 | .callee = callee, | ||
| 8169 | .param_index = @intCast(u32, i), | ||
| 8170 | } }, | ||
| 8171 | }); | ||
| 8172 | const arg_ref = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node); | ||
| 8173 | astgen.extra.items[extra_index] = @enumToInt(arg_ref); | ||
| 8174 | extra_index += 1; | ||
| 8175 | } | 8302 | } |
| 8176 | 8303 | gz.astgen.instructions.set(call_index, .{ | |
| 8177 | const call_inst = try gz.addPlNodePayloadIndex(.call, node, payload_index); | 8304 | .tag = .call, |
| 8305 | .data = .{ .pl_node = .{ | ||
| 8306 | .src_node = gz.nodeIndexToRelative(node), | ||
| 8307 | .payload_index = payload_index, | ||
| 8308 | } }, | ||
| 8309 | }); | ||
| 8178 | return rvalue(gz, rl, call_inst, node); // TODO function call with result location | 8310 | return rvalue(gz, rl, call_inst, node); // TODO function call with result location |
| 8179 | } | 8311 | } |
| 8180 | 8312 | ||
| ... | @@ -11158,6 +11290,8 @@ const GenZir = struct { | ... | @@ -11158,6 +11290,8 @@ const GenZir = struct { |
| 11158 | src_node: Ast.Node.Index, | 11290 | src_node: Ast.Node.Index, |
| 11159 | fields_len: u32, | 11291 | fields_len: u32, |
| 11160 | decls_len: u32, | 11292 | decls_len: u32, |
| 11293 | backing_int_ref: Zir.Inst.Ref, | ||
| 11294 | backing_int_body_len: u32, | ||
| 11161 | layout: std.builtin.Type.ContainerLayout, | 11295 | layout: std.builtin.Type.ContainerLayout, |
| 11162 | known_non_opv: bool, | 11296 | known_non_opv: bool, |
| 11163 | known_comptime_only: bool, | 11297 | known_comptime_only: bool, |
| ... | @@ -11165,7 +11299,7 @@ const GenZir = struct { | ... | @@ -11165,7 +11299,7 @@ const GenZir = struct { |
| 11165 | const astgen = gz.astgen; | 11299 | const astgen = gz.astgen; |
| 11166 | const gpa = astgen.gpa; | 11300 | const gpa = astgen.gpa; |
| 11167 | 11301 | ||
| 11168 | try astgen.extra.ensureUnusedCapacity(gpa, 4); | 11302 | try astgen.extra.ensureUnusedCapacity(gpa, 6); |
| 11169 | const payload_index = @intCast(u32, astgen.extra.items.len); | 11303 | const payload_index = @intCast(u32, astgen.extra.items.len); |
| 11170 | 11304 | ||
| 11171 | if (args.src_node != 0) { | 11305 | if (args.src_node != 0) { |
| ... | @@ -11178,6 +11312,12 @@ const GenZir = struct { | ... | @@ -11178,6 +11312,12 @@ const GenZir = struct { |
| 11178 | if (args.decls_len != 0) { | 11312 | if (args.decls_len != 0) { |
| 11179 | astgen.extra.appendAssumeCapacity(args.decls_len); | 11313 | astgen.extra.appendAssumeCapacity(args.decls_len); |
| 11180 | } | 11314 | } |
| 11315 | if (args.backing_int_ref != .none) { | ||
| 11316 | astgen.extra.appendAssumeCapacity(args.backing_int_body_len); | ||
| 11317 | if (args.backing_int_body_len == 0) { | ||
| 11318 | astgen.extra.appendAssumeCapacity(@enumToInt(args.backing_int_ref)); | ||
| 11319 | } | ||
| 11320 | } | ||
| 11181 | astgen.instructions.set(inst, .{ | 11321 | astgen.instructions.set(inst, .{ |
| 11182 | .tag = .extended, | 11322 | .tag = .extended, |
| 11183 | .data = .{ .extended = .{ | 11323 | .data = .{ .extended = .{ |
| ... | @@ -11186,6 +11326,7 @@ const GenZir = struct { | ... | @@ -11186,6 +11326,7 @@ const GenZir = struct { |
| 11186 | .has_src_node = args.src_node != 0, | 11326 | .has_src_node = args.src_node != 0, |
| 11187 | .has_fields_len = args.fields_len != 0, | 11327 | .has_fields_len = args.fields_len != 0, |
| 11188 | .has_decls_len = args.decls_len != 0, | 11328 | .has_decls_len = args.decls_len != 0, |
| 11329 | .has_backing_int = args.backing_int_ref != .none, | ||
| 11189 | .known_non_opv = args.known_non_opv, | 11330 | .known_non_opv = args.known_non_opv, |
| 11190 | .known_comptime_only = args.known_comptime_only, | 11331 | .known_comptime_only = args.known_comptime_only, |
| 11191 | .name_strategy = gz.anon_name_strategy, | 11332 | .name_strategy = gz.anon_name_strategy, |
| ... | @@ -11667,3 +11808,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 { | ... | @@ -11667,3 +11808,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 { |
| 11667 | } | 11808 | } |
| 11668 | return @intCast(u32, count); | 11809 | return @intCast(u32, count); |
| 11669 | } | 11810 | } |
| 11811 | |||
| 11812 | fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void { | ||
| 11813 | if (gz.force_comptime) return; | ||
| 11814 | |||
| 11815 | _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ | ||
| 11816 | .dbg_stmt = .{ | ||
| 11817 | .line = line, | ||
| 11818 | .column = column, | ||
| 11819 | }, | ||
| 11820 | } }); | ||
| 11821 | } |
src/Autodoc.zig+20-4| ... | @@ -1220,7 +1220,6 @@ fn walkInstruction( | ... | @@ -1220,7 +1220,6 @@ fn walkInstruction( |
| 1220 | .trunc, | 1220 | .trunc, |
| 1221 | .round, | 1221 | .round, |
| 1222 | .tag_name, | 1222 | .tag_name, |
| 1223 | .reify, | ||
| 1224 | .type_name, | 1223 | .type_name, |
| 1225 | .frame_type, | 1224 | .frame_type, |
| 1226 | .frame_size, | 1225 | .frame_size, |
| ... | @@ -2079,14 +2078,19 @@ fn walkInstruction( | ... | @@ -2079,14 +2078,19 @@ fn walkInstruction( |
| 2079 | 2078 | ||
| 2080 | const args_len = extra.data.flags.args_len; | 2079 | const args_len = extra.data.flags.args_len; |
| 2081 | var args = try self.arena.alloc(DocData.Expr, args_len); | 2080 | var args = try self.arena.alloc(DocData.Expr, args_len); |
| 2082 | const arg_refs = file.zir.refSlice(extra.end, args_len); | 2081 | const body = file.zir.extra[extra.end..]; |
| 2083 | for (arg_refs) |ref, idx| { | 2082 | |
| 2083 | var i: usize = 0; | ||
| 2084 | while (i < args_len) : (i += 1) { | ||
| 2085 | const arg_end = file.zir.extra[extra.end + i]; | ||
| 2086 | const break_index = body[arg_end - 1]; | ||
| 2087 | const ref = data[break_index].@"break".operand; | ||
| 2084 | // TODO: consider toggling need_type to true if we ever want | 2088 | // TODO: consider toggling need_type to true if we ever want |
| 2085 | // to show discrepancies between the types of provided | 2089 | // to show discrepancies between the types of provided |
| 2086 | // arguments and the types declared in the function | 2090 | // arguments and the types declared in the function |
| 2087 | // signature for its parameters. | 2091 | // signature for its parameters. |
| 2088 | const wr = try self.walkRef(file, parent_scope, ref, false); | 2092 | const wr = try self.walkRef(file, parent_scope, ref, false); |
| 2089 | args[idx] = wr.expr; | 2093 | args[i] = wr.expr; |
| 2090 | } | 2094 | } |
| 2091 | 2095 | ||
| 2092 | const cte_slot_index = self.comptime_exprs.items.len; | 2096 | const cte_slot_index = self.comptime_exprs.items.len; |
| ... | @@ -2532,6 +2536,17 @@ fn walkInstruction( | ... | @@ -2532,6 +2536,17 @@ fn walkInstruction( |
| 2532 | break :blk decls_len; | 2536 | break :blk decls_len; |
| 2533 | } else 0; | 2537 | } else 0; |
| 2534 | 2538 | ||
| 2539 | // TODO: Expose explicit backing integer types in some way. | ||
| 2540 | if (small.has_backing_int) { | ||
| 2541 | const backing_int_body_len = file.zir.extra[extra_index]; | ||
| 2542 | extra_index += 1; // backing_int_body_len | ||
| 2543 | if (backing_int_body_len == 0) { | ||
| 2544 | extra_index += 1; // backing_int_ref | ||
| 2545 | } else { | ||
| 2546 | extra_index += backing_int_body_len; // backing_int_body_inst | ||
| 2547 | } | ||
| 2548 | } | ||
| 2549 | |||
| 2535 | var decl_indexes: std.ArrayListUnmanaged(usize) = .{}; | 2550 | var decl_indexes: std.ArrayListUnmanaged(usize) = .{}; |
| 2536 | var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{}; | 2551 | var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{}; |
| 2537 | 2552 | ||
| ... | @@ -2605,6 +2620,7 @@ fn walkInstruction( | ... | @@ -2605,6 +2620,7 @@ fn walkInstruction( |
| 2605 | }, | 2620 | }, |
| 2606 | .error_to_int, | 2621 | .error_to_int, |
| 2607 | .int_to_error, | 2622 | .int_to_error, |
| 2623 | .reify, | ||
| 2608 | => { | 2624 | => { |
| 2609 | const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data; | 2625 | const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 2610 | const bin_index = self.exprs.items.len; | 2626 | const bin_index = self.exprs.items.len; |
src/Compilation.zig+4| ... | @@ -1041,6 +1041,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1041,6 +1041,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1041 | } | 1041 | } |
| 1042 | } | 1042 | } |
| 1043 | 1043 | ||
| 1044 | // If LLVM does not support the target, then we can't use it. | ||
| 1045 | if (!target_util.hasLlvmSupport(options.target, ofmt)) | ||
| 1046 | break :blk false; | ||
| 1047 | |||
| 1044 | break :blk build_options.is_stage1; | 1048 | break :blk build_options.is_stage1; |
| 1045 | }; | 1049 | }; |
| 1046 | 1050 |
src/Liveness.zig+2| ... | @@ -267,6 +267,7 @@ pub fn categorizeOperand( | ... | @@ -267,6 +267,7 @@ pub fn categorizeOperand( |
| 267 | .byte_swap, | 267 | .byte_swap, |
| 268 | .bit_reverse, | 268 | .bit_reverse, |
| 269 | .splat, | 269 | .splat, |
| 270 | .error_set_has_value, | ||
| 270 | => { | 271 | => { |
| 271 | const o = air_datas[inst].ty_op; | 272 | const o = air_datas[inst].ty_op; |
| 272 | if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); | 273 | if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); |
| ... | @@ -842,6 +843,7 @@ fn analyzeInst( | ... | @@ -842,6 +843,7 @@ fn analyzeInst( |
| 842 | .byte_swap, | 843 | .byte_swap, |
| 843 | .bit_reverse, | 844 | .bit_reverse, |
| 844 | .splat, | 845 | .splat, |
| 846 | .error_set_has_value, | ||
| 845 | => { | 847 | => { |
| 846 | const o = inst_datas[inst].ty_op; | 848 | const o = inst_datas[inst].ty_op; |
| 847 | return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none }); | 849 | return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none }); |
src/Module.zig+24-40| ... | @@ -84,7 +84,6 @@ string_literal_bytes: std.ArrayListUnmanaged(u8) = .{}, | ... | @@ -84,7 +84,6 @@ string_literal_bytes: std.ArrayListUnmanaged(u8) = .{}, |
| 84 | /// The set of all the generic function instantiations. This is used so that when a generic | 84 | /// The set of all the generic function instantiations. This is used so that when a generic |
| 85 | /// function is called twice with the same comptime parameter arguments, both calls dispatch | 85 | /// function is called twice with the same comptime parameter arguments, both calls dispatch |
| 86 | /// to the same function. | 86 | /// to the same function. |
| 87 | /// TODO: remove functions from this set when they are destroyed. | ||
| 88 | monomorphed_funcs: MonomorphedFuncsSet = .{}, | 87 | monomorphed_funcs: MonomorphedFuncsSet = .{}, |
| 89 | /// The set of all comptime function calls that have been cached so that future calls | 88 | /// The set of all comptime function calls that have been cached so that future calls |
| 90 | /// with the same parameters will get the same return value. | 89 | /// with the same parameters will get the same return value. |
| ... | @@ -92,7 +91,6 @@ memoized_calls: MemoizedCallSet = .{}, | ... | @@ -92,7 +91,6 @@ memoized_calls: MemoizedCallSet = .{}, |
| 92 | /// Contains the values from `@setAlignStack`. A sparse table is used here | 91 | /// Contains the values from `@setAlignStack`. A sparse table is used here |
| 93 | /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while | 92 | /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while |
| 94 | /// functions are many. | 93 | /// functions are many. |
| 95 | /// TODO: remove functions from this set when they are destroyed. | ||
| 96 | align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{}, | 94 | align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{}, |
| 97 | 95 | ||
| 98 | /// We optimize memory usage for a compilation with no compile errors by storing the | 96 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| ... | @@ -560,6 +558,8 @@ pub const Decl = struct { | ... | @@ -560,6 +558,8 @@ pub const Decl = struct { |
| 560 | gpa.destroy(extern_fn); | 558 | gpa.destroy(extern_fn); |
| 561 | } | 559 | } |
| 562 | if (decl.getFunction()) |func| { | 560 | if (decl.getFunction()) |func| { |
| 561 | _ = mod.align_stack_fns.remove(func); | ||
| 562 | _ = mod.monomorphed_funcs.remove(func); | ||
| 563 | func.deinit(gpa); | 563 | func.deinit(gpa); |
| 564 | gpa.destroy(func); | 564 | gpa.destroy(func); |
| 565 | } | 565 | } |
| ... | @@ -853,8 +853,6 @@ pub const EmitH = struct { | ... | @@ -853,8 +853,6 @@ pub const EmitH = struct { |
| 853 | pub const ErrorSet = struct { | 853 | pub const ErrorSet = struct { |
| 854 | /// The Decl that corresponds to the error set itself. | 854 | /// The Decl that corresponds to the error set itself. |
| 855 | owner_decl: Decl.Index, | 855 | owner_decl: Decl.Index, |
| 856 | /// Offset from Decl node index, points to the error set AST node. | ||
| 857 | node_offset: i32, | ||
| 858 | /// The string bytes are stored in the owner Decl arena. | 856 | /// The string bytes are stored in the owner Decl arena. |
| 859 | /// These must be in sorted order. See sortNames. | 857 | /// These must be in sorted order. See sortNames. |
| 860 | names: NameMap, | 858 | names: NameMap, |
| ... | @@ -866,7 +864,7 @@ pub const ErrorSet = struct { | ... | @@ -866,7 +864,7 @@ pub const ErrorSet = struct { |
| 866 | return .{ | 864 | return .{ |
| 867 | .file_scope = owner_decl.getFileScope(), | 865 | .file_scope = owner_decl.getFileScope(), |
| 868 | .parent_decl_node = owner_decl.src_node, | 866 | .parent_decl_node = owner_decl.src_node, |
| 869 | .lazy = LazySrcLoc.nodeOffset(self.node_offset), | 867 | .lazy = LazySrcLoc.nodeOffset(0), |
| 870 | }; | 868 | }; |
| 871 | } | 869 | } |
| 872 | 870 | ||
| ... | @@ -893,12 +891,15 @@ pub const Struct = struct { | ... | @@ -893,12 +891,15 @@ pub const Struct = struct { |
| 893 | namespace: Namespace, | 891 | namespace: Namespace, |
| 894 | /// The Decl that corresponds to the struct itself. | 892 | /// The Decl that corresponds to the struct itself. |
| 895 | owner_decl: Decl.Index, | 893 | owner_decl: Decl.Index, |
| 896 | /// Offset from `owner_decl`, points to the struct AST node. | ||
| 897 | node_offset: i32, | ||
| 898 | /// Index of the struct_decl ZIR instruction. | 894 | /// Index of the struct_decl ZIR instruction. |
| 899 | zir_index: Zir.Inst.Index, | 895 | zir_index: Zir.Inst.Index, |
| 900 | 896 | ||
| 901 | layout: std.builtin.Type.ContainerLayout, | 897 | layout: std.builtin.Type.ContainerLayout, |
| 898 | /// If the layout is not packed, this is the noreturn type. | ||
| 899 | /// If the layout is packed, this is the backing integer type of the packed struct. | ||
| 900 | /// Whether zig chooses this type or the user specifies it, it is stored here. | ||
| 901 | /// This will be set to the noreturn type until status is `have_layout`. | ||
| 902 | backing_int_ty: Type = Type.initTag(.noreturn), | ||
| 902 | status: enum { | 903 | status: enum { |
| 903 | none, | 904 | none, |
| 904 | field_types_wip, | 905 | field_types_wip, |
| ... | @@ -953,7 +954,7 @@ pub const Struct = struct { | ... | @@ -953,7 +954,7 @@ pub const Struct = struct { |
| 953 | return .{ | 954 | return .{ |
| 954 | .file_scope = owner_decl.getFileScope(), | 955 | .file_scope = owner_decl.getFileScope(), |
| 955 | .parent_decl_node = owner_decl.src_node, | 956 | .parent_decl_node = owner_decl.src_node, |
| 956 | .lazy = LazySrcLoc.nodeOffset(s.node_offset), | 957 | .lazy = LazySrcLoc.nodeOffset(0), |
| 957 | }; | 958 | }; |
| 958 | } | 959 | } |
| 959 | 960 | ||
| ... | @@ -968,7 +969,7 @@ pub const Struct = struct { | ... | @@ -968,7 +969,7 @@ pub const Struct = struct { |
| 968 | }); | 969 | }); |
| 969 | return s.srcLoc(mod); | 970 | return s.srcLoc(mod); |
| 970 | }; | 971 | }; |
| 971 | const node = owner_decl.relativeToNodeIndex(s.node_offset); | 972 | const node = owner_decl.relativeToNodeIndex(0); |
| 972 | const node_tags = tree.nodes.items(.tag); | 973 | const node_tags = tree.nodes.items(.tag); |
| 973 | switch (node_tags[node]) { | 974 | switch (node_tags[node]) { |
| 974 | .container_decl, | 975 | .container_decl, |
| ... | @@ -1029,7 +1030,7 @@ pub const Struct = struct { | ... | @@ -1029,7 +1030,7 @@ pub const Struct = struct { |
| 1029 | 1030 | ||
| 1030 | pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 { | 1031 | pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 { |
| 1031 | assert(s.layout == .Packed); | 1032 | assert(s.layout == .Packed); |
| 1032 | assert(s.haveFieldTypes()); | 1033 | assert(s.haveLayout()); |
| 1033 | var bit_sum: u64 = 0; | 1034 | var bit_sum: u64 = 0; |
| 1034 | for (s.fields.values()) |field, i| { | 1035 | for (s.fields.values()) |field, i| { |
| 1035 | if (i == index) { | 1036 | if (i == index) { |
| ... | @@ -1037,19 +1038,7 @@ pub const Struct = struct { | ... | @@ -1037,19 +1038,7 @@ pub const Struct = struct { |
| 1037 | } | 1038 | } |
| 1038 | bit_sum += field.ty.bitSize(target); | 1039 | bit_sum += field.ty.bitSize(target); |
| 1039 | } | 1040 | } |
| 1040 | return @intCast(u16, bit_sum); | 1041 | unreachable; // index out of bounds |
| 1041 | } | ||
| 1042 | |||
| 1043 | pub fn packedIntegerBits(s: Struct, target: Target) u16 { | ||
| 1044 | return s.packedFieldBitOffset(target, s.fields.count()); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | pub fn packedIntegerType(s: Struct, target: Target, buf: *Type.Payload.Bits) Type { | ||
| 1048 | buf.* = .{ | ||
| 1049 | .base = .{ .tag = .int_unsigned }, | ||
| 1050 | .data = s.packedIntegerBits(target), | ||
| 1051 | }; | ||
| 1052 | return Type.initPayload(&buf.base); | ||
| 1053 | } | 1042 | } |
| 1054 | }; | 1043 | }; |
| 1055 | 1044 | ||
| ... | @@ -1060,8 +1049,6 @@ pub const Struct = struct { | ... | @@ -1060,8 +1049,6 @@ pub const Struct = struct { |
| 1060 | pub const EnumSimple = struct { | 1049 | pub const EnumSimple = struct { |
| 1061 | /// The Decl that corresponds to the enum itself. | 1050 | /// The Decl that corresponds to the enum itself. |
| 1062 | owner_decl: Decl.Index, | 1051 | owner_decl: Decl.Index, |
| 1063 | /// Offset from `owner_decl`, points to the enum decl AST node. | ||
| 1064 | node_offset: i32, | ||
| 1065 | /// Set of field names in declaration order. | 1052 | /// Set of field names in declaration order. |
| 1066 | fields: NameMap, | 1053 | fields: NameMap, |
| 1067 | 1054 | ||
| ... | @@ -1072,7 +1059,7 @@ pub const EnumSimple = struct { | ... | @@ -1072,7 +1059,7 @@ pub const EnumSimple = struct { |
| 1072 | return .{ | 1059 | return .{ |
| 1073 | .file_scope = owner_decl.getFileScope(), | 1060 | .file_scope = owner_decl.getFileScope(), |
| 1074 | .parent_decl_node = owner_decl.src_node, | 1061 | .parent_decl_node = owner_decl.src_node, |
| 1075 | .lazy = LazySrcLoc.nodeOffset(self.node_offset), | 1062 | .lazy = LazySrcLoc.nodeOffset(0), |
| 1076 | }; | 1063 | }; |
| 1077 | } | 1064 | } |
| 1078 | }; | 1065 | }; |
| ... | @@ -1083,8 +1070,6 @@ pub const EnumSimple = struct { | ... | @@ -1083,8 +1070,6 @@ pub const EnumSimple = struct { |
| 1083 | pub const EnumNumbered = struct { | 1070 | pub const EnumNumbered = struct { |
| 1084 | /// The Decl that corresponds to the enum itself. | 1071 | /// The Decl that corresponds to the enum itself. |
| 1085 | owner_decl: Decl.Index, | 1072 | owner_decl: Decl.Index, |
| 1086 | /// Offset from `owner_decl`, points to the enum decl AST node. | ||
| 1087 | node_offset: i32, | ||
| 1088 | /// An integer type which is used for the numerical value of the enum. | 1073 | /// An integer type which is used for the numerical value of the enum. |
| 1089 | /// Whether zig chooses this type or the user specifies it, it is stored here. | 1074 | /// Whether zig chooses this type or the user specifies it, it is stored here. |
| 1090 | tag_ty: Type, | 1075 | tag_ty: Type, |
| ... | @@ -1103,7 +1088,7 @@ pub const EnumNumbered = struct { | ... | @@ -1103,7 +1088,7 @@ pub const EnumNumbered = struct { |
| 1103 | return .{ | 1088 | return .{ |
| 1104 | .file_scope = owner_decl.getFileScope(), | 1089 | .file_scope = owner_decl.getFileScope(), |
| 1105 | .parent_decl_node = owner_decl.src_node, | 1090 | .parent_decl_node = owner_decl.src_node, |
| 1106 | .lazy = LazySrcLoc.nodeOffset(self.node_offset), | 1091 | .lazy = LazySrcLoc.nodeOffset(0), |
| 1107 | }; | 1092 | }; |
| 1108 | } | 1093 | } |
| 1109 | }; | 1094 | }; |
| ... | @@ -1113,8 +1098,6 @@ pub const EnumNumbered = struct { | ... | @@ -1113,8 +1098,6 @@ pub const EnumNumbered = struct { |
| 1113 | pub const EnumFull = struct { | 1098 | pub const EnumFull = struct { |
| 1114 | /// The Decl that corresponds to the enum itself. | 1099 | /// The Decl that corresponds to the enum itself. |
| 1115 | owner_decl: Decl.Index, | 1100 | owner_decl: Decl.Index, |
| 1116 | /// Offset from `owner_decl`, points to the enum decl AST node. | ||
| 1117 | node_offset: i32, | ||
| 1118 | /// An integer type which is used for the numerical value of the enum. | 1101 | /// An integer type which is used for the numerical value of the enum. |
| 1119 | /// Whether zig chooses this type or the user specifies it, it is stored here. | 1102 | /// Whether zig chooses this type or the user specifies it, it is stored here. |
| 1120 | tag_ty: Type, | 1103 | tag_ty: Type, |
| ... | @@ -1137,7 +1120,7 @@ pub const EnumFull = struct { | ... | @@ -1137,7 +1120,7 @@ pub const EnumFull = struct { |
| 1137 | return .{ | 1120 | return .{ |
| 1138 | .file_scope = owner_decl.getFileScope(), | 1121 | .file_scope = owner_decl.getFileScope(), |
| 1139 | .parent_decl_node = owner_decl.src_node, | 1122 | .parent_decl_node = owner_decl.src_node, |
| 1140 | .lazy = LazySrcLoc.nodeOffset(self.node_offset), | 1123 | .lazy = LazySrcLoc.nodeOffset(0), |
| 1141 | }; | 1124 | }; |
| 1142 | } | 1125 | } |
| 1143 | }; | 1126 | }; |
| ... | @@ -1155,8 +1138,6 @@ pub const Union = struct { | ... | @@ -1155,8 +1138,6 @@ pub const Union = struct { |
| 1155 | namespace: Namespace, | 1138 | namespace: Namespace, |
| 1156 | /// The Decl that corresponds to the union itself. | 1139 | /// The Decl that corresponds to the union itself. |
| 1157 | owner_decl: Decl.Index, | 1140 | owner_decl: Decl.Index, |
| 1158 | /// Offset from `owner_decl`, points to the union decl AST node. | ||
| 1159 | node_offset: i32, | ||
| 1160 | /// Index of the union_decl ZIR instruction. | 1141 | /// Index of the union_decl ZIR instruction. |
| 1161 | zir_index: Zir.Inst.Index, | 1142 | zir_index: Zir.Inst.Index, |
| 1162 | 1143 | ||
| ... | @@ -1203,7 +1184,7 @@ pub const Union = struct { | ... | @@ -1203,7 +1184,7 @@ pub const Union = struct { |
| 1203 | return .{ | 1184 | return .{ |
| 1204 | .file_scope = owner_decl.getFileScope(), | 1185 | .file_scope = owner_decl.getFileScope(), |
| 1205 | .parent_decl_node = owner_decl.src_node, | 1186 | .parent_decl_node = owner_decl.src_node, |
| 1206 | .lazy = LazySrcLoc.nodeOffset(self.node_offset), | 1187 | .lazy = LazySrcLoc.nodeOffset(0), |
| 1207 | }; | 1188 | }; |
| 1208 | } | 1189 | } |
| 1209 | 1190 | ||
| ... | @@ -1218,7 +1199,7 @@ pub const Union = struct { | ... | @@ -1218,7 +1199,7 @@ pub const Union = struct { |
| 1218 | }); | 1199 | }); |
| 1219 | return u.srcLoc(mod); | 1200 | return u.srcLoc(mod); |
| 1220 | }; | 1201 | }; |
| 1221 | const node = owner_decl.relativeToNodeIndex(u.node_offset); | 1202 | const node = owner_decl.relativeToNodeIndex(0); |
| 1222 | const node_tags = tree.nodes.items(.tag); | 1203 | const node_tags = tree.nodes.items(.tag); |
| 1223 | var buf: [2]Ast.Node.Index = undefined; | 1204 | var buf: [2]Ast.Node.Index = undefined; |
| 1224 | switch (node_tags[node]) { | 1205 | switch (node_tags[node]) { |
| ... | @@ -1410,8 +1391,6 @@ pub const Union = struct { | ... | @@ -1410,8 +1391,6 @@ pub const Union = struct { |
| 1410 | pub const Opaque = struct { | 1391 | pub const Opaque = struct { |
| 1411 | /// The Decl that corresponds to the opaque itself. | 1392 | /// The Decl that corresponds to the opaque itself. |
| 1412 | owner_decl: Decl.Index, | 1393 | owner_decl: Decl.Index, |
| 1413 | /// Offset from `owner_decl`, points to the opaque decl AST node. | ||
| 1414 | node_offset: i32, | ||
| 1415 | /// Represents the declarations inside this opaque. | 1394 | /// Represents the declarations inside this opaque. |
| 1416 | namespace: Namespace, | 1395 | namespace: Namespace, |
| 1417 | 1396 | ||
| ... | @@ -1420,7 +1399,7 @@ pub const Opaque = struct { | ... | @@ -1420,7 +1399,7 @@ pub const Opaque = struct { |
| 1420 | return .{ | 1399 | return .{ |
| 1421 | .file_scope = owner_decl.getFileScope(), | 1400 | .file_scope = owner_decl.getFileScope(), |
| 1422 | .parent_decl_node = owner_decl.src_node, | 1401 | .parent_decl_node = owner_decl.src_node, |
| 1423 | .lazy = LazySrcLoc.nodeOffset(self.node_offset), | 1402 | .lazy = LazySrcLoc.nodeOffset(0), |
| 1424 | }; | 1403 | }; |
| 1425 | } | 1404 | } |
| 1426 | 1405 | ||
| ... | @@ -4115,6 +4094,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4115,6 +4094,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4115 | // The exports this Decl performs will be re-discovered, so we remove them here | 4094 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 4116 | // prior to re-analysis. | 4095 | // prior to re-analysis. |
| 4117 | mod.deleteDeclExports(decl_index); | 4096 | mod.deleteDeclExports(decl_index); |
| 4097 | |||
| 4098 | // Similarly, `@setAlignStack` invocations will be re-discovered. | ||
| 4099 | if (decl.getFunction()) |func| { | ||
| 4100 | _ = mod.align_stack_fns.remove(func); | ||
| 4101 | } | ||
| 4102 | |||
| 4118 | // Dependencies will be re-discovered, so we remove them here prior to re-analysis. | 4103 | // Dependencies will be re-discovered, so we remove them here prior to re-analysis. |
| 4119 | for (decl.dependencies.keys()) |dep_index| { | 4104 | for (decl.dependencies.keys()) |dep_index| { |
| 4120 | const dep = mod.declPtr(dep_index); | 4105 | const dep = mod.declPtr(dep_index); |
| ... | @@ -4337,7 +4322,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -4337,7 +4322,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4337 | struct_obj.* = .{ | 4322 | struct_obj.* = .{ |
| 4338 | .owner_decl = undefined, // set below | 4323 | .owner_decl = undefined, // set below |
| 4339 | .fields = .{}, | 4324 | .fields = .{}, |
| 4340 | .node_offset = 0, // it's the struct for the root file | ||
| 4341 | .zir_index = undefined, // set below | 4325 | .zir_index = undefined, // set below |
| 4342 | .layout = .Auto, | 4326 | .layout = .Auto, |
| 4343 | .status = .none, | 4327 | .status = .none, |
src/Sema.zig+617-170| ... | @@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, | ... | @@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, |
| 78 | err: ?*Module.ErrorMsg = null, | 78 | err: ?*Module.ErrorMsg = null, |
| 79 | 79 | ||
| 80 | const std = @import("std"); | 80 | const std = @import("std"); |
| 81 | const math = std.math; | ||
| 81 | const mem = std.mem; | 82 | const mem = std.mem; |
| 82 | const Allocator = std.mem.Allocator; | 83 | const Allocator = std.mem.Allocator; |
| 83 | const assert = std.debug.assert; | 84 | const assert = std.debug.assert; |
| ... | @@ -772,7 +773,6 @@ fn analyzeBodyInner( | ... | @@ -772,7 +773,6 @@ fn analyzeBodyInner( |
| 772 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), | 773 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), |
| 773 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), | 774 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), |
| 774 | .optional_type => try sema.zirOptionalType(block, inst), | 775 | .optional_type => try sema.zirOptionalType(block, inst), |
| 775 | .param_type => try sema.zirParamType(block, inst), | ||
| 776 | .ptr_type => try sema.zirPtrType(block, inst), | 776 | .ptr_type => try sema.zirPtrType(block, inst), |
| 777 | .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst), | 777 | .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst), |
| 778 | .ref => try sema.zirRef(block, inst), | 778 | .ref => try sema.zirRef(block, inst), |
| ... | @@ -816,7 +816,6 @@ fn analyzeBodyInner( | ... | @@ -816,7 +816,6 @@ fn analyzeBodyInner( |
| 816 | .embed_file => try sema.zirEmbedFile(block, inst), | 816 | .embed_file => try sema.zirEmbedFile(block, inst), |
| 817 | .error_name => try sema.zirErrorName(block, inst), | 817 | .error_name => try sema.zirErrorName(block, inst), |
| 818 | .tag_name => try sema.zirTagName(block, inst), | 818 | .tag_name => try sema.zirTagName(block, inst), |
| 819 | .reify => try sema.zirReify(block, inst), | ||
| 820 | .type_name => try sema.zirTypeName(block, inst), | 819 | .type_name => try sema.zirTypeName(block, inst), |
| 821 | .frame_type => try sema.zirFrameType(block, inst), | 820 | .frame_type => try sema.zirFrameType(block, inst), |
| 822 | .frame_size => try sema.zirFrameSize(block, inst), | 821 | .frame_size => try sema.zirFrameSize(block, inst), |
| ... | @@ -951,6 +950,7 @@ fn analyzeBodyInner( | ... | @@ -951,6 +950,7 @@ fn analyzeBodyInner( |
| 951 | .select => try sema.zirSelect( block, extended), | 950 | .select => try sema.zirSelect( block, extended), |
| 952 | .error_to_int => try sema.zirErrorToInt( block, extended), | 951 | .error_to_int => try sema.zirErrorToInt( block, extended), |
| 953 | .int_to_error => try sema.zirIntToError( block, extended), | 952 | .int_to_error => try sema.zirIntToError( block, extended), |
| 953 | .reify => try sema.zirReify( block, extended, inst), | ||
| 954 | // zig fmt: on | 954 | // zig fmt: on |
| 955 | .fence => { | 955 | .fence => { |
| 956 | try sema.zirFence(block, extended); | 956 | try sema.zirFence(block, extended); |
| ... | @@ -1818,10 +1818,10 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS | ... | @@ -1818,10 +1818,10 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS |
| 1818 | 1818 | ||
| 1819 | const tree = try sema.getAstTree(block); | 1819 | const tree = try sema.getAstTree(block); |
| 1820 | const decl = sema.mod.declPtr(decl_index); | 1820 | const decl = sema.mod.declPtr(decl_index); |
| 1821 | const field_src = enumFieldSrcLoc(decl, tree.*, container_ty.getNodeOffset(), field_index); | 1821 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); |
| 1822 | const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x }; | 1822 | const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x }; |
| 1823 | 1823 | ||
| 1824 | try sema.errNote(block, default_value_src, msg, "default value set here", .{}); | 1824 | try sema.mod.errNoteNonLazy(default_value_src.toSrcLoc(decl), msg, "default value set here", .{}); |
| 1825 | break :msg msg; | 1825 | break :msg msg; |
| 1826 | }; | 1826 | }; |
| 1827 | return sema.failWithOwnedErrorMsg(msg); | 1827 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -1866,7 +1866,7 @@ fn addFieldErrNote( | ... | @@ -1866,7 +1866,7 @@ fn addFieldErrNote( |
| 1866 | const decl_index = container_ty.getOwnerDecl(); | 1866 | const decl_index = container_ty.getOwnerDecl(); |
| 1867 | const decl = mod.declPtr(decl_index); | 1867 | const decl = mod.declPtr(decl_index); |
| 1868 | const tree = try sema.getAstTree(block); | 1868 | const tree = try sema.getAstTree(block); |
| 1869 | const field_src = enumFieldSrcLoc(decl, tree.*, container_ty.getNodeOffset(), field_index); | 1869 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); |
| 1870 | try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args); | 1870 | try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args); |
| 1871 | } | 1871 | } |
| 1872 | 1872 | ||
| ... | @@ -1906,8 +1906,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { | ... | @@ -1906,8 +1906,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 1906 | } | 1906 | } |
| 1907 | 1907 | ||
| 1908 | const mod = sema.mod; | 1908 | const mod = sema.mod; |
| 1909 | sema.err = err_msg; | ||
| 1910 | |||
| 1911 | { | 1909 | { |
| 1912 | errdefer err_msg.destroy(mod.gpa); | 1910 | errdefer err_msg.destroy(mod.gpa); |
| 1913 | if (err_msg.src_loc.lazy == .unneeded) { | 1911 | if (err_msg.src_loc.lazy == .unneeded) { |
| ... | @@ -1925,8 +1923,10 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { | ... | @@ -1925,8 +1923,10 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 1925 | const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index); | 1923 | const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index); |
| 1926 | if (gop.found_existing) { | 1924 | if (gop.found_existing) { |
| 1927 | // If there are multiple errors for the same Decl, prefer the first one added. | 1925 | // If there are multiple errors for the same Decl, prefer the first one added. |
| 1926 | sema.err = null; | ||
| 1928 | err_msg.destroy(mod.gpa); | 1927 | err_msg.destroy(mod.gpa); |
| 1929 | } else { | 1928 | } else { |
| 1929 | sema.err = err_msg; | ||
| 1930 | gop.value_ptr.* = err_msg; | 1930 | gop.value_ptr.* = err_msg; |
| 1931 | } | 1931 | } |
| 1932 | return error.AnalysisFail; | 1932 | return error.AnalysisFail; |
| ... | @@ -2239,6 +2239,16 @@ pub fn analyzeStructDecl( | ... | @@ -2239,6 +2239,16 @@ pub fn analyzeStructDecl( |
| 2239 | break :blk decls_len; | 2239 | break :blk decls_len; |
| 2240 | } else 0; | 2240 | } else 0; |
| 2241 | 2241 | ||
| 2242 | if (small.has_backing_int) { | ||
| 2243 | const backing_int_body_len = sema.code.extra[extra_index]; | ||
| 2244 | extra_index += 1; // backing_int_body_len | ||
| 2245 | if (backing_int_body_len == 0) { | ||
| 2246 | extra_index += 1; // backing_int_ref | ||
| 2247 | } else { | ||
| 2248 | extra_index += backing_int_body_len; // backing_int_body_inst | ||
| 2249 | } | ||
| 2250 | } | ||
| 2251 | |||
| 2242 | _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl); | 2252 | _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl); |
| 2243 | } | 2253 | } |
| 2244 | 2254 | ||
| ... | @@ -2262,7 +2272,7 @@ fn zirStructDecl( | ... | @@ -2262,7 +2272,7 @@ fn zirStructDecl( |
| 2262 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); | 2272 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); |
| 2263 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | 2273 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); |
| 2264 | const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | 2274 | const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); |
| 2265 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 2275 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2266 | .ty = Type.type, | 2276 | .ty = Type.type, |
| 2267 | .val = struct_val, | 2277 | .val = struct_val, |
| 2268 | }, small.name_strategy, "struct", inst); | 2278 | }, small.name_strategy, "struct", inst); |
| ... | @@ -2272,7 +2282,6 @@ fn zirStructDecl( | ... | @@ -2272,7 +2282,6 @@ fn zirStructDecl( |
| 2272 | struct_obj.* = .{ | 2282 | struct_obj.* = .{ |
| 2273 | .owner_decl = new_decl_index, | 2283 | .owner_decl = new_decl_index, |
| 2274 | .fields = .{}, | 2284 | .fields = .{}, |
| 2275 | .node_offset = src.node_offset.x, | ||
| 2276 | .zir_index = inst, | 2285 | .zir_index = inst, |
| 2277 | .layout = small.layout, | 2286 | .layout = small.layout, |
| 2278 | .status = .none, | 2287 | .status = .none, |
| ... | @@ -2294,6 +2303,7 @@ fn zirStructDecl( | ... | @@ -2294,6 +2303,7 @@ fn zirStructDecl( |
| 2294 | fn createAnonymousDeclTypeNamed( | 2303 | fn createAnonymousDeclTypeNamed( |
| 2295 | sema: *Sema, | 2304 | sema: *Sema, |
| 2296 | block: *Block, | 2305 | block: *Block, |
| 2306 | src: LazySrcLoc, | ||
| 2297 | typed_value: TypedValue, | 2307 | typed_value: TypedValue, |
| 2298 | name_strategy: Zir.Inst.NameStrategy, | 2308 | name_strategy: Zir.Inst.NameStrategy, |
| 2299 | anon_prefix: []const u8, | 2309 | anon_prefix: []const u8, |
| ... | @@ -2303,7 +2313,8 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2303,7 +2313,8 @@ fn createAnonymousDeclTypeNamed( |
| 2303 | const namespace = block.namespace; | 2313 | const namespace = block.namespace; |
| 2304 | const src_scope = block.wip_capture_scope; | 2314 | const src_scope = block.wip_capture_scope; |
| 2305 | const src_decl = mod.declPtr(block.src_decl); | 2315 | const src_decl = mod.declPtr(block.src_decl); |
| 2306 | const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope); | 2316 | const src_node = src_decl.relativeToNodeIndex(src.node_offset.x); |
| 2317 | const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope); | ||
| 2307 | errdefer mod.destroyDecl(new_decl_index); | 2318 | errdefer mod.destroyDecl(new_decl_index); |
| 2308 | 2319 | ||
| 2309 | switch (name_strategy) { | 2320 | switch (name_strategy) { |
| ... | @@ -2378,7 +2389,7 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2378,7 +2389,7 @@ fn createAnonymousDeclTypeNamed( |
| 2378 | }, | 2389 | }, |
| 2379 | else => {}, | 2390 | else => {}, |
| 2380 | }; | 2391 | }; |
| 2381 | return sema.createAnonymousDeclTypeNamed(block, typed_value, .anon, anon_prefix, null); | 2392 | return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); |
| 2382 | }, | 2393 | }, |
| 2383 | } | 2394 | } |
| 2384 | } | 2395 | } |
| ... | @@ -2442,7 +2453,7 @@ fn zirEnumDecl( | ... | @@ -2442,7 +2453,7 @@ fn zirEnumDecl( |
| 2442 | }; | 2453 | }; |
| 2443 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | 2454 | const enum_ty = Type.initPayload(&enum_ty_payload.base); |
| 2444 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | 2455 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); |
| 2445 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 2456 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2446 | .ty = Type.type, | 2457 | .ty = Type.type, |
| 2447 | .val = enum_val, | 2458 | .val = enum_val, |
| 2448 | }, small.name_strategy, "enum", inst); | 2459 | }, small.name_strategy, "enum", inst); |
| ... | @@ -2456,7 +2467,6 @@ fn zirEnumDecl( | ... | @@ -2456,7 +2467,6 @@ fn zirEnumDecl( |
| 2456 | .tag_ty_inferred = true, | 2467 | .tag_ty_inferred = true, |
| 2457 | .fields = .{}, | 2468 | .fields = .{}, |
| 2458 | .values = .{}, | 2469 | .values = .{}, |
| 2459 | .node_offset = src.node_offset.x, | ||
| 2460 | .namespace = .{ | 2470 | .namespace = .{ |
| 2461 | .parent = block.namespace, | 2471 | .parent = block.namespace, |
| 2462 | .ty = enum_ty, | 2472 | .ty = enum_ty, |
| ... | @@ -2684,7 +2694,7 @@ fn zirUnionDecl( | ... | @@ -2684,7 +2694,7 @@ fn zirUnionDecl( |
| 2684 | const union_ty = Type.initPayload(&union_payload.base); | 2694 | const union_ty = Type.initPayload(&union_payload.base); |
| 2685 | const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); | 2695 | const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); |
| 2686 | const mod = sema.mod; | 2696 | const mod = sema.mod; |
| 2687 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 2697 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2688 | .ty = Type.type, | 2698 | .ty = Type.type, |
| 2689 | .val = union_val, | 2699 | .val = union_val, |
| 2690 | }, small.name_strategy, "union", inst); | 2700 | }, small.name_strategy, "union", inst); |
| ... | @@ -2695,7 +2705,6 @@ fn zirUnionDecl( | ... | @@ -2695,7 +2705,6 @@ fn zirUnionDecl( |
| 2695 | .owner_decl = new_decl_index, | 2705 | .owner_decl = new_decl_index, |
| 2696 | .tag_ty = Type.initTag(.@"null"), | 2706 | .tag_ty = Type.initTag(.@"null"), |
| 2697 | .fields = .{}, | 2707 | .fields = .{}, |
| 2698 | .node_offset = src.node_offset.x, | ||
| 2699 | .zir_index = inst, | 2708 | .zir_index = inst, |
| 2700 | .layout = small.layout, | 2709 | .layout = small.layout, |
| 2701 | .status = .none, | 2710 | .status = .none, |
| ... | @@ -2753,7 +2762,7 @@ fn zirOpaqueDecl( | ... | @@ -2753,7 +2762,7 @@ fn zirOpaqueDecl( |
| 2753 | }; | 2762 | }; |
| 2754 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); | 2763 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); |
| 2755 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); | 2764 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); |
| 2756 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 2765 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2757 | .ty = Type.type, | 2766 | .ty = Type.type, |
| 2758 | .val = opaque_val, | 2767 | .val = opaque_val, |
| 2759 | }, small.name_strategy, "opaque", inst); | 2768 | }, small.name_strategy, "opaque", inst); |
| ... | @@ -2763,7 +2772,6 @@ fn zirOpaqueDecl( | ... | @@ -2763,7 +2772,6 @@ fn zirOpaqueDecl( |
| 2763 | 2772 | ||
| 2764 | opaque_obj.* = .{ | 2773 | opaque_obj.* = .{ |
| 2765 | .owner_decl = new_decl_index, | 2774 | .owner_decl = new_decl_index, |
| 2766 | .node_offset = src.node_offset.x, | ||
| 2767 | .namespace = .{ | 2775 | .namespace = .{ |
| 2768 | .parent = block.namespace, | 2776 | .parent = block.namespace, |
| 2769 | .ty = opaque_ty, | 2777 | .ty = opaque_ty, |
| ... | @@ -2802,7 +2810,7 @@ fn zirErrorSetDecl( | ... | @@ -2802,7 +2810,7 @@ fn zirErrorSetDecl( |
| 2802 | const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set); | 2810 | const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set); |
| 2803 | const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty); | 2811 | const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty); |
| 2804 | const mod = sema.mod; | 2812 | const mod = sema.mod; |
| 2805 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 2813 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2806 | .ty = Type.type, | 2814 | .ty = Type.type, |
| 2807 | .val = error_set_val, | 2815 | .val = error_set_val, |
| 2808 | }, name_strategy, "error", inst); | 2816 | }, name_strategy, "error", inst); |
| ... | @@ -2827,7 +2835,6 @@ fn zirErrorSetDecl( | ... | @@ -2827,7 +2835,6 @@ fn zirErrorSetDecl( |
| 2827 | 2835 | ||
| 2828 | error_set.* = .{ | 2836 | error_set.* = .{ |
| 2829 | .owner_decl = new_decl_index, | 2837 | .owner_decl = new_decl_index, |
| 2830 | .node_offset = inst_data.src_node, | ||
| 2831 | .names = names, | 2838 | .names = names, |
| 2832 | }; | 2839 | }; |
| 2833 | try new_decl.finalizeNewArena(&new_decl_arena); | 2840 | try new_decl.finalizeNewArena(&new_decl_arena); |
| ... | @@ -4444,43 +4451,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v | ... | @@ -4444,43 +4451,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 4444 | return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store); | 4451 | return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store); |
| 4445 | } | 4452 | } |
| 4446 | 4453 | ||
| 4447 | fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 4448 | const callee_src = sema.src; | ||
| 4449 | |||
| 4450 | const inst_data = sema.code.instructions.items(.data)[inst].param_type; | ||
| 4451 | const callee = try sema.resolveInst(inst_data.callee); | ||
| 4452 | const callee_ty = sema.typeOf(callee); | ||
| 4453 | var param_index = inst_data.param_index; | ||
| 4454 | |||
| 4455 | const fn_ty = if (callee_ty.tag() == .bound_fn) fn_ty: { | ||
| 4456 | const bound_fn_val = try sema.resolveConstValue(block, .unneeded, callee, undefined); | ||
| 4457 | const bound_fn = bound_fn_val.castTag(.bound_fn).?.data; | ||
| 4458 | const fn_ty = sema.typeOf(bound_fn.func_inst); | ||
| 4459 | param_index += 1; | ||
| 4460 | break :fn_ty fn_ty; | ||
| 4461 | } else callee_ty; | ||
| 4462 | |||
| 4463 | const fn_info = if (fn_ty.zigTypeTag() == .Pointer) | ||
| 4464 | fn_ty.childType().fnInfo() | ||
| 4465 | else | ||
| 4466 | fn_ty.fnInfo(); | ||
| 4467 | |||
| 4468 | if (param_index >= fn_info.param_types.len) { | ||
| 4469 | if (fn_info.is_var_args) { | ||
| 4470 | return sema.addType(Type.initTag(.var_args_param)); | ||
| 4471 | } | ||
| 4472 | // TODO implement begin_call/end_call Zir instructions and check | ||
| 4473 | // argument count before casting arguments to parameter types. | ||
| 4474 | return sema.fail(block, callee_src, "wrong number of arguments", .{}); | ||
| 4475 | } | ||
| 4476 | |||
| 4477 | if (fn_info.param_types[param_index].tag() == .generic_poison) { | ||
| 4478 | return sema.addType(Type.initTag(.var_args_param)); | ||
| 4479 | } | ||
| 4480 | |||
| 4481 | return sema.addType(fn_info.param_types[param_index]); | ||
| 4482 | } | ||
| 4483 | |||
| 4484 | fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 4454 | fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4485 | const tracy = trace(@src()); | 4455 | const tracy = trace(@src()); |
| 4486 | defer tracy.end(); | 4456 | defer tracy.end(); |
| ... | @@ -5450,6 +5420,19 @@ fn lookupInNamespace( | ... | @@ -5450,6 +5420,19 @@ fn lookupInNamespace( |
| 5450 | return null; | 5420 | return null; |
| 5451 | } | 5421 | } |
| 5452 | 5422 | ||
| 5423 | fn funcDeclSrc(sema: *Sema, block: *Block, src: LazySrcLoc, func_inst: Air.Inst.Ref) !?Module.SrcLoc { | ||
| 5424 | const func_val = (try sema.resolveMaybeUndefVal(block, src, func_inst)) orelse return null; | ||
| 5425 | if (func_val.isUndef()) return null; | ||
| 5426 | const owner_decl_index = switch (func_val.tag()) { | ||
| 5427 | .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl, | ||
| 5428 | .function => func_val.castTag(.function).?.data.owner_decl, | ||
| 5429 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, | ||
| 5430 | else => return null, | ||
| 5431 | }; | ||
| 5432 | const owner_decl = sema.mod.declPtr(owner_decl_index); | ||
| 5433 | return owner_decl.srcLoc(); | ||
| 5434 | } | ||
| 5435 | |||
| 5453 | fn zirCall( | 5436 | fn zirCall( |
| 5454 | sema: *Sema, | 5437 | sema: *Sema, |
| 5455 | block: *Block, | 5438 | block: *Block, |
| ... | @@ -5462,13 +5445,14 @@ fn zirCall( | ... | @@ -5462,13 +5445,14 @@ fn zirCall( |
| 5462 | const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; | 5445 | const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; |
| 5463 | const call_src = inst_data.src(); | 5446 | const call_src = inst_data.src(); |
| 5464 | const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index); | 5447 | const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index); |
| 5465 | const args = sema.code.refSlice(extra.end, extra.data.flags.args_len); | 5448 | const args_len = extra.data.flags.args_len; |
| 5466 | 5449 | ||
| 5467 | const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier); | 5450 | const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier); |
| 5468 | const ensure_result_used = extra.data.flags.ensure_result_used; | 5451 | const ensure_result_used = extra.data.flags.ensure_result_used; |
| 5469 | 5452 | ||
| 5470 | var func = try sema.resolveInst(extra.data.callee); | 5453 | var func = try sema.resolveInst(extra.data.callee); |
| 5471 | var resolved_args: []Air.Inst.Ref = undefined; | 5454 | var resolved_args: []Air.Inst.Ref = undefined; |
| 5455 | var arg_index: u32 = 0; | ||
| 5472 | 5456 | ||
| 5473 | const func_type = sema.typeOf(func); | 5457 | const func_type = sema.typeOf(func); |
| 5474 | 5458 | ||
| ... | @@ -5479,16 +5463,93 @@ fn zirCall( | ... | @@ -5479,16 +5463,93 @@ fn zirCall( |
| 5479 | const bound_func = try sema.resolveValue(block, .unneeded, func, undefined); | 5463 | const bound_func = try sema.resolveValue(block, .unneeded, func, undefined); |
| 5480 | const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data; | 5464 | const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data; |
| 5481 | func = bound_data.func_inst; | 5465 | func = bound_data.func_inst; |
| 5482 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len + 1); | 5466 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1); |
| 5483 | resolved_args[0] = bound_data.arg0_inst; | 5467 | resolved_args[arg_index] = bound_data.arg0_inst; |
| 5484 | for (args) |zir_arg, i| { | 5468 | arg_index += 1; |
| 5485 | resolved_args[i + 1] = try sema.resolveInst(zir_arg); | ||
| 5486 | } | ||
| 5487 | } else { | 5469 | } else { |
| 5488 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len); | 5470 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len); |
| 5489 | for (args) |zir_arg, i| { | 5471 | } |
| 5490 | resolved_args[i] = try sema.resolveInst(zir_arg); | 5472 | const total_args = args_len + @boolToInt(bound_arg_src != null); |
| 5473 | |||
| 5474 | const callee_ty = sema.typeOf(func); | ||
| 5475 | const func_ty = func_ty: { | ||
| 5476 | switch (callee_ty.zigTypeTag()) { | ||
| 5477 | .Fn => break :func_ty callee_ty, | ||
| 5478 | .Pointer => { | ||
| 5479 | const ptr_info = callee_ty.ptrInfo().data; | ||
| 5480 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { | ||
| 5481 | break :func_ty ptr_info.pointee_type; | ||
| 5482 | } | ||
| 5483 | }, | ||
| 5484 | else => {}, | ||
| 5485 | } | ||
| 5486 | return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)}); | ||
| 5487 | }; | ||
| 5488 | const func_ty_info = func_ty.fnInfo(); | ||
| 5489 | |||
| 5490 | const fn_params_len = func_ty_info.param_types.len; | ||
| 5491 | check_args: { | ||
| 5492 | if (func_ty_info.is_var_args) { | ||
| 5493 | assert(func_ty_info.cc == .C); | ||
| 5494 | if (total_args >= fn_params_len) break :check_args; | ||
| 5495 | } else if (fn_params_len == total_args) { | ||
| 5496 | break :check_args; | ||
| 5491 | } | 5497 | } |
| 5498 | |||
| 5499 | const decl_src = try sema.funcDeclSrc(block, func_src, func); | ||
| 5500 | const member_str = if (bound_arg_src != null) "member function " else ""; | ||
| 5501 | const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; | ||
| 5502 | const msg = msg: { | ||
| 5503 | const msg = try sema.errMsg( | ||
| 5504 | block, | ||
| 5505 | func_src, | ||
| 5506 | "{s}expected {s}{d} argument(s), found {d}", | ||
| 5507 | .{ | ||
| 5508 | member_str, | ||
| 5509 | variadic_str, | ||
| 5510 | fn_params_len - @boolToInt(bound_arg_src != null), | ||
| 5511 | args_len, | ||
| 5512 | }, | ||
| 5513 | ); | ||
| 5514 | errdefer msg.destroy(sema.gpa); | ||
| 5515 | |||
| 5516 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | ||
| 5517 | break :msg msg; | ||
| 5518 | }; | ||
| 5519 | return sema.failWithOwnedErrorMsg(msg); | ||
| 5520 | } | ||
| 5521 | |||
| 5522 | const args_body = sema.code.extra[extra.end..]; | ||
| 5523 | |||
| 5524 | const parent_comptime = block.is_comptime; | ||
| 5525 | // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument. | ||
| 5526 | var extra_index: usize = 0; | ||
| 5527 | var arg_start: u32 = args_len; | ||
| 5528 | while (extra_index < args_len) : ({ | ||
| 5529 | extra_index += 1; | ||
| 5530 | arg_index += 1; | ||
| 5531 | }) { | ||
| 5532 | const arg_end = sema.code.extra[extra.end + extra_index]; | ||
| 5533 | defer arg_start = arg_end; | ||
| 5534 | |||
| 5535 | const param_ty = if (arg_index >= fn_params_len or | ||
| 5536 | func_ty_info.param_types[arg_index].tag() == .generic_poison) | ||
| 5537 | Type.initTag(.var_args_param) | ||
| 5538 | else | ||
| 5539 | func_ty_info.param_types[arg_index]; | ||
| 5540 | |||
| 5541 | const old_comptime = block.is_comptime; | ||
| 5542 | defer block.is_comptime = old_comptime; | ||
| 5543 | // Generate args to comptime params in comptime block. | ||
| 5544 | block.is_comptime = parent_comptime; | ||
| 5545 | if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) { | ||
| 5546 | block.is_comptime = true; | ||
| 5547 | } | ||
| 5548 | |||
| 5549 | const param_ty_inst = try sema.addType(param_ty); | ||
| 5550 | try sema.inst_map.put(sema.gpa, inst, param_ty_inst); | ||
| 5551 | |||
| 5552 | resolved_args[arg_index] = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); | ||
| 5492 | } | 5553 | } |
| 5493 | 5554 | ||
| 5494 | return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src); | 5555 | return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src); |
| ... | @@ -5582,13 +5643,20 @@ fn analyzeCall( | ... | @@ -5582,13 +5643,20 @@ fn analyzeCall( |
| 5582 | const func_ty_info = func_ty.fnInfo(); | 5643 | const func_ty_info = func_ty.fnInfo(); |
| 5583 | const cc = func_ty_info.cc; | 5644 | const cc = func_ty_info.cc; |
| 5584 | if (cc == .Naked) { | 5645 | if (cc == .Naked) { |
| 5585 | // TODO add error note: declared here | 5646 | const decl_src = try sema.funcDeclSrc(block, func_src, func); |
| 5586 | return sema.fail( | 5647 | const msg = msg: { |
| 5587 | block, | 5648 | const msg = try sema.errMsg( |
| 5588 | func_src, | 5649 | block, |
| 5589 | "unable to call function with naked calling convention", | 5650 | func_src, |
| 5590 | .{}, | 5651 | "unable to call function with naked calling convention", |
| 5591 | ); | 5652 | .{}, |
| 5653 | ); | ||
| 5654 | errdefer msg.destroy(sema.gpa); | ||
| 5655 | |||
| 5656 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | ||
| 5657 | break :msg msg; | ||
| 5658 | }; | ||
| 5659 | return sema.failWithOwnedErrorMsg(msg); | ||
| 5592 | } | 5660 | } |
| 5593 | const fn_params_len = func_ty_info.param_types.len; | 5661 | const fn_params_len = func_ty_info.param_types.len; |
| 5594 | if (func_ty_info.is_var_args) { | 5662 | if (func_ty_info.is_var_args) { |
| ... | @@ -5967,7 +6035,18 @@ fn analyzeCall( | ... | @@ -5967,7 +6035,18 @@ fn analyzeCall( |
| 5967 | else => |e| return e, | 6035 | else => |e| return e, |
| 5968 | }; | 6036 | }; |
| 5969 | } else { | 6037 | } else { |
| 5970 | args[i] = uncasted_arg; | 6038 | args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) { |
| 6039 | error.NeededSourceLocation => { | ||
| 6040 | const decl = sema.mod.declPtr(block.src_decl); | ||
| 6041 | _ = try sema.coerceVarArgParam( | ||
| 6042 | block, | ||
| 6043 | uncasted_arg, | ||
| 6044 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), | ||
| 6045 | ); | ||
| 6046 | return error.AnalysisFail; | ||
| 6047 | }, | ||
| 6048 | else => |e| return e, | ||
| 6049 | }; | ||
| 5971 | } | 6050 | } |
| 5972 | } | 6051 | } |
| 5973 | 6052 | ||
| ... | @@ -6272,6 +6351,7 @@ fn instantiateGenericCall( | ... | @@ -6272,6 +6351,7 @@ fn instantiateGenericCall( |
| 6272 | new_decl.is_exported = fn_owner_decl.is_exported; | 6351 | new_decl.is_exported = fn_owner_decl.is_exported; |
| 6273 | new_decl.has_align = fn_owner_decl.has_align; | 6352 | new_decl.has_align = fn_owner_decl.has_align; |
| 6274 | new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace; | 6353 | new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace; |
| 6354 | new_decl.@"linksection" = fn_owner_decl.@"linksection"; | ||
| 6275 | new_decl.@"addrspace" = fn_owner_decl.@"addrspace"; | 6355 | new_decl.@"addrspace" = fn_owner_decl.@"addrspace"; |
| 6276 | new_decl.zir_decl_index = fn_owner_decl.zir_decl_index; | 6356 | new_decl.zir_decl_index = fn_owner_decl.zir_decl_index; |
| 6277 | new_decl.alive = true; // This Decl is called at runtime. | 6357 | new_decl.alive = true; // This Decl is called at runtime. |
| ... | @@ -6724,11 +6804,10 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -6724,11 +6804,10 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 6724 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 6804 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 6725 | const uncasted_operand = try sema.resolveInst(extra.operand); | 6805 | const uncasted_operand = try sema.resolveInst(extra.operand); |
| 6726 | const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src); | 6806 | const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src); |
| 6727 | const result_ty = Type.u16; | ||
| 6728 | 6807 | ||
| 6729 | if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| { | 6808 | if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| { |
| 6730 | if (val.isUndef()) { | 6809 | if (val.isUndef()) { |
| 6731 | return sema.addConstUndef(result_ty); | 6810 | return sema.addConstUndef(Type.err_int); |
| 6732 | } | 6811 | } |
| 6733 | switch (val.tag()) { | 6812 | switch (val.tag()) { |
| 6734 | .@"error" => { | 6813 | .@"error" => { |
| ... | @@ -6737,14 +6816,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -6737,14 +6816,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 6737 | .base = .{ .tag = .int_u64 }, | 6816 | .base = .{ .tag = .int_u64 }, |
| 6738 | .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, | 6817 | .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, |
| 6739 | }; | 6818 | }; |
| 6740 | return sema.addConstant(result_ty, Value.initPayload(&payload.base)); | 6819 | return sema.addConstant(Type.err_int, Value.initPayload(&payload.base)); |
| 6741 | }, | 6820 | }, |
| 6742 | 6821 | ||
| 6743 | // This is not a valid combination with the type `anyerror`. | 6822 | // This is not a valid combination with the type `anyerror`. |
| 6744 | .the_only_possible_value => unreachable, | 6823 | .the_only_possible_value => unreachable, |
| 6745 | 6824 | ||
| 6746 | // Assume it's already encoded as an integer. | 6825 | // Assume it's already encoded as an integer. |
| 6747 | else => return sema.addConstant(result_ty, val), | 6826 | else => return sema.addConstant(Type.err_int, val), |
| 6748 | } | 6827 | } |
| 6749 | } | 6828 | } |
| 6750 | 6829 | ||
| ... | @@ -6753,14 +6832,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -6753,14 +6832,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 6753 | if (!op_ty.isAnyError()) { | 6832 | if (!op_ty.isAnyError()) { |
| 6754 | const names = op_ty.errorSetNames(); | 6833 | const names = op_ty.errorSetNames(); |
| 6755 | switch (names.len) { | 6834 | switch (names.len) { |
| 6756 | 0 => return sema.addConstant(result_ty, Value.zero), | 6835 | 0 => return sema.addConstant(Type.err_int, Value.zero), |
| 6757 | 1 => return sema.addIntUnsigned(result_ty, sema.mod.global_error_set.get(names[0]).?), | 6836 | 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?), |
| 6758 | else => {}, | 6837 | else => {}, |
| 6759 | } | 6838 | } |
| 6760 | } | 6839 | } |
| 6761 | 6840 | ||
| 6762 | try sema.requireRuntimeBlock(block, src, operand_src); | 6841 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 6763 | return block.addBitCast(result_ty, operand); | 6842 | return block.addBitCast(Type.err_int, operand); |
| 6764 | } | 6843 | } |
| 6765 | 6844 | ||
| 6766 | fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 6845 | fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | @@ -6771,7 +6850,7 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -6771,7 +6850,7 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 6771 | const src = LazySrcLoc.nodeOffset(extra.node); | 6850 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 6772 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 6851 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 6773 | const uncasted_operand = try sema.resolveInst(extra.operand); | 6852 | const uncasted_operand = try sema.resolveInst(extra.operand); |
| 6774 | const operand = try sema.coerce(block, Type.u16, uncasted_operand, operand_src); | 6853 | const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src); |
| 6775 | const target = sema.mod.getTarget(); | 6854 | const target = sema.mod.getTarget(); |
| 6776 | 6855 | ||
| 6777 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { | 6856 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { |
| ... | @@ -6788,7 +6867,10 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -6788,7 +6867,10 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 6788 | try sema.requireRuntimeBlock(block, src, operand_src); | 6867 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 6789 | if (block.wantSafety()) { | 6868 | if (block.wantSafety()) { |
| 6790 | const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand); | 6869 | const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand); |
| 6791 | try sema.addSafetyCheck(block, is_lt_len, .invalid_error_code); | 6870 | const zero_val = try sema.addConstant(Type.err_int, Value.zero); |
| 6871 | const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); | ||
| 6872 | const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero); | ||
| 6873 | try sema.addSafetyCheck(block, ok, .invalid_error_code); | ||
| 6792 | } | 6874 | } |
| 6793 | return block.addInst(.{ | 6875 | return block.addInst(.{ |
| 6794 | .tag = .bitcast, | 6876 | .tag = .bitcast, |
| ... | @@ -10201,16 +10283,14 @@ fn zirShl( | ... | @@ -10201,16 +10283,14 @@ fn zirShl( |
| 10201 | 10283 | ||
| 10202 | const val = switch (air_tag) { | 10284 | const val = switch (air_tag) { |
| 10203 | .shl_exact => val: { | 10285 | .shl_exact => val: { |
| 10204 | const shifted = try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target); | 10286 | const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, target); |
| 10205 | if (scalar_ty.zigTypeTag() == .ComptimeInt) { | 10287 | if (scalar_ty.zigTypeTag() == .ComptimeInt) { |
| 10206 | break :val shifted; | 10288 | break :val shifted.wrapped_result; |
| 10207 | } | 10289 | } |
| 10208 | const int_info = scalar_ty.intInfo(target); | 10290 | if (shifted.overflowed.compareWithZero(.eq)) { |
| 10209 | const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits, target); | 10291 | break :val shifted.wrapped_result; |
| 10210 | if (try sema.compare(block, src, truncated, .eq, shifted, lhs_ty)) { | ||
| 10211 | break :val shifted; | ||
| 10212 | } | 10292 | } |
| 10213 | return sema.addConstUndef(lhs_ty); | 10293 | return sema.fail(block, src, "operation caused overflow", .{}); |
| 10214 | }, | 10294 | }, |
| 10215 | 10295 | ||
| 10216 | .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt) | 10296 | .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt) |
| ... | @@ -10363,7 +10443,7 @@ fn zirShr( | ... | @@ -10363,7 +10443,7 @@ fn zirShr( |
| 10363 | // Detect if any ones would be shifted out. | 10443 | // Detect if any ones would be shifted out. |
| 10364 | const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target); | 10444 | const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target); |
| 10365 | if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { | 10445 | if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) { |
| 10366 | return sema.addConstUndef(lhs_ty); | 10446 | return sema.fail(block, src, "exact shift shifted out 1 bits", .{}); |
| 10367 | } | 10447 | } |
| 10368 | } | 10448 | } |
| 10369 | const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target); | 10449 | const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target); |
| ... | @@ -11183,7 +11263,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -11183,7 +11263,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 11183 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); | 11263 | try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int); |
| 11184 | } | 11264 | } |
| 11185 | 11265 | ||
| 11186 | const air_tag = if (is_int) Air.Inst.Tag.div_trunc else switch (block.float_mode) { | 11266 | const air_tag = if (is_int) blk: { |
| 11267 | if (lhs_ty.isSignedInt() or rhs_ty.isSignedInt()) { | ||
| 11268 | return sema.fail(block, src, "division with '{s}' and '{s}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()) }); | ||
| 11269 | } | ||
| 11270 | break :blk Air.Inst.Tag.div_trunc; | ||
| 11271 | } else switch (block.float_mode) { | ||
| 11187 | .Optimized => Air.Inst.Tag.div_float_optimized, | 11272 | .Optimized => Air.Inst.Tag.div_float_optimized, |
| 11188 | .Strict => Air.Inst.Tag.div_float, | 11273 | .Strict => Air.Inst.Tag.div_float, |
| 11189 | }; | 11274 | }; |
| ... | @@ -11263,13 +11348,19 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -11263,13 +11348,19 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 11263 | if (maybe_lhs_val) |lhs_val| { | 11348 | if (maybe_lhs_val) |lhs_val| { |
| 11264 | if (maybe_rhs_val) |rhs_val| { | 11349 | if (maybe_rhs_val) |rhs_val| { |
| 11265 | if (is_int) { | 11350 | if (is_int) { |
| 11266 | // TODO: emit compile error if there is a remainder | 11351 | const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target); |
| 11352 | if (modulus_val.compareWithZero(.neq)) { | ||
| 11353 | return sema.fail(block, src, "exact division produced remainder", .{}); | ||
| 11354 | } | ||
| 11267 | return sema.addConstant( | 11355 | return sema.addConstant( |
| 11268 | resolved_type, | 11356 | resolved_type, |
| 11269 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), | 11357 | try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target), |
| 11270 | ); | 11358 | ); |
| 11271 | } else { | 11359 | } else { |
| 11272 | // TODO: emit compile error if there is a remainder | 11360 | const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target); |
| 11361 | if (modulus_val.compareWithZero(.neq)) { | ||
| 11362 | return sema.fail(block, src, "exact division produced remainder", .{}); | ||
| 11363 | } | ||
| 11273 | return sema.addConstant( | 11364 | return sema.addConstant( |
| 11274 | resolved_type, | 11365 | resolved_type, |
| 11275 | try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), | 11366 | try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), |
| ... | @@ -11756,7 +11847,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -11756,7 +11847,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 11756 | return sema.failWithDivideByZero(block, rhs_src); | 11847 | return sema.failWithDivideByZero(block, rhs_src); |
| 11757 | } | 11848 | } |
| 11758 | if (maybe_lhs_val) |lhs_val| { | 11849 | if (maybe_lhs_val) |lhs_val| { |
| 11759 | const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target); | 11850 | const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src); |
| 11760 | // If this answer could possibly be different by doing `intMod`, | 11851 | // If this answer could possibly be different by doing `intMod`, |
| 11761 | // we must emit a compile error. Otherwise, it's OK. | 11852 | // we must emit a compile error. Otherwise, it's OK. |
| 11762 | if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and | 11853 | if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and |
| ... | @@ -11818,6 +11909,60 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -11818,6 +11909,60 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 11818 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); | 11909 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); |
| 11819 | } | 11910 | } |
| 11820 | 11911 | ||
| 11912 | fn intRem( | ||
| 11913 | sema: *Sema, | ||
| 11914 | block: *Block, | ||
| 11915 | ty: Type, | ||
| 11916 | lhs: Value, | ||
| 11917 | lhs_src: LazySrcLoc, | ||
| 11918 | rhs: Value, | ||
| 11919 | rhs_src: LazySrcLoc, | ||
| 11920 | ) CompileError!Value { | ||
| 11921 | if (ty.zigTypeTag() == .Vector) { | ||
| 11922 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | ||
| 11923 | for (result_data) |*scalar, i| { | ||
| 11924 | scalar.* = try sema.intRemScalar(block, lhs.indexVectorlike(i), lhs_src, rhs.indexVectorlike(i), rhs_src); | ||
| 11925 | } | ||
| 11926 | return Value.Tag.aggregate.create(sema.arena, result_data); | ||
| 11927 | } | ||
| 11928 | return sema.intRemScalar(block, lhs, lhs_src, rhs, rhs_src); | ||
| 11929 | } | ||
| 11930 | |||
| 11931 | fn intRemScalar( | ||
| 11932 | sema: *Sema, | ||
| 11933 | block: *Block, | ||
| 11934 | lhs: Value, | ||
| 11935 | lhs_src: LazySrcLoc, | ||
| 11936 | rhs: Value, | ||
| 11937 | rhs_src: LazySrcLoc, | ||
| 11938 | ) CompileError!Value { | ||
| 11939 | const target = sema.mod.getTarget(); | ||
| 11940 | // TODO is this a performance issue? maybe we should try the operation without | ||
| 11941 | // resorting to BigInt first. | ||
| 11942 | var lhs_space: Value.BigIntSpace = undefined; | ||
| 11943 | var rhs_space: Value.BigIntSpace = undefined; | ||
| 11944 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, lhs_src)); | ||
| 11945 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, rhs_src)); | ||
| 11946 | const limbs_q = try sema.arena.alloc( | ||
| 11947 | math.big.Limb, | ||
| 11948 | lhs_bigint.limbs.len, | ||
| 11949 | ); | ||
| 11950 | const limbs_r = try sema.arena.alloc( | ||
| 11951 | math.big.Limb, | ||
| 11952 | // TODO: consider reworking Sema to re-use Values rather than | ||
| 11953 | // always producing new Value objects. | ||
| 11954 | rhs_bigint.limbs.len, | ||
| 11955 | ); | ||
| 11956 | const limbs_buffer = try sema.arena.alloc( | ||
| 11957 | math.big.Limb, | ||
| 11958 | math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len), | ||
| 11959 | ); | ||
| 11960 | var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | ||
| 11961 | var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | ||
| 11962 | result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); | ||
| 11963 | return Value.fromBigInt(sema.arena, result_r.toConst()); | ||
| 11964 | } | ||
| 11965 | |||
| 11821 | fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 11966 | fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 11822 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 11967 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 11823 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 11968 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| ... | @@ -11982,7 +12127,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -11982,7 +12127,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 11982 | if (maybe_lhs_val) |lhs_val| { | 12127 | if (maybe_lhs_val) |lhs_val| { |
| 11983 | return sema.addConstant( | 12128 | return sema.addConstant( |
| 11984 | resolved_type, | 12129 | resolved_type, |
| 11985 | try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target), | 12130 | try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src), |
| 11986 | ); | 12131 | ); |
| 11987 | } | 12132 | } |
| 11988 | break :rs lhs_src; | 12133 | break :rs lhs_src; |
| ... | @@ -14162,13 +14307,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14162,13 +14307,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14162 | 14307 | ||
| 14163 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace()); | 14308 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace()); |
| 14164 | 14309 | ||
| 14165 | const field_values = try sema.arena.create([4]Value); | 14310 | const backing_integer_val = blk: { |
| 14311 | if (layout == .Packed) { | ||
| 14312 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | ||
| 14313 | assert(struct_obj.haveLayout()); | ||
| 14314 | assert(struct_obj.backing_int_ty.isInt()); | ||
| 14315 | const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty); | ||
| 14316 | break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val); | ||
| 14317 | } else { | ||
| 14318 | break :blk Value.initTag(.null_value); | ||
| 14319 | } | ||
| 14320 | }; | ||
| 14321 | |||
| 14322 | const field_values = try sema.arena.create([5]Value); | ||
| 14166 | field_values.* = .{ | 14323 | field_values.* = .{ |
| 14167 | // layout: ContainerLayout, | 14324 | // layout: ContainerLayout, |
| 14168 | try Value.Tag.enum_field_index.create( | 14325 | try Value.Tag.enum_field_index.create( |
| 14169 | sema.arena, | 14326 | sema.arena, |
| 14170 | @enumToInt(layout), | 14327 | @enumToInt(layout), |
| 14171 | ), | 14328 | ), |
| 14329 | // backing_integer: ?type, | ||
| 14330 | backing_integer_val, | ||
| 14172 | // fields: []const StructField, | 14331 | // fields: []const StructField, |
| 14173 | fields_val, | 14332 | fields_val, |
| 14174 | // decls: []const Declaration, | 14333 | // decls: []const Declaration, |
| ... | @@ -14492,6 +14651,20 @@ fn zirBoolBr( | ... | @@ -14492,6 +14651,20 @@ fn zirBoolBr( |
| 14492 | const rhs_result = try sema.resolveBody(rhs_block, body, inst); | 14651 | const rhs_result = try sema.resolveBody(rhs_block, body, inst); |
| 14493 | _ = try rhs_block.addBr(block_inst, rhs_result); | 14652 | _ = try rhs_block.addBr(block_inst, rhs_result); |
| 14494 | 14653 | ||
| 14654 | return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst); | ||
| 14655 | } | ||
| 14656 | |||
| 14657 | fn finishCondBr( | ||
| 14658 | sema: *Sema, | ||
| 14659 | parent_block: *Block, | ||
| 14660 | child_block: *Block, | ||
| 14661 | then_block: *Block, | ||
| 14662 | else_block: *Block, | ||
| 14663 | cond: Air.Inst.Ref, | ||
| 14664 | block_inst: Air.Inst.Index, | ||
| 14665 | ) !Air.Inst.Ref { | ||
| 14666 | const gpa = sema.gpa; | ||
| 14667 | |||
| 14495 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + | 14668 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + |
| 14496 | then_block.instructions.items.len + else_block.instructions.items.len + | 14669 | then_block.instructions.items.len + else_block.instructions.items.len + |
| 14497 | @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1); | 14670 | @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1); |
| ... | @@ -14504,7 +14677,7 @@ fn zirBoolBr( | ... | @@ -14504,7 +14677,7 @@ fn zirBoolBr( |
| 14504 | sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); | 14677 | sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); |
| 14505 | 14678 | ||
| 14506 | _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ | 14679 | _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ |
| 14507 | .operand = lhs, | 14680 | .operand = cond, |
| 14508 | .payload = cond_br_payload, | 14681 | .payload = cond_br_payload, |
| 14509 | } } }); | 14682 | } } }); |
| 14510 | 14683 | ||
| ... | @@ -14874,10 +15047,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir | ... | @@ -14874,10 +15047,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir |
| 14874 | const operand = try sema.analyzeLoad(block, src, ret_ptr, src); | 15047 | const operand = try sema.analyzeLoad(block, src, ret_ptr, src); |
| 14875 | return sema.analyzeRet(block, operand, src); | 15048 | return sema.analyzeRet(block, operand, src); |
| 14876 | } | 15049 | } |
| 15050 | |||
| 15051 | if (sema.wantErrorReturnTracing()) { | ||
| 15052 | const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr); | ||
| 15053 | return retWithErrTracing(sema, block, src, is_non_err, .ret_load, ret_ptr); | ||
| 15054 | } | ||
| 15055 | |||
| 14877 | _ = try block.addUnOp(.ret_load, ret_ptr); | 15056 | _ = try block.addUnOp(.ret_load, ret_ptr); |
| 14878 | return always_noreturn; | 15057 | return always_noreturn; |
| 14879 | } | 15058 | } |
| 14880 | 15059 | ||
| 15060 | fn retWithErrTracing( | ||
| 15061 | sema: *Sema, | ||
| 15062 | block: *Block, | ||
| 15063 | src: LazySrcLoc, | ||
| 15064 | is_non_err: Air.Inst.Ref, | ||
| 15065 | ret_tag: Air.Inst.Tag, | ||
| 15066 | operand: Air.Inst.Ref, | ||
| 15067 | ) CompileError!Zir.Inst.Index { | ||
| 15068 | const need_check = switch (is_non_err) { | ||
| 15069 | .bool_true => { | ||
| 15070 | _ = try block.addUnOp(ret_tag, operand); | ||
| 15071 | return always_noreturn; | ||
| 15072 | }, | ||
| 15073 | .bool_false => false, | ||
| 15074 | else => true, | ||
| 15075 | }; | ||
| 15076 | const gpa = sema.gpa; | ||
| 15077 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); | ||
| 15078 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); | ||
| 15079 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); | ||
| 15080 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | ||
| 15081 | const return_err_fn = try sema.getBuiltin(block, src, "returnError"); | ||
| 15082 | const args: [1]Air.Inst.Ref = .{err_return_trace}; | ||
| 15083 | |||
| 15084 | if (!need_check) { | ||
| 15085 | _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); | ||
| 15086 | _ = try block.addUnOp(ret_tag, operand); | ||
| 15087 | return always_noreturn; | ||
| 15088 | } | ||
| 15089 | |||
| 15090 | var then_block = block.makeSubBlock(); | ||
| 15091 | defer then_block.instructions.deinit(gpa); | ||
| 15092 | _ = try then_block.addUnOp(ret_tag, operand); | ||
| 15093 | |||
| 15094 | var else_block = block.makeSubBlock(); | ||
| 15095 | defer else_block.instructions.deinit(gpa); | ||
| 15096 | _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null); | ||
| 15097 | _ = try else_block.addUnOp(ret_tag, operand); | ||
| 15098 | |||
| 15099 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + | ||
| 15100 | then_block.instructions.items.len + else_block.instructions.items.len + | ||
| 15101 | @typeInfo(Air.Block).Struct.fields.len + 1); | ||
| 15102 | |||
| 15103 | const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ | ||
| 15104 | .then_body_len = @intCast(u32, then_block.instructions.items.len), | ||
| 15105 | .else_body_len = @intCast(u32, else_block.instructions.items.len), | ||
| 15106 | }); | ||
| 15107 | sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); | ||
| 15108 | sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); | ||
| 15109 | |||
| 15110 | _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ | ||
| 15111 | .operand = is_non_err, | ||
| 15112 | .payload = cond_br_payload, | ||
| 15113 | } } }); | ||
| 15114 | |||
| 15115 | return always_noreturn; | ||
| 15116 | } | ||
| 15117 | |||
| 15118 | fn wantErrorReturnTracing(sema: *Sema) bool { | ||
| 15119 | // TODO implement this feature in all the backends and then delete this check. | ||
| 15120 | const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; | ||
| 15121 | |||
| 15122 | return sema.fn_ret_ty.isError() and | ||
| 15123 | sema.mod.comp.bin_file.options.error_return_tracing and | ||
| 15124 | backend_supports_error_return_tracing; | ||
| 15125 | } | ||
| 15126 | |||
| 14881 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { | 15127 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { |
| 14882 | assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); | 15128 | assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); |
| 14883 | 15129 | ||
| ... | @@ -14923,27 +15169,15 @@ fn analyzeRet( | ... | @@ -14923,27 +15169,15 @@ fn analyzeRet( |
| 14923 | return always_noreturn; | 15169 | return always_noreturn; |
| 14924 | } | 15170 | } |
| 14925 | 15171 | ||
| 14926 | // TODO implement this feature in all the backends and then delete this check. | 15172 | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); |
| 14927 | const backend_supports_error_return_tracing = | ||
| 14928 | sema.mod.comp.bin_file.options.use_llvm; | ||
| 14929 | 15173 | ||
| 14930 | if (sema.fn_ret_ty.isError() and | 15174 | if (sema.wantErrorReturnTracing()) { |
| 14931 | sema.mod.comp.bin_file.options.error_return_tracing and | 15175 | // Avoid adding a frame to the error return trace in case the value is comptime-known |
| 14932 | backend_supports_error_return_tracing) | 15176 | // to be not an error. |
| 14933 | ret_err: { | 15177 | const is_non_err = try sema.analyzeIsNonErr(block, src, operand); |
| 14934 | if (try sema.resolveMaybeUndefVal(block, src, operand)) |ret_val| { | 15178 | return retWithErrTracing(sema, block, src, is_non_err, .ret, operand); |
| 14935 | if (ret_val.tag() != .@"error") break :ret_err; | ||
| 14936 | } | ||
| 14937 | const return_err_fn = try sema.getBuiltin(block, src, "returnError"); | ||
| 14938 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); | ||
| 14939 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); | ||
| 14940 | const ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty); | ||
| 14941 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | ||
| 14942 | const args: [1]Air.Inst.Ref = .{err_return_trace}; | ||
| 14943 | _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); | ||
| 14944 | } | 15179 | } |
| 14945 | 15180 | ||
| 14946 | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); | ||
| 14947 | _ = try block.addUnOp(.ret, operand); | 15181 | _ = try block.addUnOp(.ret, operand); |
| 14948 | return always_noreturn; | 15182 | return always_noreturn; |
| 14949 | } | 15183 | } |
| ... | @@ -16023,13 +16257,14 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16023,13 +16257,14 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16023 | return block.addUnOp(.tag_name, casted_operand); | 16257 | return block.addUnOp(.tag_name, casted_operand); |
| 16024 | } | 16258 | } |
| 16025 | 16259 | ||
| 16026 | fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 16260 | fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 16027 | const mod = sema.mod; | 16261 | const mod = sema.mod; |
| 16028 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 16262 | const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small); |
| 16029 | const src = inst_data.src(); | 16263 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 16264 | const src = LazySrcLoc.nodeOffset(extra.node); | ||
| 16030 | const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type"); | 16265 | const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type"); |
| 16031 | const uncasted_operand = try sema.resolveInst(inst_data.operand); | 16266 | const uncasted_operand = try sema.resolveInst(extra.operand); |
| 16032 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 16267 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 16033 | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); | 16268 | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); |
| 16034 | const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known"); | 16269 | const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known"); |
| 16035 | const union_val = val.cast(Value.Payload.Union).?.data; | 16270 | const union_val = val.cast(Value.Payload.Union).?.data; |
| ... | @@ -16109,7 +16344,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -16109,7 +16344,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 16109 | if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { | 16344 | if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) { |
| 16110 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | 16345 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); |
| 16111 | } | 16346 | } |
| 16112 | const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target)); | 16347 | const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?); |
| 16113 | 16348 | ||
| 16114 | var buffer: Value.ToTypeBuffer = undefined; | 16349 | var buffer: Value.ToTypeBuffer = undefined; |
| 16115 | const unresolved_elem_ty = child_val.toType(&buffer); | 16350 | const unresolved_elem_ty = child_val.toType(&buffer); |
| ... | @@ -16274,22 +16509,31 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -16274,22 +16509,31 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 16274 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 16509 | const struct_val = union_val.val.castTag(.aggregate).?.data; |
| 16275 | // layout: containerlayout, | 16510 | // layout: containerlayout, |
| 16276 | const layout_val = struct_val[0]; | 16511 | const layout_val = struct_val[0]; |
| 16512 | // backing_int: ?type, | ||
| 16513 | const backing_int_val = struct_val[1]; | ||
| 16277 | // fields: []const enumfield, | 16514 | // fields: []const enumfield, |
| 16278 | const fields_val = struct_val[1]; | 16515 | const fields_val = struct_val[2]; |
| 16279 | // decls: []const declaration, | 16516 | // decls: []const declaration, |
| 16280 | const decls_val = struct_val[2]; | 16517 | const decls_val = struct_val[3]; |
| 16281 | // is_tuple: bool, | 16518 | // is_tuple: bool, |
| 16282 | const is_tuple_val = struct_val[3]; | 16519 | const is_tuple_val = struct_val[4]; |
| 16520 | assert(struct_val.len == 5); | ||
| 16521 | |||
| 16522 | const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); | ||
| 16283 | 16523 | ||
| 16284 | // Decls | 16524 | // Decls |
| 16285 | if (decls_val.sliceLen(mod) > 0) { | 16525 | if (decls_val.sliceLen(mod) > 0) { |
| 16286 | return sema.fail(block, src, "reified structs must have no decls", .{}); | 16526 | return sema.fail(block, src, "reified structs must have no decls", .{}); |
| 16287 | } | 16527 | } |
| 16288 | 16528 | ||
| 16529 | if (layout != .Packed and !backing_int_val.isNull()) { | ||
| 16530 | return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); | ||
| 16531 | } | ||
| 16532 | |||
| 16289 | return if (is_tuple_val.toBool()) | 16533 | return if (is_tuple_val.toBool()) |
| 16290 | try sema.reifyTuple(block, src, fields_val) | 16534 | try sema.reifyTuple(block, src, fields_val) |
| 16291 | else | 16535 | else |
| 16292 | try sema.reifyStruct(block, inst, src, layout_val, fields_val); | 16536 | try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy); |
| 16293 | }, | 16537 | }, |
| 16294 | .Enum => { | 16538 | .Enum => { |
| 16295 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 16539 | const struct_val = union_val.val.castTag(.aggregate).?.data; |
| ... | @@ -16335,10 +16579,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -16335,10 +16579,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 16335 | }; | 16579 | }; |
| 16336 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | 16580 | const enum_ty = Type.initPayload(&enum_ty_payload.base); |
| 16337 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | 16581 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); |
| 16338 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 16582 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 16339 | .ty = Type.type, | 16583 | .ty = Type.type, |
| 16340 | .val = enum_val, | 16584 | .val = enum_val, |
| 16341 | }, .anon, "enum", null); | 16585 | }, name_strategy, "enum", inst); |
| 16342 | const new_decl = mod.declPtr(new_decl_index); | 16586 | const new_decl = mod.declPtr(new_decl_index); |
| 16343 | new_decl.owns_tv = true; | 16587 | new_decl.owns_tv = true; |
| 16344 | errdefer mod.abortAnonDecl(new_decl_index); | 16588 | errdefer mod.abortAnonDecl(new_decl_index); |
| ... | @@ -16349,7 +16593,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -16349,7 +16593,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 16349 | .tag_ty_inferred = false, | 16593 | .tag_ty_inferred = false, |
| 16350 | .fields = .{}, | 16594 | .fields = .{}, |
| 16351 | .values = .{}, | 16595 | .values = .{}, |
| 16352 | .node_offset = src.node_offset.x, | ||
| 16353 | .namespace = .{ | 16596 | .namespace = .{ |
| 16354 | .parent = block.namespace, | 16597 | .parent = block.namespace, |
| 16355 | .ty = enum_ty, | 16598 | .ty = enum_ty, |
| ... | @@ -16432,17 +16675,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -16432,17 +16675,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 16432 | }; | 16675 | }; |
| 16433 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); | 16676 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); |
| 16434 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); | 16677 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); |
| 16435 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 16678 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 16436 | .ty = Type.type, | 16679 | .ty = Type.type, |
| 16437 | .val = opaque_val, | 16680 | .val = opaque_val, |
| 16438 | }, .anon, "opaque", null); | 16681 | }, name_strategy, "opaque", inst); |
| 16439 | const new_decl = mod.declPtr(new_decl_index); | 16682 | const new_decl = mod.declPtr(new_decl_index); |
| 16440 | new_decl.owns_tv = true; | 16683 | new_decl.owns_tv = true; |
| 16441 | errdefer mod.abortAnonDecl(new_decl_index); | 16684 | errdefer mod.abortAnonDecl(new_decl_index); |
| 16442 | 16685 | ||
| 16443 | opaque_obj.* = .{ | 16686 | opaque_obj.* = .{ |
| 16444 | .owner_decl = new_decl_index, | 16687 | .owner_decl = new_decl_index, |
| 16445 | .node_offset = src.node_offset.x, | ||
| 16446 | .namespace = .{ | 16688 | .namespace = .{ |
| 16447 | .parent = block.namespace, | 16689 | .parent = block.namespace, |
| 16448 | .ty = opaque_ty, | 16690 | .ty = opaque_ty, |
| ... | @@ -16491,10 +16733,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -16491,10 +16733,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 16491 | }; | 16733 | }; |
| 16492 | const union_ty = Type.initPayload(&union_payload.base); | 16734 | const union_ty = Type.initPayload(&union_payload.base); |
| 16493 | const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); | 16735 | const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); |
| 16494 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 16736 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 16495 | .ty = Type.type, | 16737 | .ty = Type.type, |
| 16496 | .val = new_union_val, | 16738 | .val = new_union_val, |
| 16497 | }, .anon, "union", null); | 16739 | }, name_strategy, "union", inst); |
| 16498 | const new_decl = mod.declPtr(new_decl_index); | 16740 | const new_decl = mod.declPtr(new_decl_index); |
| 16499 | new_decl.owns_tv = true; | 16741 | new_decl.owns_tv = true; |
| 16500 | errdefer mod.abortAnonDecl(new_decl_index); | 16742 | errdefer mod.abortAnonDecl(new_decl_index); |
| ... | @@ -16502,7 +16744,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -16502,7 +16744,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 16502 | .owner_decl = new_decl_index, | 16744 | .owner_decl = new_decl_index, |
| 16503 | .tag_ty = Type.initTag(.@"null"), | 16745 | .tag_ty = Type.initTag(.@"null"), |
| 16504 | .fields = .{}, | 16746 | .fields = .{}, |
| 16505 | .node_offset = src.node_offset.x, | ||
| 16506 | .zir_index = inst, | 16747 | .zir_index = inst, |
| 16507 | .layout = layout, | 16748 | .layout = layout, |
| 16508 | .status = .have_field_types, | 16749 | .status = .have_field_types, |
| ... | @@ -16785,8 +17026,10 @@ fn reifyStruct( | ... | @@ -16785,8 +17026,10 @@ fn reifyStruct( |
| 16785 | block: *Block, | 17026 | block: *Block, |
| 16786 | inst: Zir.Inst.Index, | 17027 | inst: Zir.Inst.Index, |
| 16787 | src: LazySrcLoc, | 17028 | src: LazySrcLoc, |
| 16788 | layout_val: Value, | 17029 | layout: std.builtin.Type.ContainerLayout, |
| 17030 | backing_int_val: Value, | ||
| 16789 | fields_val: Value, | 17031 | fields_val: Value, |
| 17032 | name_strategy: Zir.Inst.NameStrategy, | ||
| 16790 | ) CompileError!Air.Inst.Ref { | 17033 | ) CompileError!Air.Inst.Ref { |
| 16791 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 17034 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| 16792 | errdefer new_decl_arena.deinit(); | 17035 | errdefer new_decl_arena.deinit(); |
| ... | @@ -16796,19 +17039,18 @@ fn reifyStruct( | ... | @@ -16796,19 +17039,18 @@ fn reifyStruct( |
| 16796 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | 17039 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); |
| 16797 | const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | 17040 | const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); |
| 16798 | const mod = sema.mod; | 17041 | const mod = sema.mod; |
| 16799 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{ | 17042 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 16800 | .ty = Type.type, | 17043 | .ty = Type.type, |
| 16801 | .val = new_struct_val, | 17044 | .val = new_struct_val, |
| 16802 | }, .anon, "struct", null); | 17045 | }, name_strategy, "struct", inst); |
| 16803 | const new_decl = mod.declPtr(new_decl_index); | 17046 | const new_decl = mod.declPtr(new_decl_index); |
| 16804 | new_decl.owns_tv = true; | 17047 | new_decl.owns_tv = true; |
| 16805 | errdefer mod.abortAnonDecl(new_decl_index); | 17048 | errdefer mod.abortAnonDecl(new_decl_index); |
| 16806 | struct_obj.* = .{ | 17049 | struct_obj.* = .{ |
| 16807 | .owner_decl = new_decl_index, | 17050 | .owner_decl = new_decl_index, |
| 16808 | .fields = .{}, | 17051 | .fields = .{}, |
| 16809 | .node_offset = src.node_offset.x, | ||
| 16810 | .zir_index = inst, | 17052 | .zir_index = inst, |
| 16811 | .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout), | 17053 | .layout = layout, |
| 16812 | .status = .have_field_types, | 17054 | .status = .have_field_types, |
| 16813 | .known_non_opv = false, | 17055 | .known_non_opv = false, |
| 16814 | .namespace = .{ | 17056 | .namespace = .{ |
| ... | @@ -16874,6 +17116,41 @@ fn reifyStruct( | ... | @@ -16874,6 +17116,41 @@ fn reifyStruct( |
| 16874 | }; | 17116 | }; |
| 16875 | } | 17117 | } |
| 16876 | 17118 | ||
| 17119 | if (layout == .Packed) { | ||
| 17120 | struct_obj.status = .layout_wip; | ||
| 17121 | |||
| 17122 | for (struct_obj.fields.values()) |field, index| { | ||
| 17123 | sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) { | ||
| 17124 | error.AnalysisFail => { | ||
| 17125 | const msg = sema.err orelse return err; | ||
| 17126 | try sema.addFieldErrNote(block, struct_ty, index, msg, "while checking this field", .{}); | ||
| 17127 | return err; | ||
| 17128 | }, | ||
| 17129 | else => return err, | ||
| 17130 | }; | ||
| 17131 | } | ||
| 17132 | |||
| 17133 | var fields_bit_sum: u64 = 0; | ||
| 17134 | for (struct_obj.fields.values()) |field| { | ||
| 17135 | fields_bit_sum += field.ty.bitSize(target); | ||
| 17136 | } | ||
| 17137 | |||
| 17138 | if (backing_int_val.optionalValue()) |payload| { | ||
| 17139 | var buf: Value.ToTypeBuffer = undefined; | ||
| 17140 | const backing_int_ty = payload.toType(&buf); | ||
| 17141 | try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); | ||
| 17142 | struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator); | ||
| 17143 | } else { | ||
| 17144 | var buf: Type.Payload.Bits = .{ | ||
| 17145 | .base = .{ .tag = .int_unsigned }, | ||
| 17146 | .data = @intCast(u16, fields_bit_sum), | ||
| 17147 | }; | ||
| 17148 | struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(new_decl_arena_allocator); | ||
| 17149 | } | ||
| 17150 | |||
| 17151 | struct_obj.status = .have_layout; | ||
| 17152 | } | ||
| 17153 | |||
| 16877 | try new_decl.finalizeNewArena(&new_decl_arena); | 17154 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 16878 | return sema.analyzeDeclVal(block, src, new_decl_index); | 17155 | return sema.analyzeDeclVal(block, src, new_decl_index); |
| 16879 | } | 17156 | } |
| ... | @@ -17095,17 +17372,10 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -17095,17 +17372,10 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 17095 | } | 17372 | } |
| 17096 | 17373 | ||
| 17097 | try sema.requireRuntimeBlock(block, src, operand_src); | 17374 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 17098 | if (block.wantSafety() and !dest_ty.isAnyError()) { | 17375 | if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) { |
| 17099 | const err_int_inst = try block.addBitCast(Type.u16, operand); | 17376 | const err_int_inst = try block.addBitCast(Type.err_int, operand); |
| 17100 | // TODO: Output a switch instead of chained OR's. | 17377 | const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); |
| 17101 | var found_match: Air.Inst.Ref = undefined; | 17378 | try sema.addSafetyCheck(block, ok, .invalid_error_code); |
| 17102 | for (dest_ty.errorSetNames()) |dest_err_name, i| { | ||
| 17103 | const dest_err_int = (try sema.mod.getErrorValue(dest_err_name)).value; | ||
| 17104 | const dest_err_int_inst = try sema.addIntUnsigned(Type.u16, dest_err_int); | ||
| 17105 | const next_match = try block.addBinOp(.cmp_eq, dest_err_int_inst, err_int_inst); | ||
| 17106 | found_match = if (i == 0) next_match else try block.addBinOp(.bool_or, found_match, next_match); | ||
| 17107 | } | ||
| 17108 | try sema.addSafetyCheck(block, found_match, .invalid_error_code); | ||
| 17109 | } | 17379 | } |
| 17110 | return block.addBitCast(dest_ty, operand); | 17380 | return block.addBitCast(dest_ty, operand); |
| 17111 | } | 17381 | } |
| ... | @@ -17133,6 +17403,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -17133,6 +17403,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 17133 | else | 17403 | else |
| 17134 | operand; | 17404 | operand; |
| 17135 | 17405 | ||
| 17406 | if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| { | ||
| 17407 | if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) { | ||
| 17408 | return sema.failWithUseOfUndef(block, operand_src); | ||
| 17409 | } | ||
| 17410 | if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) { | ||
| 17411 | return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)}); | ||
| 17412 | } | ||
| 17413 | } | ||
| 17414 | |||
| 17136 | const dest_elem_ty = dest_ty.elemType2(); | 17415 | const dest_elem_ty = dest_ty.elemType2(); |
| 17137 | try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty); | 17416 | try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty); |
| 17138 | const dest_align = dest_ty.ptrAlignment(target); | 17417 | const dest_align = dest_ty.ptrAlignment(target); |
| ... | @@ -23464,7 +23743,10 @@ fn coerceVarArgParam( | ... | @@ -23464,7 +23743,10 @@ fn coerceVarArgParam( |
| 23464 | inst_src: LazySrcLoc, | 23743 | inst_src: LazySrcLoc, |
| 23465 | ) !Air.Inst.Ref { | 23744 | ) !Air.Inst.Ref { |
| 23466 | const inst_ty = sema.typeOf(inst); | 23745 | const inst_ty = sema.typeOf(inst); |
| 23746 | if (block.is_typeof) return inst; | ||
| 23747 | |||
| 23467 | switch (inst_ty.zigTypeTag()) { | 23748 | switch (inst_ty.zigTypeTag()) { |
| 23749 | // TODO consider casting to c_int/f64 if they fit | ||
| 23468 | .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}), | 23750 | .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}), |
| 23469 | else => {}, | 23751 | else => {}, |
| 23470 | } | 23752 | } |
| ... | @@ -23846,7 +24128,10 @@ fn beginComptimePtrMutation( | ... | @@ -23846,7 +24128,10 @@ fn beginComptimePtrMutation( |
| 23846 | const array_len_including_sentinel = | 24128 | const array_len_including_sentinel = |
| 23847 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); | 24129 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); |
| 23848 | const elems = try arena.alloc(Value, array_len_including_sentinel); | 24130 | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 23849 | mem.set(Value, elems, repeated_val); | 24131 | if (elems.len > 0) elems[0] = repeated_val; |
| 24132 | for (elems[1..]) |*elem| { | ||
| 24133 | elem.* = try repeated_val.copy(arena); | ||
| 24134 | } | ||
| 23850 | 24135 | ||
| 23851 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | 24136 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 23852 | 24137 | ||
| ... | @@ -25423,6 +25708,27 @@ fn analyzeIsNull( | ... | @@ -25423,6 +25708,27 @@ fn analyzeIsNull( |
| 25423 | return block.addUnOp(air_tag, operand); | 25708 | return block.addUnOp(air_tag, operand); |
| 25424 | } | 25709 | } |
| 25425 | 25710 | ||
| 25711 | fn analyzePtrIsNonErrComptimeOnly( | ||
| 25712 | sema: *Sema, | ||
| 25713 | block: *Block, | ||
| 25714 | src: LazySrcLoc, | ||
| 25715 | operand: Air.Inst.Ref, | ||
| 25716 | ) CompileError!Air.Inst.Ref { | ||
| 25717 | const ptr_ty = sema.typeOf(operand); | ||
| 25718 | assert(ptr_ty.zigTypeTag() == .Pointer); | ||
| 25719 | const child_ty = ptr_ty.childType(); | ||
| 25720 | |||
| 25721 | const child_tag = child_ty.zigTypeTag(); | ||
| 25722 | if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; | ||
| 25723 | if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; | ||
| 25724 | assert(child_tag == .ErrorUnion); | ||
| 25725 | |||
| 25726 | _ = block; | ||
| 25727 | _ = src; | ||
| 25728 | |||
| 25729 | return Air.Inst.Ref.none; | ||
| 25730 | } | ||
| 25731 | |||
| 25426 | fn analyzeIsNonErrComptimeOnly( | 25732 | fn analyzeIsNonErrComptimeOnly( |
| 25427 | sema: *Sema, | 25733 | sema: *Sema, |
| 25428 | block: *Block, | 25734 | block: *Block, |
| ... | @@ -25436,10 +25742,16 @@ fn analyzeIsNonErrComptimeOnly( | ... | @@ -25436,10 +25742,16 @@ fn analyzeIsNonErrComptimeOnly( |
| 25436 | assert(ot == .ErrorUnion); | 25742 | assert(ot == .ErrorUnion); |
| 25437 | 25743 | ||
| 25438 | if (Air.refToIndex(operand)) |operand_inst| { | 25744 | if (Air.refToIndex(operand)) |operand_inst| { |
| 25439 | const air_tags = sema.air_instructions.items(.tag); | 25745 | switch (sema.air_instructions.items(.tag)[operand_inst]) { |
| 25440 | if (air_tags[operand_inst] == .wrap_errunion_payload) { | 25746 | .wrap_errunion_payload => return Air.Inst.Ref.bool_true, |
| 25441 | return Air.Inst.Ref.bool_true; | 25747 | .wrap_errunion_err => return Air.Inst.Ref.bool_false, |
| 25748 | else => {}, | ||
| 25442 | } | 25749 | } |
| 25750 | } else if (operand == .undef) { | ||
| 25751 | return sema.addConstUndef(Type.bool); | ||
| 25752 | } else { | ||
| 25753 | // None of the ref tags can be errors. | ||
| 25754 | return Air.Inst.Ref.bool_true; | ||
| 25443 | } | 25755 | } |
| 25444 | 25756 | ||
| 25445 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand); | 25757 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand); |
| ... | @@ -25515,6 +25827,21 @@ fn analyzeIsNonErr( | ... | @@ -25515,6 +25827,21 @@ fn analyzeIsNonErr( |
| 25515 | } | 25827 | } |
| 25516 | } | 25828 | } |
| 25517 | 25829 | ||
| 25830 | fn analyzePtrIsNonErr( | ||
| 25831 | sema: *Sema, | ||
| 25832 | block: *Block, | ||
| 25833 | src: LazySrcLoc, | ||
| 25834 | operand: Air.Inst.Ref, | ||
| 25835 | ) CompileError!Air.Inst.Ref { | ||
| 25836 | const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand); | ||
| 25837 | if (result == .none) { | ||
| 25838 | try sema.requireRuntimeBlock(block, src, null); | ||
| 25839 | return block.addUnOp(.is_non_err_ptr, operand); | ||
| 25840 | } else { | ||
| 25841 | return result; | ||
| 25842 | } | ||
| 25843 | } | ||
| 25844 | |||
| 25518 | fn analyzeSlice( | 25845 | fn analyzeSlice( |
| 25519 | sema: *Sema, | 25846 | sema: *Sema, |
| 25520 | block: *Block, | 25847 | block: *Block, |
| ... | @@ -26913,6 +27240,11 @@ fn resolveStructLayout( | ... | @@ -26913,6 +27240,11 @@ fn resolveStructLayout( |
| 26913 | else => return err, | 27240 | else => return err, |
| 26914 | }; | 27241 | }; |
| 26915 | } | 27242 | } |
| 27243 | |||
| 27244 | if (struct_obj.layout == .Packed) { | ||
| 27245 | try semaBackingIntType(sema.mod, struct_obj); | ||
| 27246 | } | ||
| 27247 | |||
| 26916 | struct_obj.status = .have_layout; | 27248 | struct_obj.status = .have_layout; |
| 26917 | 27249 | ||
| 26918 | // In case of querying the ABI alignment of this struct, we will ask | 27250 | // In case of querying the ABI alignment of this struct, we will ask |
| ... | @@ -26932,6 +27264,109 @@ fn resolveStructLayout( | ... | @@ -26932,6 +27264,109 @@ fn resolveStructLayout( |
| 26932 | // otherwise it's a tuple; no need to resolve anything | 27264 | // otherwise it's a tuple; no need to resolve anything |
| 26933 | } | 27265 | } |
| 26934 | 27266 | ||
| 27267 | fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { | ||
| 27268 | const gpa = mod.gpa; | ||
| 27269 | const target = mod.getTarget(); | ||
| 27270 | |||
| 27271 | var fields_bit_sum: u64 = 0; | ||
| 27272 | for (struct_obj.fields.values()) |field| { | ||
| 27273 | fields_bit_sum += field.ty.bitSize(target); | ||
| 27274 | } | ||
| 27275 | |||
| 27276 | const decl_index = struct_obj.owner_decl; | ||
| 27277 | const decl = mod.declPtr(decl_index); | ||
| 27278 | var decl_arena = decl.value_arena.?.promote(gpa); | ||
| 27279 | defer decl.value_arena.?.* = decl_arena.state; | ||
| 27280 | const decl_arena_allocator = decl_arena.allocator(); | ||
| 27281 | |||
| 27282 | const zir = struct_obj.namespace.file_scope.zir; | ||
| 27283 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | ||
| 27284 | assert(extended.opcode == .struct_decl); | ||
| 27285 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | ||
| 27286 | |||
| 27287 | if (small.has_backing_int) { | ||
| 27288 | var extra_index: usize = extended.operand; | ||
| 27289 | extra_index += @boolToInt(small.has_src_node); | ||
| 27290 | extra_index += @boolToInt(small.has_fields_len); | ||
| 27291 | extra_index += @boolToInt(small.has_decls_len); | ||
| 27292 | |||
| 27293 | const backing_int_body_len = zir.extra[extra_index]; | ||
| 27294 | extra_index += 1; | ||
| 27295 | |||
| 27296 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 27297 | defer analysis_arena.deinit(); | ||
| 27298 | |||
| 27299 | var sema: Sema = .{ | ||
| 27300 | .mod = mod, | ||
| 27301 | .gpa = gpa, | ||
| 27302 | .arena = analysis_arena.allocator(), | ||
| 27303 | .perm_arena = decl_arena_allocator, | ||
| 27304 | .code = zir, | ||
| 27305 | .owner_decl = decl, | ||
| 27306 | .owner_decl_index = decl_index, | ||
| 27307 | .func = null, | ||
| 27308 | .fn_ret_ty = Type.void, | ||
| 27309 | .owner_func = null, | ||
| 27310 | }; | ||
| 27311 | defer sema.deinit(); | ||
| 27312 | |||
| 27313 | var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); | ||
| 27314 | defer wip_captures.deinit(); | ||
| 27315 | |||
| 27316 | var block: Block = .{ | ||
| 27317 | .parent = null, | ||
| 27318 | .sema = &sema, | ||
| 27319 | .src_decl = decl_index, | ||
| 27320 | .namespace = &struct_obj.namespace, | ||
| 27321 | .wip_capture_scope = wip_captures.scope, | ||
| 27322 | .instructions = .{}, | ||
| 27323 | .inlining = null, | ||
| 27324 | .is_comptime = true, | ||
| 27325 | }; | ||
| 27326 | defer { | ||
| 27327 | assert(block.instructions.items.len == 0); | ||
| 27328 | block.params.deinit(gpa); | ||
| 27329 | } | ||
| 27330 | |||
| 27331 | const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 }; | ||
| 27332 | const backing_int_ty = blk: { | ||
| 27333 | if (backing_int_body_len == 0) { | ||
| 27334 | const backing_int_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | ||
| 27335 | break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref); | ||
| 27336 | } else { | ||
| 27337 | const body = zir.extra[extra_index..][0..backing_int_body_len]; | ||
| 27338 | const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index); | ||
| 27339 | break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref); | ||
| 27340 | } | ||
| 27341 | }; | ||
| 27342 | |||
| 27343 | try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); | ||
| 27344 | struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator); | ||
| 27345 | } else { | ||
| 27346 | var buf: Type.Payload.Bits = .{ | ||
| 27347 | .base = .{ .tag = .int_unsigned }, | ||
| 27348 | .data = @intCast(u16, fields_bit_sum), | ||
| 27349 | }; | ||
| 27350 | struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(decl_arena_allocator); | ||
| 27351 | } | ||
| 27352 | } | ||
| 27353 | |||
| 27354 | fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { | ||
| 27355 | const target = sema.mod.getTarget(); | ||
| 27356 | |||
| 27357 | if (!backing_int_ty.isInt()) { | ||
| 27358 | return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)}); | ||
| 27359 | } | ||
| 27360 | if (backing_int_ty.bitSize(target) != fields_bit_sum) { | ||
| 27361 | return sema.fail( | ||
| 27362 | block, | ||
| 27363 | src, | ||
| 27364 | "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}", | ||
| 27365 | .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(target), fields_bit_sum }, | ||
| 27366 | ); | ||
| 27367 | } | ||
| 27368 | } | ||
| 27369 | |||
| 26935 | fn resolveUnionLayout( | 27370 | fn resolveUnionLayout( |
| 26936 | sema: *Sema, | 27371 | sema: *Sema, |
| 26937 | block: *Block, | 27372 | block: *Block, |
| ... | @@ -27239,7 +27674,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -27239,7 +27674,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27239 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | 27674 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| 27240 | var extra_index: usize = extended.operand; | 27675 | var extra_index: usize = extended.operand; |
| 27241 | 27676 | ||
| 27242 | const src = LazySrcLoc.nodeOffset(struct_obj.node_offset); | 27677 | const src = LazySrcLoc.nodeOffset(0); |
| 27243 | extra_index += @boolToInt(small.has_src_node); | 27678 | extra_index += @boolToInt(small.has_src_node); |
| 27244 | 27679 | ||
| 27245 | const fields_len = if (small.has_fields_len) blk: { | 27680 | const fields_len = if (small.has_fields_len) blk: { |
| ... | @@ -27254,12 +27689,26 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -27254,12 +27689,26 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27254 | break :decls_len decls_len; | 27689 | break :decls_len decls_len; |
| 27255 | } else 0; | 27690 | } else 0; |
| 27256 | 27691 | ||
| 27692 | // The backing integer cannot be handled until `resolveStructLayout()`. | ||
| 27693 | if (small.has_backing_int) { | ||
| 27694 | const backing_int_body_len = zir.extra[extra_index]; | ||
| 27695 | extra_index += 1; // backing_int_body_len | ||
| 27696 | if (backing_int_body_len == 0) { | ||
| 27697 | extra_index += 1; // backing_int_ref | ||
| 27698 | } else { | ||
| 27699 | extra_index += backing_int_body_len; // backing_int_body_inst | ||
| 27700 | } | ||
| 27701 | } | ||
| 27702 | |||
| 27257 | // Skip over decls. | 27703 | // Skip over decls. |
| 27258 | var decls_it = zir.declIteratorInner(extra_index, decls_len); | 27704 | var decls_it = zir.declIteratorInner(extra_index, decls_len); |
| 27259 | while (decls_it.next()) |_| {} | 27705 | while (decls_it.next()) |_| {} |
| 27260 | extra_index = decls_it.extra_index; | 27706 | extra_index = decls_it.extra_index; |
| 27261 | 27707 | ||
| 27262 | if (fields_len == 0) { | 27708 | if (fields_len == 0) { |
| 27709 | if (struct_obj.layout == .Packed) { | ||
| 27710 | try semaBackingIntType(mod, struct_obj); | ||
| 27711 | } | ||
| 27263 | struct_obj.status = .have_layout; | 27712 | struct_obj.status = .have_layout; |
| 27264 | return; | 27713 | return; |
| 27265 | } | 27714 | } |
| ... | @@ -27358,12 +27807,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -27358,12 +27807,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27358 | if (gop.found_existing) { | 27807 | if (gop.found_existing) { |
| 27359 | const msg = msg: { | 27808 | const msg = msg: { |
| 27360 | const tree = try sema.getAstTree(&block_scope); | 27809 | const tree = try sema.getAstTree(&block_scope); |
| 27361 | const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, field_i); | 27810 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| 27362 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); | 27811 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); |
| 27363 | errdefer msg.destroy(gpa); | 27812 | errdefer msg.destroy(gpa); |
| 27364 | 27813 | ||
| 27365 | const prev_field_index = struct_obj.fields.getIndex(field_name).?; | 27814 | const prev_field_index = struct_obj.fields.getIndex(field_name).?; |
| 27366 | const prev_field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, prev_field_index); | 27815 | const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index); |
| 27367 | try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); | 27816 | try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); |
| 27368 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); | 27817 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); |
| 27369 | break :msg msg; | 27818 | break :msg msg; |
| ... | @@ -27420,7 +27869,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -27420,7 +27869,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27420 | if (field_ty.zigTypeTag() == .Opaque) { | 27869 | if (field_ty.zigTypeTag() == .Opaque) { |
| 27421 | const msg = msg: { | 27870 | const msg = msg: { |
| 27422 | const tree = try sema.getAstTree(&block_scope); | 27871 | const tree = try sema.getAstTree(&block_scope); |
| 27423 | const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i); | 27872 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| 27424 | const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | 27873 | const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 27425 | errdefer msg.destroy(sema.gpa); | 27874 | errdefer msg.destroy(sema.gpa); |
| 27426 | 27875 | ||
| ... | @@ -27432,7 +27881,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -27432,7 +27881,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27432 | if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) { | 27881 | if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) { |
| 27433 | const msg = msg: { | 27882 | const msg = msg: { |
| 27434 | const tree = try sema.getAstTree(&block_scope); | 27883 | const tree = try sema.getAstTree(&block_scope); |
| 27435 | const fields_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i); | 27884 | const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| 27436 | const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); | 27885 | const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); |
| 27437 | errdefer msg.destroy(sema.gpa); | 27886 | errdefer msg.destroy(sema.gpa); |
| 27438 | 27887 | ||
| ... | @@ -27445,7 +27894,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -27445,7 +27894,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 27445 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) { | 27894 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) { |
| 27446 | const msg = msg: { | 27895 | const msg = msg: { |
| 27447 | const tree = try sema.getAstTree(&block_scope); | 27896 | const tree = try sema.getAstTree(&block_scope); |
| 27448 | const fields_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i); | 27897 | const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| 27449 | const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); | 27898 | const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); |
| 27450 | errdefer msg.destroy(sema.gpa); | 27899 | errdefer msg.destroy(sema.gpa); |
| 27451 | 27900 | ||
| ... | @@ -27502,7 +27951,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -27502,7 +27951,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 27502 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); | 27951 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); |
| 27503 | var extra_index: usize = extended.operand; | 27952 | var extra_index: usize = extended.operand; |
| 27504 | 27953 | ||
| 27505 | const src = LazySrcLoc.nodeOffset(union_obj.node_offset); | 27954 | const src = LazySrcLoc.nodeOffset(0); |
| 27506 | extra_index += @boolToInt(small.has_src_node); | 27955 | extra_index += @boolToInt(small.has_src_node); |
| 27507 | 27956 | ||
| 27508 | const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: { | 27957 | const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: { |
| ... | @@ -27726,12 +28175,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -27726,12 +28175,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 27726 | if (gop.found_existing) { | 28175 | if (gop.found_existing) { |
| 27727 | const msg = msg: { | 28176 | const msg = msg: { |
| 27728 | const tree = try sema.getAstTree(&block_scope); | 28177 | const tree = try sema.getAstTree(&block_scope); |
| 27729 | const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i); | 28178 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| 27730 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); | 28179 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); |
| 27731 | errdefer msg.destroy(gpa); | 28180 | errdefer msg.destroy(gpa); |
| 27732 | 28181 | ||
| 27733 | const prev_field_index = union_obj.fields.getIndex(field_name).?; | 28182 | const prev_field_index = union_obj.fields.getIndex(field_name).?; |
| 27734 | const prev_field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, prev_field_index); | 28183 | const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index); |
| 27735 | try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); | 28184 | try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); |
| 27736 | try sema.errNote(&block_scope, src, msg, "union declared here", .{}); | 28185 | try sema.errNote(&block_scope, src, msg, "union declared here", .{}); |
| 27737 | break :msg msg; | 28186 | break :msg msg; |
| ... | @@ -27744,7 +28193,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -27744,7 +28193,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 27744 | if (!enum_has_field) { | 28193 | if (!enum_has_field) { |
| 27745 | const msg = msg: { | 28194 | const msg = msg: { |
| 27746 | const tree = try sema.getAstTree(&block_scope); | 28195 | const tree = try sema.getAstTree(&block_scope); |
| 27747 | const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i); | 28196 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| 27748 | const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); | 28197 | const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); |
| 27749 | errdefer msg.destroy(sema.gpa); | 28198 | errdefer msg.destroy(sema.gpa); |
| 27750 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); | 28199 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| ... | @@ -27757,7 +28206,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -27757,7 +28206,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 27757 | if (field_ty.zigTypeTag() == .Opaque) { | 28206 | if (field_ty.zigTypeTag() == .Opaque) { |
| 27758 | const msg = msg: { | 28207 | const msg = msg: { |
| 27759 | const tree = try sema.getAstTree(&block_scope); | 28208 | const tree = try sema.getAstTree(&block_scope); |
| 27760 | const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i); | 28209 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| 27761 | const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); | 28210 | const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); |
| 27762 | errdefer msg.destroy(sema.gpa); | 28211 | errdefer msg.destroy(sema.gpa); |
| 27763 | 28212 | ||
| ... | @@ -27769,7 +28218,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -27769,7 +28218,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 27769 | if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) { | 28218 | if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) { |
| 27770 | const msg = msg: { | 28219 | const msg = msg: { |
| 27771 | const tree = try sema.getAstTree(&block_scope); | 28220 | const tree = try sema.getAstTree(&block_scope); |
| 27772 | const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i); | 28221 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| 27773 | const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 28222 | const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 27774 | errdefer msg.destroy(sema.gpa); | 28223 | errdefer msg.destroy(sema.gpa); |
| 27775 | 28224 | ||
| ... | @@ -27782,7 +28231,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -27782,7 +28231,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 27782 | } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) { | 28231 | } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) { |
| 27783 | const msg = msg: { | 28232 | const msg = msg: { |
| 27784 | const tree = try sema.getAstTree(&block_scope); | 28233 | const tree = try sema.getAstTree(&block_scope); |
| 27785 | const fields_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i); | 28234 | const fields_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| 27786 | const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 28235 | const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 27787 | errdefer msg.destroy(sema.gpa); | 28236 | errdefer msg.destroy(sema.gpa); |
| 27788 | 28237 | ||
| ... | @@ -27874,7 +28323,6 @@ fn generateUnionTagTypeNumbered( | ... | @@ -27874,7 +28323,6 @@ fn generateUnionTagTypeNumbered( |
| 27874 | .tag_ty = int_ty, | 28323 | .tag_ty = int_ty, |
| 27875 | .fields = .{}, | 28324 | .fields = .{}, |
| 27876 | .values = .{}, | 28325 | .values = .{}, |
| 27877 | .node_offset = 0, | ||
| 27878 | }; | 28326 | }; |
| 27879 | // Here we pre-allocate the maps using the decl arena. | 28327 | // Here we pre-allocate the maps using the decl arena. |
| 27880 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | 28328 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| ... | @@ -27932,7 +28380,6 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, may | ... | @@ -27932,7 +28380,6 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, may |
| 27932 | enum_obj.* = .{ | 28380 | enum_obj.* = .{ |
| 27933 | .owner_decl = new_decl_index, | 28381 | .owner_decl = new_decl_index, |
| 27934 | .fields = .{}, | 28382 | .fields = .{}, |
| 27935 | .node_offset = 0, | ||
| 27936 | }; | 28383 | }; |
| 27937 | // Here we pre-allocate the maps using the decl arena. | 28384 | // Here we pre-allocate the maps using the decl arena. |
| 27938 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | 28385 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| ... | @@ -28243,7 +28690,7 @@ fn enumFieldSrcLoc( | ... | @@ -28243,7 +28690,7 @@ fn enumFieldSrcLoc( |
| 28243 | => tree.containerDeclArg(enum_node), | 28690 | => tree.containerDeclArg(enum_node), |
| 28244 | 28691 | ||
| 28245 | // Container was constructed with `@Type`. | 28692 | // Container was constructed with `@Type`. |
| 28246 | else => return LazySrcLoc.nodeOffset(node_offset), | 28693 | else => return LazySrcLoc.nodeOffset(0), |
| 28247 | }; | 28694 | }; |
| 28248 | var it_index: usize = 0; | 28695 | var it_index: usize = 0; |
| 28249 | for (container_decl.ast.members) |member_node| { | 28696 | for (container_decl.ast.members) |member_node| { |
src/Zir.zig+27-28| ... | @@ -490,14 +490,6 @@ pub const Inst = struct { | ... | @@ -490,14 +490,6 @@ pub const Inst = struct { |
| 490 | /// Merge two error sets into one, `E1 || E2`. | 490 | /// Merge two error sets into one, `E1 || E2`. |
| 491 | /// Uses the `pl_node` field with payload `Bin`. | 491 | /// Uses the `pl_node` field with payload `Bin`. |
| 492 | merge_error_sets, | 492 | merge_error_sets, |
| 493 | /// Given a reference to a function and a parameter index, returns the | ||
| 494 | /// type of the parameter. The only usage of this instruction is for the | ||
| 495 | /// result location of parameters of function calls. In the case of a function's | ||
| 496 | /// parameter type being `anytype`, it is the type coercion's job to detect this | ||
| 497 | /// scenario and skip the coercion, so that semantic analysis of this instruction | ||
| 498 | /// is not in a position where it must create an invalid type. | ||
| 499 | /// Uses the `param_type` union field. | ||
| 500 | param_type, | ||
| 501 | /// Turns an R-Value into a const L-Value. In other words, it takes a value, | 493 | /// Turns an R-Value into a const L-Value. In other words, it takes a value, |
| 502 | /// stores it in a memory location, and returns a const pointer to it. If the value | 494 | /// stores it in a memory location, and returns a const pointer to it. If the value |
| 503 | /// is `comptime`, the memory location is global static constant data. Otherwise, | 495 | /// is `comptime`, the memory location is global static constant data. Otherwise, |
| ... | @@ -839,8 +831,6 @@ pub const Inst = struct { | ... | @@ -839,8 +831,6 @@ pub const Inst = struct { |
| 839 | round, | 831 | round, |
| 840 | /// Implement builtin `@tagName`. Uses `un_node`. | 832 | /// Implement builtin `@tagName`. Uses `un_node`. |
| 841 | tag_name, | 833 | tag_name, |
| 842 | /// Implement builtin `@Type`. Uses `un_node`. | ||
| 843 | reify, | ||
| 844 | /// Implement builtin `@typeName`. Uses `un_node`. | 834 | /// Implement builtin `@typeName`. Uses `un_node`. |
| 845 | type_name, | 835 | type_name, |
| 846 | /// Implement builtin `@Frame`. Uses `un_node`. | 836 | /// Implement builtin `@Frame`. Uses `un_node`. |
| ... | @@ -1097,7 +1087,6 @@ pub const Inst = struct { | ... | @@ -1097,7 +1087,6 @@ pub const Inst = struct { |
| 1097 | .mul, | 1087 | .mul, |
| 1098 | .mulwrap, | 1088 | .mulwrap, |
| 1099 | .mul_sat, | 1089 | .mul_sat, |
| 1100 | .param_type, | ||
| 1101 | .ref, | 1090 | .ref, |
| 1102 | .shl, | 1091 | .shl, |
| 1103 | .shl_sat, | 1092 | .shl_sat, |
| ... | @@ -1197,7 +1186,6 @@ pub const Inst = struct { | ... | @@ -1197,7 +1186,6 @@ pub const Inst = struct { |
| 1197 | .trunc, | 1186 | .trunc, |
| 1198 | .round, | 1187 | .round, |
| 1199 | .tag_name, | 1188 | .tag_name, |
| 1200 | .reify, | ||
| 1201 | .type_name, | 1189 | .type_name, |
| 1202 | .frame_type, | 1190 | .frame_type, |
| 1203 | .frame_size, | 1191 | .frame_size, |
| ... | @@ -1400,7 +1388,6 @@ pub const Inst = struct { | ... | @@ -1400,7 +1388,6 @@ pub const Inst = struct { |
| 1400 | .mul, | 1388 | .mul, |
| 1401 | .mulwrap, | 1389 | .mulwrap, |
| 1402 | .mul_sat, | 1390 | .mul_sat, |
| 1403 | .param_type, | ||
| 1404 | .ref, | 1391 | .ref, |
| 1405 | .shl, | 1392 | .shl, |
| 1406 | .shl_sat, | 1393 | .shl_sat, |
| ... | @@ -1484,7 +1471,6 @@ pub const Inst = struct { | ... | @@ -1484,7 +1471,6 @@ pub const Inst = struct { |
| 1484 | .trunc, | 1471 | .trunc, |
| 1485 | .round, | 1472 | .round, |
| 1486 | .tag_name, | 1473 | .tag_name, |
| 1487 | .reify, | ||
| 1488 | .type_name, | 1474 | .type_name, |
| 1489 | .frame_type, | 1475 | .frame_type, |
| 1490 | .frame_size, | 1476 | .frame_size, |
| ... | @@ -1573,7 +1559,6 @@ pub const Inst = struct { | ... | @@ -1573,7 +1559,6 @@ pub const Inst = struct { |
| 1573 | .mulwrap = .pl_node, | 1559 | .mulwrap = .pl_node, |
| 1574 | .mul_sat = .pl_node, | 1560 | .mul_sat = .pl_node, |
| 1575 | 1561 | ||
| 1576 | .param_type = .param_type, | ||
| 1577 | .param = .pl_tok, | 1562 | .param = .pl_tok, |
| 1578 | .param_comptime = .pl_tok, | 1563 | .param_comptime = .pl_tok, |
| 1579 | .param_anytype = .str_tok, | 1564 | .param_anytype = .str_tok, |
| ... | @@ -1759,7 +1744,6 @@ pub const Inst = struct { | ... | @@ -1759,7 +1744,6 @@ pub const Inst = struct { |
| 1759 | .trunc = .un_node, | 1744 | .trunc = .un_node, |
| 1760 | .round = .un_node, | 1745 | .round = .un_node, |
| 1761 | .tag_name = .un_node, | 1746 | .tag_name = .un_node, |
| 1762 | .reify = .un_node, | ||
| 1763 | .type_name = .un_node, | 1747 | .type_name = .un_node, |
| 1764 | .frame_type = .un_node, | 1748 | .frame_type = .un_node, |
| 1765 | .frame_size = .un_node, | 1749 | .frame_size = .un_node, |
| ... | @@ -1980,6 +1964,10 @@ pub const Inst = struct { | ... | @@ -1980,6 +1964,10 @@ pub const Inst = struct { |
| 1980 | /// Implement builtin `@intToError`. | 1964 | /// Implement builtin `@intToError`. |
| 1981 | /// `operand` is payload index to `UnNode`. | 1965 | /// `operand` is payload index to `UnNode`. |
| 1982 | int_to_error, | 1966 | int_to_error, |
| 1967 | /// Implement builtin `@Type`. | ||
| 1968 | /// `operand` is payload index to `UnNode`. | ||
| 1969 | /// `small` contains `NameStrategy | ||
| 1970 | reify, | ||
| 1983 | 1971 | ||
| 1984 | pub const InstData = struct { | 1972 | pub const InstData = struct { |
| 1985 | opcode: Extended, | 1973 | opcode: Extended, |
| ... | @@ -2541,10 +2529,6 @@ pub const Inst = struct { | ... | @@ -2541,10 +2529,6 @@ pub const Inst = struct { |
| 2541 | /// Points to a `Block`. | 2529 | /// Points to a `Block`. |
| 2542 | payload_index: u32, | 2530 | payload_index: u32, |
| 2543 | }, | 2531 | }, |
| 2544 | param_type: struct { | ||
| 2545 | callee: Ref, | ||
| 2546 | param_index: u32, | ||
| 2547 | }, | ||
| 2548 | @"unreachable": struct { | 2532 | @"unreachable": struct { |
| 2549 | /// Offset from Decl AST node index. | 2533 | /// Offset from Decl AST node index. |
| 2550 | /// `Tag` determines which kind of AST node this points to. | 2534 | /// `Tag` determines which kind of AST node this points to. |
| ... | @@ -2615,7 +2599,6 @@ pub const Inst = struct { | ... | @@ -2615,7 +2599,6 @@ pub const Inst = struct { |
| 2615 | ptr_type, | 2599 | ptr_type, |
| 2616 | int_type, | 2600 | int_type, |
| 2617 | bool_br, | 2601 | bool_br, |
| 2618 | param_type, | ||
| 2619 | @"unreachable", | 2602 | @"unreachable", |
| 2620 | @"break", | 2603 | @"break", |
| 2621 | switch_capture, | 2604 | switch_capture, |
| ... | @@ -2795,7 +2778,9 @@ pub const Inst = struct { | ... | @@ -2795,7 +2778,9 @@ pub const Inst = struct { |
| 2795 | }; | 2778 | }; |
| 2796 | 2779 | ||
| 2797 | /// Stored inside extra, with trailing arguments according to `args_len`. | 2780 | /// Stored inside extra, with trailing arguments according to `args_len`. |
| 2798 | /// Each argument is a `Ref`. | 2781 | /// Implicit 0. arg_0_start: u32, // always same as `args_len` |
| 2782 | /// 1. arg_end: u32, // for each `args_len` | ||
| 2783 | /// arg_N_start is the same as arg_N-1_end | ||
| 2799 | pub const Call = struct { | 2784 | pub const Call = struct { |
| 2800 | // Note: Flags *must* come first so that unusedResultExpr | 2785 | // Note: Flags *must* come first so that unusedResultExpr |
| 2801 | // can find it when it goes to modify them. | 2786 | // can find it when it goes to modify them. |
| ... | @@ -3100,13 +3085,16 @@ pub const Inst = struct { | ... | @@ -3100,13 +3085,16 @@ pub const Inst = struct { |
| 3100 | /// 0. src_node: i32, // if has_src_node | 3085 | /// 0. src_node: i32, // if has_src_node |
| 3101 | /// 1. fields_len: u32, // if has_fields_len | 3086 | /// 1. fields_len: u32, // if has_fields_len |
| 3102 | /// 2. decls_len: u32, // if has_decls_len | 3087 | /// 2. decls_len: u32, // if has_decls_len |
| 3103 | /// 3. decl_bits: u32 // for every 8 decls | 3088 | /// 3. backing_int_body_len: u32, // if has_backing_int |
| 3089 | /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0 | ||
| 3090 | /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0 | ||
| 3091 | /// 6. decl_bits: u32 // for every 8 decls | ||
| 3104 | /// - sets of 4 bits: | 3092 | /// - sets of 4 bits: |
| 3105 | /// 0b000X: whether corresponding decl is pub | 3093 | /// 0b000X: whether corresponding decl is pub |
| 3106 | /// 0b00X0: whether corresponding decl is exported | 3094 | /// 0b00X0: whether corresponding decl is exported |
| 3107 | /// 0b0X00: whether corresponding decl has an align expression | 3095 | /// 0b0X00: whether corresponding decl has an align expression |
| 3108 | /// 0bX000: whether corresponding decl has a linksection or an address space expression | 3096 | /// 0bX000: whether corresponding decl has a linksection or an address space expression |
| 3109 | /// 4. decl: { // for every decls_len | 3097 | /// 7. decl: { // for every decls_len |
| 3110 | /// src_hash: [4]u32, // hash of source bytes | 3098 | /// src_hash: [4]u32, // hash of source bytes |
| 3111 | /// line: u32, // line number of decl, relative to parent | 3099 | /// line: u32, // line number of decl, relative to parent |
| 3112 | /// name: u32, // null terminated string index | 3100 | /// name: u32, // null terminated string index |
| ... | @@ -3124,13 +3112,13 @@ pub const Inst = struct { | ... | @@ -3124,13 +3112,13 @@ pub const Inst = struct { |
| 3124 | /// address_space: Ref, | 3112 | /// address_space: Ref, |
| 3125 | /// } | 3113 | /// } |
| 3126 | /// } | 3114 | /// } |
| 3127 | /// 5. flags: u32 // for every 8 fields | 3115 | /// 8. flags: u32 // for every 8 fields |
| 3128 | /// - sets of 4 bits: | 3116 | /// - sets of 4 bits: |
| 3129 | /// 0b000X: whether corresponding field has an align expression | 3117 | /// 0b000X: whether corresponding field has an align expression |
| 3130 | /// 0b00X0: whether corresponding field has a default expression | 3118 | /// 0b00X0: whether corresponding field has a default expression |
| 3131 | /// 0b0X00: whether corresponding field is comptime | 3119 | /// 0b0X00: whether corresponding field is comptime |
| 3132 | /// 0bX000: whether corresponding field has a type expression | 3120 | /// 0bX000: whether corresponding field has a type expression |
| 3133 | /// 6. fields: { // for every fields_len | 3121 | /// 9. fields: { // for every fields_len |
| 3134 | /// field_name: u32, | 3122 | /// field_name: u32, |
| 3135 | /// doc_comment: u32, // 0 if no doc comment | 3123 | /// doc_comment: u32, // 0 if no doc comment |
| 3136 | /// field_type: Ref, // if corresponding bit is not set. none means anytype. | 3124 | /// field_type: Ref, // if corresponding bit is not set. none means anytype. |
| ... | @@ -3138,7 +3126,7 @@ pub const Inst = struct { | ... | @@ -3138,7 +3126,7 @@ pub const Inst = struct { |
| 3138 | /// align_body_len: u32, // if corresponding bit is set | 3126 | /// align_body_len: u32, // if corresponding bit is set |
| 3139 | /// init_body_len: u32, // if corresponding bit is set | 3127 | /// init_body_len: u32, // if corresponding bit is set |
| 3140 | /// } | 3128 | /// } |
| 3141 | /// 7. bodies: { // for every fields_len | 3129 | /// 10. bodies: { // for every fields_len |
| 3142 | /// field_type_body_inst: Inst, // for each field_type_body_len | 3130 | /// field_type_body_inst: Inst, // for each field_type_body_len |
| 3143 | /// align_body_inst: Inst, // for each align_body_len | 3131 | /// align_body_inst: Inst, // for each align_body_len |
| 3144 | /// init_body_inst: Inst, // for each init_body_len | 3132 | /// init_body_inst: Inst, // for each init_body_len |
| ... | @@ -3148,11 +3136,12 @@ pub const Inst = struct { | ... | @@ -3148,11 +3136,12 @@ pub const Inst = struct { |
| 3148 | has_src_node: bool, | 3136 | has_src_node: bool, |
| 3149 | has_fields_len: bool, | 3137 | has_fields_len: bool, |
| 3150 | has_decls_len: bool, | 3138 | has_decls_len: bool, |
| 3139 | has_backing_int: bool, | ||
| 3151 | known_non_opv: bool, | 3140 | known_non_opv: bool, |
| 3152 | known_comptime_only: bool, | 3141 | known_comptime_only: bool, |
| 3153 | name_strategy: NameStrategy, | 3142 | name_strategy: NameStrategy, |
| 3154 | layout: std.builtin.Type.ContainerLayout, | 3143 | layout: std.builtin.Type.ContainerLayout, |
| 3155 | _: u7 = undefined, | 3144 | _: u6 = undefined, |
| 3156 | }; | 3145 | }; |
| 3157 | }; | 3146 | }; |
| 3158 | 3147 | ||
| ... | @@ -3619,6 +3608,16 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator { | ... | @@ -3619,6 +3608,16 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator { |
| 3619 | break :decls_len decls_len; | 3608 | break :decls_len decls_len; |
| 3620 | } else 0; | 3609 | } else 0; |
| 3621 | 3610 | ||
| 3611 | if (small.has_backing_int) { | ||
| 3612 | const backing_int_body_len = zir.extra[extra_index]; | ||
| 3613 | extra_index += 1; // backing_int_body_len | ||
| 3614 | if (backing_int_body_len == 0) { | ||
| 3615 | extra_index += 1; // backing_int_ref | ||
| 3616 | } else { | ||
| 3617 | extra_index += backing_int_body_len; // backing_int_body_inst | ||
| 3618 | } | ||
| 3619 | } | ||
| 3620 | |||
| 3622 | return declIteratorInner(zir, extra_index, decls_len); | 3621 | return declIteratorInner(zir, extra_index, decls_len); |
| 3623 | }, | 3622 | }, |
| 3624 | .enum_decl => { | 3623 | .enum_decl => { |
src/arch/aarch64/CodeGen.zig+1| ... | @@ -778,6 +778,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -778,6 +778,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 778 | => return self.fail("TODO implement optimized float mode", .{}), | 778 | => return self.fail("TODO implement optimized float mode", .{}), |
| 779 | 779 | ||
| 780 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | 780 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), |
| 781 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | ||
| 781 | 782 | ||
| 782 | .wasm_memory_size => unreachable, | 783 | .wasm_memory_size => unreachable, |
| 783 | .wasm_memory_grow => unreachable, | 784 | .wasm_memory_grow => unreachable, |
src/arch/arm/CodeGen.zig+165-30| ... | @@ -247,6 +247,31 @@ const BigTomb = struct { | ... | @@ -247,6 +247,31 @@ const BigTomb = struct { |
| 247 | log.debug("%{d} => {}", .{ bt.inst, result }); | 247 | log.debug("%{d} => {}", .{ bt.inst, result }); |
| 248 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; | 248 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; |
| 249 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); | 249 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); |
| 250 | |||
| 251 | switch (result) { | ||
| 252 | .register => |reg| { | ||
| 253 | // In some cases (such as bitcast), an operand | ||
| 254 | // may be the same MCValue as the result. If | ||
| 255 | // that operand died and was a register, it | ||
| 256 | // was freed by processDeath. We have to | ||
| 257 | // "re-allocate" the register. | ||
| 258 | if (bt.function.register_manager.isRegFree(reg)) { | ||
| 259 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); | ||
| 260 | } | ||
| 261 | }, | ||
| 262 | .register_c_flag, | ||
| 263 | .register_v_flag, | ||
| 264 | => |reg| { | ||
| 265 | if (bt.function.register_manager.isRegFree(reg)) { | ||
| 266 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); | ||
| 267 | } | ||
| 268 | bt.function.cpsr_flags_inst = bt.inst; | ||
| 269 | }, | ||
| 270 | .cpsr_flags => { | ||
| 271 | bt.function.cpsr_flags_inst = bt.inst; | ||
| 272 | }, | ||
| 273 | else => {}, | ||
| 274 | } | ||
| 250 | } | 275 | } |
| 251 | bt.function.finishAirBookkeeping(); | 276 | bt.function.finishAirBookkeeping(); |
| 252 | } | 277 | } |
| ... | @@ -332,7 +357,7 @@ pub fn generate( | ... | @@ -332,7 +357,7 @@ pub fn generate( |
| 332 | }; | 357 | }; |
| 333 | 358 | ||
| 334 | for (function.dbg_arg_relocs.items) |reloc| { | 359 | for (function.dbg_arg_relocs.items) |reloc| { |
| 335 | try function.genArgDbgInfo(reloc.inst, reloc.index, call_info.stack_byte_count); | 360 | try function.genArgDbgInfo(reloc.inst, reloc.index); |
| 336 | } | 361 | } |
| 337 | 362 | ||
| 338 | var mir = Mir{ | 363 | var mir = Mir{ |
| ... | @@ -351,7 +376,8 @@ pub fn generate( | ... | @@ -351,7 +376,8 @@ pub fn generate( |
| 351 | .prev_di_pc = 0, | 376 | .prev_di_pc = 0, |
| 352 | .prev_di_line = module_fn.lbrace_line, | 377 | .prev_di_line = module_fn.lbrace_line, |
| 353 | .prev_di_column = module_fn.lbrace_column, | 378 | .prev_di_column = module_fn.lbrace_column, |
| 354 | .prologue_stack_space = call_info.stack_byte_count + function.saved_regs_stack_space, | 379 | .stack_size = function.max_end_stack, |
| 380 | .saved_regs_stack_space = function.saved_regs_stack_space, | ||
| 355 | }; | 381 | }; |
| 356 | defer emit.deinit(); | 382 | defer emit.deinit(); |
| 357 | 383 | ||
| ... | @@ -464,6 +490,7 @@ fn gen(self: *Self) !void { | ... | @@ -464,6 +490,7 @@ fn gen(self: *Self) !void { |
| 464 | const total_stack_size = self.max_end_stack + self.saved_regs_stack_space; | 490 | const total_stack_size = self.max_end_stack + self.saved_regs_stack_space; |
| 465 | const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align); | 491 | const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align); |
| 466 | const stack_size = aligned_total_stack_end - self.saved_regs_stack_space; | 492 | const stack_size = aligned_total_stack_end - self.saved_regs_stack_space; |
| 493 | self.max_end_stack = stack_size; | ||
| 467 | if (Instruction.Operand.fromU32(stack_size)) |op| { | 494 | if (Instruction.Operand.fromU32(stack_size)) |op| { |
| 468 | self.mir_instructions.set(sub_reloc, .{ | 495 | self.mir_instructions.set(sub_reloc, .{ |
| 469 | .tag = .sub, | 496 | .tag = .sub, |
| ... | @@ -769,6 +796,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -769,6 +796,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 769 | => return self.fail("TODO implement optimized float mode", .{}), | 796 | => return self.fail("TODO implement optimized float mode", .{}), |
| 770 | 797 | ||
| 771 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | 798 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), |
| 799 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | ||
| 772 | 800 | ||
| 773 | .wasm_memory_size => unreachable, | 801 | .wasm_memory_size => unreachable, |
| 774 | .wasm_memory_grow => unreachable, | 802 | .wasm_memory_grow => unreachable, |
| ... | @@ -1812,7 +1840,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV | ... | @@ -1812,7 +1840,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV |
| 1812 | switch (error_union_mcv) { | 1840 | switch (error_union_mcv) { |
| 1813 | .register => return self.fail("TODO errUnionErr for registers", .{}), | 1841 | .register => return self.fail("TODO errUnionErr for registers", .{}), |
| 1814 | .stack_argument_offset => |off| { | 1842 | .stack_argument_offset => |off| { |
| 1815 | return MCValue{ .stack_argument_offset = off - err_offset }; | 1843 | return MCValue{ .stack_argument_offset = off + err_offset }; |
| 1816 | }, | 1844 | }, |
| 1817 | .stack_offset => |off| { | 1845 | .stack_offset => |off| { |
| 1818 | return MCValue{ .stack_offset = off - err_offset }; | 1846 | return MCValue{ .stack_offset = off - err_offset }; |
| ... | @@ -1849,7 +1877,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) | ... | @@ -1849,7 +1877,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) |
| 1849 | switch (error_union_mcv) { | 1877 | switch (error_union_mcv) { |
| 1850 | .register => return self.fail("TODO errUnionPayload for registers", .{}), | 1878 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| 1851 | .stack_argument_offset => |off| { | 1879 | .stack_argument_offset => |off| { |
| 1852 | return MCValue{ .stack_argument_offset = off - payload_offset }; | 1880 | return MCValue{ .stack_argument_offset = off + payload_offset }; |
| 1853 | }, | 1881 | }, |
| 1854 | .stack_offset => |off| { | 1882 | .stack_offset => |off| { |
| 1855 | return MCValue{ .stack_offset = off - payload_offset }; | 1883 | return MCValue{ .stack_offset = off - payload_offset }; |
| ... | @@ -1983,7 +2011,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1983,7 +2011,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1983 | .dead, .unreach => unreachable, | 2011 | .dead, .unreach => unreachable, |
| 1984 | .register => unreachable, // a slice doesn't fit in one register | 2012 | .register => unreachable, // a slice doesn't fit in one register |
| 1985 | .stack_argument_offset => |off| { | 2013 | .stack_argument_offset => |off| { |
| 1986 | break :result MCValue{ .stack_argument_offset = off - 4 }; | 2014 | break :result MCValue{ .stack_argument_offset = off + 4 }; |
| 1987 | }, | 2015 | }, |
| 1988 | .stack_offset => |off| { | 2016 | .stack_offset => |off| { |
| 1989 | break :result MCValue{ .stack_offset = off - 4 }; | 2017 | break :result MCValue{ .stack_offset = off - 4 }; |
| ... | @@ -2259,16 +2287,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2259,16 +2287,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2259 | .register_c_flag, | 2287 | .register_c_flag, |
| 2260 | .register_v_flag, | 2288 | .register_v_flag, |
| 2261 | => unreachable, // cannot hold an address | 2289 | => unreachable, // cannot hold an address |
| 2262 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 2290 | .immediate => |imm| { |
| 2263 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), | 2291 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }); |
| 2292 | }, | ||
| 2293 | .ptr_stack_offset => |off| { | ||
| 2294 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }); | ||
| 2295 | }, | ||
| 2264 | .register => |reg| { | 2296 | .register => |reg| { |
| 2265 | const reg_lock = self.register_manager.lockReg(reg); | 2297 | const reg_lock = self.register_manager.lockReg(reg); |
| 2266 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 2298 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); |
| 2267 | 2299 | ||
| 2268 | switch (dst_mcv) { | 2300 | switch (dst_mcv) { |
| 2269 | .dead => unreachable, | ||
| 2270 | .undef => unreachable, | ||
| 2271 | .cpsr_flags => unreachable, | ||
| 2272 | .register => |dst_reg| { | 2301 | .register => |dst_reg| { |
| 2273 | try self.genLdrRegister(dst_reg, reg, elem_ty); | 2302 | try self.genLdrRegister(dst_reg, reg, elem_ty); |
| 2274 | }, | 2303 | }, |
| ... | @@ -2304,7 +2333,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2304,7 +2333,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2304 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); | 2333 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 2305 | } | 2334 | } |
| 2306 | }, | 2335 | }, |
| 2307 | else => return self.fail("TODO load from register into {}", .{dst_mcv}), | 2336 | else => unreachable, // attempting to load into non-register or non-stack MCValue |
| 2308 | } | 2337 | } |
| 2309 | }, | 2338 | }, |
| 2310 | .memory, | 2339 | .memory, |
| ... | @@ -2401,7 +2430,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2401,7 +2430,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2401 | // sub src_reg, fp, #off | 2430 | // sub src_reg, fp, #off |
| 2402 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); | 2431 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 2403 | }, | 2432 | }, |
| 2404 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }), | 2433 | .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }), |
| 2405 | .stack_argument_offset => |off| { | 2434 | .stack_argument_offset => |off| { |
| 2406 | _ = try self.addInst(.{ | 2435 | _ = try self.addInst(.{ |
| 2407 | .tag = .ldr_ptr_stack_argument, | 2436 | .tag = .ldr_ptr_stack_argument, |
| ... | @@ -2507,7 +2536,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2507,7 +2536,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2507 | switch (mcv) { | 2536 | switch (mcv) { |
| 2508 | .dead, .unreach => unreachable, | 2537 | .dead, .unreach => unreachable, |
| 2509 | .stack_argument_offset => |off| { | 2538 | .stack_argument_offset => |off| { |
| 2510 | break :result MCValue{ .stack_argument_offset = off - struct_field_offset }; | 2539 | break :result MCValue{ .stack_argument_offset = off + struct_field_offset }; |
| 2511 | }, | 2540 | }, |
| 2512 | .stack_offset => |off| { | 2541 | .stack_offset => |off| { |
| 2513 | break :result MCValue{ .stack_offset = off - struct_field_offset }; | 2542 | break :result MCValue{ .stack_offset = off - struct_field_offset }; |
| ... | @@ -3347,6 +3376,102 @@ fn genInlineMemcpy( | ... | @@ -3347,6 +3376,102 @@ fn genInlineMemcpy( |
| 3347 | // end: | 3376 | // end: |
| 3348 | } | 3377 | } |
| 3349 | 3378 | ||
| 3379 | fn genInlineMemset( | ||
| 3380 | self: *Self, | ||
| 3381 | dst: MCValue, | ||
| 3382 | val: MCValue, | ||
| 3383 | len: MCValue, | ||
| 3384 | ) !void { | ||
| 3385 | const dst_reg = switch (dst) { | ||
| 3386 | .register => |r| r, | ||
| 3387 | else => try self.copyToTmpRegister(Type.initTag(.manyptr_u8), dst), | ||
| 3388 | }; | ||
| 3389 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | ||
| 3390 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | ||
| 3391 | |||
| 3392 | const val_reg = switch (val) { | ||
| 3393 | .register => |r| r, | ||
| 3394 | else => try self.copyToTmpRegister(Type.initTag(.u8), val), | ||
| 3395 | }; | ||
| 3396 | const val_reg_lock = self.register_manager.lockReg(val_reg); | ||
| 3397 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); | ||
| 3398 | |||
| 3399 | const len_reg = switch (len) { | ||
| 3400 | .register => |r| r, | ||
| 3401 | else => try self.copyToTmpRegister(Type.usize, len), | ||
| 3402 | }; | ||
| 3403 | const len_reg_lock = self.register_manager.lockReg(len_reg); | ||
| 3404 | defer if (len_reg_lock) |lock| self.register_manager.unlockReg(lock); | ||
| 3405 | |||
| 3406 | const count_reg = try self.register_manager.allocReg(null, gp); | ||
| 3407 | |||
| 3408 | try self.genInlineMemsetCode(dst_reg, val_reg, len_reg, count_reg); | ||
| 3409 | } | ||
| 3410 | |||
| 3411 | fn genInlineMemsetCode( | ||
| 3412 | self: *Self, | ||
| 3413 | dst: Register, | ||
| 3414 | val: Register, | ||
| 3415 | len: Register, | ||
| 3416 | count: Register, | ||
| 3417 | ) !void { | ||
| 3418 | // mov count, #0 | ||
| 3419 | _ = try self.addInst(.{ | ||
| 3420 | .tag = .mov, | ||
| 3421 | .data = .{ .rr_op = .{ | ||
| 3422 | .rd = count, | ||
| 3423 | .rn = .r0, | ||
| 3424 | .op = Instruction.Operand.imm(0, 0), | ||
| 3425 | } }, | ||
| 3426 | }); | ||
| 3427 | |||
| 3428 | // loop: | ||
| 3429 | // cmp count, len | ||
| 3430 | _ = try self.addInst(.{ | ||
| 3431 | .tag = .cmp, | ||
| 3432 | .data = .{ .rr_op = .{ | ||
| 3433 | .rd = .r0, | ||
| 3434 | .rn = count, | ||
| 3435 | .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none), | ||
| 3436 | } }, | ||
| 3437 | }); | ||
| 3438 | |||
| 3439 | // bge end | ||
| 3440 | _ = try self.addInst(.{ | ||
| 3441 | .tag = .b, | ||
| 3442 | .cond = .ge, | ||
| 3443 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len + 4) }, | ||
| 3444 | }); | ||
| 3445 | |||
| 3446 | // strb val, [src, count] | ||
| 3447 | _ = try self.addInst(.{ | ||
| 3448 | .tag = .strb, | ||
| 3449 | .data = .{ .rr_offset = .{ | ||
| 3450 | .rt = val, | ||
| 3451 | .rn = dst, | ||
| 3452 | .offset = .{ .offset = Instruction.Offset.reg(count, .none) }, | ||
| 3453 | } }, | ||
| 3454 | }); | ||
| 3455 | |||
| 3456 | // add count, count, #1 | ||
| 3457 | _ = try self.addInst(.{ | ||
| 3458 | .tag = .add, | ||
| 3459 | .data = .{ .rr_op = .{ | ||
| 3460 | .rd = count, | ||
| 3461 | .rn = count, | ||
| 3462 | .op = Instruction.Operand.imm(1, 0), | ||
| 3463 | } }, | ||
| 3464 | }); | ||
| 3465 | |||
| 3466 | // b loop | ||
| 3467 | _ = try self.addInst(.{ | ||
| 3468 | .tag = .b, | ||
| 3469 | .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 4) }, | ||
| 3470 | }); | ||
| 3471 | |||
| 3472 | // end: | ||
| 3473 | } | ||
| 3474 | |||
| 3350 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | 3475 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 3351 | /// after codegen for this symbol is done. | 3476 | /// after codegen for this symbol is done. |
| 3352 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { | 3477 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { |
| ... | @@ -3369,9 +3494,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { | ... | @@ -3369,9 +3494,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { |
| 3369 | } | 3494 | } |
| 3370 | } | 3495 | } |
| 3371 | 3496 | ||
| 3372 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void { | 3497 | fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void { |
| 3373 | const prologue_stack_space = stack_byte_count + self.saved_regs_stack_space; | ||
| 3374 | |||
| 3375 | const mcv = self.args[arg_index]; | 3498 | const mcv = self.args[arg_index]; |
| 3376 | const ty = self.air.instructions.items(.data)[inst].ty; | 3499 | const ty = self.air.instructions.items(.data)[inst].ty; |
| 3377 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); | 3500 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); |
| ... | @@ -3404,7 +3527,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c | ... | @@ -3404,7 +3527,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c |
| 3404 | // const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 3527 | // const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 3405 | const adjusted_stack_offset = switch (mcv) { | 3528 | const adjusted_stack_offset = switch (mcv) { |
| 3406 | .stack_offset => |offset| -@intCast(i32, offset), | 3529 | .stack_offset => |offset| -@intCast(i32, offset), |
| 3407 | .stack_argument_offset => |offset| @intCast(i32, prologue_stack_space - offset), | 3530 | .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset), |
| 3408 | else => unreachable, | 3531 | else => unreachable, |
| 3409 | }; | 3532 | }; |
| 3410 | 3533 | ||
| ... | @@ -3524,7 +3647,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3524,7 +3647,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3524 | try self.register_manager.getReg(reg, null); | 3647 | try self.register_manager.getReg(reg, null); |
| 3525 | } | 3648 | } |
| 3526 | 3649 | ||
| 3527 | if (info.return_value == .stack_offset) { | 3650 | // If returning by reference, r0 will contain the address of where |
| 3651 | // to put the result into. In that case, make sure that r0 remains | ||
| 3652 | // untouched by the parameter passing code | ||
| 3653 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { | ||
| 3528 | log.debug("airCall: return by reference", .{}); | 3654 | log.debug("airCall: return by reference", .{}); |
| 3529 | const ret_ty = fn_ty.fnReturnType(); | 3655 | const ret_ty = fn_ty.fnReturnType(); |
| 3530 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 3656 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| ... | @@ -3540,7 +3666,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3540,7 +3666,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3540 | try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset }); | 3666 | try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset }); |
| 3541 | 3667 | ||
| 3542 | info.return_value = .{ .stack_offset = stack_offset }; | 3668 | info.return_value = .{ .stack_offset = stack_offset }; |
| 3543 | } | 3669 | |
| 3670 | break :blk self.register_manager.lockRegAssumeUnused(.r0); | ||
| 3671 | } else null; | ||
| 3672 | defer if (r0_lock) |reg| self.register_manager.unlockReg(reg); | ||
| 3544 | 3673 | ||
| 3545 | // Make space for the arguments passed via the stack | 3674 | // Make space for the arguments passed via the stack |
| 3546 | self.max_end_stack += info.stack_byte_count; | 3675 | self.max_end_stack += info.stack_byte_count; |
| ... | @@ -3559,7 +3688,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3559,7 +3688,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3559 | .stack_offset => unreachable, | 3688 | .stack_offset => unreachable, |
| 3560 | .stack_argument_offset => |offset| try self.genSetStackArgument( | 3689 | .stack_argument_offset => |offset| try self.genSetStackArgument( |
| 3561 | arg_ty, | 3690 | arg_ty, |
| 3562 | info.stack_byte_count - offset, | 3691 | offset, |
| 3563 | arg_mcv, | 3692 | arg_mcv, |
| 3564 | ), | 3693 | ), |
| 3565 | else => unreachable, | 3694 | else => unreachable, |
| ... | @@ -4621,11 +4750,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4621,11 +4750,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4621 | if (!self.wantSafety()) | 4750 | if (!self.wantSafety()) |
| 4622 | return; // The already existing value will do just fine. | 4751 | return; // The already existing value will do just fine. |
| 4623 | // TODO Upgrade this to a memset call when we have that available. | 4752 | // TODO Upgrade this to a memset call when we have that available. |
| 4624 | switch (ty.abiSize(self.target.*)) { | 4753 | switch (abi_size) { |
| 4625 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), | 4754 | 1 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 4626 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 4755 | 2 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 4627 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 4756 | 4 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 4628 | else => return self.fail("TODO implement memset", .{}), | 4757 | else => try self.genInlineMemset( |
| 4758 | .{ .ptr_stack_offset = stack_offset }, | ||
| 4759 | .{ .immediate = 0xaa }, | ||
| 4760 | .{ .immediate = abi_size }, | ||
| 4761 | ), | ||
| 4629 | } | 4762 | } |
| 4630 | }, | 4763 | }, |
| 4631 | .cpsr_flags, | 4764 | .cpsr_flags, |
| ... | @@ -5037,9 +5170,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5037,9 +5170,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5037 | return; // The already existing value will do just fine. | 5170 | return; // The already existing value will do just fine. |
| 5038 | // TODO Upgrade this to a memset call when we have that available. | 5171 | // TODO Upgrade this to a memset call when we have that available. |
| 5039 | switch (abi_size) { | 5172 | switch (abi_size) { |
| 5040 | 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), | 5173 | 1 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5041 | 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), | 5174 | 2 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5042 | 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 5175 | 4 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 5043 | else => return self.fail("TODO implement memset", .{}), | 5176 | else => return self.fail("TODO implement memset", .{}), |
| 5044 | } | 5177 | } |
| 5045 | }, | 5178 | }, |
| ... | @@ -5653,8 +5786,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -5653,8 +5786,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5653 | if (ty.abiAlignment(self.target.*) == 8) | 5786 | if (ty.abiAlignment(self.target.*) == 8) |
| 5654 | nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8); | 5787 | nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8); |
| 5655 | 5788 | ||
| 5656 | nsaa += param_size; | ||
| 5657 | result.args[i] = .{ .stack_argument_offset = nsaa }; | 5789 | result.args[i] = .{ .stack_argument_offset = nsaa }; |
| 5790 | nsaa += param_size; | ||
| 5658 | } | 5791 | } |
| 5659 | } | 5792 | } |
| 5660 | 5793 | ||
| ... | @@ -5687,9 +5820,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -5687,9 +5820,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5687 | for (param_types) |ty, i| { | 5820 | for (param_types) |ty, i| { |
| 5688 | if (ty.abiSize(self.target.*) > 0) { | 5821 | if (ty.abiSize(self.target.*) > 0) { |
| 5689 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 5822 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 5823 | const param_alignment = ty.abiAlignment(self.target.*); | ||
| 5690 | 5824 | ||
| 5691 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, ty.abiAlignment(self.target.*)) + param_size; | 5825 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); |
| 5692 | result.args[i] = .{ .stack_argument_offset = stack_offset }; | 5826 | result.args[i] = .{ .stack_argument_offset = stack_offset }; |
| 5827 | stack_offset += param_size; | ||
| 5693 | } else { | 5828 | } else { |
| 5694 | result.args[i] = .{ .none = {} }; | 5829 | result.args[i] = .{ .none = {} }; |
| 5695 | } | 5830 | } |
src/arch/arm/Emit.zig+19-38| ... | @@ -33,9 +33,13 @@ prev_di_column: u32, | ... | @@ -33,9 +33,13 @@ prev_di_column: u32, |
| 33 | /// Relative to the beginning of `code`. | 33 | /// Relative to the beginning of `code`. |
| 34 | prev_di_pc: usize, | 34 | prev_di_pc: usize, |
| 35 | 35 | ||
| 36 | /// The amount of stack space consumed by all stack arguments as well | 36 | /// The amount of stack space consumed by the saved callee-saved |
| 37 | /// as the saved callee-saved registers | 37 | /// registers in bytes |
| 38 | prologue_stack_space: u32, | 38 | saved_regs_stack_space: u32, |
| 39 | |||
| 40 | /// The final stack frame size of the function (already aligned to the | ||
| 41 | /// respective stack alignment). Does not include prologue stack space. | ||
| 42 | stack_size: u32, | ||
| 39 | 43 | ||
| 40 | /// The branch type of every branch | 44 | /// The branch type of every branch |
| 41 | branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{}, | 45 | branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{}, |
| ... | @@ -500,14 +504,15 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -500,14 +504,15 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 500 | const tag = emit.mir.instructions.items(.tag)[inst]; | 504 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 501 | const cond = emit.mir.instructions.items(.cond)[inst]; | 505 | const cond = emit.mir.instructions.items(.cond)[inst]; |
| 502 | const r_stack_offset = emit.mir.instructions.items(.data)[inst].r_stack_offset; | 506 | const r_stack_offset = emit.mir.instructions.items(.data)[inst].r_stack_offset; |
| 507 | const rt = r_stack_offset.rt; | ||
| 503 | 508 | ||
| 504 | const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset; | 509 | const raw_offset = emit.stack_size + emit.saved_regs_stack_space + r_stack_offset.stack_offset; |
| 505 | switch (tag) { | 510 | switch (tag) { |
| 506 | .ldr_ptr_stack_argument => { | 511 | .ldr_ptr_stack_argument => { |
| 507 | const operand = Instruction.Operand.fromU32(raw_offset) orelse | 512 | const operand = Instruction.Operand.fromU32(raw_offset) orelse |
| 508 | return emit.fail("TODO mirLoadStack larger offsets", .{}); | 513 | return emit.fail("TODO mirLoadStack larger offsets", .{}); |
| 509 | 514 | ||
| 510 | try emit.writeInstruction(Instruction.add(cond, r_stack_offset.rt, .fp, operand)); | 515 | try emit.writeInstruction(Instruction.add(cond, rt, .sp, operand)); |
| 511 | }, | 516 | }, |
| 512 | .ldr_stack_argument, | 517 | .ldr_stack_argument, |
| 513 | .ldrb_stack_argument, | 518 | .ldrb_stack_argument, |
| ... | @@ -516,23 +521,11 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -516,23 +521,11 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 516 | break :blk Instruction.Offset.imm(@intCast(u12, raw_offset)); | 521 | break :blk Instruction.Offset.imm(@intCast(u12, raw_offset)); |
| 517 | } else return emit.fail("TODO mirLoadStack larger offsets", .{}); | 522 | } else return emit.fail("TODO mirLoadStack larger offsets", .{}); |
| 518 | 523 | ||
| 519 | const ldr = switch (tag) { | 524 | switch (tag) { |
| 520 | .ldr_stack_argument => &Instruction.ldr, | 525 | .ldr_stack_argument => try emit.writeInstruction(Instruction.ldr(cond, rt, .sp, .{ .offset = offset })), |
| 521 | .ldrb_stack_argument => &Instruction.ldrb, | 526 | .ldrb_stack_argument => try emit.writeInstruction(Instruction.ldrb(cond, rt, .sp, .{ .offset = offset })), |
| 522 | else => unreachable, | 527 | else => unreachable, |
| 523 | }; | 528 | } |
| 524 | |||
| 525 | const ldr_workaround = switch (builtin.zig_backend) { | ||
| 526 | .stage1 => ldr.*, | ||
| 527 | else => ldr, | ||
| 528 | }; | ||
| 529 | |||
| 530 | try emit.writeInstruction(ldr_workaround( | ||
| 531 | cond, | ||
| 532 | r_stack_offset.rt, | ||
| 533 | .fp, | ||
| 534 | .{ .offset = offset }, | ||
| 535 | )); | ||
| 536 | }, | 529 | }, |
| 537 | .ldrh_stack_argument, | 530 | .ldrh_stack_argument, |
| 538 | .ldrsb_stack_argument, | 531 | .ldrsb_stack_argument, |
| ... | @@ -542,24 +535,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -542,24 +535,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 542 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset)); | 535 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset)); |
| 543 | } else return emit.fail("TODO mirLoadStack larger offsets", .{}); | 536 | } else return emit.fail("TODO mirLoadStack larger offsets", .{}); |
| 544 | 537 | ||
| 545 | const ldr = switch (tag) { | 538 | switch (tag) { |
| 546 | .ldrh_stack_argument => &Instruction.ldrh, | 539 | .ldrh_stack_argument => try emit.writeInstruction(Instruction.ldrh(cond, rt, .sp, .{ .offset = offset })), |
| 547 | .ldrsb_stack_argument => &Instruction.ldrsb, | 540 | .ldrsb_stack_argument => try emit.writeInstruction(Instruction.ldrsb(cond, rt, .sp, .{ .offset = offset })), |
| 548 | .ldrsh_stack_argument => &Instruction.ldrsh, | 541 | .ldrsh_stack_argument => try emit.writeInstruction(Instruction.ldrsh(cond, rt, .sp, .{ .offset = offset })), |
| 549 | else => unreachable, | 542 | else => unreachable, |
| 550 | }; | 543 | } |
| 551 | |||
| 552 | const ldr_workaround = switch (builtin.zig_backend) { | ||
| 553 | .stage1 => ldr.*, | ||
| 554 | else => ldr, | ||
| 555 | }; | ||
| 556 | |||
| 557 | try emit.writeInstruction(ldr_workaround( | ||
| 558 | cond, | ||
| 559 | r_stack_offset.rt, | ||
| 560 | .fp, | ||
| 561 | .{ .offset = offset }, | ||
| 562 | )); | ||
| 563 | }, | 544 | }, |
| 564 | else => unreachable, | 545 | else => unreachable, |
| 565 | } | 546 | } |
src/arch/riscv64/CodeGen.zig+1| ... | @@ -694,6 +694,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -694,6 +694,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 694 | => return self.fail("TODO implement optimized float mode", .{}), | 694 | => return self.fail("TODO implement optimized float mode", .{}), |
| 695 | 695 | ||
| 696 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | 696 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), |
| 697 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | ||
| 697 | 698 | ||
| 698 | .wasm_memory_size => unreachable, | 699 | .wasm_memory_size => unreachable, |
| 699 | .wasm_memory_grow => unreachable, | 700 | .wasm_memory_grow => unreachable, |
src/arch/sparc64/CodeGen.zig+1| ... | @@ -706,6 +706,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -706,6 +706,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 706 | => @panic("TODO implement optimized float mode"), | 706 | => @panic("TODO implement optimized float mode"), |
| 707 | 707 | ||
| 708 | .is_named_enum_value => @panic("TODO implement is_named_enum_value"), | 708 | .is_named_enum_value => @panic("TODO implement is_named_enum_value"), |
| 709 | .error_set_has_value => @panic("TODO implement error_set_has_value"), | ||
| 709 | 710 | ||
| 710 | .wasm_memory_size => unreachable, | 711 | .wasm_memory_size => unreachable, |
| 711 | .wasm_memory_grow => unreachable, | 712 | .wasm_memory_grow => unreachable, |
src/arch/wasm/CodeGen.zig+419-325| ... | @@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset; | ... | @@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 29 | const WValue = union(enum) { | 29 | const WValue = union(enum) { |
| 30 | /// May be referenced but is unused | 30 | /// May be referenced but is unused |
| 31 | none: void, | 31 | none: void, |
| 32 | /// The value lives on top of the stack | ||
| 33 | stack: void, | ||
| 32 | /// Index of the local variable | 34 | /// Index of the local variable |
| 33 | local: u32, | 35 | local: u32, |
| 34 | /// An immediate 32bit value | 36 | /// An immediate 32bit value |
| ... | @@ -55,7 +57,7 @@ const WValue = union(enum) { | ... | @@ -55,7 +57,7 @@ const WValue = union(enum) { |
| 55 | /// In wasm function pointers are indexes into a function table, | 57 | /// In wasm function pointers are indexes into a function table, |
| 56 | /// rather than an address in the data section. | 58 | /// rather than an address in the data section. |
| 57 | function_index: u32, | 59 | function_index: u32, |
| 58 | /// Offset from the bottom of the stack, with the offset | 60 | /// Offset from the bottom of the virtual stack, with the offset |
| 59 | /// pointing to where the value lives. | 61 | /// pointing to where the value lives. |
| 60 | stack_offset: u32, | 62 | stack_offset: u32, |
| 61 | 63 | ||
| ... | @@ -71,6 +73,38 @@ const WValue = union(enum) { | ... | @@ -71,6 +73,38 @@ const WValue = union(enum) { |
| 71 | else => return 0, | 73 | else => return 0, |
| 72 | } | 74 | } |
| 73 | } | 75 | } |
| 76 | |||
| 77 | /// Promotes a `WValue` to a local when given value is on top of the stack. | ||
| 78 | /// When encountering a `local` or `stack_offset` this is essentially a no-op. | ||
| 79 | /// All other tags are illegal. | ||
| 80 | fn toLocal(value: WValue, gen: *Self, ty: Type) InnerError!WValue { | ||
| 81 | switch (value) { | ||
| 82 | .stack => { | ||
| 83 | const local = try gen.allocLocal(ty); | ||
| 84 | try gen.addLabel(.local_set, local.local); | ||
| 85 | return local; | ||
| 86 | }, | ||
| 87 | .local, .stack_offset => return value, | ||
| 88 | else => unreachable, | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Marks a local as no longer being referenced and essentially allows | ||
| 93 | /// us to re-use it somewhere else within the function. | ||
| 94 | /// The valtype of the local is deducted by using the index of the given. | ||
| 95 | fn free(value: *WValue, gen: *Self) void { | ||
| 96 | if (value.* != .local) return; | ||
| 97 | const local_value = value.local; | ||
| 98 | const index = local_value - gen.args.len - @boolToInt(gen.return_value != .none); | ||
| 99 | const valtype = @intToEnum(wasm.Valtype, gen.locals.items[index]); | ||
| 100 | switch (valtype) { | ||
| 101 | .i32 => gen.free_locals_i32.append(gen.gpa, local_value) catch return, // It's ok to fail any of those, a new local can be allocated instead | ||
| 102 | .i64 => gen.free_locals_i64.append(gen.gpa, local_value) catch return, | ||
| 103 | .f32 => gen.free_locals_f32.append(gen.gpa, local_value) catch return, | ||
| 104 | .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return, | ||
| 105 | } | ||
| 106 | value.* = WValue{ .none = {} }; | ||
| 107 | } | ||
| 74 | }; | 108 | }; |
| 75 | 109 | ||
| 76 | /// Wasm ops, but without input/output/signedness information | 110 | /// Wasm ops, but without input/output/signedness information |
| ... | @@ -601,6 +635,21 @@ stack_size: u32 = 0, | ... | @@ -601,6 +635,21 @@ stack_size: u32 = 0, |
| 601 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. | 635 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. |
| 602 | stack_alignment: u32 = 16, | 636 | stack_alignment: u32 = 16, |
| 603 | 637 | ||
| 638 | // For each individual Wasm valtype we store a seperate free list which | ||
| 639 | // allows us to re-use locals that are no longer used. e.g. a temporary local. | ||
| 640 | /// A list of indexes which represents a local of valtype `i32`. | ||
| 641 | /// It is illegal to store a non-i32 valtype in this list. | ||
| 642 | free_locals_i32: std.ArrayListUnmanaged(u32) = .{}, | ||
| 643 | /// A list of indexes which represents a local of valtype `i64`. | ||
| 644 | /// It is illegal to store a non-i32 valtype in this list. | ||
| 645 | free_locals_i64: std.ArrayListUnmanaged(u32) = .{}, | ||
| 646 | /// A list of indexes which represents a local of valtype `f32`. | ||
| 647 | /// It is illegal to store a non-i32 valtype in this list. | ||
| 648 | free_locals_f32: std.ArrayListUnmanaged(u32) = .{}, | ||
| 649 | /// A list of indexes which represents a local of valtype `f64`. | ||
| 650 | /// It is illegal to store a non-i32 valtype in this list. | ||
| 651 | free_locals_f64: std.ArrayListUnmanaged(u32) = .{}, | ||
| 652 | |||
| 604 | const InnerError = error{ | 653 | const InnerError = error{ |
| 605 | OutOfMemory, | 654 | OutOfMemory, |
| 606 | /// An error occurred when trying to lower AIR to MIR. | 655 | /// An error occurred when trying to lower AIR to MIR. |
| ... | @@ -759,7 +808,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 { | ... | @@ -759,7 +808,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 { |
| 759 | /// Writes the bytecode depending on the given `WValue` in `val` | 808 | /// Writes the bytecode depending on the given `WValue` in `val` |
| 760 | fn emitWValue(self: *Self, value: WValue) InnerError!void { | 809 | fn emitWValue(self: *Self, value: WValue) InnerError!void { |
| 761 | switch (value) { | 810 | switch (value) { |
| 762 | .none => {}, // no-op | 811 | .none, .stack => {}, // no-op |
| 763 | .local => |idx| try self.addLabel(.local_get, idx), | 812 | .local => |idx| try self.addLabel(.local_get, idx), |
| 764 | .imm32 => |val| try self.addImm32(@bitCast(i32, val)), | 813 | .imm32 => |val| try self.addImm32(@bitCast(i32, val)), |
| 765 | .imm64 => |val| try self.addImm64(val), | 814 | .imm64 => |val| try self.addImm64(val), |
| ... | @@ -781,9 +830,30 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { | ... | @@ -781,9 +830,30 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { |
| 781 | /// Creates one locals for a given `Type`. | 830 | /// Creates one locals for a given `Type`. |
| 782 | /// Returns a corresponding `Wvalue` with `local` as active tag | 831 | /// Returns a corresponding `Wvalue` with `local` as active tag |
| 783 | fn allocLocal(self: *Self, ty: Type) InnerError!WValue { | 832 | fn allocLocal(self: *Self, ty: Type) InnerError!WValue { |
| 833 | const valtype = typeToValtype(ty, self.target); | ||
| 834 | switch (valtype) { | ||
| 835 | .i32 => if (self.free_locals_i32.popOrNull()) |index| { | ||
| 836 | return WValue{ .local = index }; | ||
| 837 | }, | ||
| 838 | .i64 => if (self.free_locals_i64.popOrNull()) |index| { | ||
| 839 | return WValue{ .local = index }; | ||
| 840 | }, | ||
| 841 | .f32 => if (self.free_locals_f32.popOrNull()) |index| { | ||
| 842 | return WValue{ .local = index }; | ||
| 843 | }, | ||
| 844 | .f64 => if (self.free_locals_f64.popOrNull()) |index| { | ||
| 845 | return WValue{ .local = index }; | ||
| 846 | }, | ||
| 847 | } | ||
| 848 | // no local was free to be re-used, so allocate a new local instead | ||
| 849 | return self.ensureAllocLocal(ty); | ||
| 850 | } | ||
| 851 | |||
| 852 | /// Ensures a new local will be created. This is useful when it's useful | ||
| 853 | /// to use a zero-initialized local. | ||
| 854 | fn ensureAllocLocal(self: *Self, ty: Type) InnerError!WValue { | ||
| 855 | try self.locals.append(self.gpa, genValtype(ty, self.target)); | ||
| 784 | const initial_index = self.local_index; | 856 | const initial_index = self.local_index; |
| 785 | const valtype = genValtype(ty, self.target); | ||
| 786 | try self.locals.append(self.gpa, valtype); | ||
| 787 | self.local_index += 1; | 857 | self.local_index += 1; |
| 788 | return WValue{ .local = initial_index }; | 858 | return WValue{ .local = initial_index }; |
| 789 | } | 859 | } |
| ... | @@ -1135,9 +1205,9 @@ fn initializeStack(self: *Self) !void { | ... | @@ -1135,9 +1205,9 @@ fn initializeStack(self: *Self) !void { |
| 1135 | // Reserve a local to store the current stack pointer | 1205 | // Reserve a local to store the current stack pointer |
| 1136 | // We can later use this local to set the stack pointer back to the value | 1206 | // We can later use this local to set the stack pointer back to the value |
| 1137 | // we have stored here. | 1207 | // we have stored here. |
| 1138 | self.initial_stack_value = try self.allocLocal(Type.usize); | 1208 | self.initial_stack_value = try self.ensureAllocLocal(Type.usize); |
| 1139 | // Also reserve a local to store the bottom stack value | 1209 | // Also reserve a local to store the bottom stack value |
| 1140 | self.bottom_stack_value = try self.allocLocal(Type.usize); | 1210 | self.bottom_stack_value = try self.ensureAllocLocal(Type.usize); |
| 1141 | } | 1211 | } |
| 1142 | 1212 | ||
| 1143 | /// Reads the stack pointer from `Context.initial_stack_value` and writes it | 1213 | /// Reads the stack pointer from `Context.initial_stack_value` and writes it |
| ... | @@ -1268,7 +1338,9 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void { | ... | @@ -1268,7 +1338,9 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void { |
| 1268 | else => { | 1338 | else => { |
| 1269 | // TODO: We should probably lower this to a call to compiler_rt | 1339 | // TODO: We should probably lower this to a call to compiler_rt |
| 1270 | // But for now, we implement it manually | 1340 | // But for now, we implement it manually |
| 1271 | const offset = try self.allocLocal(Type.usize); // local for counter | 1341 | var offset = try self.ensureAllocLocal(Type.usize); // local for counter |
| 1342 | defer offset.free(self); | ||
| 1343 | |||
| 1272 | // outer block to jump to when loop is done | 1344 | // outer block to jump to when loop is done |
| 1273 | try self.startBlock(.block, wasm.block_empty); | 1345 | try self.startBlock(.block, wasm.block_empty); |
| 1274 | try self.startBlock(.loop, wasm.block_empty); | 1346 | try self.startBlock(.loop, wasm.block_empty); |
| ... | @@ -1405,7 +1477,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum | ... | @@ -1405,7 +1477,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum |
| 1405 | // do not perform arithmetic when offset is 0. | 1477 | // do not perform arithmetic when offset is 0. |
| 1406 | if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value; | 1478 | if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value; |
| 1407 | const result_ptr: WValue = switch (action) { | 1479 | const result_ptr: WValue = switch (action) { |
| 1408 | .new => try self.allocLocal(Type.usize), | 1480 | .new => try self.ensureAllocLocal(Type.usize), |
| 1409 | .modify => ptr_value, | 1481 | .modify => ptr_value, |
| 1410 | }; | 1482 | }; |
| 1411 | try self.emitWValue(ptr_value); | 1483 | try self.emitWValue(ptr_value); |
| ... | @@ -1622,6 +1694,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1622,6 +1694,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1622 | .err_return_trace, | 1694 | .err_return_trace, |
| 1623 | .set_err_return_trace, | 1695 | .set_err_return_trace, |
| 1624 | .is_named_enum_value, | 1696 | .is_named_enum_value, |
| 1697 | .error_set_has_value, | ||
| 1625 | => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), | 1698 | => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), |
| 1626 | 1699 | ||
| 1627 | .add_optimized, | 1700 | .add_optimized, |
| ... | @@ -1653,7 +1726,10 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1653,7 +1726,10 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1653 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 1726 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1654 | for (body) |inst| { | 1727 | for (body) |inst| { |
| 1655 | const result = try self.genInst(inst); | 1728 | const result = try self.genInst(inst); |
| 1656 | try self.values.putNoClobber(self.gpa, Air.indexToRef(inst), result); | 1729 | if (result != .none) { |
| 1730 | assert(result != .stack); // not allowed to store stack values as we cannot keep track of where they are on the stack | ||
| 1731 | try self.values.putNoClobber(self.gpa, Air.indexToRef(inst), result); | ||
| 1732 | } | ||
| 1657 | } | 1733 | } |
| 1658 | } | 1734 | } |
| 1659 | 1735 | ||
| ... | @@ -1727,8 +1803,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1727,8 +1803,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1727 | 1803 | ||
| 1728 | const fn_info = self.decl.ty.fnInfo(); | 1804 | const fn_info = self.decl.ty.fnInfo(); |
| 1729 | if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) { | 1805 | if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) { |
| 1730 | const result = try self.load(operand, ret_ty, 0); | 1806 | // leave on the stack |
| 1731 | try self.emitWValue(result); | 1807 | _ = try self.load(operand, ret_ty, 0); |
| 1732 | } | 1808 | } |
| 1733 | 1809 | ||
| 1734 | try self.restoreStackPointer(); | 1810 | try self.restoreStackPointer(); |
| ... | @@ -1847,6 +1923,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1847,6 +1923,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1847 | } | 1923 | } |
| 1848 | 1924 | ||
| 1849 | fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { | 1925 | fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { |
| 1926 | assert(!(lhs != .stack and rhs == .stack)); | ||
| 1850 | switch (ty.zigTypeTag()) { | 1927 | switch (ty.zigTypeTag()) { |
| 1851 | .ErrorUnion => { | 1928 | .ErrorUnion => { |
| 1852 | const pl_ty = ty.errorUnionPayload(); | 1929 | const pl_ty = ty.errorUnionPayload(); |
| ... | @@ -1880,20 +1957,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1880,20 +1957,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1880 | .Pointer => { | 1957 | .Pointer => { |
| 1881 | if (ty.isSlice()) { | 1958 | if (ty.isSlice()) { |
| 1882 | // store pointer first | 1959 | // store pointer first |
| 1960 | // lower it to the stack so we do not have to store rhs into a local first | ||
| 1961 | try self.emitWValue(lhs); | ||
| 1883 | const ptr_local = try self.load(rhs, Type.usize, 0); | 1962 | const ptr_local = try self.load(rhs, Type.usize, 0); |
| 1884 | try self.store(lhs, ptr_local, Type.usize, 0); | 1963 | try self.store(.{ .stack = {} }, ptr_local, Type.usize, 0 + lhs.offset()); |
| 1885 | 1964 | ||
| 1886 | // retrieve length from rhs, and store that alongside lhs as well | 1965 | // retrieve length from rhs, and store that alongside lhs as well |
| 1966 | try self.emitWValue(lhs); | ||
| 1887 | const len_local = try self.load(rhs, Type.usize, self.ptrSize()); | 1967 | const len_local = try self.load(rhs, Type.usize, self.ptrSize()); |
| 1888 | try self.store(lhs, len_local, Type.usize, self.ptrSize()); | 1968 | try self.store(.{ .stack = {} }, len_local, Type.usize, self.ptrSize() + lhs.offset()); |
| 1889 | return; | 1969 | return; |
| 1890 | } | 1970 | } |
| 1891 | }, | 1971 | }, |
| 1892 | .Int => if (ty.intInfo(self.target).bits > 64) { | 1972 | .Int => if (ty.intInfo(self.target).bits > 64) { |
| 1973 | try self.emitWValue(lhs); | ||
| 1893 | const lsb = try self.load(rhs, Type.u64, 0); | 1974 | const lsb = try self.load(rhs, Type.u64, 0); |
| 1975 | try self.store(.{ .stack = {} }, lsb, Type.u64, 0 + lhs.offset()); | ||
| 1976 | |||
| 1977 | try self.emitWValue(lhs); | ||
| 1894 | const msb = try self.load(rhs, Type.u64, 8); | 1978 | const msb = try self.load(rhs, Type.u64, 8); |
| 1895 | try self.store(lhs, lsb, Type.u64, 0); | 1979 | try self.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset()); |
| 1896 | try self.store(lhs, msb, Type.u64, 8); | ||
| 1897 | return; | 1980 | return; |
| 1898 | }, | 1981 | }, |
| 1899 | else => {}, | 1982 | else => {}, |
| ... | @@ -1932,9 +2015,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1932,9 +2015,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1932 | return new_local; | 2015 | return new_local; |
| 1933 | } | 2016 | } |
| 1934 | 2017 | ||
| 1935 | return self.load(operand, ty, 0); | 2018 | const stack_loaded = try self.load(operand, ty, 0); |
| 2019 | return stack_loaded.toLocal(self, ty); | ||
| 1936 | } | 2020 | } |
| 1937 | 2021 | ||
| 2022 | /// Loads an operand from the linear memory section. | ||
| 2023 | /// NOTE: Leaves the value on the stack. | ||
| 1938 | fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { | 2024 | fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 1939 | // load local's value from memory by its stack position | 2025 | // load local's value from memory by its stack position |
| 1940 | try self.emitWValue(operand); | 2026 | try self.emitWValue(operand); |
| ... | @@ -1952,10 +2038,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { | ... | @@ -1952,10 +2038,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 1952 | .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) }, | 2038 | .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) }, |
| 1953 | ); | 2039 | ); |
| 1954 | 2040 | ||
| 1955 | // store the result in a local | 2041 | return WValue{ .stack = {} }; |
| 1956 | const result = try self.allocLocal(ty); | ||
| 1957 | try self.addLabel(.local_set, result.local); | ||
| 1958 | return result; | ||
| 1959 | } | 2042 | } |
| 1960 | 2043 | ||
| 1961 | fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2044 | fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -2025,10 +2108,14 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -2025,10 +2108,14 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 2025 | const rhs = try self.resolveInst(bin_op.rhs); | 2108 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2026 | const ty = self.air.typeOf(bin_op.lhs); | 2109 | const ty = self.air.typeOf(bin_op.lhs); |
| 2027 | 2110 | ||
| 2028 | return self.binOp(lhs, rhs, ty, op); | 2111 | const stack_value = try self.binOp(lhs, rhs, ty, op); |
| 2112 | return stack_value.toLocal(self, ty); | ||
| 2029 | } | 2113 | } |
| 2030 | 2114 | ||
| 2115 | /// Performs a binary operation on the given `WValue`'s | ||
| 2116 | /// NOTE: THis leaves the value on top of the stack. | ||
| 2031 | fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2117 | fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| 2118 | assert(!(lhs != .stack and rhs == .stack)); | ||
| 2032 | if (isByRef(ty, self.target)) { | 2119 | if (isByRef(ty, self.target)) { |
| 2033 | if (ty.zigTypeTag() == .Int) { | 2120 | if (ty.zigTypeTag() == .Int) { |
| 2034 | return self.binOpBigInt(lhs, rhs, ty, op); | 2121 | return self.binOpBigInt(lhs, rhs, ty, op); |
| ... | @@ -2054,24 +2141,18 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa | ... | @@ -2054,24 +2141,18 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa |
| 2054 | 2141 | ||
| 2055 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 2142 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2056 | 2143 | ||
| 2057 | // save the result in a temporary | 2144 | return WValue{ .stack = {} }; |
| 2058 | const bin_local = try self.allocLocal(ty); | ||
| 2059 | try self.addLabel(.local_set, bin_local.local); | ||
| 2060 | return bin_local; | ||
| 2061 | } | 2145 | } |
| 2062 | 2146 | ||
| 2147 | /// Performs a binary operation for 16-bit floats. | ||
| 2148 | /// NOTE: Leaves the result value on the stack | ||
| 2063 | fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue { | 2149 | fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue { |
| 2064 | const ext_lhs = try self.fpext(lhs, Type.f16, Type.f32); | ||
| 2065 | const ext_rhs = try self.fpext(rhs, Type.f16, Type.f32); | ||
| 2066 | |||
| 2067 | const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned }); | 2150 | const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned }); |
| 2068 | try self.emitWValue(ext_lhs); | 2151 | _ = try self.fpext(lhs, Type.f16, Type.f32); |
| 2069 | try self.emitWValue(ext_rhs); | 2152 | _ = try self.fpext(rhs, Type.f16, Type.f32); |
| 2070 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 2153 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2071 | 2154 | ||
| 2072 | // re-use temporary local | 2155 | return self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16); |
| 2073 | try self.addLabel(.local_set, ext_lhs.local); | ||
| 2074 | return self.fptrunc(ext_lhs, Type.f32, Type.f16); | ||
| 2075 | } | 2156 | } |
| 2076 | 2157 | ||
| 2077 | fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2158 | fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| ... | @@ -2084,13 +2165,16 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr | ... | @@ -2084,13 +2165,16 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr |
| 2084 | } | 2165 | } |
| 2085 | 2166 | ||
| 2086 | const result = try self.allocStack(ty); | 2167 | const result = try self.allocStack(ty); |
| 2087 | const lhs_high_bit = try self.load(lhs, Type.u64, 0); | 2168 | var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64); |
| 2169 | defer lhs_high_bit.free(self); | ||
| 2170 | var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64); | ||
| 2171 | defer rhs_high_bit.free(self); | ||
| 2172 | var high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64); | ||
| 2173 | defer high_op_res.free(self); | ||
| 2174 | |||
| 2088 | const lhs_low_bit = try self.load(lhs, Type.u64, 8); | 2175 | const lhs_low_bit = try self.load(lhs, Type.u64, 8); |
| 2089 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); | ||
| 2090 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); | 2176 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); |
| 2091 | |||
| 2092 | const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); | 2177 | const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); |
| 2093 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); | ||
| 2094 | 2178 | ||
| 2095 | const lt = if (op == .add) blk: { | 2179 | const lt = if (op == .add) blk: { |
| 2096 | break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); | 2180 | break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt); |
| ... | @@ -2098,7 +2182,8 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr | ... | @@ -2098,7 +2182,8 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr |
| 2098 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); | 2182 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); |
| 2099 | } else unreachable; | 2183 | } else unreachable; |
| 2100 | const tmp = try self.intcast(lt, Type.u32, Type.u64); | 2184 | const tmp = try self.intcast(lt, Type.u32, Type.u64); |
| 2101 | const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op); | 2185 | var tmp_op = try (try self.binOp(low_op_res, tmp, Type.u64, op)).toLocal(self, Type.u64); |
| 2186 | defer tmp_op.free(self); | ||
| 2102 | 2187 | ||
| 2103 | try self.store(result, high_op_res, Type.u64, 0); | 2188 | try self.store(result, high_op_res, Type.u64, 0); |
| 2104 | try self.store(result, tmp_op, Type.u64, 8); | 2189 | try self.store(result, tmp_op, Type.u64, 8); |
| ... | @@ -2115,40 +2200,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -2115,40 +2200,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 2115 | return self.fail("TODO: Implement wrapping arithmetic for vectors", .{}); | 2200 | return self.fail("TODO: Implement wrapping arithmetic for vectors", .{}); |
| 2116 | } | 2201 | } |
| 2117 | 2202 | ||
| 2118 | return self.wrapBinOp(lhs, rhs, ty, op); | 2203 | return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty); |
| 2119 | } | 2204 | } |
| 2120 | 2205 | ||
| 2206 | /// Performs a wrapping binary operation. | ||
| 2207 | /// Asserts rhs is not a stack value when lhs also isn't. | ||
| 2208 | /// NOTE: Leaves the result on the stack when its Type is <= 64 bits | ||
| 2121 | fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2209 | fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| 2122 | const bit_size = ty.intInfo(self.target).bits; | 2210 | const bin_local = try self.binOp(lhs, rhs, ty, op); |
| 2123 | var wasm_bits = toWasmBits(bit_size) orelse { | ||
| 2124 | return self.fail("TODO: Implement wrapping arithmetic for integers with bitsize: {d}\n", .{bit_size}); | ||
| 2125 | }; | ||
| 2126 | |||
| 2127 | if (wasm_bits == 128) { | ||
| 2128 | const bin_op = try self.binOpBigInt(lhs, rhs, ty, op); | ||
| 2129 | return self.wrapOperand(bin_op, ty); | ||
| 2130 | } | ||
| 2131 | |||
| 2132 | const opcode: wasm.Opcode = buildOpcode(.{ | ||
| 2133 | .op = op, | ||
| 2134 | .valtype1 = typeToValtype(ty, self.target), | ||
| 2135 | .signedness = if (ty.isSignedInt()) .signed else .unsigned, | ||
| 2136 | }); | ||
| 2137 | |||
| 2138 | try self.emitWValue(lhs); | ||
| 2139 | try self.emitWValue(rhs); | ||
| 2140 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | ||
| 2141 | const bin_local = try self.allocLocal(ty); | ||
| 2142 | try self.addLabel(.local_set, bin_local.local); | ||
| 2143 | |||
| 2144 | return self.wrapOperand(bin_local, ty); | 2211 | return self.wrapOperand(bin_local, ty); |
| 2145 | } | 2212 | } |
| 2146 | 2213 | ||
| 2147 | /// Wraps an operand based on a given type's bitsize. | 2214 | /// Wraps an operand based on a given type's bitsize. |
| 2148 | /// Asserts `Type` is <= 128 bits. | 2215 | /// Asserts `Type` is <= 128 bits. |
| 2216 | /// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack. | ||
| 2149 | fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | 2217 | fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2150 | assert(ty.abiSize(self.target) <= 16); | 2218 | assert(ty.abiSize(self.target) <= 16); |
| 2151 | const result_local = try self.allocLocal(ty); | ||
| 2152 | const bitsize = ty.intInfo(self.target).bits; | 2219 | const bitsize = ty.intInfo(self.target).bits; |
| 2153 | const wasm_bits = toWasmBits(bitsize) orelse { | 2220 | const wasm_bits = toWasmBits(bitsize) orelse { |
| 2154 | return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); | 2221 | return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); |
| ... | @@ -2157,14 +2224,15 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -2157,14 +2224,15 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2157 | if (wasm_bits == bitsize) return operand; | 2224 | if (wasm_bits == bitsize) return operand; |
| 2158 | 2225 | ||
| 2159 | if (wasm_bits == 128) { | 2226 | if (wasm_bits == 128) { |
| 2160 | const msb = try self.load(operand, Type.u64, 0); | 2227 | assert(operand != .stack); |
| 2161 | const lsb = try self.load(operand, Type.u64, 8); | 2228 | const lsb = try self.load(operand, Type.u64, 8); |
| 2162 | 2229 | ||
| 2163 | const result_ptr = try self.allocStack(ty); | 2230 | const result_ptr = try self.allocStack(ty); |
| 2164 | try self.store(result_ptr, lsb, Type.u64, 8); | 2231 | try self.emitWValue(result_ptr); |
| 2232 | try self.store(.{ .stack = {} }, lsb, Type.u64, 8 + result_ptr.offset()); | ||
| 2165 | const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1; | 2233 | const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1; |
| 2166 | try self.emitWValue(result_ptr); | 2234 | try self.emitWValue(result_ptr); |
| 2167 | try self.emitWValue(msb); | 2235 | _ = try self.load(operand, Type.u64, 0); |
| 2168 | try self.addImm64(result); | 2236 | try self.addImm64(result); |
| 2169 | try self.addTag(.i64_and); | 2237 | try self.addTag(.i64_and); |
| 2170 | try self.addMemArg(.i64_store, .{ .offset = result_ptr.offset(), .alignment = 8 }); | 2238 | try self.addMemArg(.i64_store, .{ .offset = result_ptr.offset(), .alignment = 8 }); |
| ... | @@ -2181,8 +2249,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -2181,8 +2249,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2181 | try self.addTag(.i64_and); | 2249 | try self.addTag(.i64_and); |
| 2182 | } else unreachable; | 2250 | } else unreachable; |
| 2183 | 2251 | ||
| 2184 | try self.addLabel(.local_set, result_local.local); | 2252 | return WValue{ .stack = {} }; |
| 2185 | return result_local; | ||
| 2186 | } | 2253 | } |
| 2187 | 2254 | ||
| 2188 | fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue { | 2255 | fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue { |
| ... | @@ -2594,10 +2661,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner | ... | @@ -2594,10 +2661,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner |
| 2594 | const lhs = try self.resolveInst(bin_op.lhs); | 2661 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2595 | const rhs = try self.resolveInst(bin_op.rhs); | 2662 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2596 | const operand_ty = self.air.typeOf(bin_op.lhs); | 2663 | const operand_ty = self.air.typeOf(bin_op.lhs); |
| 2597 | return self.cmp(lhs, rhs, operand_ty, op); | 2664 | return (try self.cmp(lhs, rhs, operand_ty, op)).toLocal(self, Type.u32); // comparison result is always 32 bits |
| 2598 | } | 2665 | } |
| 2599 | 2666 | ||
| 2667 | /// Compares two operands. | ||
| 2668 | /// Asserts rhs is not a stack value when the lhs isn't a stack value either | ||
| 2669 | /// NOTE: This leaves the result on top of the stack, rather than a new local. | ||
| 2600 | fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue { | 2670 | fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 2671 | assert(!(lhs != .stack and rhs == .stack)); | ||
| 2601 | if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) { | 2672 | if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) { |
| 2602 | var buf: Type.Payload.ElemType = undefined; | 2673 | var buf: Type.Payload.ElemType = undefined; |
| 2603 | const payload_ty = ty.optionalChild(&buf); | 2674 | const payload_ty = ty.optionalChild(&buf); |
| ... | @@ -2639,15 +2710,12 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper | ... | @@ -2639,15 +2710,12 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper |
| 2639 | }); | 2710 | }); |
| 2640 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 2711 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2641 | 2712 | ||
| 2642 | const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i32 | 2713 | return WValue{ .stack = {} }; |
| 2643 | try self.addLabel(.local_set, cmp_tmp.local); | ||
| 2644 | return cmp_tmp; | ||
| 2645 | } | 2714 | } |
| 2646 | 2715 | ||
| 2716 | /// Compares 16-bit floats | ||
| 2717 | /// NOTE: The result value remains on top of the stack. | ||
| 2647 | fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue { | 2718 | fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue { |
| 2648 | const ext_lhs = try self.fpext(lhs, Type.f16, Type.f32); | ||
| 2649 | const ext_rhs = try self.fpext(rhs, Type.f16, Type.f32); | ||
| 2650 | |||
| 2651 | const opcode: wasm.Opcode = buildOpcode(.{ | 2719 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 2652 | .op = switch (op) { | 2720 | .op = switch (op) { |
| 2653 | .lt => .lt, | 2721 | .lt => .lt, |
| ... | @@ -2660,13 +2728,11 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato | ... | @@ -2660,13 +2728,11 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato |
| 2660 | .valtype1 = .f32, | 2728 | .valtype1 = .f32, |
| 2661 | .signedness = .unsigned, | 2729 | .signedness = .unsigned, |
| 2662 | }); | 2730 | }); |
| 2663 | try self.emitWValue(ext_lhs); | 2731 | _ = try self.fpext(lhs, Type.f16, Type.f32); |
| 2664 | try self.emitWValue(ext_rhs); | 2732 | _ = try self.fpext(rhs, Type.f16, Type.f32); |
| 2665 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 2733 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2666 | 2734 | ||
| 2667 | const result = try self.allocLocal(Type.initTag(.i32)); // bool is always i32 | 2735 | return WValue{ .stack = {} }; |
| 2668 | try self.addLabel(.local_set, result.local); | ||
| 2669 | return result; | ||
| 2670 | } | 2736 | } |
| 2671 | 2737 | ||
| 2672 | fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2738 | fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -2727,21 +2793,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2727,21 +2793,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2727 | switch (wasm_bits) { | 2793 | switch (wasm_bits) { |
| 2728 | 32 => { | 2794 | 32 => { |
| 2729 | const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); | 2795 | const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor); |
| 2730 | return self.wrapOperand(bin_op, operand_ty); | 2796 | return (try self.wrapOperand(bin_op, operand_ty)).toLocal(self, operand_ty); |
| 2731 | }, | 2797 | }, |
| 2732 | 64 => { | 2798 | 64 => { |
| 2733 | const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor); | 2799 | const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor); |
| 2734 | return self.wrapOperand(bin_op, operand_ty); | 2800 | return (try self.wrapOperand(bin_op, operand_ty)).toLocal(self, operand_ty); |
| 2735 | }, | 2801 | }, |
| 2736 | 128 => { | 2802 | 128 => { |
| 2737 | const result_ptr = try self.allocStack(operand_ty); | 2803 | const result_ptr = try self.allocStack(operand_ty); |
| 2804 | try self.emitWValue(result_ptr); | ||
| 2738 | const msb = try self.load(operand, Type.u64, 0); | 2805 | const msb = try self.load(operand, Type.u64, 0); |
| 2739 | const lsb = try self.load(operand, Type.u64, 8); | ||
| 2740 | |||
| 2741 | const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); | 2806 | const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 2807 | try self.store(.{ .stack = {} }, msb_xor, Type.u64, 0 + result_ptr.offset()); | ||
| 2808 | |||
| 2809 | try self.emitWValue(result_ptr); | ||
| 2810 | const lsb = try self.load(operand, Type.u64, 8); | ||
| 2742 | const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); | 2811 | const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 2743 | try self.store(result_ptr, msb_xor, Type.u64, 0); | 2812 | try self.store(result_ptr, lsb_xor, Type.u64, 8 + result_ptr.offset()); |
| 2744 | try self.store(result_ptr, lsb_xor, Type.u64, 8); | ||
| 2745 | return result_ptr; | 2813 | return result_ptr; |
| 2746 | }, | 2814 | }, |
| 2747 | else => unreachable, | 2815 | else => unreachable, |
| ... | @@ -2829,7 +2897,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2829,7 +2897,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2829 | } | 2897 | } |
| 2830 | } | 2898 | } |
| 2831 | 2899 | ||
| 2832 | return self.load(operand, field_ty, offset); | 2900 | const field = try self.load(operand, field_ty, offset); |
| 2901 | return field.toLocal(self, field_ty); | ||
| 2833 | } | 2902 | } |
| 2834 | 2903 | ||
| 2835 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2904 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3039,7 +3108,9 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) | ... | @@ -3039,7 +3108,9 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) |
| 3039 | if (op_is_ptr or isByRef(payload_ty, self.target)) { | 3108 | if (op_is_ptr or isByRef(payload_ty, self.target)) { |
| 3040 | return self.buildPointerOffset(operand, pl_offset, .new); | 3109 | return self.buildPointerOffset(operand, pl_offset, .new); |
| 3041 | } | 3110 | } |
| 3042 | return self.load(operand, payload_ty, pl_offset); | 3111 | |
| 3112 | const payload = try self.load(operand, payload_ty, pl_offset); | ||
| 3113 | return payload.toLocal(self, payload_ty); | ||
| 3043 | } | 3114 | } |
| 3044 | 3115 | ||
| 3045 | fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue { | 3116 | fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue { |
| ... | @@ -3059,7 +3130,8 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In | ... | @@ -3059,7 +3130,8 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In |
| 3059 | return operand; | 3130 | return operand; |
| 3060 | } | 3131 | } |
| 3061 | 3132 | ||
| 3062 | return self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target))); | 3133 | const error_val = try self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target))); |
| 3134 | return error_val.toLocal(self, Type.anyerror); | ||
| 3063 | } | 3135 | } |
| 3064 | 3136 | ||
| 3065 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3137 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3125,12 +3197,13 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3125,12 +3197,13 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3125 | return self.fail("todo Wasm intcast for bitsize > 128", .{}); | 3197 | return self.fail("todo Wasm intcast for bitsize > 128", .{}); |
| 3126 | } | 3198 | } |
| 3127 | 3199 | ||
| 3128 | return self.intcast(operand, operand_ty, ty); | 3200 | return (try self.intcast(operand, operand_ty, ty)).toLocal(self, ty); |
| 3129 | } | 3201 | } |
| 3130 | 3202 | ||
| 3131 | /// Upcasts or downcasts an integer based on the given and wanted types, | 3203 | /// Upcasts or downcasts an integer based on the given and wanted types, |
| 3132 | /// and stores the result in a new operand. | 3204 | /// and stores the result in a new operand. |
| 3133 | /// Asserts type's bitsize <= 128 | 3205 | /// Asserts type's bitsize <= 128 |
| 3206 | /// NOTE: May leave the result on the top of the stack. | ||
| 3134 | fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { | 3207 | fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { |
| 3135 | const given_info = given.intInfo(self.target); | 3208 | const given_info = given.intInfo(self.target); |
| 3136 | const wanted_info = wanted.intInfo(self.target); | 3209 | const wanted_info = wanted.intInfo(self.target); |
| ... | @@ -3153,25 +3226,22 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W | ... | @@ -3153,25 +3226,22 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W |
| 3153 | } else if (wanted_bits == 128) { | 3226 | } else if (wanted_bits == 128) { |
| 3154 | // for 128bit integers we store the integer in the virtual stack, rather than a local | 3227 | // for 128bit integers we store the integer in the virtual stack, rather than a local |
| 3155 | const stack_ptr = try self.allocStack(wanted); | 3228 | const stack_ptr = try self.allocStack(wanted); |
| 3229 | try self.emitWValue(stack_ptr); | ||
| 3156 | 3230 | ||
| 3157 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it | 3231 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it |
| 3158 | // meaning less store operations are required. | 3232 | // meaning less store operations are required. |
| 3159 | const lhs = if (op_bits == 32) blk: { | 3233 | const lhs = if (op_bits == 32) blk: { |
| 3160 | const tmp = try self.intcast( | 3234 | break :blk try self.intcast(operand, given, if (wanted.isSignedInt()) Type.i64 else Type.u64); |
| 3161 | operand, | ||
| 3162 | given, | ||
| 3163 | if (wanted.isSignedInt()) Type.i64 else Type.u64, | ||
| 3164 | ); | ||
| 3165 | break :blk tmp; | ||
| 3166 | } else operand; | 3235 | } else operand; |
| 3167 | 3236 | ||
| 3168 | // store msb first | 3237 | // store msb first |
| 3169 | try self.store(stack_ptr, lhs, Type.u64, 0); | 3238 | try self.store(.{ .stack = {} }, lhs, Type.u64, 0 + stack_ptr.offset()); |
| 3170 | 3239 | ||
| 3171 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value | 3240 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value |
| 3172 | if (wanted.isSignedInt()) { | 3241 | if (wanted.isSignedInt()) { |
| 3242 | try self.emitWValue(stack_ptr); | ||
| 3173 | const shr = try self.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); | 3243 | const shr = try self.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); |
| 3174 | try self.store(stack_ptr, shr, Type.u64, 8); | 3244 | try self.store(.{ .stack = {} }, shr, Type.u64, 8 + stack_ptr.offset()); |
| 3175 | } else { | 3245 | } else { |
| 3176 | // Ensure memory of lsb is zero'd | 3246 | // Ensure memory of lsb is zero'd |
| 3177 | try self.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8); | 3247 | try self.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8); |
| ... | @@ -3179,9 +3249,7 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W | ... | @@ -3179,9 +3249,7 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W |
| 3179 | return stack_ptr; | 3249 | return stack_ptr; |
| 3180 | } else return self.load(operand, wanted, 0); | 3250 | } else return self.load(operand, wanted, 0); |
| 3181 | 3251 | ||
| 3182 | const result = try self.allocLocal(wanted); | 3252 | return WValue{ .stack = {} }; |
| 3183 | try self.addLabel(.local_set, result.local); | ||
| 3184 | return result; | ||
| 3185 | } | 3253 | } |
| 3186 | 3254 | ||
| 3187 | fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue { | 3255 | fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue { |
| ... | @@ -3190,9 +3258,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en | ... | @@ -3190,9 +3258,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en |
| 3190 | 3258 | ||
| 3191 | const op_ty = self.air.typeOf(un_op); | 3259 | const op_ty = self.air.typeOf(un_op); |
| 3192 | const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty; | 3260 | const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty; |
| 3193 | return self.isNull(operand, optional_ty, opcode); | 3261 | const is_null = try self.isNull(operand, optional_ty, opcode); |
| 3262 | return is_null.toLocal(self, optional_ty); | ||
| 3194 | } | 3263 | } |
| 3195 | 3264 | ||
| 3265 | /// For a given type and operand, checks if it's considered `null`. | ||
| 3266 | /// NOTE: Leaves the result on the stack | ||
| 3196 | fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue { | 3267 | fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue { |
| 3197 | try self.emitWValue(operand); | 3268 | try self.emitWValue(operand); |
| 3198 | if (!optional_ty.optionalReprIsPayload()) { | 3269 | if (!optional_ty.optionalReprIsPayload()) { |
| ... | @@ -3209,9 +3280,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) | ... | @@ -3209,9 +3280,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) |
| 3209 | try self.addImm32(0); | 3280 | try self.addImm32(0); |
| 3210 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 3281 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 3211 | 3282 | ||
| 3212 | const is_null_tmp = try self.allocLocal(Type.initTag(.i32)); | 3283 | return WValue{ .stack = {} }; |
| 3213 | try self.addLabel(.local_set, is_null_tmp.local); | ||
| 3214 | return is_null_tmp; | ||
| 3215 | } | 3284 | } |
| 3216 | 3285 | ||
| 3217 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3286 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3229,7 +3298,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3229,7 +3298,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3229 | return self.buildPointerOffset(operand, offset, .new); | 3298 | return self.buildPointerOffset(operand, offset, .new); |
| 3230 | } | 3299 | } |
| 3231 | 3300 | ||
| 3232 | return self.load(operand, payload_ty, @intCast(u32, offset)); | 3301 | const payload = try self.load(operand, payload_ty, @intCast(u32, offset)); |
| 3302 | return payload.toLocal(self, payload_ty); | ||
| 3233 | } | 3303 | } |
| 3234 | 3304 | ||
| 3235 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3305 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3332,7 +3402,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3332,7 +3402,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3332 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3402 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3333 | const operand = try self.resolveInst(ty_op.operand); | 3403 | const operand = try self.resolveInst(ty_op.operand); |
| 3334 | 3404 | ||
| 3335 | return self.load(operand, Type.usize, self.ptrSize()); | 3405 | const len = try self.load(operand, Type.usize, self.ptrSize()); |
| 3406 | return len.toLocal(self, Type.usize); | ||
| 3336 | } | 3407 | } |
| 3337 | 3408 | ||
| 3338 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3409 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3346,8 +3417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3346,8 +3417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3346 | const elem_size = elem_ty.abiSize(self.target); | 3417 | const elem_size = elem_ty.abiSize(self.target); |
| 3347 | 3418 | ||
| 3348 | // load pointer onto stack | 3419 | // load pointer onto stack |
| 3349 | const slice_ptr = try self.load(slice, Type.usize, 0); | 3420 | _ = try self.load(slice, Type.usize, 0); |
| 3350 | try self.addLabel(.local_get, slice_ptr.local); | ||
| 3351 | 3421 | ||
| 3352 | // calculate index into slice | 3422 | // calculate index into slice |
| 3353 | try self.emitWValue(index); | 3423 | try self.emitWValue(index); |
| ... | @@ -3361,7 +3431,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3361,7 +3431,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3361 | if (isByRef(elem_ty, self.target)) { | 3431 | if (isByRef(elem_ty, self.target)) { |
| 3362 | return result; | 3432 | return result; |
| 3363 | } | 3433 | } |
| 3364 | return self.load(result, elem_ty, 0); | 3434 | |
| 3435 | const elem_val = try self.load(result, elem_ty, 0); | ||
| 3436 | return elem_val.toLocal(self, elem_ty); | ||
| 3365 | } | 3437 | } |
| 3366 | 3438 | ||
| 3367 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3439 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3374,8 +3446,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3374,8 +3446,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3374 | const slice = try self.resolveInst(bin_op.lhs); | 3446 | const slice = try self.resolveInst(bin_op.lhs); |
| 3375 | const index = try self.resolveInst(bin_op.rhs); | 3447 | const index = try self.resolveInst(bin_op.rhs); |
| 3376 | 3448 | ||
| 3377 | const slice_ptr = try self.load(slice, Type.usize, 0); | 3449 | _ = try self.load(slice, Type.usize, 0); |
| 3378 | try self.addLabel(.local_get, slice_ptr.local); | ||
| 3379 | 3450 | ||
| 3380 | // calculate index into slice | 3451 | // calculate index into slice |
| 3381 | try self.emitWValue(index); | 3452 | try self.emitWValue(index); |
| ... | @@ -3383,7 +3454,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3383,7 +3454,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3383 | try self.addTag(.i32_mul); | 3454 | try self.addTag(.i32_mul); |
| 3384 | try self.addTag(.i32_add); | 3455 | try self.addTag(.i32_add); |
| 3385 | 3456 | ||
| 3386 | const result = try self.allocLocal(Type.initTag(.i32)); | 3457 | const result = try self.allocLocal(Type.i32); |
| 3387 | try self.addLabel(.local_set, result.local); | 3458 | try self.addLabel(.local_set, result.local); |
| 3388 | return result; | 3459 | return result; |
| 3389 | } | 3460 | } |
| ... | @@ -3392,7 +3463,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3392,7 +3463,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3392 | if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; | 3463 | if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; |
| 3393 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3464 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3394 | const operand = try self.resolveInst(ty_op.operand); | 3465 | const operand = try self.resolveInst(ty_op.operand); |
| 3395 | return self.load(operand, Type.usize, 0); | 3466 | const ptr = try self.load(operand, Type.usize, 0); |
| 3467 | return ptr.toLocal(self, Type.usize); | ||
| 3396 | } | 3468 | } |
| 3397 | 3469 | ||
| 3398 | fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3470 | fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3407,13 +3479,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3407,13 +3479,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3407 | return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits}); | 3479 | return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits}); |
| 3408 | } | 3480 | } |
| 3409 | 3481 | ||
| 3410 | const result = try self.intcast(operand, op_ty, wanted_ty); | 3482 | var result = try self.intcast(operand, op_ty, wanted_ty); |
| 3411 | const wanted_bits = wanted_ty.intInfo(self.target).bits; | 3483 | const wanted_bits = wanted_ty.intInfo(self.target).bits; |
| 3412 | const wasm_bits = toWasmBits(wanted_bits).?; | 3484 | const wasm_bits = toWasmBits(wanted_bits).?; |
| 3413 | if (wasm_bits != wanted_bits) { | 3485 | if (wasm_bits != wanted_bits) { |
| 3414 | return self.wrapOperand(result, wanted_ty); | 3486 | result = try self.wrapOperand(result, wanted_ty); |
| 3415 | } | 3487 | } |
| 3416 | return result; | 3488 | return result.toLocal(self, wanted_ty); |
| 3417 | } | 3489 | } |
| 3418 | 3490 | ||
| 3419 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3491 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3466,8 +3538,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3466,8 +3538,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3466 | 3538 | ||
| 3467 | // load pointer onto the stack | 3539 | // load pointer onto the stack |
| 3468 | if (ptr_ty.isSlice()) { | 3540 | if (ptr_ty.isSlice()) { |
| 3469 | const ptr_local = try self.load(ptr, Type.usize, 0); | 3541 | _ = try self.load(ptr, Type.usize, 0); |
| 3470 | try self.addLabel(.local_get, ptr_local.local); | ||
| 3471 | } else { | 3542 | } else { |
| 3472 | try self.lowerToStack(ptr); | 3543 | try self.lowerToStack(ptr); |
| 3473 | } | 3544 | } |
| ... | @@ -3478,12 +3549,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3478,12 +3549,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3478 | try self.addTag(.i32_mul); | 3549 | try self.addTag(.i32_mul); |
| 3479 | try self.addTag(.i32_add); | 3550 | try self.addTag(.i32_add); |
| 3480 | 3551 | ||
| 3481 | const result = try self.allocLocal(elem_ty); | 3552 | var result = try self.allocLocal(elem_ty); |
| 3482 | try self.addLabel(.local_set, result.local); | 3553 | try self.addLabel(.local_set, result.local); |
| 3483 | if (isByRef(elem_ty, self.target)) { | 3554 | if (isByRef(elem_ty, self.target)) { |
| 3484 | return result; | 3555 | return result; |
| 3485 | } | 3556 | } |
| 3486 | return self.load(result, elem_ty, 0); | 3557 | defer result.free(self); // only free if it's not returned like above |
| 3558 | |||
| 3559 | const elem_val = try self.load(result, elem_ty, 0); | ||
| 3560 | return elem_val.toLocal(self, elem_ty); | ||
| 3487 | } | 3561 | } |
| 3488 | 3562 | ||
| 3489 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3563 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3499,8 +3573,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3499,8 +3573,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3499 | 3573 | ||
| 3500 | // load pointer onto the stack | 3574 | // load pointer onto the stack |
| 3501 | if (ptr_ty.isSlice()) { | 3575 | if (ptr_ty.isSlice()) { |
| 3502 | const ptr_local = try self.load(ptr, Type.usize, 0); | 3576 | _ = try self.load(ptr, Type.usize, 0); |
| 3503 | try self.addLabel(.local_get, ptr_local.local); | ||
| 3504 | } else { | 3577 | } else { |
| 3505 | try self.lowerToStack(ptr); | 3578 | try self.lowerToStack(ptr); |
| 3506 | } | 3579 | } |
| ... | @@ -3511,7 +3584,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3511,7 +3584,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3511 | try self.addTag(.i32_mul); | 3584 | try self.addTag(.i32_mul); |
| 3512 | try self.addTag(.i32_add); | 3585 | try self.addTag(.i32_add); |
| 3513 | 3586 | ||
| 3514 | const result = try self.allocLocal(Type.initTag(.i32)); | 3587 | const result = try self.allocLocal(Type.i32); |
| 3515 | try self.addLabel(.local_set, result.local); | 3588 | try self.addLabel(.local_set, result.local); |
| 3516 | return result; | 3589 | return result; |
| 3517 | } | 3590 | } |
| ... | @@ -3599,7 +3672,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void | ... | @@ -3599,7 +3672,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void |
| 3599 | else => { | 3672 | else => { |
| 3600 | // TODO: We should probably lower this to a call to compiler_rt | 3673 | // TODO: We should probably lower this to a call to compiler_rt |
| 3601 | // But for now, we implement it manually | 3674 | // But for now, we implement it manually |
| 3602 | const offset = try self.allocLocal(Type.usize); // local for counter | 3675 | const offset = try self.ensureAllocLocal(Type.usize); // local for counter |
| 3603 | // outer block to jump to when loop is done | 3676 | // outer block to jump to when loop is done |
| 3604 | try self.startBlock(.block, wasm.block_empty); | 3677 | try self.startBlock(.block, wasm.block_empty); |
| 3605 | try self.startBlock(.loop, wasm.block_empty); | 3678 | try self.startBlock(.loop, wasm.block_empty); |
| ... | @@ -3656,13 +3729,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3656,13 +3729,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3656 | try self.addTag(.i32_mul); | 3729 | try self.addTag(.i32_mul); |
| 3657 | try self.addTag(.i32_add); | 3730 | try self.addTag(.i32_add); |
| 3658 | 3731 | ||
| 3659 | const result = try self.allocLocal(Type.usize); | 3732 | var result = try self.allocLocal(Type.usize); |
| 3660 | try self.addLabel(.local_set, result.local); | 3733 | try self.addLabel(.local_set, result.local); |
| 3661 | 3734 | ||
| 3662 | if (isByRef(elem_ty, self.target)) { | 3735 | if (isByRef(elem_ty, self.target)) { |
| 3663 | return result; | 3736 | return result; |
| 3664 | } | 3737 | } |
| 3665 | return self.load(result, elem_ty, 0); | 3738 | defer result.free(self); // only free if no longer needed and not returned like above |
| 3739 | |||
| 3740 | const elem_val = try self.load(result, elem_ty, 0); | ||
| 3741 | return elem_val.toLocal(self, elem_ty); | ||
| 3666 | } | 3742 | } |
| 3667 | 3743 | ||
| 3668 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3744 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3685,11 +3761,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3685,11 +3761,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3685 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, | 3761 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, |
| 3686 | }); | 3762 | }); |
| 3687 | try self.addTag(Mir.Inst.Tag.fromOpcode(op)); | 3763 | try self.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| 3688 | 3764 | const wrapped = try self.wrapOperand(.{ .stack = {} }, dest_ty); | |
| 3689 | const result = try self.allocLocal(dest_ty); | 3765 | return wrapped.toLocal(self, dest_ty); |
| 3690 | try self.addLabel(.local_set, result.local); | ||
| 3691 | |||
| 3692 | return self.wrapOperand(result, dest_ty); | ||
| 3693 | } | 3766 | } |
| 3694 | 3767 | ||
| 3695 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3768 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -3887,24 +3960,19 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std | ... | @@ -3887,24 +3960,19 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 3887 | const payload_ty = operand_ty.optionalChild(&buf); | 3960 | const payload_ty = operand_ty.optionalChild(&buf); |
| 3888 | const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target)); | 3961 | const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target)); |
| 3889 | 3962 | ||
| 3890 | const lhs_is_null = try self.isNull(lhs, operand_ty, .i32_eq); | ||
| 3891 | const rhs_is_null = try self.isNull(rhs, operand_ty, .i32_eq); | ||
| 3892 | |||
| 3893 | // We store the final result in here that will be validated | 3963 | // We store the final result in here that will be validated |
| 3894 | // if the optional is truly equal. | 3964 | // if the optional is truly equal. |
| 3895 | const result = try self.allocLocal(Type.initTag(.i32)); | 3965 | var result = try self.ensureAllocLocal(Type.initTag(.i32)); |
| 3966 | defer result.free(self); | ||
| 3896 | 3967 | ||
| 3897 | try self.startBlock(.block, wasm.block_empty); | 3968 | try self.startBlock(.block, wasm.block_empty); |
| 3898 | try self.emitWValue(lhs_is_null); | 3969 | _ = try self.isNull(lhs, operand_ty, .i32_eq); |
| 3899 | try self.emitWValue(rhs_is_null); | 3970 | _ = try self.isNull(rhs, operand_ty, .i32_eq); |
| 3900 | try self.addTag(.i32_ne); // inverse so we can exit early | 3971 | try self.addTag(.i32_ne); // inverse so we can exit early |
| 3901 | try self.addLabel(.br_if, 0); | 3972 | try self.addLabel(.br_if, 0); |
| 3902 | 3973 | ||
| 3903 | const lhs_pl = try self.load(lhs, payload_ty, offset); | 3974 | _ = try self.load(lhs, payload_ty, offset); |
| 3904 | const rhs_pl = try self.load(rhs, payload_ty, offset); | 3975 | _ = try self.load(rhs, payload_ty, offset); |
| 3905 | |||
| 3906 | try self.emitWValue(lhs_pl); | ||
| 3907 | try self.emitWValue(rhs_pl); | ||
| 3908 | const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) }); | 3976 | const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) }); |
| 3909 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 3977 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 3910 | try self.addLabel(.br_if, 0); | 3978 | try self.addLabel(.br_if, 0); |
| ... | @@ -3916,26 +3984,29 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std | ... | @@ -3916,26 +3984,29 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 3916 | try self.emitWValue(result); | 3984 | try self.emitWValue(result); |
| 3917 | try self.addImm32(0); | 3985 | try self.addImm32(0); |
| 3918 | try self.addTag(if (op == .eq) .i32_ne else .i32_eq); | 3986 | try self.addTag(if (op == .eq) .i32_ne else .i32_eq); |
| 3919 | try self.addLabel(.local_set, result.local); | 3987 | return WValue{ .stack = {} }; |
| 3920 | return result; | ||
| 3921 | } | 3988 | } |
| 3922 | 3989 | ||
| 3923 | /// Compares big integers by checking both its high bits and low bits. | 3990 | /// Compares big integers by checking both its high bits and low bits. |
| 3991 | /// NOTE: Leaves the result of the comparison on top of the stack. | ||
| 3924 | /// TODO: Lower this to compiler_rt call when bitsize > 128 | 3992 | /// TODO: Lower this to compiler_rt call when bitsize > 128 |
| 3925 | fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { | 3993 | fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 3926 | assert(operand_ty.abiSize(self.target) >= 16); | 3994 | assert(operand_ty.abiSize(self.target) >= 16); |
| 3995 | assert(!(lhs != .stack and rhs == .stack)); | ||
| 3927 | if (operand_ty.intInfo(self.target).bits > 128) { | 3996 | if (operand_ty.intInfo(self.target).bits > 128) { |
| 3928 | return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits}); | 3997 | return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits}); |
| 3929 | } | 3998 | } |
| 3930 | 3999 | ||
| 3931 | const lhs_high_bit = try self.load(lhs, Type.u64, 0); | 4000 | var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64); |
| 3932 | const lhs_low_bit = try self.load(lhs, Type.u64, 8); | 4001 | defer lhs_high_bit.free(self); |
| 3933 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); | 4002 | var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64); |
| 3934 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); | 4003 | defer rhs_high_bit.free(self); |
| 3935 | 4004 | ||
| 3936 | switch (op) { | 4005 | switch (op) { |
| 3937 | .eq, .neq => { | 4006 | .eq, .neq => { |
| 3938 | const xor_high = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor); | 4007 | const xor_high = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor); |
| 4008 | const lhs_low_bit = try self.load(lhs, Type.u64, 8); | ||
| 4009 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); | ||
| 3939 | const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); | 4010 | const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); |
| 3940 | const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or"); | 4011 | const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or"); |
| 3941 | 4012 | ||
| ... | @@ -3947,20 +4018,17 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma | ... | @@ -3947,20 +4018,17 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma |
| 3947 | }, | 4018 | }, |
| 3948 | else => { | 4019 | else => { |
| 3949 | const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64; | 4020 | const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64; |
| 3950 | const high_bit_eql = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq); | 4021 | // leave those value on top of the stack for '.select' |
| 3951 | const high_bit_cmp = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op); | 4022 | const lhs_low_bit = try self.load(lhs, Type.u64, 8); |
| 3952 | const low_bit_cmp = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op); | 4023 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); |
| 3953 | 4024 | _ = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op); | |
| 3954 | try self.emitWValue(low_bit_cmp); | 4025 | _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op); |
| 3955 | try self.emitWValue(high_bit_cmp); | 4026 | _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq); |
| 3956 | try self.emitWValue(high_bit_eql); | ||
| 3957 | try self.addTag(.select); | 4027 | try self.addTag(.select); |
| 3958 | }, | 4028 | }, |
| 3959 | } | 4029 | } |
| 3960 | 4030 | ||
| 3961 | const result = try self.allocLocal(Type.initTag(.i32)); | 4031 | return WValue{ .stack = {} }; |
| 3962 | try self.addLabel(.local_set, result.local); | ||
| 3963 | return result; | ||
| 3964 | } | 4032 | } |
| 3965 | 4033 | ||
| 3966 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4034 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4000,7 +4068,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4000,7 +4068,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4000 | const offset = if (layout.tag_align < layout.payload_align) blk: { | 4068 | const offset = if (layout.tag_align < layout.payload_align) blk: { |
| 4001 | break :blk @intCast(u32, layout.payload_size); | 4069 | break :blk @intCast(u32, layout.payload_size); |
| 4002 | } else @as(u32, 0); | 4070 | } else @as(u32, 0); |
| 4003 | return self.load(operand, tag_ty, offset); | 4071 | const tag = try self.load(operand, tag_ty, offset); |
| 4072 | return tag.toLocal(self, tag_ty); | ||
| 4004 | } | 4073 | } |
| 4005 | 4074 | ||
| 4006 | fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4075 | fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4010,19 +4079,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4010,19 +4079,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4010 | const dest_ty = self.air.typeOfIndex(inst); | 4079 | const dest_ty = self.air.typeOfIndex(inst); |
| 4011 | const operand = try self.resolveInst(ty_op.operand); | 4080 | const operand = try self.resolveInst(ty_op.operand); |
| 4012 | 4081 | ||
| 4013 | return self.fpext(operand, self.air.typeOf(ty_op.operand), dest_ty); | 4082 | const extended = try self.fpext(operand, self.air.typeOf(ty_op.operand), dest_ty); |
| 4083 | return extended.toLocal(self, dest_ty); | ||
| 4014 | } | 4084 | } |
| 4015 | 4085 | ||
| 4086 | /// Extends a float from a given `Type` to a larger wanted `Type` | ||
| 4087 | /// NOTE: Leaves the result on the stack | ||
| 4016 | fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { | 4088 | fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { |
| 4017 | const given_bits = given.floatBits(self.target); | 4089 | const given_bits = given.floatBits(self.target); |
| 4018 | const wanted_bits = wanted.floatBits(self.target); | 4090 | const wanted_bits = wanted.floatBits(self.target); |
| 4019 | 4091 | ||
| 4020 | if (wanted_bits == 64 and given_bits == 32) { | 4092 | if (wanted_bits == 64 and given_bits == 32) { |
| 4021 | const result = try self.allocLocal(wanted); | ||
| 4022 | try self.emitWValue(operand); | 4093 | try self.emitWValue(operand); |
| 4023 | try self.addTag(.f64_promote_f32); | 4094 | try self.addTag(.f64_promote_f32); |
| 4024 | try self.addLabel(.local_set, result.local); | 4095 | return WValue{ .stack = {} }; |
| 4025 | return result; | ||
| 4026 | } else if (given_bits == 16) { | 4096 | } else if (given_bits == 16) { |
| 4027 | // call __extendhfsf2(f16) f32 | 4097 | // call __extendhfsf2(f16) f32 |
| 4028 | const f32_result = try self.callIntrinsic( | 4098 | const f32_result = try self.callIntrinsic( |
| ... | @@ -4036,11 +4106,9 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa | ... | @@ -4036,11 +4106,9 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa |
| 4036 | return f32_result; | 4106 | return f32_result; |
| 4037 | } | 4107 | } |
| 4038 | if (wanted_bits == 64) { | 4108 | if (wanted_bits == 64) { |
| 4039 | const result = try self.allocLocal(wanted); | ||
| 4040 | try self.emitWValue(f32_result); | 4109 | try self.emitWValue(f32_result); |
| 4041 | try self.addTag(.f64_promote_f32); | 4110 | try self.addTag(.f64_promote_f32); |
| 4042 | try self.addLabel(.local_set, result.local); | 4111 | return WValue{ .stack = {} }; |
| 4043 | return result; | ||
| 4044 | } | 4112 | } |
| 4045 | return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits}); | 4113 | return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits}); |
| 4046 | } else { | 4114 | } else { |
| ... | @@ -4055,26 +4123,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4055,26 +4123,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4055 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4123 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4056 | const dest_ty = self.air.typeOfIndex(inst); | 4124 | const dest_ty = self.air.typeOfIndex(inst); |
| 4057 | const operand = try self.resolveInst(ty_op.operand); | 4125 | const operand = try self.resolveInst(ty_op.operand); |
| 4058 | return self.fptrunc(operand, self.air.typeOf(ty_op.operand), dest_ty); | 4126 | const trunc = try self.fptrunc(operand, self.air.typeOf(ty_op.operand), dest_ty); |
| 4127 | return trunc.toLocal(self, dest_ty); | ||
| 4059 | } | 4128 | } |
| 4060 | 4129 | ||
| 4130 | /// Truncates a float from a given `Type` to its wanted `Type` | ||
| 4131 | /// NOTE: The result value remains on the stack | ||
| 4061 | fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { | 4132 | fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { |
| 4062 | const given_bits = given.floatBits(self.target); | 4133 | const given_bits = given.floatBits(self.target); |
| 4063 | const wanted_bits = wanted.floatBits(self.target); | 4134 | const wanted_bits = wanted.floatBits(self.target); |
| 4064 | 4135 | ||
| 4065 | if (wanted_bits == 32 and given_bits == 64) { | 4136 | if (wanted_bits == 32 and given_bits == 64) { |
| 4066 | const result = try self.allocLocal(wanted); | ||
| 4067 | try self.emitWValue(operand); | 4137 | try self.emitWValue(operand); |
| 4068 | try self.addTag(.f32_demote_f64); | 4138 | try self.addTag(.f32_demote_f64); |
| 4069 | try self.addLabel(.local_set, result.local); | 4139 | return WValue{ .stack = {} }; |
| 4070 | return result; | ||
| 4071 | } else if (wanted_bits == 16) { | 4140 | } else if (wanted_bits == 16) { |
| 4072 | const op: WValue = if (given_bits == 64) blk: { | 4141 | const op: WValue = if (given_bits == 64) blk: { |
| 4073 | const tmp = try self.allocLocal(Type.f32); | ||
| 4074 | try self.emitWValue(operand); | 4142 | try self.emitWValue(operand); |
| 4075 | try self.addTag(.f32_demote_f64); | 4143 | try self.addTag(.f32_demote_f64); |
| 4076 | try self.addLabel(.local_set, tmp.local); | 4144 | break :blk WValue{ .stack = {} }; |
| 4077 | break :blk tmp; | ||
| 4078 | } else operand; | 4145 | } else operand; |
| 4079 | 4146 | ||
| 4080 | // call __truncsfhf2(f32) f16 | 4147 | // call __truncsfhf2(f32) f16 |
| ... | @@ -4159,12 +4226,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4159,12 +4226,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4159 | 4226 | ||
| 4160 | switch (wasm_bits) { | 4227 | switch (wasm_bits) { |
| 4161 | 128 => { | 4228 | 128 => { |
| 4162 | const msb = try self.load(operand, Type.u64, 0); | 4229 | _ = try self.load(operand, Type.u64, 0); |
| 4163 | const lsb = try self.load(operand, Type.u64, 8); | ||
| 4164 | |||
| 4165 | try self.emitWValue(msb); | ||
| 4166 | try self.addTag(.i64_popcnt); | 4230 | try self.addTag(.i64_popcnt); |
| 4167 | try self.emitWValue(lsb); | 4231 | _ = try self.load(operand, Type.u64, 8); |
| 4168 | try self.addTag(.i64_popcnt); | 4232 | try self.addTag(.i64_popcnt); |
| 4169 | try self.addTag(.i64_add); | 4233 | try self.addTag(.i64_add); |
| 4170 | try self.addTag(.i32_wrap_i64); | 4234 | try self.addTag(.i32_wrap_i64); |
| ... | @@ -4268,24 +4332,26 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W | ... | @@ -4268,24 +4332,26 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4268 | 4332 | ||
| 4269 | // for signed integers, we first apply signed shifts by the difference in bits | 4333 | // for signed integers, we first apply signed shifts by the difference in bits |
| 4270 | // to get the signed value, as we store it internally as 2's complement. | 4334 | // to get the signed value, as we store it internally as 2's complement. |
| 4271 | const lhs = if (wasm_bits != int_info.bits and is_signed) blk: { | 4335 | var lhs = if (wasm_bits != int_info.bits and is_signed) blk: { |
| 4272 | break :blk try self.signAbsValue(lhs_op, lhs_ty); | 4336 | break :blk try (try self.signAbsValue(lhs_op, lhs_ty)).toLocal(self, lhs_ty); |
| 4273 | } else lhs_op; | 4337 | } else lhs_op; |
| 4274 | const rhs = if (wasm_bits != int_info.bits and is_signed) blk: { | 4338 | var rhs = if (wasm_bits != int_info.bits and is_signed) blk: { |
| 4275 | break :blk try self.signAbsValue(rhs_op, lhs_ty); | 4339 | break :blk try (try self.signAbsValue(rhs_op, lhs_ty)).toLocal(self, lhs_ty); |
| 4276 | } else rhs_op; | 4340 | } else rhs_op; |
| 4277 | 4341 | ||
| 4278 | const bin_op = try self.binOp(lhs, rhs, lhs_ty, op); | 4342 | var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty); |
| 4279 | const result = if (wasm_bits != int_info.bits) blk: { | 4343 | defer bin_op.free(self); |
| 4280 | break :blk try self.wrapOperand(bin_op, lhs_ty); | 4344 | var result = if (wasm_bits != int_info.bits) blk: { |
| 4345 | break :blk try (try self.wrapOperand(bin_op, lhs_ty)).toLocal(self, lhs_ty); | ||
| 4281 | } else bin_op; | 4346 | } else bin_op; |
| 4347 | defer result.free(self); // no-op when wasm_bits == int_info.bits | ||
| 4282 | 4348 | ||
| 4283 | const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt; | 4349 | const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt; |
| 4284 | const overflow_bit: WValue = if (is_signed) blk: { | 4350 | const overflow_bit: WValue = if (is_signed) blk: { |
| 4285 | if (wasm_bits == int_info.bits) { | 4351 | if (wasm_bits == int_info.bits) { |
| 4286 | const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op); | 4352 | const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op); |
| 4287 | const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt); | 4353 | const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt); |
| 4288 | break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); // result of cmp_zero and lt is always 32bit | 4354 | break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); |
| 4289 | } | 4355 | } |
| 4290 | const abs = try self.signAbsValue(bin_op, lhs_ty); | 4356 | const abs = try self.signAbsValue(bin_op, lhs_ty); |
| 4291 | break :blk try self.cmp(abs, bin_op, lhs_ty, .neq); | 4357 | break :blk try self.cmp(abs, bin_op, lhs_ty, .neq); |
| ... | @@ -4293,11 +4359,22 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W | ... | @@ -4293,11 +4359,22 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4293 | try self.cmp(bin_op, lhs, lhs_ty, cmp_op) | 4359 | try self.cmp(bin_op, lhs, lhs_ty, cmp_op) |
| 4294 | else | 4360 | else |
| 4295 | try self.cmp(bin_op, result, lhs_ty, .neq); | 4361 | try self.cmp(bin_op, result, lhs_ty, .neq); |
| 4362 | var overflow_local = try overflow_bit.toLocal(self, Type.u32); | ||
| 4363 | defer overflow_local.free(self); | ||
| 4296 | 4364 | ||
| 4297 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); | 4365 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); |
| 4298 | try self.store(result_ptr, result, lhs_ty, 0); | 4366 | try self.store(result_ptr, result, lhs_ty, 0); |
| 4299 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); | 4367 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); |
| 4300 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); | 4368 | try self.store(result_ptr, overflow_local, Type.initTag(.u1), offset); |
| 4369 | |||
| 4370 | // in this case, we performed a signAbsValue which created a temporary local | ||
| 4371 | // so let's free this so it can be re-used instead. | ||
| 4372 | // In the other case we do not want to free it, because that would free the | ||
| 4373 | // resolved instructions which may be referenced by other instructions. | ||
| 4374 | if (wasm_bits != int_info.bits and is_signed) { | ||
| 4375 | lhs.free(self); | ||
| 4376 | rhs.free(self); | ||
| 4377 | } | ||
| 4301 | 4378 | ||
| 4302 | return result_ptr; | 4379 | return result_ptr; |
| 4303 | } | 4380 | } |
| ... | @@ -4310,52 +4387,58 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, | ... | @@ -4310,52 +4387,58 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, |
| 4310 | return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits}); | 4387 | return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits}); |
| 4311 | } | 4388 | } |
| 4312 | 4389 | ||
| 4313 | const lhs_high_bit = try self.load(lhs, Type.u64, 0); | 4390 | var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64); |
| 4314 | const lhs_low_bit = try self.load(lhs, Type.u64, 8); | 4391 | defer lhs_high_bit.free(self); |
| 4315 | const rhs_high_bit = try self.load(rhs, Type.u64, 0); | 4392 | var lhs_low_bit = try (try self.load(lhs, Type.u64, 8)).toLocal(self, Type.u64); |
| 4316 | const rhs_low_bit = try self.load(rhs, Type.u64, 8); | 4393 | defer lhs_low_bit.free(self); |
| 4394 | var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64); | ||
| 4395 | defer rhs_high_bit.free(self); | ||
| 4396 | var rhs_low_bit = try (try self.load(rhs, Type.u64, 8)).toLocal(self, Type.u64); | ||
| 4397 | defer rhs_low_bit.free(self); | ||
| 4317 | 4398 | ||
| 4318 | const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op); | 4399 | var low_op_res = try (try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(self, Type.u64); |
| 4319 | const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op); | 4400 | defer low_op_res.free(self); |
| 4401 | var high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64); | ||
| 4402 | defer high_op_res.free(self); | ||
| 4320 | 4403 | ||
| 4321 | const lt = if (op == .add) blk: { | 4404 | var lt = if (op == .add) blk: { |
| 4322 | break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt); | 4405 | break :blk try (try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32); |
| 4323 | } else if (op == .sub) blk: { | 4406 | } else if (op == .sub) blk: { |
| 4324 | break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt); | 4407 | break :blk try (try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32); |
| 4325 | } else unreachable; | 4408 | } else unreachable; |
| 4326 | const tmp = try self.intcast(lt, Type.u32, Type.u64); | 4409 | defer lt.free(self); |
| 4327 | const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op); | 4410 | var tmp = try (try self.intcast(lt, Type.u32, Type.u64)).toLocal(self, Type.u64); |
| 4411 | defer tmp.free(self); | ||
| 4412 | var tmp_op = try (try self.binOp(low_op_res, tmp, Type.u64, op)).toLocal(self, Type.u64); | ||
| 4413 | defer tmp_op.free(self); | ||
| 4328 | 4414 | ||
| 4329 | const overflow_bit = if (is_signed) blk: { | 4415 | const overflow_bit = if (is_signed) blk: { |
| 4330 | const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor); | ||
| 4331 | const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); | 4416 | const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor); |
| 4332 | const to_wrap = if (op == .add) wrap: { | 4417 | const to_wrap = if (op == .add) wrap: { |
| 4333 | break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); | 4418 | break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor); |
| 4334 | } else xor_low; | 4419 | } else xor_low; |
| 4420 | const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor); | ||
| 4335 | const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and"); | 4421 | const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and"); |
| 4336 | break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed | 4422 | break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed |
| 4337 | } else blk: { | 4423 | } else blk: { |
| 4338 | const eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq); | ||
| 4339 | const op_eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt); | ||
| 4340 | |||
| 4341 | const first_arg = if (op == .sub) arg: { | 4424 | const first_arg = if (op == .sub) arg: { |
| 4342 | break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt); | 4425 | break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt); |
| 4343 | } else lt; | 4426 | } else lt; |
| 4344 | 4427 | ||
| 4345 | try self.emitWValue(first_arg); | 4428 | try self.emitWValue(first_arg); |
| 4346 | try self.emitWValue(op_eq); | 4429 | _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt); |
| 4347 | try self.emitWValue(eq); | 4430 | _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq); |
| 4348 | try self.addTag(.select); | 4431 | try self.addTag(.select); |
| 4349 | 4432 | ||
| 4350 | const overflow_bit = try self.allocLocal(Type.initTag(.u1)); | 4433 | break :blk WValue{ .stack = {} }; |
| 4351 | try self.addLabel(.local_set, overflow_bit.local); | ||
| 4352 | break :blk overflow_bit; | ||
| 4353 | }; | 4434 | }; |
| 4435 | var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1)); | ||
| 4436 | defer overflow_local.free(self); | ||
| 4354 | 4437 | ||
| 4355 | const result_ptr = try self.allocStack(result_ty); | 4438 | const result_ptr = try self.allocStack(result_ty); |
| 4356 | try self.store(result_ptr, high_op_res, Type.u64, 0); | 4439 | try self.store(result_ptr, high_op_res, Type.u64, 0); |
| 4357 | try self.store(result_ptr, tmp_op, Type.u64, 8); | 4440 | try self.store(result_ptr, tmp_op, Type.u64, 8); |
| 4358 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), 16); | 4441 | try self.store(result_ptr, overflow_local, Type.initTag(.u1), 16); |
| 4359 | 4442 | ||
| 4360 | return result_ptr; | 4443 | return result_ptr; |
| 4361 | } | 4444 | } |
| ... | @@ -4377,24 +4460,31 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4377,24 +4460,31 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4377 | return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); | 4460 | return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 4378 | }; | 4461 | }; |
| 4379 | 4462 | ||
| 4380 | const shl = try self.binOp(lhs, rhs, lhs_ty, .shl); | 4463 | var shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty); |
| 4381 | const result = if (wasm_bits != int_info.bits) blk: { | 4464 | defer shl.free(self); |
| 4382 | break :blk try self.wrapOperand(shl, lhs_ty); | 4465 | var result = if (wasm_bits != int_info.bits) blk: { |
| 4466 | break :blk try (try self.wrapOperand(shl, lhs_ty)).toLocal(self, lhs_ty); | ||
| 4383 | } else shl; | 4467 | } else shl; |
| 4468 | defer result.free(self); // it's a no-op to free the same local twice (when wasm_bits == int_info.bits) | ||
| 4384 | 4469 | ||
| 4385 | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: { | 4470 | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: { |
| 4471 | // emit lhs to stack to we can keep 'wrapped' on the stack also | ||
| 4472 | try self.emitWValue(lhs); | ||
| 4386 | const abs = try self.signAbsValue(shl, lhs_ty); | 4473 | const abs = try self.signAbsValue(shl, lhs_ty); |
| 4387 | const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr); | 4474 | const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr); |
| 4388 | break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq); | 4475 | break :blk try self.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq); |
| 4389 | } else blk: { | 4476 | } else blk: { |
| 4477 | try self.emitWValue(lhs); | ||
| 4390 | const shr = try self.binOp(result, rhs, lhs_ty, .shr); | 4478 | const shr = try self.binOp(result, rhs, lhs_ty, .shr); |
| 4391 | break :blk try self.cmp(lhs, shr, lhs_ty, .neq); | 4479 | break :blk try self.cmp(.{ .stack = {} }, shr, lhs_ty, .neq); |
| 4392 | }; | 4480 | }; |
| 4481 | var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1)); | ||
| 4482 | defer overflow_local.free(self); | ||
| 4393 | 4483 | ||
| 4394 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); | 4484 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); |
| 4395 | try self.store(result_ptr, result, lhs_ty, 0); | 4485 | try self.store(result_ptr, result, lhs_ty, 0); |
| 4396 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); | 4486 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); |
| 4397 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); | 4487 | try self.store(result_ptr, overflow_local, Type.initTag(.u1), offset); |
| 4398 | 4488 | ||
| 4399 | return result_ptr; | 4489 | return result_ptr; |
| 4400 | } | 4490 | } |
| ... | @@ -4412,7 +4502,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4412,7 +4502,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4412 | 4502 | ||
| 4413 | // We store the bit if it's overflowed or not in this. As it's zero-initialized | 4503 | // We store the bit if it's overflowed or not in this. As it's zero-initialized |
| 4414 | // we only need to update it if an overflow (or underflow) occurred. | 4504 | // we only need to update it if an overflow (or underflow) occurred. |
| 4415 | const overflow_bit = try self.allocLocal(Type.initTag(.u1)); | 4505 | var overflow_bit = try self.ensureAllocLocal(Type.initTag(.u1)); |
| 4506 | defer overflow_bit.free(self); | ||
| 4507 | |||
| 4416 | const int_info = lhs_ty.intInfo(self.target); | 4508 | const int_info = lhs_ty.intInfo(self.target); |
| 4417 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 4509 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 4418 | return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); | 4510 | return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits}); |
| ... | @@ -4433,49 +4525,49 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4433,49 +4525,49 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4433 | const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64; | 4525 | const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64; |
| 4434 | const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty); | 4526 | const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty); |
| 4435 | const rhs_upcast = try self.intcast(rhs, lhs_ty, new_ty); | 4527 | const rhs_upcast = try self.intcast(rhs, lhs_ty, new_ty); |
| 4436 | const bin_op = try self.binOp(lhs_upcast, rhs_upcast, new_ty, .mul); | 4528 | const bin_op = try (try self.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(self, new_ty); |
| 4437 | if (int_info.signedness == .unsigned) { | 4529 | if (int_info.signedness == .unsigned) { |
| 4438 | const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); | 4530 | const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 4439 | const wrap = try self.intcast(shr, new_ty, lhs_ty); | 4531 | const wrap = try self.intcast(shr, new_ty, lhs_ty); |
| 4440 | const cmp_res = try self.cmp(wrap, zero, lhs_ty, .neq); | 4532 | _ = try self.cmp(wrap, zero, lhs_ty, .neq); |
| 4441 | try self.emitWValue(cmp_res); | ||
| 4442 | try self.addLabel(.local_set, overflow_bit.local); | 4533 | try self.addLabel(.local_set, overflow_bit.local); |
| 4443 | break :blk try self.intcast(bin_op, new_ty, lhs_ty); | 4534 | break :blk try self.intcast(bin_op, new_ty, lhs_ty); |
| 4444 | } else { | 4535 | } else { |
| 4445 | const down_cast = try self.intcast(bin_op, new_ty, lhs_ty); | 4536 | const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty); |
| 4446 | const shr = try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr); | 4537 | var shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty); |
| 4538 | defer shr.free(self); | ||
| 4447 | 4539 | ||
| 4448 | const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); | 4540 | const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); |
| 4449 | const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty); | 4541 | const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty); |
| 4450 | const cmp_res = try self.cmp(down_shr_res, shr, lhs_ty, .neq); | 4542 | _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq); |
| 4451 | try self.emitWValue(cmp_res); | ||
| 4452 | try self.addLabel(.local_set, overflow_bit.local); | 4543 | try self.addLabel(.local_set, overflow_bit.local); |
| 4453 | break :blk down_cast; | 4544 | break :blk down_cast; |
| 4454 | } | 4545 | } |
| 4455 | } else if (int_info.signedness == .signed) blk: { | 4546 | } else if (int_info.signedness == .signed) blk: { |
| 4456 | const lhs_abs = try self.signAbsValue(lhs, lhs_ty); | 4547 | const lhs_abs = try self.signAbsValue(lhs, lhs_ty); |
| 4457 | const rhs_abs = try self.signAbsValue(rhs, lhs_ty); | 4548 | const rhs_abs = try self.signAbsValue(rhs, lhs_ty); |
| 4458 | const bin_op = try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul); | 4549 | const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty); |
| 4459 | const mul_abs = try self.signAbsValue(bin_op, lhs_ty); | 4550 | const mul_abs = try self.signAbsValue(bin_op, lhs_ty); |
| 4460 | const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq); | 4551 | _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq); |
| 4461 | try self.emitWValue(cmp_op); | ||
| 4462 | try self.addLabel(.local_set, overflow_bit.local); | 4552 | try self.addLabel(.local_set, overflow_bit.local); |
| 4463 | break :blk try self.wrapOperand(bin_op, lhs_ty); | 4553 | break :blk try self.wrapOperand(bin_op, lhs_ty); |
| 4464 | } else blk: { | 4554 | } else blk: { |
| 4465 | const bin_op = try self.binOp(lhs, rhs, lhs_ty, .mul); | 4555 | var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(self, lhs_ty); |
| 4556 | defer bin_op.free(self); | ||
| 4466 | const shift_imm = if (wasm_bits == 32) | 4557 | const shift_imm = if (wasm_bits == 32) |
| 4467 | WValue{ .imm32 = int_info.bits } | 4558 | WValue{ .imm32 = int_info.bits } |
| 4468 | else | 4559 | else |
| 4469 | WValue{ .imm64 = int_info.bits }; | 4560 | WValue{ .imm64 = int_info.bits }; |
| 4470 | const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr); | 4561 | const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr); |
| 4471 | const cmp_op = try self.cmp(shr, zero, lhs_ty, .neq); | 4562 | _ = try self.cmp(shr, zero, lhs_ty, .neq); |
| 4472 | try self.emitWValue(cmp_op); | ||
| 4473 | try self.addLabel(.local_set, overflow_bit.local); | 4563 | try self.addLabel(.local_set, overflow_bit.local); |
| 4474 | break :blk try self.wrapOperand(bin_op, lhs_ty); | 4564 | break :blk try self.wrapOperand(bin_op, lhs_ty); |
| 4475 | }; | 4565 | }; |
| 4566 | var bin_op_local = try bin_op.toLocal(self, lhs_ty); | ||
| 4567 | defer bin_op_local.free(self); | ||
| 4476 | 4568 | ||
| 4477 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); | 4569 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); |
| 4478 | try self.store(result_ptr, bin_op, lhs_ty, 0); | 4570 | try self.store(result_ptr, bin_op_local, lhs_ty, 0); |
| 4479 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); | 4571 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); |
| 4480 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); | 4572 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); |
| 4481 | 4573 | ||
| ... | @@ -4497,12 +4589,10 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro | ... | @@ -4497,12 +4589,10 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro |
| 4497 | const lhs = try self.resolveInst(bin_op.lhs); | 4589 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4498 | const rhs = try self.resolveInst(bin_op.rhs); | 4590 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4499 | 4591 | ||
| 4500 | const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt); | ||
| 4501 | |||
| 4502 | // operands to select from | 4592 | // operands to select from |
| 4503 | try self.lowerToStack(lhs); | 4593 | try self.lowerToStack(lhs); |
| 4504 | try self.lowerToStack(rhs); | 4594 | try self.lowerToStack(rhs); |
| 4505 | try self.emitWValue(cmp_result); | 4595 | _ = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt); |
| 4506 | 4596 | ||
| 4507 | // based on the result from comparison, return operand 0 or 1. | 4597 | // based on the result from comparison, return operand 0 or 1. |
| 4508 | try self.addTag(.select); | 4598 | try self.addTag(.select); |
| ... | @@ -4528,21 +4618,22 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4528,21 +4618,22 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4528 | const rhs = try self.resolveInst(bin_op.rhs); | 4618 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4529 | 4619 | ||
| 4530 | if (ty.floatBits(self.target) == 16) { | 4620 | if (ty.floatBits(self.target) == 16) { |
| 4531 | const addend_ext = try self.fpext(addend, ty, Type.f32); | ||
| 4532 | const lhs_ext = try self.fpext(lhs, ty, Type.f32); | ||
| 4533 | const rhs_ext = try self.fpext(rhs, ty, Type.f32); | 4621 | const rhs_ext = try self.fpext(rhs, ty, Type.f32); |
| 4622 | const lhs_ext = try self.fpext(lhs, ty, Type.f32); | ||
| 4623 | const addend_ext = try self.fpext(addend, ty, Type.f32); | ||
| 4534 | // call to compiler-rt `fn fmaf(f32, f32, f32) f32` | 4624 | // call to compiler-rt `fn fmaf(f32, f32, f32) f32` |
| 4535 | const result = try self.callIntrinsic( | 4625 | var result = try self.callIntrinsic( |
| 4536 | "fmaf", | 4626 | "fmaf", |
| 4537 | &.{ Type.f32, Type.f32, Type.f32 }, | 4627 | &.{ Type.f32, Type.f32, Type.f32 }, |
| 4538 | Type.f32, | 4628 | Type.f32, |
| 4539 | &.{ rhs_ext, lhs_ext, addend_ext }, | 4629 | &.{ rhs_ext, lhs_ext, addend_ext }, |
| 4540 | ); | 4630 | ); |
| 4541 | return try self.fptrunc(result, Type.f32, ty); | 4631 | defer result.free(self); |
| 4632 | return try (try self.fptrunc(result, Type.f32, ty)).toLocal(self, ty); | ||
| 4542 | } | 4633 | } |
| 4543 | 4634 | ||
| 4544 | const mul_result = try self.binOp(lhs, rhs, ty, .mul); | 4635 | const mul_result = try self.binOp(lhs, rhs, ty, .mul); |
| 4545 | return self.binOp(mul_result, addend, ty, .add); | 4636 | return (try self.binOp(mul_result, addend, ty, .add)).toLocal(self, ty); |
| 4546 | } | 4637 | } |
| 4547 | 4638 | ||
| 4548 | fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4639 | fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4571,17 +4662,16 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4571,17 +4662,16 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4571 | try self.addTag(.i32_wrap_i64); | 4662 | try self.addTag(.i32_wrap_i64); |
| 4572 | }, | 4663 | }, |
| 4573 | 128 => { | 4664 | 128 => { |
| 4574 | const msb = try self.load(operand, Type.u64, 0); | 4665 | var lsb = try (try self.load(operand, Type.u64, 8)).toLocal(self, Type.u64); |
| 4575 | const lsb = try self.load(operand, Type.u64, 8); | 4666 | defer lsb.free(self); |
| 4576 | const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq); | ||
| 4577 | 4667 | ||
| 4578 | try self.emitWValue(lsb); | 4668 | try self.emitWValue(lsb); |
| 4579 | try self.addTag(.i64_clz); | 4669 | try self.addTag(.i64_clz); |
| 4580 | try self.emitWValue(msb); | 4670 | _ = try self.load(operand, Type.u64, 0); |
| 4581 | try self.addTag(.i64_clz); | 4671 | try self.addTag(.i64_clz); |
| 4582 | try self.emitWValue(.{ .imm64 = 64 }); | 4672 | try self.emitWValue(.{ .imm64 = 64 }); |
| 4583 | try self.addTag(.i64_add); | 4673 | try self.addTag(.i64_add); |
| 4584 | try self.emitWValue(neq); | 4674 | _ = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 4585 | try self.addTag(.select); | 4675 | try self.addTag(.select); |
| 4586 | try self.addTag(.i32_wrap_i64); | 4676 | try self.addTag(.i32_wrap_i64); |
| 4587 | }, | 4677 | }, |
| ... | @@ -4618,28 +4708,27 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4618,28 +4708,27 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4618 | 32 => { | 4708 | 32 => { |
| 4619 | if (wasm_bits != int_info.bits) { | 4709 | if (wasm_bits != int_info.bits) { |
| 4620 | const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits); | 4710 | const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits); |
| 4621 | const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or"); | 4711 | // leave value on the stack |
| 4622 | try self.emitWValue(bin_op); | 4712 | _ = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or"); |
| 4623 | } else try self.emitWValue(operand); | 4713 | } else try self.emitWValue(operand); |
| 4624 | try self.addTag(.i32_ctz); | 4714 | try self.addTag(.i32_ctz); |
| 4625 | }, | 4715 | }, |
| 4626 | 64 => { | 4716 | 64 => { |
| 4627 | if (wasm_bits != int_info.bits) { | 4717 | if (wasm_bits != int_info.bits) { |
| 4628 | const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits); | 4718 | const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits); |
| 4629 | const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or"); | 4719 | // leave value on the stack |
| 4630 | try self.emitWValue(bin_op); | 4720 | _ = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or"); |
| 4631 | } else try self.emitWValue(operand); | 4721 | } else try self.emitWValue(operand); |
| 4632 | try self.addTag(.i64_ctz); | 4722 | try self.addTag(.i64_ctz); |
| 4633 | try self.addTag(.i32_wrap_i64); | 4723 | try self.addTag(.i32_wrap_i64); |
| 4634 | }, | 4724 | }, |
| 4635 | 128 => { | 4725 | 128 => { |
| 4636 | const msb = try self.load(operand, Type.u64, 0); | 4726 | var msb = try (try self.load(operand, Type.u64, 0)).toLocal(self, Type.u64); |
| 4637 | const lsb = try self.load(operand, Type.u64, 8); | 4727 | defer msb.free(self); |
| 4638 | const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq); | ||
| 4639 | 4728 | ||
| 4640 | try self.emitWValue(msb); | 4729 | try self.emitWValue(msb); |
| 4641 | try self.addTag(.i64_ctz); | 4730 | try self.addTag(.i64_ctz); |
| 4642 | try self.emitWValue(lsb); | 4731 | _ = try self.load(operand, Type.u64, 8); |
| 4643 | if (wasm_bits != int_info.bits) { | 4732 | if (wasm_bits != int_info.bits) { |
| 4644 | try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64)); | 4733 | try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64)); |
| 4645 | try self.addTag(.i64_or); | 4734 | try self.addTag(.i64_or); |
| ... | @@ -4651,7 +4740,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4651,7 +4740,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4651 | } else { | 4740 | } else { |
| 4652 | try self.addTag(.i64_add); | 4741 | try self.addTag(.i64_add); |
| 4653 | } | 4742 | } |
| 4654 | try self.emitWValue(neq); | 4743 | _ = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq); |
| 4655 | try self.addTag(.select); | 4744 | try self.addTag(.select); |
| 4656 | try self.addTag(.i32_wrap_i64); | 4745 | try self.addTag(.i32_wrap_i64); |
| 4657 | }, | 4746 | }, |
| ... | @@ -4777,7 +4866,8 @@ fn lowerTry( | ... | @@ -4777,7 +4866,8 @@ fn lowerTry( |
| 4777 | if (isByRef(pl_ty, self.target)) { | 4866 | if (isByRef(pl_ty, self.target)) { |
| 4778 | return buildPointerOffset(self, err_union, pl_offset, .new); | 4867 | return buildPointerOffset(self, err_union, pl_offset, .new); |
| 4779 | } | 4868 | } |
| 4780 | return self.load(err_union, pl_ty, pl_offset); | 4869 | const payload = try self.load(err_union, pl_ty, pl_offset); |
| 4870 | return payload.toLocal(self, pl_ty); | ||
| 4781 | } | 4871 | } |
| 4782 | 4872 | ||
| 4783 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4873 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4807,11 +4897,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4807,11 +4897,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4807 | const res = if (int_info.signedness == .signed) blk: { | 4897 | const res = if (int_info.signedness == .signed) blk: { |
| 4808 | break :blk try self.wrapOperand(shr_res, Type.u8); | 4898 | break :blk try self.wrapOperand(shr_res, Type.u8); |
| 4809 | } else shr_res; | 4899 | } else shr_res; |
| 4810 | return self.binOp(lhs, res, ty, .@"or"); | 4900 | return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty); |
| 4811 | }, | 4901 | }, |
| 4812 | 24 => { | 4902 | 24 => { |
| 4813 | const msb = try self.wrapOperand(operand, Type.u16); | 4903 | var msb = try (try self.wrapOperand(operand, Type.u16)).toLocal(self, Type.u16); |
| 4814 | const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr); | 4904 | defer msb.free(self); |
| 4815 | 4905 | ||
| 4816 | const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl); | 4906 | const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl); |
| 4817 | const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and"); | 4907 | const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and"); |
| ... | @@ -4825,22 +4915,26 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4825,22 +4915,26 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4825 | const rhs_wrap = try self.wrapOperand(msb, Type.u8); | 4915 | const rhs_wrap = try self.wrapOperand(msb, Type.u8); |
| 4826 | const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl); | 4916 | const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl); |
| 4827 | 4917 | ||
| 4918 | const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr); | ||
| 4828 | const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or"); | 4919 | const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or"); |
| 4829 | return self.binOp(tmp, lsb, ty, .@"or"); | 4920 | return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty); |
| 4830 | }, | 4921 | }, |
| 4831 | 32 => { | 4922 | 32 => { |
| 4832 | const shl_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); | 4923 | const shl_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); |
| 4833 | const lhs = try self.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and"); | 4924 | var lhs = try (try self.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and")).toLocal(self, ty); |
| 4925 | defer lhs.free(self); | ||
| 4834 | const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr); | 4926 | const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr); |
| 4835 | const rhs = try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and"); | 4927 | var rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty); |
| 4836 | const tmp_or = try self.binOp(lhs, rhs, ty, .@"or"); | 4928 | defer rhs.free(self); |
| 4929 | var tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty); | ||
| 4930 | defer tmp_or.free(self); | ||
| 4837 | 4931 | ||
| 4838 | const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl); | 4932 | const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl); |
| 4839 | const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr); | 4933 | const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr); |
| 4840 | const res = if (int_info.signedness == .signed) blk: { | 4934 | const res = if (int_info.signedness == .signed) blk: { |
| 4841 | break :blk try self.wrapOperand(shr, Type.u16); | 4935 | break :blk try self.wrapOperand(shr, Type.u16); |
| 4842 | } else shr; | 4936 | } else shr; |
| 4843 | return self.binOp(shl, res, ty, .@"or"); | 4937 | return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty); |
| 4844 | }, | 4938 | }, |
| 4845 | else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), | 4939 | else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), |
| 4846 | } | 4940 | } |
| ... | @@ -4857,7 +4951,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4857,7 +4951,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4857 | if (ty.isSignedInt()) { | 4951 | if (ty.isSignedInt()) { |
| 4858 | return self.divSigned(lhs, rhs, ty); | 4952 | return self.divSigned(lhs, rhs, ty); |
| 4859 | } | 4953 | } |
| 4860 | return self.binOp(lhs, rhs, ty, .div); | 4954 | return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty); |
| 4861 | } | 4955 | } |
| 4862 | 4956 | ||
| 4863 | fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4957 | fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4869,33 +4963,31 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4869,33 +4963,31 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4869 | const rhs = try self.resolveInst(bin_op.rhs); | 4963 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4870 | 4964 | ||
| 4871 | if (ty.isUnsignedInt()) { | 4965 | if (ty.isUnsignedInt()) { |
| 4872 | return self.binOp(lhs, rhs, ty, .div); | 4966 | return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty); |
| 4873 | } else if (ty.isSignedInt()) { | 4967 | } else if (ty.isSignedInt()) { |
| 4874 | const int_bits = ty.intInfo(self.target).bits; | 4968 | const int_bits = ty.intInfo(self.target).bits; |
| 4875 | const wasm_bits = toWasmBits(int_bits) orelse { | 4969 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 4876 | return self.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits}); | 4970 | return self.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits}); |
| 4877 | }; | 4971 | }; |
| 4878 | const lhs_res = if (wasm_bits != int_bits) blk: { | 4972 | const lhs_res = if (wasm_bits != int_bits) blk: { |
| 4879 | break :blk try self.signAbsValue(lhs, ty); | 4973 | break :blk try (try self.signAbsValue(lhs, ty)).toLocal(self, ty); |
| 4880 | } else lhs; | 4974 | } else lhs; |
| 4881 | const rhs_res = if (wasm_bits != int_bits) blk: { | 4975 | const rhs_res = if (wasm_bits != int_bits) blk: { |
| 4882 | break :blk try self.signAbsValue(rhs, ty); | 4976 | break :blk try (try self.signAbsValue(rhs, ty)).toLocal(self, ty); |
| 4883 | } else rhs; | 4977 | } else rhs; |
| 4884 | 4978 | ||
| 4885 | const div_result = try self.binOp(lhs_res, rhs_res, ty, .div); | ||
| 4886 | const rem_result = try self.binOp(lhs_res, rhs_res, ty, .rem); | ||
| 4887 | |||
| 4888 | const zero = switch (wasm_bits) { | 4979 | const zero = switch (wasm_bits) { |
| 4889 | 32 => WValue{ .imm32 = 0 }, | 4980 | 32 => WValue{ .imm32 = 0 }, |
| 4890 | 64 => WValue{ .imm64 = 0 }, | 4981 | 64 => WValue{ .imm64 = 0 }, |
| 4891 | else => unreachable, | 4982 | else => unreachable, |
| 4892 | }; | 4983 | }; |
| 4893 | const lhs_less_than_zero = try self.cmp(lhs_res, zero, ty, .lt); | ||
| 4894 | const rhs_less_than_zero = try self.cmp(rhs_res, zero, ty, .lt); | ||
| 4895 | 4984 | ||
| 4896 | try self.emitWValue(div_result); | 4985 | const div_result = try self.allocLocal(ty); |
| 4897 | try self.emitWValue(lhs_less_than_zero); | 4986 | // leave on stack |
| 4898 | try self.emitWValue(rhs_less_than_zero); | 4987 | _ = try self.binOp(lhs_res, rhs_res, ty, .div); |
| 4988 | try self.addLabel(.local_tee, div_result.local); | ||
| 4989 | _ = try self.cmp(lhs_res, zero, ty, .lt); | ||
| 4990 | _ = try self.cmp(rhs_res, zero, ty, .lt); | ||
| 4899 | switch (wasm_bits) { | 4991 | switch (wasm_bits) { |
| 4900 | 32 => { | 4992 | 32 => { |
| 4901 | try self.addTag(.i32_xor); | 4993 | try self.addTag(.i32_xor); |
| ... | @@ -4908,7 +5000,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4908,7 +5000,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4908 | else => unreachable, | 5000 | else => unreachable, |
| 4909 | } | 5001 | } |
| 4910 | try self.emitWValue(div_result); | 5002 | try self.emitWValue(div_result); |
| 4911 | try self.emitWValue(rem_result); | 5003 | // leave value on the stack |
| 5004 | _ = try self.binOp(lhs_res, rhs_res, ty, .rem); | ||
| 4912 | try self.addTag(.select); | 5005 | try self.addTag(.select); |
| 4913 | } else { | 5006 | } else { |
| 4914 | const float_bits = ty.floatBits(self.target); | 5007 | const float_bits = ty.floatBits(self.target); |
| ... | @@ -4940,9 +5033,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4940,9 +5033,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4940 | } | 5033 | } |
| 4941 | 5034 | ||
| 4942 | if (is_f16) { | 5035 | if (is_f16) { |
| 4943 | // we can re-use temporary local | 5036 | _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16); |
| 4944 | try self.addLabel(.local_set, lhs_operand.local); | ||
| 4945 | return self.fptrunc(lhs_operand, Type.f32, Type.f16); | ||
| 4946 | } | 5037 | } |
| 4947 | } | 5038 | } |
| 4948 | 5039 | ||
| ... | @@ -4962,10 +5053,9 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue | ... | @@ -4962,10 +5053,9 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue |
| 4962 | } | 5053 | } |
| 4963 | 5054 | ||
| 4964 | if (wasm_bits != int_bits) { | 5055 | if (wasm_bits != int_bits) { |
| 4965 | const lhs_abs = try self.signAbsValue(lhs, ty); | 5056 | // Leave both values on the stack |
| 4966 | const rhs_abs = try self.signAbsValue(rhs, ty); | 5057 | _ = try self.signAbsValue(lhs, ty); |
| 4967 | try self.emitWValue(lhs_abs); | 5058 | _ = try self.signAbsValue(rhs, ty); |
| 4968 | try self.emitWValue(rhs_abs); | ||
| 4969 | } else { | 5059 | } else { |
| 4970 | try self.emitWValue(lhs); | 5060 | try self.emitWValue(lhs); |
| 4971 | try self.emitWValue(rhs); | 5061 | try self.emitWValue(rhs); |
| ... | @@ -4977,6 +5067,8 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue | ... | @@ -4977,6 +5067,8 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue |
| 4977 | return result; | 5067 | return result; |
| 4978 | } | 5068 | } |
| 4979 | 5069 | ||
| 5070 | /// Retrieves the absolute value of a signed integer | ||
| 5071 | /// NOTE: Leaves the result value on the stack. | ||
| 4980 | fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | 5072 | fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 4981 | const int_bits = ty.intInfo(self.target).bits; | 5073 | const int_bits = ty.intInfo(self.target).bits; |
| 4982 | const wasm_bits = toWasmBits(int_bits) orelse { | 5074 | const wasm_bits = toWasmBits(int_bits) orelse { |
| ... | @@ -5005,9 +5097,8 @@ fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -5005,9 +5097,8 @@ fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 5005 | }, | 5097 | }, |
| 5006 | else => unreachable, | 5098 | else => unreachable, |
| 5007 | } | 5099 | } |
| 5008 | const result = try self.allocLocal(ty); | 5100 | |
| 5009 | try self.addLabel(.local_set, result.local); | 5101 | return WValue{ .stack = {} }; |
| 5010 | return result; | ||
| 5011 | } | 5102 | } |
| 5012 | 5103 | ||
| 5013 | fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | 5104 | fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| ... | @@ -5034,9 +5125,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValu | ... | @@ -5034,9 +5125,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValu |
| 5034 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 5125 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 5035 | 5126 | ||
| 5036 | if (is_f16) { | 5127 | if (is_f16) { |
| 5037 | // re-use temporary to save locals | 5128 | _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16); |
| 5038 | try self.addLabel(.local_set, op_to_lower.local); | ||
| 5039 | return self.fptrunc(op_to_lower, Type.f32, Type.f16); | ||
| 5040 | } | 5129 | } |
| 5041 | 5130 | ||
| 5042 | const result = try self.allocLocal(ty); | 5131 | const result = try self.allocLocal(ty); |
| ... | @@ -5065,7 +5154,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -5065,7 +5154,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 5065 | } | 5154 | } |
| 5066 | 5155 | ||
| 5067 | const wasm_bits = toWasmBits(int_info.bits).?; | 5156 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 5068 | const bin_result = try self.binOp(lhs, rhs, ty, op); | 5157 | var bin_result = try (try self.binOp(lhs, rhs, ty, op)).toLocal(self, ty); |
| 5158 | defer bin_result.free(self); | ||
| 5069 | if (wasm_bits != int_info.bits and op == .add) { | 5159 | if (wasm_bits != int_info.bits and op == .add) { |
| 5070 | const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1); | 5160 | const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1); |
| 5071 | const imm_val = switch (wasm_bits) { | 5161 | const imm_val = switch (wasm_bits) { |
| ... | @@ -5074,19 +5164,17 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -5074,19 +5164,17 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 5074 | else => unreachable, | 5164 | else => unreachable, |
| 5075 | }; | 5165 | }; |
| 5076 | 5166 | ||
| 5077 | const cmp_result = try self.cmp(bin_result, imm_val, ty, .lt); | ||
| 5078 | try self.emitWValue(bin_result); | 5167 | try self.emitWValue(bin_result); |
| 5079 | try self.emitWValue(imm_val); | 5168 | try self.emitWValue(imm_val); |
| 5080 | try self.emitWValue(cmp_result); | 5169 | _ = try self.cmp(bin_result, imm_val, ty, .lt); |
| 5081 | } else { | 5170 | } else { |
| 5082 | const cmp_result = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt); | ||
| 5083 | switch (wasm_bits) { | 5171 | switch (wasm_bits) { |
| 5084 | 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0), | 5172 | 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0), |
| 5085 | 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0), | 5173 | 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0), |
| 5086 | else => unreachable, | 5174 | else => unreachable, |
| 5087 | } | 5175 | } |
| 5088 | try self.emitWValue(bin_result); | 5176 | try self.emitWValue(bin_result); |
| 5089 | try self.emitWValue(cmp_result); | 5177 | _ = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt); |
| 5090 | } | 5178 | } |
| 5091 | 5179 | ||
| 5092 | try self.addTag(.select); | 5180 | try self.addTag(.select); |
| ... | @@ -5100,8 +5188,12 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op | ... | @@ -5100,8 +5188,12 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 5100 | const wasm_bits = toWasmBits(int_info.bits).?; | 5188 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 5101 | const is_wasm_bits = wasm_bits == int_info.bits; | 5189 | const is_wasm_bits = wasm_bits == int_info.bits; |
| 5102 | 5190 | ||
| 5103 | const lhs = if (!is_wasm_bits) try self.signAbsValue(lhs_operand, ty) else lhs_operand; | 5191 | var lhs = if (!is_wasm_bits) lhs: { |
| 5104 | const rhs = if (!is_wasm_bits) try self.signAbsValue(rhs_operand, ty) else rhs_operand; | 5192 | break :lhs try (try self.signAbsValue(lhs_operand, ty)).toLocal(self, ty); |
| 5193 | } else lhs_operand; | ||
| 5194 | var rhs = if (!is_wasm_bits) rhs: { | ||
| 5195 | break :rhs try (try self.signAbsValue(rhs_operand, ty)).toLocal(self, ty); | ||
| 5196 | } else rhs_operand; | ||
| 5105 | 5197 | ||
| 5106 | const max_val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits - 1)) - 1); | 5198 | const max_val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits - 1)) - 1); |
| 5107 | const min_val: i64 = (-@intCast(i64, @intCast(u63, max_val))) - 1; | 5199 | const min_val: i64 = (-@intCast(i64, @intCast(u63, max_val))) - 1; |
| ... | @@ -5116,38 +5208,38 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op | ... | @@ -5116,38 +5208,38 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 5116 | else => unreachable, | 5208 | else => unreachable, |
| 5117 | }; | 5209 | }; |
| 5118 | 5210 | ||
| 5119 | const bin_result = try self.binOp(lhs, rhs, ty, op); | 5211 | var bin_result = try (try self.binOp(lhs, rhs, ty, op)).toLocal(self, ty); |
| 5120 | if (!is_wasm_bits) { | 5212 | if (!is_wasm_bits) { |
| 5121 | const cmp_result_lt = try self.cmp(bin_result, max_wvalue, ty, .lt); | 5213 | defer bin_result.free(self); // not returned in this branch |
| 5214 | defer lhs.free(self); // uses temporary local for absvalue | ||
| 5215 | defer rhs.free(self); // uses temporary local for absvalue | ||
| 5122 | try self.emitWValue(bin_result); | 5216 | try self.emitWValue(bin_result); |
| 5123 | try self.emitWValue(max_wvalue); | 5217 | try self.emitWValue(max_wvalue); |
| 5124 | try self.emitWValue(cmp_result_lt); | 5218 | _ = try self.cmp(bin_result, max_wvalue, ty, .lt); |
| 5125 | try self.addTag(.select); | 5219 | try self.addTag(.select); |
| 5126 | try self.addLabel(.local_set, bin_result.local); // re-use local | 5220 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| 5127 | 5221 | ||
| 5128 | const cmp_result_gt = try self.cmp(bin_result, min_wvalue, ty, .gt); | ||
| 5129 | try self.emitWValue(bin_result); | 5222 | try self.emitWValue(bin_result); |
| 5130 | try self.emitWValue(min_wvalue); | 5223 | try self.emitWValue(min_wvalue); |
| 5131 | try self.emitWValue(cmp_result_gt); | 5224 | _ = try self.cmp(bin_result, min_wvalue, ty, .gt); |
| 5132 | try self.addTag(.select); | 5225 | try self.addTag(.select); |
| 5133 | try self.addLabel(.local_set, bin_result.local); // re-use local | 5226 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| 5134 | return self.wrapOperand(bin_result, ty); | 5227 | return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty); |
| 5135 | } else { | 5228 | } else { |
| 5136 | const zero = switch (wasm_bits) { | 5229 | const zero = switch (wasm_bits) { |
| 5137 | 32 => WValue{ .imm32 = 0 }, | 5230 | 32 => WValue{ .imm32 = 0 }, |
| 5138 | 64 => WValue{ .imm64 = 0 }, | 5231 | 64 => WValue{ .imm64 = 0 }, |
| 5139 | else => unreachable, | 5232 | else => unreachable, |
| 5140 | }; | 5233 | }; |
| 5141 | const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); | ||
| 5142 | const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt); | ||
| 5143 | const xor = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor. | ||
| 5144 | const cmp_bin_zero_result = try self.cmp(bin_result, zero, ty, .lt); | ||
| 5145 | try self.emitWValue(max_wvalue); | 5234 | try self.emitWValue(max_wvalue); |
| 5146 | try self.emitWValue(min_wvalue); | 5235 | try self.emitWValue(min_wvalue); |
| 5147 | try self.emitWValue(cmp_bin_zero_result); | 5236 | _ = try self.cmp(bin_result, zero, ty, .lt); |
| 5148 | try self.addTag(.select); | 5237 | try self.addTag(.select); |
| 5149 | try self.emitWValue(bin_result); | 5238 | try self.emitWValue(bin_result); |
| 5150 | try self.emitWValue(xor); | 5239 | // leave on stack |
| 5240 | const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt); | ||
| 5241 | const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); | ||
| 5242 | _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor. | ||
| 5151 | try self.addTag(.select); | 5243 | try self.addTag(.select); |
| 5152 | try self.addLabel(.local_set, bin_result.local); // re-use local | 5244 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| 5153 | return bin_result; | 5245 | return bin_result; |
| ... | @@ -5171,9 +5263,10 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5171,9 +5263,10 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5171 | const result = try self.allocLocal(ty); | 5263 | const result = try self.allocLocal(ty); |
| 5172 | 5264 | ||
| 5173 | if (wasm_bits == int_info.bits) { | 5265 | if (wasm_bits == int_info.bits) { |
| 5174 | const shl = try self.binOp(lhs, rhs, ty, .shl); | 5266 | var shl = try (try self.binOp(lhs, rhs, ty, .shl)).toLocal(self, ty); |
| 5175 | const shr = try self.binOp(shl, rhs, ty, .shr); | 5267 | defer shl.free(self); |
| 5176 | const cmp_result = try self.cmp(lhs, shr, ty, .neq); | 5268 | var shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty); |
| 5269 | defer shr.free(self); | ||
| 5177 | 5270 | ||
| 5178 | switch (wasm_bits) { | 5271 | switch (wasm_bits) { |
| 5179 | 32 => blk: { | 5272 | 32 => blk: { |
| ... | @@ -5181,10 +5274,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5181,10 +5274,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5181 | try self.addImm32(-1); | 5274 | try self.addImm32(-1); |
| 5182 | break :blk; | 5275 | break :blk; |
| 5183 | } | 5276 | } |
| 5184 | const less_than_zero = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt); | ||
| 5185 | try self.addImm32(std.math.minInt(i32)); | 5277 | try self.addImm32(std.math.minInt(i32)); |
| 5186 | try self.addImm32(std.math.maxInt(i32)); | 5278 | try self.addImm32(std.math.maxInt(i32)); |
| 5187 | try self.emitWValue(less_than_zero); | 5279 | _ = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt); |
| 5188 | try self.addTag(.select); | 5280 | try self.addTag(.select); |
| 5189 | }, | 5281 | }, |
| 5190 | 64 => blk: { | 5282 | 64 => blk: { |
| ... | @@ -5192,16 +5284,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5192,16 +5284,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5192 | try self.addImm64(@bitCast(u64, @as(i64, -1))); | 5284 | try self.addImm64(@bitCast(u64, @as(i64, -1))); |
| 5193 | break :blk; | 5285 | break :blk; |
| 5194 | } | 5286 | } |
| 5195 | const less_than_zero = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt); | ||
| 5196 | try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64)))); | 5287 | try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64)))); |
| 5197 | try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64)))); | 5288 | try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64)))); |
| 5198 | try self.emitWValue(less_than_zero); | 5289 | _ = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt); |
| 5199 | try self.addTag(.select); | 5290 | try self.addTag(.select); |
| 5200 | }, | 5291 | }, |
| 5201 | else => unreachable, | 5292 | else => unreachable, |
| 5202 | } | 5293 | } |
| 5203 | try self.emitWValue(shl); | 5294 | try self.emitWValue(shl); |
| 5204 | try self.emitWValue(cmp_result); | 5295 | _ = try self.cmp(lhs, shr, ty, .neq); |
| 5205 | try self.addTag(.select); | 5296 | try self.addTag(.select); |
| 5206 | try self.addLabel(.local_set, result.local); | 5297 | try self.addLabel(.local_set, result.local); |
| 5207 | return result; | 5298 | return result; |
| ... | @@ -5213,10 +5304,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5213,10 +5304,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5213 | else => unreachable, | 5304 | else => unreachable, |
| 5214 | }; | 5305 | }; |
| 5215 | 5306 | ||
| 5216 | const shl_res = try self.binOp(lhs, shift_value, ty, .shl); | 5307 | var shl_res = try (try self.binOp(lhs, shift_value, ty, .shl)).toLocal(self, ty); |
| 5217 | const shl = try self.binOp(shl_res, rhs, ty, .shl); | 5308 | defer shl_res.free(self); |
| 5218 | const shr = try self.binOp(shl, rhs, ty, .shr); | 5309 | var shl = try (try self.binOp(shl_res, rhs, ty, .shl)).toLocal(self, ty); |
| 5219 | const cmp_result = try self.cmp(shl_res, shr, ty, .neq); | 5310 | defer shl.free(self); |
| 5311 | var shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty); | ||
| 5312 | defer shr.free(self); | ||
| 5220 | 5313 | ||
| 5221 | switch (wasm_bits) { | 5314 | switch (wasm_bits) { |
| 5222 | 32 => blk: { | 5315 | 32 => blk: { |
| ... | @@ -5225,10 +5318,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5225,10 +5318,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5225 | break :blk; | 5318 | break :blk; |
| 5226 | } | 5319 | } |
| 5227 | 5320 | ||
| 5228 | const less_than_zero = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt); | ||
| 5229 | try self.addImm32(std.math.minInt(i32)); | 5321 | try self.addImm32(std.math.minInt(i32)); |
| 5230 | try self.addImm32(std.math.maxInt(i32)); | 5322 | try self.addImm32(std.math.maxInt(i32)); |
| 5231 | try self.emitWValue(less_than_zero); | 5323 | _ = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt); |
| 5232 | try self.addTag(.select); | 5324 | try self.addTag(.select); |
| 5233 | }, | 5325 | }, |
| 5234 | 64 => blk: { | 5326 | 64 => blk: { |
| ... | @@ -5237,29 +5329,30 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5237,29 +5329,30 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5237 | break :blk; | 5329 | break :blk; |
| 5238 | } | 5330 | } |
| 5239 | 5331 | ||
| 5240 | const less_than_zero = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt); | ||
| 5241 | try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64)))); | 5332 | try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64)))); |
| 5242 | try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64)))); | 5333 | try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64)))); |
| 5243 | try self.emitWValue(less_than_zero); | 5334 | _ = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt); |
| 5244 | try self.addTag(.select); | 5335 | try self.addTag(.select); |
| 5245 | }, | 5336 | }, |
| 5246 | else => unreachable, | 5337 | else => unreachable, |
| 5247 | } | 5338 | } |
| 5248 | try self.emitWValue(shl); | 5339 | try self.emitWValue(shl); |
| 5249 | try self.emitWValue(cmp_result); | 5340 | _ = try self.cmp(shl_res, shr, ty, .neq); |
| 5250 | try self.addTag(.select); | 5341 | try self.addTag(.select); |
| 5251 | try self.addLabel(.local_set, result.local); | 5342 | try self.addLabel(.local_set, result.local); |
| 5252 | const shift_result = try self.binOp(result, shift_value, ty, .shr); | 5343 | var shift_result = try self.binOp(result, shift_value, ty, .shr); |
| 5253 | if (is_signed) { | 5344 | if (is_signed) { |
| 5254 | return self.wrapOperand(shift_result, ty); | 5345 | shift_result = try self.wrapOperand(shift_result, ty); |
| 5255 | } | 5346 | } |
| 5256 | return shift_result; | 5347 | return shift_result.toLocal(self, ty); |
| 5257 | } | 5348 | } |
| 5258 | } | 5349 | } |
| 5259 | 5350 | ||
| 5260 | /// Calls a compiler-rt intrinsic by creating an undefined symbol, | 5351 | /// Calls a compiler-rt intrinsic by creating an undefined symbol, |
| 5261 | /// then lowering the arguments and calling the symbol as a function call. | 5352 | /// then lowering the arguments and calling the symbol as a function call. |
| 5262 | /// This function call assumes the C-ABI. | 5353 | /// This function call assumes the C-ABI. |
| 5354 | /// Asserts arguments are not stack values when the return value is | ||
| 5355 | /// passed as the first parameter. | ||
| 5263 | fn callIntrinsic( | 5356 | fn callIntrinsic( |
| 5264 | self: *Self, | 5357 | self: *Self, |
| 5265 | name: []const u8, | 5358 | name: []const u8, |
| ... | @@ -5289,6 +5382,7 @@ fn callIntrinsic( | ... | @@ -5289,6 +5382,7 @@ fn callIntrinsic( |
| 5289 | 5382 | ||
| 5290 | // Lower all arguments to the stack before we call our function | 5383 | // Lower all arguments to the stack before we call our function |
| 5291 | for (args) |arg, arg_i| { | 5384 | for (args) |arg, arg_i| { |
| 5385 | assert(!(want_sret_param and arg == .stack)); | ||
| 5292 | assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime()); | 5386 | assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime()); |
| 5293 | try self.lowerArg(.C, param_types[arg_i], arg); | 5387 | try self.lowerArg(.C, param_types[arg_i], arg); |
| 5294 | } | 5388 | } |
src/arch/x86_64/CodeGen.zig+48-1| ... | @@ -776,6 +776,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -776,6 +776,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 776 | => return self.fail("TODO implement optimized float mode", .{}), | 776 | => return self.fail("TODO implement optimized float mode", .{}), |
| 777 | 777 | ||
| 778 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), | 778 | .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), |
| 779 | .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), | ||
| 779 | 780 | ||
| 780 | .wasm_memory_size => unreachable, | 781 | .wasm_memory_size => unreachable, |
| 781 | .wasm_memory_grow => unreachable, | 782 | .wasm_memory_grow => unreachable, |
| ... | @@ -4370,6 +4371,7 @@ fn genVarDbgInfo( | ... | @@ -4370,6 +4371,7 @@ fn genVarDbgInfo( |
| 4370 | .dwarf => |dw| { | 4371 | .dwarf => |dw| { |
| 4371 | const dbg_info = &dw.dbg_info; | 4372 | const dbg_info = &dw.dbg_info; |
| 4372 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | 4373 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); |
| 4374 | const endian = self.target.cpu.arch.endian(); | ||
| 4373 | 4375 | ||
| 4374 | switch (mcv) { | 4376 | switch (mcv) { |
| 4375 | .register => |reg| { | 4377 | .register => |reg| { |
| ... | @@ -4390,7 +4392,6 @@ fn genVarDbgInfo( | ... | @@ -4390,7 +4392,6 @@ fn genVarDbgInfo( |
| 4390 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | 4392 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); |
| 4391 | }, | 4393 | }, |
| 4392 | .memory, .got_load, .direct_load => { | 4394 | .memory, .got_load, .direct_load => { |
| 4393 | const endian = self.target.cpu.arch.endian(); | ||
| 4394 | const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); | 4395 | const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); |
| 4395 | const is_ptr = switch (tag) { | 4396 | const is_ptr = switch (tag) { |
| 4396 | .dbg_var_ptr => true, | 4397 | .dbg_var_ptr => true, |
| ... | @@ -4425,7 +4426,53 @@ fn genVarDbgInfo( | ... | @@ -4425,7 +4426,53 @@ fn genVarDbgInfo( |
| 4425 | else => {}, | 4426 | else => {}, |
| 4426 | } | 4427 | } |
| 4427 | }, | 4428 | }, |
| 4429 | .immediate => |x| { | ||
| 4430 | const signedness: std.builtin.Signedness = blk: { | ||
| 4431 | if (ty.zigTypeTag() != .Int) break :blk .unsigned; | ||
| 4432 | break :blk ty.intInfo(self.target.*).signedness; | ||
| 4433 | }; | ||
| 4434 | try dbg_info.ensureUnusedCapacity(2); | ||
| 4435 | const fixup = dbg_info.items.len; | ||
| 4436 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | ||
| 4437 | 1, | ||
| 4438 | switch (signedness) { | ||
| 4439 | .signed => DW.OP.consts, | ||
| 4440 | .unsigned => DW.OP.constu, | ||
| 4441 | }, | ||
| 4442 | }); | ||
| 4443 | switch (signedness) { | ||
| 4444 | .signed => try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)), | ||
| 4445 | .unsigned => try leb128.writeULEB128(dbg_info.writer(), x), | ||
| 4446 | } | ||
| 4447 | try dbg_info.append(DW.OP.stack_value); | ||
| 4448 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | ||
| 4449 | }, | ||
| 4450 | .undef => { | ||
| 4451 | // DW.AT.location, DW.FORM.exprloc | ||
| 4452 | // uleb128(exprloc_len) | ||
| 4453 | // DW.OP.implicit_value uleb128(len_of_bytes) bytes | ||
| 4454 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | ||
| 4455 | var implicit_value_len = std.ArrayList(u8).init(self.gpa); | ||
| 4456 | defer implicit_value_len.deinit(); | ||
| 4457 | try leb128.writeULEB128(implicit_value_len.writer(), abi_size); | ||
| 4458 | const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size; | ||
| 4459 | try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len); | ||
| 4460 | try dbg_info.ensureUnusedCapacity(total_exprloc_len); | ||
| 4461 | dbg_info.appendAssumeCapacity(DW.OP.implicit_value); | ||
| 4462 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); | ||
| 4463 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); | ||
| 4464 | }, | ||
| 4465 | .none => { | ||
| 4466 | try dbg_info.ensureUnusedCapacity(3); | ||
| 4467 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc | ||
| 4468 | 2, DW.OP.lit0, DW.OP.stack_value, | ||
| 4469 | }); | ||
| 4470 | }, | ||
| 4428 | else => { | 4471 | else => { |
| 4472 | try dbg_info.ensureUnusedCapacity(2); | ||
| 4473 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | ||
| 4474 | 1, DW.OP.nop, | ||
| 4475 | }); | ||
| 4429 | log.debug("TODO generate debug info for {}", .{mcv}); | 4476 | log.debug("TODO generate debug info for {}", .{mcv}); |
| 4430 | }, | 4477 | }, |
| 4431 | } | 4478 | } |
src/clang_options_data.zig+10-3| ... | @@ -33,7 +33,14 @@ flagpd1("H"), | ... | @@ -33,7 +33,14 @@ flagpd1("H"), |
| 33 | .psl = false, | 33 | .psl = false, |
| 34 | }, | 34 | }, |
| 35 | flagpd1("I-"), | 35 | flagpd1("I-"), |
| 36 | flagpd1("M"), | 36 | .{ |
| 37 | .name = "M", | ||
| 38 | .syntax = .flag, | ||
| 39 | .zig_equivalent = .dep_file_to_stdout, | ||
| 40 | .pd1 = true, | ||
| 41 | .pd2 = false, | ||
| 42 | .psl = false, | ||
| 43 | }, | ||
| 37 | .{ | 44 | .{ |
| 38 | .name = "MD", | 45 | .name = "MD", |
| 39 | .syntax = .flag, | 46 | .syntax = .flag, |
| ... | @@ -53,7 +60,7 @@ flagpd1("M"), | ... | @@ -53,7 +60,7 @@ flagpd1("M"), |
| 53 | .{ | 60 | .{ |
| 54 | .name = "MM", | 61 | .name = "MM", |
| 55 | .syntax = .flag, | 62 | .syntax = .flag, |
| 56 | .zig_equivalent = .dep_file_mm, | 63 | .zig_equivalent = .dep_file_to_stdout, |
| 57 | .pd1 = true, | 64 | .pd1 = true, |
| 58 | .pd2 = false, | 65 | .pd2 = false, |
| 59 | .psl = false, | 66 | .psl = false, |
| ... | @@ -1983,7 +1990,7 @@ flagpsl("MT"), | ... | @@ -1983,7 +1990,7 @@ flagpsl("MT"), |
| 1983 | .{ | 1990 | .{ |
| 1984 | .name = "user-dependencies", | 1991 | .name = "user-dependencies", |
| 1985 | .syntax = .flag, | 1992 | .syntax = .flag, |
| 1986 | .zig_equivalent = .dep_file_mm, | 1993 | .zig_equivalent = .dep_file_to_stdout, |
| 1987 | .pd1 = false, | 1994 | .pd1 = false, |
| 1988 | .pd2 = true, | 1995 | .pd2 = true, |
| 1989 | .psl = false, | 1996 | .psl = false, |
src/codegen/c.zig+1| ... | @@ -1954,6 +1954,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -1954,6 +1954,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1954 | => return f.fail("TODO implement optimized float mode", .{}), | 1954 | => return f.fail("TODO implement optimized float mode", .{}), |
| 1955 | 1955 | ||
| 1956 | .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}), | 1956 | .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}), |
| 1957 | .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), | ||
| 1957 | // zig fmt: on | 1958 | // zig fmt: on |
| 1958 | }; | 1959 | }; |
| 1959 | switch (result_value) { | 1960 | switch (result_value) { |
src/codegen/llvm.zig+180-18| ... | @@ -722,6 +722,10 @@ pub const Object = struct { | ... | @@ -722,6 +722,10 @@ pub const Object = struct { |
| 722 | dg.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); | 722 | dg.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); |
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | if (decl.@"linksection") |section| { | ||
| 726 | llvm_func.setSection(section); | ||
| 727 | } | ||
| 728 | |||
| 725 | // Remove all the basic blocks of a function in order to start over, generating | 729 | // Remove all the basic blocks of a function in order to start over, generating |
| 726 | // LLVM IR from an empty function body. | 730 | // LLVM IR from an empty function body. |
| 727 | while (llvm_func.getFirstBasicBlock()) |bb| { | 731 | while (llvm_func.getFirstBasicBlock()) |bb| { |
| ... | @@ -917,6 +921,40 @@ pub const Object = struct { | ... | @@ -917,6 +921,40 @@ pub const Object = struct { |
| 917 | }; | 921 | }; |
| 918 | try args.append(loaded); | 922 | try args.append(loaded); |
| 919 | }, | 923 | }, |
| 924 | .multiple_llvm_float => { | ||
| 925 | const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len]; | ||
| 926 | const param_ty = fn_info.param_types[it.zig_index - 1]; | ||
| 927 | const param_llvm_ty = try dg.lowerType(param_ty); | ||
| 928 | const param_alignment = param_ty.abiAlignment(target); | ||
| 929 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); | ||
| 930 | arg_ptr.setAlignment(param_alignment); | ||
| 931 | var field_types_buf: [8]*const llvm.Type = undefined; | ||
| 932 | const field_types = field_types_buf[0..llvm_floats.len]; | ||
| 933 | for (llvm_floats) |float_bits, i| { | ||
| 934 | switch (float_bits) { | ||
| 935 | 64 => field_types[i] = dg.context.doubleType(), | ||
| 936 | 80 => field_types[i] = dg.context.x86FP80Type(), | ||
| 937 | else => {}, | ||
| 938 | } | ||
| 939 | } | ||
| 940 | const ints_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); | ||
| 941 | const casted_ptr = builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), ""); | ||
| 942 | for (llvm_floats) |_, i_usize| { | ||
| 943 | const i = @intCast(c_uint, i_usize); | ||
| 944 | const param = llvm_func.getParam(i); | ||
| 945 | const field_ptr = builder.buildStructGEP(casted_ptr, i, ""); | ||
| 946 | const store_inst = builder.buildStore(param, field_ptr); | ||
| 947 | store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8); | ||
| 948 | } | ||
| 949 | |||
| 950 | const is_by_ref = isByRef(param_ty); | ||
| 951 | const loaded = if (is_by_ref) arg_ptr else l: { | ||
| 952 | const load_inst = builder.buildLoad(arg_ptr, ""); | ||
| 953 | load_inst.setAlignment(param_alignment); | ||
| 954 | break :l load_inst; | ||
| 955 | }; | ||
| 956 | try args.append(loaded); | ||
| 957 | }, | ||
| 920 | .as_u16 => { | 958 | .as_u16 => { |
| 921 | const param = llvm_func.getParam(llvm_arg_i); | 959 | const param = llvm_func.getParam(llvm_arg_i); |
| 922 | llvm_arg_i += 1; | 960 | llvm_arg_i += 1; |
| ... | @@ -1107,6 +1145,11 @@ pub const Object = struct { | ... | @@ -1107,6 +1145,11 @@ pub const Object = struct { |
| 1107 | .hidden => llvm_global.setVisibility(.Hidden), | 1145 | .hidden => llvm_global.setVisibility(.Hidden), |
| 1108 | .protected => llvm_global.setVisibility(.Protected), | 1146 | .protected => llvm_global.setVisibility(.Protected), |
| 1109 | } | 1147 | } |
| 1148 | if (exports[0].options.section) |section| { | ||
| 1149 | const section_z = try module.gpa.dupeZ(u8, section); | ||
| 1150 | defer module.gpa.free(section_z); | ||
| 1151 | llvm_global.setSection(section_z); | ||
| 1152 | } | ||
| 1110 | if (decl.val.castTag(.variable)) |variable| { | 1153 | if (decl.val.castTag(.variable)) |variable| { |
| 1111 | if (variable.data.is_threadlocal) { | 1154 | if (variable.data.is_threadlocal) { |
| 1112 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 1155 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| ... | @@ -1683,8 +1726,7 @@ pub const Object = struct { | ... | @@ -1683,8 +1726,7 @@ pub const Object = struct { |
| 1683 | if (ty.castTag(.@"struct")) |payload| { | 1726 | if (ty.castTag(.@"struct")) |payload| { |
| 1684 | const struct_obj = payload.data; | 1727 | const struct_obj = payload.data; |
| 1685 | if (struct_obj.layout == .Packed) { | 1728 | if (struct_obj.layout == .Packed) { |
| 1686 | var buf: Type.Payload.Bits = undefined; | 1729 | const info = struct_obj.backing_int_ty.intInfo(target); |
| 1687 | const info = struct_obj.packedIntegerType(target, &buf).intInfo(target); | ||
| 1688 | const dwarf_encoding: c_uint = switch (info.signedness) { | 1730 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| 1689 | .signed => DW.ATE.signed, | 1731 | .signed => DW.ATE.signed, |
| 1690 | .unsigned => DW.ATE.unsigned, | 1732 | .unsigned => DW.ATE.unsigned, |
| ... | @@ -2184,6 +2226,7 @@ pub const DeclGen = struct { | ... | @@ -2184,6 +2226,7 @@ pub const DeclGen = struct { |
| 2184 | const target = dg.module.getTarget(); | 2226 | const target = dg.module.getTarget(); |
| 2185 | var global = try dg.resolveGlobalDecl(decl_index); | 2227 | var global = try dg.resolveGlobalDecl(decl_index); |
| 2186 | global.setAlignment(decl.getAlignment(target)); | 2228 | global.setAlignment(decl.getAlignment(target)); |
| 2229 | if (decl.@"linksection") |section| global.setSection(section); | ||
| 2187 | assert(decl.has_tv); | 2230 | assert(decl.has_tv); |
| 2188 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { | 2231 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { |
| 2189 | const variable = payload.data; | 2232 | const variable = payload.data; |
| ... | @@ -2217,6 +2260,7 @@ pub const DeclGen = struct { | ... | @@ -2217,6 +2260,7 @@ pub const DeclGen = struct { |
| 2217 | new_global.setLinkage(global.getLinkage()); | 2260 | new_global.setLinkage(global.getLinkage()); |
| 2218 | new_global.setUnnamedAddr(global.getUnnamedAddress()); | 2261 | new_global.setUnnamedAddr(global.getUnnamedAddress()); |
| 2219 | new_global.setAlignment(global.getAlignment()); | 2262 | new_global.setAlignment(global.getAlignment()); |
| 2263 | if (decl.@"linksection") |section| new_global.setSection(section); | ||
| 2220 | new_global.setInitializer(llvm_init); | 2264 | new_global.setInitializer(llvm_init); |
| 2221 | // replaceAllUsesWith requires the type to be unchanged. So we bitcast | 2265 | // replaceAllUsesWith requires the type to be unchanged. So we bitcast |
| 2222 | // the new global to the old type and use that as the thing to replace | 2266 | // the new global to the old type and use that as the thing to replace |
| ... | @@ -2331,6 +2375,14 @@ pub const DeclGen = struct { | ... | @@ -2331,6 +2375,14 @@ pub const DeclGen = struct { |
| 2331 | dg.addFnAttr(llvm_fn, "noreturn"); | 2375 | dg.addFnAttr(llvm_fn, "noreturn"); |
| 2332 | } | 2376 | } |
| 2333 | 2377 | ||
| 2378 | var llvm_arg_i = @as(c_uint, @boolToInt(sret)) + @boolToInt(err_return_tracing); | ||
| 2379 | var it = iterateParamTypes(dg, fn_info); | ||
| 2380 | while (it.next()) |_| : (llvm_arg_i += 1) { | ||
| 2381 | if (!it.byval_attr) continue; | ||
| 2382 | const param = llvm_fn.getParam(llvm_arg_i); | ||
| 2383 | llvm_fn.addByValAttr(llvm_arg_i, param.typeOf().getElementType()); | ||
| 2384 | } | ||
| 2385 | |||
| 2334 | return llvm_fn; | 2386 | return llvm_fn; |
| 2335 | } | 2387 | } |
| 2336 | 2388 | ||
| ... | @@ -2679,9 +2731,7 @@ pub const DeclGen = struct { | ... | @@ -2679,9 +2731,7 @@ pub const DeclGen = struct { |
| 2679 | const struct_obj = t.castTag(.@"struct").?.data; | 2731 | const struct_obj = t.castTag(.@"struct").?.data; |
| 2680 | 2732 | ||
| 2681 | if (struct_obj.layout == .Packed) { | 2733 | if (struct_obj.layout == .Packed) { |
| 2682 | var buf: Type.Payload.Bits = undefined; | 2734 | const int_llvm_ty = try dg.lowerType(struct_obj.backing_int_ty); |
| 2683 | const int_ty = struct_obj.packedIntegerType(target, &buf); | ||
| 2684 | const int_llvm_ty = try dg.lowerType(int_ty); | ||
| 2685 | gop.value_ptr.* = int_llvm_ty; | 2735 | gop.value_ptr.* = int_llvm_ty; |
| 2686 | return int_llvm_ty; | 2736 | return int_llvm_ty; |
| 2687 | } | 2737 | } |
| ... | @@ -2886,6 +2936,18 @@ pub const DeclGen = struct { | ... | @@ -2886,6 +2936,18 @@ pub const DeclGen = struct { |
| 2886 | llvm_params.appendAssumeCapacity(big_int_ty); | 2936 | llvm_params.appendAssumeCapacity(big_int_ty); |
| 2887 | } | 2937 | } |
| 2888 | }, | 2938 | }, |
| 2939 | .multiple_llvm_float => { | ||
| 2940 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; | ||
| 2941 | try llvm_params.ensureUnusedCapacity(it.llvm_types_len); | ||
| 2942 | for (llvm_ints) |float_bits| { | ||
| 2943 | const float_ty = switch (float_bits) { | ||
| 2944 | 64 => dg.context.doubleType(), | ||
| 2945 | 80 => dg.context.x86FP80Type(), | ||
| 2946 | else => unreachable, | ||
| 2947 | }; | ||
| 2948 | llvm_params.appendAssumeCapacity(float_ty); | ||
| 2949 | } | ||
| 2950 | }, | ||
| 2889 | .as_u16 => { | 2951 | .as_u16 => { |
| 2890 | try llvm_params.append(dg.context.intType(16)); | 2952 | try llvm_params.append(dg.context.intType(16)); |
| 2891 | }, | 2953 | }, |
| ... | @@ -3330,8 +3392,8 @@ pub const DeclGen = struct { | ... | @@ -3330,8 +3392,8 @@ pub const DeclGen = struct { |
| 3330 | const struct_obj = tv.ty.castTag(.@"struct").?.data; | 3392 | const struct_obj = tv.ty.castTag(.@"struct").?.data; |
| 3331 | 3393 | ||
| 3332 | if (struct_obj.layout == .Packed) { | 3394 | if (struct_obj.layout == .Packed) { |
| 3333 | const big_bits = struct_obj.packedIntegerBits(target); | 3395 | const big_bits = struct_obj.backing_int_ty.bitSize(target); |
| 3334 | const int_llvm_ty = dg.context.intType(big_bits); | 3396 | const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits)); |
| 3335 | const fields = struct_obj.fields.values(); | 3397 | const fields = struct_obj.fields.values(); |
| 3336 | comptime assert(Type.packed_struct_layout_version == 2); | 3398 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3337 | var running_int: *const llvm.Value = int_llvm_ty.constNull(); | 3399 | var running_int: *const llvm.Value = int_llvm_ty.constNull(); |
| ... | @@ -4185,6 +4247,7 @@ pub const FuncGen = struct { | ... | @@ -4185,6 +4247,7 @@ pub const FuncGen = struct { |
| 4185 | .prefetch => try self.airPrefetch(inst), | 4247 | .prefetch => try self.airPrefetch(inst), |
| 4186 | 4248 | ||
| 4187 | .is_named_enum_value => try self.airIsNamedEnumValue(inst), | 4249 | .is_named_enum_value => try self.airIsNamedEnumValue(inst), |
| 4250 | .error_set_has_value => try self.airErrorSetHasValue(inst), | ||
| 4188 | 4251 | ||
| 4189 | .reduce => try self.airReduce(inst, false), | 4252 | .reduce => try self.airReduce(inst, false), |
| 4190 | .reduce_optimized => try self.airReduce(inst, true), | 4253 | .reduce_optimized => try self.airReduce(inst, true), |
| ... | @@ -4394,6 +4457,39 @@ pub const FuncGen = struct { | ... | @@ -4394,6 +4457,39 @@ pub const FuncGen = struct { |
| 4394 | llvm_args.appendAssumeCapacity(load_inst); | 4457 | llvm_args.appendAssumeCapacity(load_inst); |
| 4395 | } | 4458 | } |
| 4396 | }, | 4459 | }, |
| 4460 | .multiple_llvm_float => { | ||
| 4461 | const arg = args[it.zig_index - 1]; | ||
| 4462 | const param_ty = self.air.typeOf(arg); | ||
| 4463 | const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len]; | ||
| 4464 | const llvm_arg = try self.resolveInst(arg); | ||
| 4465 | const is_by_ref = isByRef(param_ty); | ||
| 4466 | const arg_ptr = if (is_by_ref) llvm_arg else p: { | ||
| 4467 | const p = self.buildAlloca(llvm_arg.typeOf()); | ||
| 4468 | const store_inst = self.builder.buildStore(llvm_arg, p); | ||
| 4469 | store_inst.setAlignment(param_ty.abiAlignment(target)); | ||
| 4470 | break :p p; | ||
| 4471 | }; | ||
| 4472 | |||
| 4473 | var field_types_buf: [8]*const llvm.Type = undefined; | ||
| 4474 | const field_types = field_types_buf[0..llvm_floats.len]; | ||
| 4475 | for (llvm_floats) |float_bits, i| { | ||
| 4476 | switch (float_bits) { | ||
| 4477 | 64 => field_types[i] = self.dg.context.doubleType(), | ||
| 4478 | 80 => field_types[i] = self.dg.context.x86FP80Type(), | ||
| 4479 | else => {}, | ||
| 4480 | } | ||
| 4481 | } | ||
| 4482 | const ints_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); | ||
| 4483 | const casted_ptr = self.builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), ""); | ||
| 4484 | try llvm_args.ensureUnusedCapacity(it.llvm_types_len); | ||
| 4485 | for (llvm_floats) |_, i_usize| { | ||
| 4486 | const i = @intCast(c_uint, i_usize); | ||
| 4487 | const field_ptr = self.builder.buildStructGEP(casted_ptr, i, ""); | ||
| 4488 | const load_inst = self.builder.buildLoad(field_ptr, ""); | ||
| 4489 | load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8); | ||
| 4490 | llvm_args.appendAssumeCapacity(load_inst); | ||
| 4491 | } | ||
| 4492 | }, | ||
| 4397 | .as_u16 => { | 4493 | .as_u16 => { |
| 4398 | const arg = args[it.zig_index - 1]; | 4494 | const arg = args[it.zig_index - 1]; |
| 4399 | const llvm_arg = try self.resolveInst(arg); | 4495 | const llvm_arg = try self.resolveInst(arg); |
| ... | @@ -7888,6 +7984,53 @@ pub const FuncGen = struct { | ... | @@ -7888,6 +7984,53 @@ pub const FuncGen = struct { |
| 7888 | } | 7984 | } |
| 7889 | } | 7985 | } |
| 7890 | 7986 | ||
| 7987 | fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | ||
| 7988 | if (self.liveness.isUnused(inst)) return null; | ||
| 7989 | |||
| 7990 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | ||
| 7991 | const operand = try self.resolveInst(ty_op.operand); | ||
| 7992 | const error_set_ty = self.air.getRefType(ty_op.ty); | ||
| 7993 | |||
| 7994 | const names = error_set_ty.errorSetNames(); | ||
| 7995 | const valid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Valid"); | ||
| 7996 | const invalid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Invalid"); | ||
| 7997 | const end_block = self.context.appendBasicBlock(self.llvm_func, "End"); | ||
| 7998 | const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len)); | ||
| 7999 | |||
| 8000 | for (names) |name| { | ||
| 8001 | const err_int = self.dg.module.global_error_set.get(name).?; | ||
| 8002 | const this_tag_int_value = int: { | ||
| 8003 | var tag_val_payload: Value.Payload.U64 = .{ | ||
| 8004 | .base = .{ .tag = .int_u64 }, | ||
| 8005 | .data = err_int, | ||
| 8006 | }; | ||
| 8007 | break :int try self.dg.lowerValue(.{ | ||
| 8008 | .ty = Type.err_int, | ||
| 8009 | .val = Value.initPayload(&tag_val_payload.base), | ||
| 8010 | }); | ||
| 8011 | }; | ||
| 8012 | switch_instr.addCase(this_tag_int_value, valid_block); | ||
| 8013 | } | ||
| 8014 | self.builder.positionBuilderAtEnd(valid_block); | ||
| 8015 | _ = self.builder.buildBr(end_block); | ||
| 8016 | |||
| 8017 | self.builder.positionBuilderAtEnd(invalid_block); | ||
| 8018 | _ = self.builder.buildBr(end_block); | ||
| 8019 | |||
| 8020 | self.builder.positionBuilderAtEnd(end_block); | ||
| 8021 | |||
| 8022 | const llvm_type = self.dg.context.intType(1); | ||
| 8023 | const incoming_values: [2]*const llvm.Value = .{ | ||
| 8024 | llvm_type.constInt(1, .False), llvm_type.constInt(0, .False), | ||
| 8025 | }; | ||
| 8026 | const incoming_blocks: [2]*const llvm.BasicBlock = .{ | ||
| 8027 | valid_block, invalid_block, | ||
| 8028 | }; | ||
| 8029 | const phi_node = self.builder.buildPhi(llvm_type, ""); | ||
| 8030 | phi_node.addIncoming(&incoming_values, &incoming_blocks, 2); | ||
| 8031 | return phi_node; | ||
| 8032 | } | ||
| 8033 | |||
| 7891 | fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 8034 | fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 7892 | if (self.liveness.isUnused(inst)) return null; | 8035 | if (self.liveness.isUnused(inst)) return null; |
| 7893 | 8036 | ||
| ... | @@ -8243,8 +8386,8 @@ pub const FuncGen = struct { | ... | @@ -8243,8 +8386,8 @@ pub const FuncGen = struct { |
| 8243 | .Struct => { | 8386 | .Struct => { |
| 8244 | if (result_ty.containerLayout() == .Packed) { | 8387 | if (result_ty.containerLayout() == .Packed) { |
| 8245 | const struct_obj = result_ty.castTag(.@"struct").?.data; | 8388 | const struct_obj = result_ty.castTag(.@"struct").?.data; |
| 8246 | const big_bits = struct_obj.packedIntegerBits(target); | 8389 | const big_bits = struct_obj.backing_int_ty.bitSize(target); |
| 8247 | const int_llvm_ty = self.dg.context.intType(big_bits); | 8390 | const int_llvm_ty = self.dg.context.intType(@intCast(c_uint, big_bits)); |
| 8248 | const fields = struct_obj.fields.values(); | 8391 | const fields = struct_obj.fields.values(); |
| 8249 | comptime assert(Type.packed_struct_layout_version == 2); | 8392 | comptime assert(Type.packed_struct_layout_version == 2); |
| 8250 | var running_int: *const llvm.Value = int_llvm_ty.constNull(); | 8393 | var running_int: *const llvm.Value = int_llvm_ty.constNull(); |
| ... | @@ -9359,16 +9502,20 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. | ... | @@ -9359,16 +9502,20 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9359 | llvm_types_index += 1; | 9502 | llvm_types_index += 1; |
| 9360 | }, | 9503 | }, |
| 9361 | .sse => { | 9504 | .sse => { |
| 9362 | @panic("TODO"); | 9505 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 9506 | llvm_types_index += 1; | ||
| 9363 | }, | 9507 | }, |
| 9364 | .sseup => { | 9508 | .sseup => { |
| 9365 | @panic("TODO"); | 9509 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 9510 | llvm_types_index += 1; | ||
| 9366 | }, | 9511 | }, |
| 9367 | .x87 => { | 9512 | .x87 => { |
| 9368 | @panic("TODO"); | 9513 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); |
| 9514 | llvm_types_index += 1; | ||
| 9369 | }, | 9515 | }, |
| 9370 | .x87up => { | 9516 | .x87up => { |
| 9371 | @panic("TODO"); | 9517 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); |
| 9518 | llvm_types_index += 1; | ||
| 9372 | }, | 9519 | }, |
| 9373 | .complex_x87 => { | 9520 | .complex_x87 => { |
| 9374 | @panic("TODO"); | 9521 | @panic("TODO"); |
| ... | @@ -9414,6 +9561,7 @@ const ParamTypeIterator = struct { | ... | @@ -9414,6 +9561,7 @@ const ParamTypeIterator = struct { |
| 9414 | target: std.Target, | 9561 | target: std.Target, |
| 9415 | llvm_types_len: u32, | 9562 | llvm_types_len: u32, |
| 9416 | llvm_types_buffer: [8]u16, | 9563 | llvm_types_buffer: [8]u16, |
| 9564 | byval_attr: bool, | ||
| 9417 | 9565 | ||
| 9418 | const Lowering = enum { | 9566 | const Lowering = enum { |
| 9419 | no_bits, | 9567 | no_bits, |
| ... | @@ -9421,6 +9569,7 @@ const ParamTypeIterator = struct { | ... | @@ -9421,6 +9569,7 @@ const ParamTypeIterator = struct { |
| 9421 | byref, | 9569 | byref, |
| 9422 | abi_sized_int, | 9570 | abi_sized_int, |
| 9423 | multiple_llvm_ints, | 9571 | multiple_llvm_ints, |
| 9572 | multiple_llvm_float, | ||
| 9424 | slice, | 9573 | slice, |
| 9425 | as_u16, | 9574 | as_u16, |
| 9426 | }; | 9575 | }; |
| ... | @@ -9428,6 +9577,7 @@ const ParamTypeIterator = struct { | ... | @@ -9428,6 +9577,7 @@ const ParamTypeIterator = struct { |
| 9428 | pub fn next(it: *ParamTypeIterator) ?Lowering { | 9577 | pub fn next(it: *ParamTypeIterator) ?Lowering { |
| 9429 | if (it.zig_index >= it.fn_info.param_types.len) return null; | 9578 | if (it.zig_index >= it.fn_info.param_types.len) return null; |
| 9430 | const ty = it.fn_info.param_types[it.zig_index]; | 9579 | const ty = it.fn_info.param_types[it.zig_index]; |
| 9580 | it.byval_attr = false; | ||
| 9431 | return nextInner(it, ty); | 9581 | return nextInner(it, ty); |
| 9432 | } | 9582 | } |
| 9433 | 9583 | ||
| ... | @@ -9513,6 +9663,7 @@ const ParamTypeIterator = struct { | ... | @@ -9513,6 +9663,7 @@ const ParamTypeIterator = struct { |
| 9513 | .memory => { | 9663 | .memory => { |
| 9514 | it.zig_index += 1; | 9664 | it.zig_index += 1; |
| 9515 | it.llvm_index += 1; | 9665 | it.llvm_index += 1; |
| 9666 | it.byval_attr = true; | ||
| 9516 | return .byref; | 9667 | return .byref; |
| 9517 | }, | 9668 | }, |
| 9518 | .sse => { | 9669 | .sse => { |
| ... | @@ -9532,6 +9683,7 @@ const ParamTypeIterator = struct { | ... | @@ -9532,6 +9683,7 @@ const ParamTypeIterator = struct { |
| 9532 | if (classes[0] == .memory) { | 9683 | if (classes[0] == .memory) { |
| 9533 | it.zig_index += 1; | 9684 | it.zig_index += 1; |
| 9534 | it.llvm_index += 1; | 9685 | it.llvm_index += 1; |
| 9686 | it.byval_attr = true; | ||
| 9535 | return .byref; | 9687 | return .byref; |
| 9536 | } | 9688 | } |
| 9537 | var llvm_types_buffer: [8]u16 = undefined; | 9689 | var llvm_types_buffer: [8]u16 = undefined; |
| ... | @@ -9543,16 +9695,20 @@ const ParamTypeIterator = struct { | ... | @@ -9543,16 +9695,20 @@ const ParamTypeIterator = struct { |
| 9543 | llvm_types_index += 1; | 9695 | llvm_types_index += 1; |
| 9544 | }, | 9696 | }, |
| 9545 | .sse => { | 9697 | .sse => { |
| 9546 | @panic("TODO"); | 9698 | llvm_types_buffer[llvm_types_index] = 64; |
| 9699 | llvm_types_index += 1; | ||
| 9547 | }, | 9700 | }, |
| 9548 | .sseup => { | 9701 | .sseup => { |
| 9549 | @panic("TODO"); | 9702 | llvm_types_buffer[llvm_types_index] = 64; |
| 9703 | llvm_types_index += 1; | ||
| 9550 | }, | 9704 | }, |
| 9551 | .x87 => { | 9705 | .x87 => { |
| 9552 | @panic("TODO"); | 9706 | llvm_types_buffer[llvm_types_index] = 80; |
| 9707 | llvm_types_index += 1; | ||
| 9553 | }, | 9708 | }, |
| 9554 | .x87up => { | 9709 | .x87up => { |
| 9555 | @panic("TODO"); | 9710 | llvm_types_buffer[llvm_types_index] = 80; |
| 9711 | llvm_types_index += 1; | ||
| 9556 | }, | 9712 | }, |
| 9557 | .complex_x87 => { | 9713 | .complex_x87 => { |
| 9558 | @panic("TODO"); | 9714 | @panic("TODO"); |
| ... | @@ -9566,11 +9722,16 @@ const ParamTypeIterator = struct { | ... | @@ -9566,11 +9722,16 @@ const ParamTypeIterator = struct { |
| 9566 | it.llvm_index += 1; | 9722 | it.llvm_index += 1; |
| 9567 | return .abi_sized_int; | 9723 | return .abi_sized_int; |
| 9568 | } | 9724 | } |
| 9725 | if (classes[0] == .sse and classes[1] == .none) { | ||
| 9726 | it.zig_index += 1; | ||
| 9727 | it.llvm_index += 1; | ||
| 9728 | return .byval; | ||
| 9729 | } | ||
| 9569 | it.llvm_types_buffer = llvm_types_buffer; | 9730 | it.llvm_types_buffer = llvm_types_buffer; |
| 9570 | it.llvm_types_len = llvm_types_index; | 9731 | it.llvm_types_len = llvm_types_index; |
| 9571 | it.llvm_index += llvm_types_index; | 9732 | it.llvm_index += llvm_types_index; |
| 9572 | it.zig_index += 1; | 9733 | it.zig_index += 1; |
| 9573 | return .multiple_llvm_ints; | 9734 | return if (classes[0] == .integer) .multiple_llvm_ints else .multiple_llvm_float; |
| 9574 | }, | 9735 | }, |
| 9575 | }, | 9736 | }, |
| 9576 | .wasm32 => { | 9737 | .wasm32 => { |
| ... | @@ -9611,6 +9772,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp | ... | @@ -9611,6 +9772,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp |
| 9611 | .target = dg.module.getTarget(), | 9772 | .target = dg.module.getTarget(), |
| 9612 | .llvm_types_buffer = undefined, | 9773 | .llvm_types_buffer = undefined, |
| 9613 | .llvm_types_len = 0, | 9774 | .llvm_types_len = 0, |
| 9775 | .byval_attr = false, | ||
| 9614 | }; | 9776 | }; |
| 9615 | } | 9777 | } |
| 9616 | 9778 |
src/codegen/llvm/bindings.zig+6| ... | @@ -126,6 +126,9 @@ pub const Value = opaque { | ... | @@ -126,6 +126,9 @@ pub const Value = opaque { |
| 126 | pub const setThreadLocalMode = LLVMSetThreadLocalMode; | 126 | pub const setThreadLocalMode = LLVMSetThreadLocalMode; |
| 127 | extern fn LLVMSetThreadLocalMode(Global: *const Value, Mode: ThreadLocalMode) void; | 127 | extern fn LLVMSetThreadLocalMode(Global: *const Value, Mode: ThreadLocalMode) void; |
| 128 | 128 | ||
| 129 | pub const setSection = LLVMSetSection; | ||
| 130 | extern fn LLVMSetSection(Global: *const Value, Section: [*:0]const u8) void; | ||
| 131 | |||
| 129 | pub const deleteGlobal = LLVMDeleteGlobal; | 132 | pub const deleteGlobal = LLVMDeleteGlobal; |
| 130 | extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void; | 133 | extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void; |
| 131 | 134 | ||
| ... | @@ -245,6 +248,9 @@ pub const Value = opaque { | ... | @@ -245,6 +248,9 @@ pub const Value = opaque { |
| 245 | 248 | ||
| 246 | pub const addFunctionAttr = ZigLLVMAddFunctionAttr; | 249 | pub const addFunctionAttr = ZigLLVMAddFunctionAttr; |
| 247 | extern fn ZigLLVMAddFunctionAttr(Fn: *const Value, attr_name: [*:0]const u8, attr_value: [*:0]const u8) void; | 250 | extern fn ZigLLVMAddFunctionAttr(Fn: *const Value, attr_name: [*:0]const u8, attr_value: [*:0]const u8) void; |
| 251 | |||
| 252 | pub const addByValAttr = ZigLLVMAddByValAttr; | ||
| 253 | extern fn ZigLLVMAddByValAttr(Fn: *const Value, ArgNo: c_uint, type: *const Type) void; | ||
| 248 | }; | 254 | }; |
| 249 | 255 | ||
| 250 | pub const Type = opaque { | 256 | pub const Type = opaque { |
src/link.zig+1| ... | @@ -435,6 +435,7 @@ pub const File = struct { | ... | @@ -435,6 +435,7 @@ pub const File = struct { |
| 435 | EmitFail, | 435 | EmitFail, |
| 436 | NameTooLong, | 436 | NameTooLong, |
| 437 | CurrentWorkingDirectoryUnlinked, | 437 | CurrentWorkingDirectoryUnlinked, |
| 438 | LockViolation, | ||
| 438 | }; | 439 | }; |
| 439 | 440 | ||
| 440 | /// Called from within the CodeGen to lower a local variable instantion as an unnamed | 441 | /// Called from within the CodeGen to lower a local variable instantion as an unnamed |
src/link/Dwarf.zig+8-5| ... | @@ -102,7 +102,7 @@ pub const DeclState = struct { | ... | @@ -102,7 +102,7 @@ pub const DeclState = struct { |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void { | 104 | pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void { |
| 105 | log.debug("{x}: target sym @{d}, via GOT {}", .{ offset, target, is_ptr }); | 105 | log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr }); |
| 106 | try self.exprloc_relocs.append(self.gpa, .{ | 106 | try self.exprloc_relocs.append(self.gpa, .{ |
| 107 | .@"type" = if (is_ptr) .got_load else .direct_load, | 107 | .@"type" = if (is_ptr) .got_load else .direct_load, |
| 108 | .target = target, | 108 | .target = target, |
| ... | @@ -135,7 +135,7 @@ pub const DeclState = struct { | ... | @@ -135,7 +135,7 @@ pub const DeclState = struct { |
| 135 | .@"type" = ty, | 135 | .@"type" = ty, |
| 136 | .offset = undefined, | 136 | .offset = undefined, |
| 137 | }); | 137 | }); |
| 138 | log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() }); | 138 | log.debug("%{d}: {}", .{ sym_index, ty.fmtDebug() }); |
| 139 | try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{ | 139 | try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{ |
| 140 | .mod = self.mod, | 140 | .mod = self.mod, |
| 141 | }); | 141 | }); |
| ... | @@ -143,7 +143,7 @@ pub const DeclState = struct { | ... | @@ -143,7 +143,7 @@ pub const DeclState = struct { |
| 143 | .mod = self.mod, | 143 | .mod = self.mod, |
| 144 | }).?; | 144 | }).?; |
| 145 | }; | 145 | }; |
| 146 | log.debug("{x}: @{d} + 0", .{ offset, resolv }); | 146 | log.debug("{x}: %{d} + 0", .{ offset, resolv }); |
| 147 | try self.abbrev_relocs.append(self.gpa, .{ | 147 | try self.abbrev_relocs.append(self.gpa, .{ |
| 148 | .target = resolv, | 148 | .target = resolv, |
| 149 | .atom = atom, | 149 | .atom = atom, |
| ... | @@ -1056,6 +1056,7 @@ pub fn commitDeclState( | ... | @@ -1056,6 +1056,7 @@ pub fn commitDeclState( |
| 1056 | break :blk false; | 1056 | break :blk false; |
| 1057 | }; | 1057 | }; |
| 1058 | if (deferred) { | 1058 | if (deferred) { |
| 1059 | log.debug("resolving %{d} deferred until flush", .{target}); | ||
| 1059 | try self.global_abbrev_relocs.append(gpa, .{ | 1060 | try self.global_abbrev_relocs.append(gpa, .{ |
| 1060 | .target = null, | 1061 | .target = null, |
| 1061 | .offset = reloc.offset, | 1062 | .offset = reloc.offset, |
| ... | @@ -1063,10 +1064,12 @@ pub fn commitDeclState( | ... | @@ -1063,10 +1064,12 @@ pub fn commitDeclState( |
| 1063 | .addend = reloc.addend, | 1064 | .addend = reloc.addend, |
| 1064 | }); | 1065 | }); |
| 1065 | } else { | 1066 | } else { |
| 1067 | const value = symbol.atom.off + symbol.offset + reloc.addend; | ||
| 1068 | log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() }); | ||
| 1066 | mem.writeInt( | 1069 | mem.writeInt( |
| 1067 | u32, | 1070 | u32, |
| 1068 | dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], | 1071 | dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], |
| 1069 | symbol.atom.off + symbol.offset + reloc.addend, | 1072 | value, |
| 1070 | target_endian, | 1073 | target_endian, |
| 1071 | ); | 1074 | ); |
| 1072 | } | 1075 | } |
| ... | @@ -1259,7 +1262,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co | ... | @@ -1259,7 +1262,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co |
| 1259 | debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff; | 1262 | debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff; |
| 1260 | } | 1263 | } |
| 1261 | debug_info_sect.size = needed_size; | 1264 | debug_info_sect.size = needed_size; |
| 1262 | d_sym.debug_line_header_dirty = true; | 1265 | d_sym.debug_info_header_dirty = true; |
| 1263 | } | 1266 | } |
| 1264 | const file_pos = debug_info_sect.offset + atom.off; | 1267 | const file_pos = debug_info_sect.offset + atom.off; |
| 1265 | try pwriteDbgInfoNops( | 1268 | try pwriteDbgInfoNops( |
src/link/MachO.zig+3-3| ... | @@ -5315,10 +5315,10 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { | ... | @@ -5315,10 +5315,10 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 5315 | } | 5315 | } |
| 5316 | 5316 | ||
| 5317 | fn filterDataInCode( | 5317 | fn filterDataInCode( |
| 5318 | dices: []const macho.data_in_code_entry, | 5318 | dices: []align(1) const macho.data_in_code_entry, |
| 5319 | start_addr: u64, | 5319 | start_addr: u64, |
| 5320 | end_addr: u64, | 5320 | end_addr: u64, |
| 5321 | ) []const macho.data_in_code_entry { | 5321 | ) []align(1) const macho.data_in_code_entry { |
| 5322 | const Predicate = struct { | 5322 | const Predicate = struct { |
| 5323 | addr: u64, | 5323 | addr: u64, |
| 5324 | 5324 | ||
| ... | @@ -5825,7 +5825,7 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc { | ... | @@ -5825,7 +5825,7 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc { |
| 5825 | return global; | 5825 | return global; |
| 5826 | } | 5826 | } |
| 5827 | 5827 | ||
| 5828 | pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize { | 5828 | pub fn findFirst(comptime T: type, haystack: []align(1) const T, start: usize, predicate: anytype) usize { |
| 5829 | if (!@hasDecl(@TypeOf(predicate), "predicate")) | 5829 | if (!@hasDecl(@TypeOf(predicate), "predicate")) |
| 5830 | @compileError("Predicate is required to define fn predicate(@This(), T) bool"); | 5830 | @compileError("Predicate is required to define fn predicate(@This(), T) bool"); |
| 5831 | 5831 |
src/link/MachO/Atom.zig+1-1| ... | @@ -218,7 +218,7 @@ const RelocContext = struct { | ... | @@ -218,7 +218,7 @@ const RelocContext = struct { |
| 218 | base_offset: i32 = 0, | 218 | base_offset: i32 = 0, |
| 219 | }; | 219 | }; |
| 220 | 220 | ||
| 221 | pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context: RelocContext) !void { | 221 | pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info, context: RelocContext) !void { |
| 222 | const tracy = trace(@src()); | 222 | const tracy = trace(@src()); |
| 223 | defer tracy.end(); | 223 | defer tracy.end(); |
| 224 | 224 |
src/link/MachO/DebugSymbols.zig+8-8| ... | @@ -63,17 +63,16 @@ pub const Reloc = struct { | ... | @@ -63,17 +63,16 @@ pub const Reloc = struct { |
| 63 | pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void { | 63 | pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void { |
| 64 | if (self.linkedit_segment_cmd_index == null) { | 64 | if (self.linkedit_segment_cmd_index == null) { |
| 65 | self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len); | 65 | self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len); |
| 66 | log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ | 66 | const fileoff = @intCast(u64, self.base.page_size); |
| 67 | self.base.page_size, | 67 | const needed_size = @intCast(u64, self.base.page_size) * 2; |
| 68 | self.base.page_size * 2, | 68 | log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ fileoff, needed_size }); |
| 69 | }); | ||
| 70 | // TODO this needs reworking | 69 | // TODO this needs reworking |
| 71 | try self.segments.append(allocator, .{ | 70 | try self.segments.append(allocator, .{ |
| 72 | .segname = makeStaticString("__LINKEDIT"), | 71 | .segname = makeStaticString("__LINKEDIT"), |
| 73 | .vmaddr = self.base.page_size, | 72 | .vmaddr = fileoff, |
| 74 | .vmsize = self.base.page_size, | 73 | .vmsize = needed_size, |
| 75 | .fileoff = self.base.page_size, | 74 | .fileoff = fileoff, |
| 76 | .filesize = self.base.page_size, | 75 | .filesize = needed_size, |
| 77 | .maxprot = macho.PROT.READ, | 76 | .maxprot = macho.PROT.READ, |
| 78 | .initprot = macho.PROT.READ, | 77 | .initprot = macho.PROT.READ, |
| 79 | .cmdsize = @sizeOf(macho.segment_command_64), | 78 | .cmdsize = @sizeOf(macho.segment_command_64), |
| ... | @@ -284,6 +283,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -284,6 +283,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 284 | const lc_writer = lc_buffer.writer(); | 283 | const lc_writer = lc_buffer.writer(); |
| 285 | var ncmds: u32 = 0; | 284 | var ncmds: u32 = 0; |
| 286 | 285 | ||
| 286 | self.updateDwarfSegment(); | ||
| 287 | try self.writeLinkeditSegmentData(&ncmds, lc_writer); | 287 | try self.writeLinkeditSegmentData(&ncmds, lc_writer); |
| 288 | self.updateDwarfSegment(); | 288 | self.updateDwarfSegment(); |
| 289 | 289 |
src/link/MachO/Object.zig+13-12| ... | @@ -24,7 +24,7 @@ mtime: u64, | ... | @@ -24,7 +24,7 @@ mtime: u64, |
| 24 | contents: []align(@alignOf(u64)) const u8, | 24 | contents: []align(@alignOf(u64)) const u8, |
| 25 | 25 | ||
| 26 | header: macho.mach_header_64 = undefined, | 26 | header: macho.mach_header_64 = undefined, |
| 27 | in_symtab: []const macho.nlist_64 = undefined, | 27 | in_symtab: []align(1) const macho.nlist_64 = undefined, |
| 28 | in_strtab: []const u8 = undefined, | 28 | in_strtab: []const u8 = undefined, |
| 29 | 29 | ||
| 30 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 30 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | @@ -99,12 +99,13 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) | ... | @@ -99,12 +99,13 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) |
| 99 | }, | 99 | }, |
| 100 | .SYMTAB => { | 100 | .SYMTAB => { |
| 101 | const symtab = cmd.cast(macho.symtab_command).?; | 101 | const symtab = cmd.cast(macho.symtab_command).?; |
| 102 | // Sadly, SYMTAB may be at an unaligned offset within the object file. | ||
| 102 | self.in_symtab = @ptrCast( | 103 | self.in_symtab = @ptrCast( |
| 103 | [*]const macho.nlist_64, | 104 | [*]align(1) const macho.nlist_64, |
| 104 | @alignCast(@alignOf(macho.nlist_64), &self.contents[symtab.symoff]), | 105 | self.contents.ptr + symtab.symoff, |
| 105 | )[0..symtab.nsyms]; | 106 | )[0..symtab.nsyms]; |
| 106 | self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize]; | 107 | self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize]; |
| 107 | try self.symtab.appendSlice(allocator, self.in_symtab); | 108 | try self.symtab.appendUnalignedSlice(allocator, self.in_symtab); |
| 108 | }, | 109 | }, |
| 109 | else => {}, | 110 | else => {}, |
| 110 | } | 111 | } |
| ... | @@ -196,10 +197,10 @@ fn filterSymbolsByAddress( | ... | @@ -196,10 +197,10 @@ fn filterSymbolsByAddress( |
| 196 | } | 197 | } |
| 197 | 198 | ||
| 198 | fn filterRelocs( | 199 | fn filterRelocs( |
| 199 | relocs: []const macho.relocation_info, | 200 | relocs: []align(1) const macho.relocation_info, |
| 200 | start_addr: u64, | 201 | start_addr: u64, |
| 201 | end_addr: u64, | 202 | end_addr: u64, |
| 202 | ) []const macho.relocation_info { | 203 | ) []align(1) const macho.relocation_info { |
| 203 | const Predicate = struct { | 204 | const Predicate = struct { |
| 204 | addr: u64, | 205 | addr: u64, |
| 205 | 206 | ||
| ... | @@ -303,8 +304,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) | ... | @@ -303,8 +304,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) |
| 303 | 304 | ||
| 304 | // Read section's list of relocations | 305 | // Read section's list of relocations |
| 305 | const relocs = @ptrCast( | 306 | const relocs = @ptrCast( |
| 306 | [*]const macho.relocation_info, | 307 | [*]align(1) const macho.relocation_info, |
| 307 | @alignCast(@alignOf(macho.relocation_info), &self.contents[sect.reloff]), | 308 | self.contents.ptr + sect.reloff, |
| 308 | )[0..sect.nreloc]; | 309 | )[0..sect.nreloc]; |
| 309 | 310 | ||
| 310 | // Symbols within this section only. | 311 | // Symbols within this section only. |
| ... | @@ -472,7 +473,7 @@ fn createAtomFromSubsection( | ... | @@ -472,7 +473,7 @@ fn createAtomFromSubsection( |
| 472 | size: u64, | 473 | size: u64, |
| 473 | alignment: u32, | 474 | alignment: u32, |
| 474 | code: ?[]const u8, | 475 | code: ?[]const u8, |
| 475 | relocs: []const macho.relocation_info, | 476 | relocs: []align(1) const macho.relocation_info, |
| 476 | indexes: []const SymbolAtIndex, | 477 | indexes: []const SymbolAtIndex, |
| 477 | match: u8, | 478 | match: u8, |
| 478 | sect: macho.section_64, | 479 | sect: macho.section_64, |
| ... | @@ -538,7 +539,7 @@ pub fn getSourceSection(self: Object, index: u16) macho.section_64 { | ... | @@ -538,7 +539,7 @@ pub fn getSourceSection(self: Object, index: u16) macho.section_64 { |
| 538 | return self.sections.items[index]; | 539 | return self.sections.items[index]; |
| 539 | } | 540 | } |
| 540 | 541 | ||
| 541 | pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry { | 542 | pub fn parseDataInCode(self: Object) ?[]align(1) const macho.data_in_code_entry { |
| 542 | var it = LoadCommandIterator{ | 543 | var it = LoadCommandIterator{ |
| 543 | .ncmds = self.header.ncmds, | 544 | .ncmds = self.header.ncmds, |
| 544 | .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds], | 545 | .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds], |
| ... | @@ -549,8 +550,8 @@ pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry { | ... | @@ -549,8 +550,8 @@ pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry { |
| 549 | const dice = cmd.cast(macho.linkedit_data_command).?; | 550 | const dice = cmd.cast(macho.linkedit_data_command).?; |
| 550 | const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry)); | 551 | const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry)); |
| 551 | return @ptrCast( | 552 | return @ptrCast( |
| 552 | [*]const macho.data_in_code_entry, | 553 | [*]align(1) const macho.data_in_code_entry, |
| 553 | @alignCast(@alignOf(macho.data_in_code_entry), &self.contents[dice.dataoff]), | 554 | self.contents.ptr + dice.dataoff, |
| 554 | )[0..ndice]; | 555 | )[0..ndice]; |
| 555 | }, | 556 | }, |
| 556 | else => {}, | 557 | else => {}, |
src/main.zig+5-3| ... | @@ -718,7 +718,7 @@ fn buildOutputType( | ... | @@ -718,7 +718,7 @@ fn buildOutputType( |
| 718 | var test_filter: ?[]const u8 = null; | 718 | var test_filter: ?[]const u8 = null; |
| 719 | var test_name_prefix: ?[]const u8 = null; | 719 | var test_name_prefix: ?[]const u8 = null; |
| 720 | var override_local_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LOCAL_CACHE_DIR"); | 720 | var override_local_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LOCAL_CACHE_DIR"); |
| 721 | var override_global_cache_dir: ?[]const u8 = null; | 721 | var override_global_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_GLOBAL_CACHE_DIR"); |
| 722 | var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR"); | 722 | var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR"); |
| 723 | var main_pkg_path: ?[]const u8 = null; | 723 | var main_pkg_path: ?[]const u8 = null; |
| 724 | var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no; | 724 | var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no; |
| ... | @@ -1657,7 +1657,8 @@ fn buildOutputType( | ... | @@ -1657,7 +1657,8 @@ fn buildOutputType( |
| 1657 | disable_c_depfile = true; | 1657 | disable_c_depfile = true; |
| 1658 | try clang_argv.appendSlice(it.other_args); | 1658 | try clang_argv.appendSlice(it.other_args); |
| 1659 | }, | 1659 | }, |
| 1660 | .dep_file_mm => { // -MM | 1660 | .dep_file_to_stdout => { // -M, -MM |
| 1661 | // "Like -MD, but also implies -E and writes to stdout by default" | ||
| 1661 | // "Like -MMD, but also implies -E and writes to stdout by default" | 1662 | // "Like -MMD, but also implies -E and writes to stdout by default" |
| 1662 | c_out_mode = .preprocessor; | 1663 | c_out_mode = .preprocessor; |
| 1663 | disable_c_depfile = true; | 1664 | disable_c_depfile = true; |
| ... | @@ -4226,6 +4227,7 @@ const FmtError = error{ | ... | @@ -4226,6 +4227,7 @@ const FmtError = error{ |
| 4226 | NotOpenForWriting, | 4227 | NotOpenForWriting, |
| 4227 | UnsupportedEncoding, | 4228 | UnsupportedEncoding, |
| 4228 | ConnectionResetByPeer, | 4229 | ConnectionResetByPeer, |
| 4230 | LockViolation, | ||
| 4229 | } || fs.File.OpenError; | 4231 | } || fs.File.OpenError; |
| 4230 | 4232 | ||
| 4231 | fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { | 4233 | fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { |
| ... | @@ -4652,7 +4654,7 @@ pub const ClangArgIterator = struct { | ... | @@ -4652,7 +4654,7 @@ pub const ClangArgIterator = struct { |
| 4652 | lib_dir, | 4654 | lib_dir, |
| 4653 | mcpu, | 4655 | mcpu, |
| 4654 | dep_file, | 4656 | dep_file, |
| 4655 | dep_file_mm, | 4657 | dep_file_to_stdout, |
| 4656 | framework_dir, | 4658 | framework_dir, |
| 4657 | framework, | 4659 | framework, |
| 4658 | nostdlibinc, | 4660 | nostdlibinc, |
src/print_air.zig+1| ... | @@ -243,6 +243,7 @@ const Writer = struct { | ... | @@ -243,6 +243,7 @@ const Writer = struct { |
| 243 | .popcount, | 243 | .popcount, |
| 244 | .byte_swap, | 244 | .byte_swap, |
| 245 | .bit_reverse, | 245 | .bit_reverse, |
| 246 | .error_set_has_value, | ||
| 246 | => try w.writeTyOp(s, inst), | 247 | => try w.writeTyOp(s, inst), |
| 247 | 248 | ||
| 248 | .block, | 249 | .block, |
src/print_zir.zig+61-19| ... | @@ -214,7 +214,6 @@ const Writer = struct { | ... | @@ -214,7 +214,6 @@ const Writer = struct { |
| 214 | .trunc, | 214 | .trunc, |
| 215 | .round, | 215 | .round, |
| 216 | .tag_name, | 216 | .tag_name, |
| 217 | .reify, | ||
| 218 | .type_name, | 217 | .type_name, |
| 219 | .frame_type, | 218 | .frame_type, |
| 220 | .frame_size, | 219 | .frame_size, |
| ... | @@ -247,7 +246,6 @@ const Writer = struct { | ... | @@ -247,7 +246,6 @@ const Writer = struct { |
| 247 | 246 | ||
| 248 | .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst), | 247 | .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst), |
| 249 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), | 248 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), |
| 250 | .param_type => try self.writeParamType(stream, inst), | ||
| 251 | .ptr_type => try self.writePtrType(stream, inst), | 249 | .ptr_type => try self.writePtrType(stream, inst), |
| 252 | .int => try self.writeInt(stream, inst), | 250 | .int => try self.writeInt(stream, inst), |
| 253 | .int_big => try self.writeIntBig(stream, inst), | 251 | .int_big => try self.writeIntBig(stream, inst), |
| ... | @@ -500,6 +498,7 @@ const Writer = struct { | ... | @@ -500,6 +498,7 @@ const Writer = struct { |
| 500 | .wasm_memory_size, | 498 | .wasm_memory_size, |
| 501 | .error_to_int, | 499 | .error_to_int, |
| 502 | .int_to_error, | 500 | .int_to_error, |
| 501 | .reify, | ||
| 503 | => { | 502 | => { |
| 504 | const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 503 | const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 505 | const src = LazySrcLoc.nodeOffset(inst_data.node); | 504 | const src = LazySrcLoc.nodeOffset(inst_data.node); |
| ... | @@ -605,16 +604,6 @@ const Writer = struct { | ... | @@ -605,16 +604,6 @@ const Writer = struct { |
| 605 | try self.writeSrc(stream, inst_data.src()); | 604 | try self.writeSrc(stream, inst_data.src()); |
| 606 | } | 605 | } |
| 607 | 606 | ||
| 608 | fn writeParamType( | ||
| 609 | self: *Writer, | ||
| 610 | stream: anytype, | ||
| 611 | inst: Zir.Inst.Index, | ||
| 612 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 613 | const inst_data = self.code.instructions.items(.data)[inst].param_type; | ||
| 614 | try self.writeInstRef(stream, inst_data.callee); | ||
| 615 | try stream.print(", {d})", .{inst_data.param_index}); | ||
| 616 | } | ||
| 617 | |||
| 618 | fn writePtrType( | 607 | fn writePtrType( |
| 619 | self: *Writer, | 608 | self: *Writer, |
| 620 | stream: anytype, | 609 | stream: anytype, |
| ... | @@ -1158,7 +1147,8 @@ const Writer = struct { | ... | @@ -1158,7 +1147,8 @@ const Writer = struct { |
| 1158 | fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | 1147 | fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
| 1159 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | 1148 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1160 | const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index); | 1149 | const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index); |
| 1161 | const args = self.code.refSlice(extra.end, extra.data.flags.args_len); | 1150 | const args_len = extra.data.flags.args_len; |
| 1151 | const body = self.code.extra[extra.end..]; | ||
| 1162 | 1152 | ||
| 1163 | if (extra.data.flags.ensure_result_used) { | 1153 | if (extra.data.flags.ensure_result_used) { |
| 1164 | try stream.writeAll("nodiscard "); | 1154 | try stream.writeAll("nodiscard "); |
| ... | @@ -1166,10 +1156,27 @@ const Writer = struct { | ... | @@ -1166,10 +1156,27 @@ const Writer = struct { |
| 1166 | try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))}); | 1156 | try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))}); |
| 1167 | try self.writeInstRef(stream, extra.data.callee); | 1157 | try self.writeInstRef(stream, extra.data.callee); |
| 1168 | try stream.writeAll(", ["); | 1158 | try stream.writeAll(", ["); |
| 1169 | for (args) |arg, i| { | 1159 | |
| 1170 | if (i != 0) try stream.writeAll(", "); | 1160 | self.indent += 2; |
| 1171 | try self.writeInstRef(stream, arg); | 1161 | if (args_len != 0) { |
| 1162 | try stream.writeAll("\n"); | ||
| 1163 | } | ||
| 1164 | var i: usize = 0; | ||
| 1165 | var arg_start: u32 = args_len; | ||
| 1166 | while (i < args_len) : (i += 1) { | ||
| 1167 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1168 | const arg_end = self.code.extra[extra.end + i]; | ||
| 1169 | defer arg_start = arg_end; | ||
| 1170 | const arg_body = body[arg_start..arg_end]; | ||
| 1171 | try self.writeBracedBody(stream, arg_body); | ||
| 1172 | |||
| 1173 | try stream.writeAll(",\n"); | ||
| 1172 | } | 1174 | } |
| 1175 | self.indent -= 2; | ||
| 1176 | if (args_len != 0) { | ||
| 1177 | try stream.writeByteNTimes(' ', self.indent); | ||
| 1178 | } | ||
| 1179 | |||
| 1173 | try stream.writeAll("]) "); | 1180 | try stream.writeAll("]) "); |
| 1174 | try self.writeSrc(stream, inst_data.src()); | 1181 | try self.writeSrc(stream, inst_data.src()); |
| 1175 | } | 1182 | } |
| ... | @@ -1238,13 +1245,36 @@ const Writer = struct { | ... | @@ -1238,13 +1245,36 @@ const Writer = struct { |
| 1238 | 1245 | ||
| 1239 | try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv); | 1246 | try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv); |
| 1240 | try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only); | 1247 | try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only); |
| 1241 | try stream.print("{s}, {s}, ", .{ | 1248 | |
| 1242 | @tagName(small.name_strategy), @tagName(small.layout), | 1249 | try stream.print("{s}, ", .{@tagName(small.name_strategy)}); |
| 1243 | }); | 1250 | |
| 1251 | if (small.layout == .Packed and small.has_backing_int) { | ||
| 1252 | const backing_int_body_len = self.code.extra[extra_index]; | ||
| 1253 | extra_index += 1; | ||
| 1254 | try stream.writeAll("Packed("); | ||
| 1255 | if (backing_int_body_len == 0) { | ||
| 1256 | const backing_int_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); | ||
| 1257 | extra_index += 1; | ||
| 1258 | try self.writeInstRef(stream, backing_int_ref); | ||
| 1259 | } else { | ||
| 1260 | const body = self.code.extra[extra_index..][0..backing_int_body_len]; | ||
| 1261 | extra_index += backing_int_body_len; | ||
| 1262 | self.indent += 2; | ||
| 1263 | try self.writeBracedDecl(stream, body); | ||
| 1264 | self.indent -= 2; | ||
| 1265 | } | ||
| 1266 | try stream.writeAll("), "); | ||
| 1267 | } else { | ||
| 1268 | try stream.print("{s}, ", .{@tagName(small.layout)}); | ||
| 1269 | } | ||
| 1244 | 1270 | ||
| 1245 | if (decls_len == 0) { | 1271 | if (decls_len == 0) { |
| 1246 | try stream.writeAll("{}, "); | 1272 | try stream.writeAll("{}, "); |
| 1247 | } else { | 1273 | } else { |
| 1274 | const prev_parent_decl_node = self.parent_decl_node; | ||
| 1275 | if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); | ||
| 1276 | defer self.parent_decl_node = prev_parent_decl_node; | ||
| 1277 | |||
| 1248 | try stream.writeAll("{\n"); | 1278 | try stream.writeAll("{\n"); |
| 1249 | self.indent += 2; | 1279 | self.indent += 2; |
| 1250 | extra_index = try self.writeDecls(stream, decls_len, extra_index); | 1280 | extra_index = try self.writeDecls(stream, decls_len, extra_index); |
| ... | @@ -1415,6 +1445,10 @@ const Writer = struct { | ... | @@ -1415,6 +1445,10 @@ const Writer = struct { |
| 1415 | if (decls_len == 0) { | 1445 | if (decls_len == 0) { |
| 1416 | try stream.writeAll("{}, "); | 1446 | try stream.writeAll("{}, "); |
| 1417 | } else { | 1447 | } else { |
| 1448 | const prev_parent_decl_node = self.parent_decl_node; | ||
| 1449 | if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); | ||
| 1450 | defer self.parent_decl_node = prev_parent_decl_node; | ||
| 1451 | |||
| 1418 | try stream.writeAll("{\n"); | 1452 | try stream.writeAll("{\n"); |
| 1419 | self.indent += 2; | 1453 | self.indent += 2; |
| 1420 | extra_index = try self.writeDecls(stream, decls_len, extra_index); | 1454 | extra_index = try self.writeDecls(stream, decls_len, extra_index); |
| ... | @@ -1662,6 +1696,10 @@ const Writer = struct { | ... | @@ -1662,6 +1696,10 @@ const Writer = struct { |
| 1662 | if (decls_len == 0) { | 1696 | if (decls_len == 0) { |
| 1663 | try stream.writeAll("{}, "); | 1697 | try stream.writeAll("{}, "); |
| 1664 | } else { | 1698 | } else { |
| 1699 | const prev_parent_decl_node = self.parent_decl_node; | ||
| 1700 | if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); | ||
| 1701 | defer self.parent_decl_node = prev_parent_decl_node; | ||
| 1702 | |||
| 1665 | try stream.writeAll("{\n"); | 1703 | try stream.writeAll("{\n"); |
| 1666 | self.indent += 2; | 1704 | self.indent += 2; |
| 1667 | extra_index = try self.writeDecls(stream, decls_len, extra_index); | 1705 | extra_index = try self.writeDecls(stream, decls_len, extra_index); |
| ... | @@ -1755,6 +1793,10 @@ const Writer = struct { | ... | @@ -1755,6 +1793,10 @@ const Writer = struct { |
| 1755 | if (decls_len == 0) { | 1793 | if (decls_len == 0) { |
| 1756 | try stream.writeAll("{})"); | 1794 | try stream.writeAll("{})"); |
| 1757 | } else { | 1795 | } else { |
| 1796 | const prev_parent_decl_node = self.parent_decl_node; | ||
| 1797 | if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off); | ||
| 1798 | defer self.parent_decl_node = prev_parent_decl_node; | ||
| 1799 | |||
| 1758 | try stream.writeAll("{\n"); | 1800 | try stream.writeAll("{\n"); |
| 1759 | self.indent += 2; | 1801 | self.indent += 2; |
| 1760 | _ = try self.writeDecls(stream, decls_len, extra_index); | 1802 | _ = try self.writeDecls(stream, decls_len, extra_index); |
src/stage1/all_types.hpp+1| ... | @@ -1116,6 +1116,7 @@ struct AstNodeContainerDecl { | ... | @@ -1116,6 +1116,7 @@ struct AstNodeContainerDecl { |
| 1116 | ContainerLayout layout; | 1116 | ContainerLayout layout; |
| 1117 | 1117 | ||
| 1118 | bool auto_enum, is_root; // union(enum) | 1118 | bool auto_enum, is_root; // union(enum) |
| 1119 | bool unsupported_explicit_backing_int; | ||
| 1119 | }; | 1120 | }; |
| 1120 | 1121 | ||
| 1121 | struct AstNodeErrorSetField { | 1122 | struct AstNodeErrorSetField { |
src/stage1/analyze.cpp+6| ... | @@ -3034,6 +3034,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { | ... | @@ -3034,6 +3034,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 3034 | 3034 | ||
| 3035 | AstNode *decl_node = struct_type->data.structure.decl_node; | 3035 | AstNode *decl_node = struct_type->data.structure.decl_node; |
| 3036 | 3036 | ||
| 3037 | if (decl_node->data.container_decl.unsupported_explicit_backing_int) { | ||
| 3038 | add_node_error(g, decl_node, buf_create_from_str( | ||
| 3039 | "the stage1 compiler does not support explicit backing integer types on packed structs")); | ||
| 3040 | return ErrorSemanticAnalyzeFail; | ||
| 3041 | } | ||
| 3042 | |||
| 3037 | if (struct_type->data.structure.resolve_loop_flag_zero_bits) { | 3043 | if (struct_type->data.structure.resolve_loop_flag_zero_bits) { |
| 3038 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { | 3044 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { |
| 3039 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 3045 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
src/stage1/ir.cpp+28-12| ... | @@ -18640,7 +18640,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour | ... | @@ -18640,7 +18640,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour |
| 18640 | result->special = ConstValSpecialStatic; | 18640 | result->special = ConstValSpecialStatic; |
| 18641 | result->type = ir_type_info_get_type(ira, "Struct", nullptr); | 18641 | result->type = ir_type_info_get_type(ira, "Struct", nullptr); |
| 18642 | 18642 | ||
| 18643 | ZigValue **fields = alloc_const_vals_ptrs(g, 4); | 18643 | ZigValue **fields = alloc_const_vals_ptrs(g, 5); |
| 18644 | result->data.x_struct.fields = fields; | 18644 | result->data.x_struct.fields = fields; |
| 18645 | 18645 | ||
| 18646 | // layout: ContainerLayout | 18646 | // layout: ContainerLayout |
| ... | @@ -18648,8 +18648,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour | ... | @@ -18648,8 +18648,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour |
| 18648 | fields[0]->special = ConstValSpecialStatic; | 18648 | fields[0]->special = ConstValSpecialStatic; |
| 18649 | fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); | 18649 | fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); |
| 18650 | bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.structure.layout); | 18650 | bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.structure.layout); |
| 18651 | |||
| 18652 | // backing_integer: ?type | ||
| 18653 | ensure_field_index(result->type, "backing_integer", 1); | ||
| 18654 | fields[1]->special = ConstValSpecialStatic; | ||
| 18655 | fields[1]->type = get_optional_type(g, g->builtin_types.entry_type); | ||
| 18656 | // This is always null in stage1, as stage1 does not support explicit backing integers | ||
| 18657 | // for packed structs. | ||
| 18658 | fields[1]->data.x_optional = nullptr; | ||
| 18659 | |||
| 18651 | // fields: []Type.StructField | 18660 | // fields: []Type.StructField |
| 18652 | ensure_field_index(result->type, "fields", 1); | 18661 | ensure_field_index(result->type, "fields", 2); |
| 18653 | 18662 | ||
| 18654 | ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr); | 18663 | ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr); |
| 18655 | if ((err = type_resolve(g, type_info_struct_field_type, ResolveStatusSizeKnown))) { | 18664 | if ((err = type_resolve(g, type_info_struct_field_type, ResolveStatusSizeKnown))) { |
| ... | @@ -18663,7 +18672,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour | ... | @@ -18663,7 +18672,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour |
| 18663 | struct_field_array->data.x_array.special = ConstArraySpecialNone; | 18672 | struct_field_array->data.x_array.special = ConstArraySpecialNone; |
| 18664 | struct_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(struct_field_count); | 18673 | struct_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(struct_field_count); |
| 18665 | 18674 | ||
| 18666 | init_const_slice(g, fields[1], struct_field_array, 0, struct_field_count, false, nullptr); | 18675 | init_const_slice(g, fields[2], struct_field_array, 0, struct_field_count, false, nullptr); |
| 18667 | 18676 | ||
| 18668 | for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) { | 18677 | for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) { |
| 18669 | TypeStructField *struct_field = type_entry->data.structure.fields[struct_field_index]; | 18678 | TypeStructField *struct_field = type_entry->data.structure.fields[struct_field_index]; |
| ... | @@ -18710,18 +18719,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour | ... | @@ -18710,18 +18719,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour |
| 18710 | struct_field_val->parent.data.p_array.elem_index = struct_field_index; | 18719 | struct_field_val->parent.data.p_array.elem_index = struct_field_index; |
| 18711 | } | 18720 | } |
| 18712 | // decls: []Type.Declaration | 18721 | // decls: []Type.Declaration |
| 18713 | ensure_field_index(result->type, "decls", 2); | 18722 | ensure_field_index(result->type, "decls", 3); |
| 18714 | if ((err = ir_make_type_info_decls(ira, source_node, fields[2], | 18723 | if ((err = ir_make_type_info_decls(ira, source_node, fields[3], |
| 18715 | type_entry->data.structure.decls_scope, false))) | 18724 | type_entry->data.structure.decls_scope, false))) |
| 18716 | { | 18725 | { |
| 18717 | return err; | 18726 | return err; |
| 18718 | } | 18727 | } |
| 18719 | 18728 | ||
| 18720 | // is_tuple: bool | 18729 | // is_tuple: bool |
| 18721 | ensure_field_index(result->type, "is_tuple", 3); | 18730 | ensure_field_index(result->type, "is_tuple", 4); |
| 18722 | fields[3]->special = ConstValSpecialStatic; | 18731 | fields[4]->special = ConstValSpecialStatic; |
| 18723 | fields[3]->type = g->builtin_types.entry_bool; | 18732 | fields[4]->type = g->builtin_types.entry_bool; |
| 18724 | fields[3]->data.x_bool = is_tuple(type_entry); | 18733 | fields[4]->data.x_bool = is_tuple(type_entry); |
| 18725 | 18734 | ||
| 18726 | break; | 18735 | break; |
| 18727 | } | 18736 | } |
| ... | @@ -19313,7 +19322,14 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ | ... | @@ -19313,7 +19322,14 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 19313 | assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); | 19322 | assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); |
| 19314 | ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); | 19323 | ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); |
| 19315 | 19324 | ||
| 19316 | ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 1); | 19325 | ZigType *tag_type = get_const_field_meta_type_optional(ira, source_node, payload, "backing_integer", 1); |
| 19326 | if (tag_type != nullptr) { | ||
| 19327 | ir_add_error_node(ira, source_node, buf_create_from_str( | ||
| 19328 | "the stage1 compiler does not support explicit backing integer types on packed structs")); | ||
| 19329 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 19330 | } | ||
| 19331 | |||
| 19332 | ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2); | ||
| 19317 | if (fields_value == nullptr) | 19333 | if (fields_value == nullptr) |
| 19318 | return ira->codegen->invalid_inst_gen->value->type; | 19334 | return ira->codegen->invalid_inst_gen->value->type; |
| 19319 | assert(fields_value->special == ConstValSpecialStatic); | 19335 | assert(fields_value->special == ConstValSpecialStatic); |
| ... | @@ -19322,7 +19338,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ | ... | @@ -19322,7 +19338,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 19322 | ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; | 19338 | ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; |
| 19323 | size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); | 19339 | size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); |
| 19324 | 19340 | ||
| 19325 | ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 2); | 19341 | ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3); |
| 19326 | if (decls_value == nullptr) | 19342 | if (decls_value == nullptr) |
| 19327 | return ira->codegen->invalid_inst_gen->value->type; | 19343 | return ira->codegen->invalid_inst_gen->value->type; |
| 19328 | assert(decls_value->special == ConstValSpecialStatic); | 19344 | assert(decls_value->special == ConstValSpecialStatic); |
| ... | @@ -19335,7 +19351,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ | ... | @@ -19335,7 +19351,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 19335 | } | 19351 | } |
| 19336 | 19352 | ||
| 19337 | bool is_tuple; | 19353 | bool is_tuple; |
| 19338 | if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 3, &is_tuple))) | 19354 | if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 4, &is_tuple))) |
| 19339 | return ira->codegen->invalid_inst_gen->value->type; | 19355 | return ira->codegen->invalid_inst_gen->value->type; |
| 19340 | 19356 | ||
| 19341 | ZigType *entry = new_type_table_entry(ZigTypeIdStruct); | 19357 | ZigType *entry = new_type_table_entry(ZigTypeIdStruct); |
src/stage1/parser.cpp+10-1| ... | @@ -2902,16 +2902,25 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { | ... | @@ -2902,16 +2902,25 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { |
| 2902 | } | 2902 | } |
| 2903 | 2903 | ||
| 2904 | // ContainerDeclType | 2904 | // ContainerDeclType |
| 2905 | // <- KEYWORD_struct | 2905 | // <- KEYWORD_struct (LPAREN Expr RPAREN)? |
| 2906 | // / KEYWORD_enum (LPAREN Expr RPAREN)? | 2906 | // / KEYWORD_enum (LPAREN Expr RPAREN)? |
| 2907 | // / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? | 2907 | // / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? |
| 2908 | // / KEYWORD_opaque | 2908 | // / KEYWORD_opaque |
| 2909 | static AstNode *ast_parse_container_decl_type(ParseContext *pc) { | 2909 | static AstNode *ast_parse_container_decl_type(ParseContext *pc) { |
| 2910 | TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct); | 2910 | TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct); |
| 2911 | if (first != 0) { | 2911 | if (first != 0) { |
| 2912 | bool explicit_backing_int = false; | ||
| 2913 | if (eat_token_if(pc, TokenIdLParen) != 0) { | ||
| 2914 | explicit_backing_int = true; | ||
| 2915 | ast_expect(pc, ast_parse_expr); | ||
| 2916 | expect_token(pc, TokenIdRParen); | ||
| 2917 | } | ||
| 2912 | AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); | 2918 | AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); |
| 2913 | res->data.container_decl.init_arg_expr = nullptr; | 2919 | res->data.container_decl.init_arg_expr = nullptr; |
| 2914 | res->data.container_decl.kind = ContainerKindStruct; | 2920 | res->data.container_decl.kind = ContainerKindStruct; |
| 2921 | // We want this to be an error in semantic analysis not parsing to make sharing | ||
| 2922 | // the test suite between stage1 and self hosted easier. | ||
| 2923 | res->data.container_decl.unsupported_explicit_backing_int = explicit_backing_int; | ||
| 2915 | return res; | 2924 | return res; |
| 2916 | } | 2925 | } |
| 2917 | 2926 |
src/test.zig+8-40| ... | @@ -1224,10 +1224,6 @@ pub const TestContext = struct { | ... | @@ -1224,10 +1224,6 @@ pub const TestContext = struct { |
| 1224 | try aux_thread_pool.init(self.gpa); | 1224 | try aux_thread_pool.init(self.gpa); |
| 1225 | defer aux_thread_pool.deinit(); | 1225 | defer aux_thread_pool.deinit(); |
| 1226 | 1226 | ||
| 1227 | var case_thread_pool: ThreadPool = undefined; | ||
| 1228 | try case_thread_pool.init(self.gpa); | ||
| 1229 | defer case_thread_pool.deinit(); | ||
| 1230 | |||
| 1231 | // Use the same global cache dir for all the tests, such that we for example don't have to | 1227 | // Use the same global cache dir for all the tests, such that we for example don't have to |
| 1232 | // rebuild musl libc for every case (when LLVM backend is enabled). | 1228 | // rebuild musl libc for every case (when LLVM backend is enabled). |
| 1233 | var global_tmp = std.testing.tmpDir(.{}); | 1229 | var global_tmp = std.testing.tmpDir(.{}); |
| ... | @@ -1245,9 +1241,6 @@ pub const TestContext = struct { | ... | @@ -1245,9 +1241,6 @@ pub const TestContext = struct { |
| 1245 | defer self.gpa.free(global_cache_directory.path.?); | 1241 | defer self.gpa.free(global_cache_directory.path.?); |
| 1246 | 1242 | ||
| 1247 | { | 1243 | { |
| 1248 | var wait_group: WaitGroup = .{}; | ||
| 1249 | defer wait_group.wait(); | ||
| 1250 | |||
| 1251 | for (self.cases.items) |*case| { | 1244 | for (self.cases.items) |*case| { |
| 1252 | if (build_options.skip_non_native) { | 1245 | if (build_options.skip_non_native) { |
| 1253 | if (case.target.getCpuArch() != builtin.cpu.arch) | 1246 | if (case.target.getCpuArch() != builtin.cpu.arch) |
| ... | @@ -1267,17 +1260,19 @@ pub const TestContext = struct { | ... | @@ -1267,17 +1260,19 @@ pub const TestContext = struct { |
| 1267 | if (std.mem.indexOf(u8, case.name, test_filter) == null) continue; | 1260 | if (std.mem.indexOf(u8, case.name, test_filter) == null) continue; |
| 1268 | } | 1261 | } |
| 1269 | 1262 | ||
| 1270 | wait_group.start(); | 1263 | var prg_node = root_node.start(case.name, case.updates.items.len); |
| 1271 | try case_thread_pool.spawn(workerRunOneCase, .{ | 1264 | prg_node.activate(); |
| 1265 | defer prg_node.end(); | ||
| 1266 | |||
| 1267 | case.result = runOneCase( | ||
| 1272 | self.gpa, | 1268 | self.gpa, |
| 1273 | root_node, | 1269 | &prg_node, |
| 1274 | case, | 1270 | case.*, |
| 1275 | zig_lib_directory, | 1271 | zig_lib_directory, |
| 1276 | &aux_thread_pool, | 1272 | &aux_thread_pool, |
| 1277 | global_cache_directory, | 1273 | global_cache_directory, |
| 1278 | host, | 1274 | host, |
| 1279 | &wait_group, | 1275 | ); |
| 1280 | }); | ||
| 1281 | } | 1276 | } |
| 1282 | } | 1277 | } |
| 1283 | 1278 | ||
| ... | @@ -1295,33 +1290,6 @@ pub const TestContext = struct { | ... | @@ -1295,33 +1290,6 @@ pub const TestContext = struct { |
| 1295 | } | 1290 | } |
| 1296 | } | 1291 | } |
| 1297 | 1292 | ||
| 1298 | fn workerRunOneCase( | ||
| 1299 | gpa: Allocator, | ||
| 1300 | root_node: *std.Progress.Node, | ||
| 1301 | case: *Case, | ||
| 1302 | zig_lib_directory: Compilation.Directory, | ||
| 1303 | thread_pool: *ThreadPool, | ||
| 1304 | global_cache_directory: Compilation.Directory, | ||
| 1305 | host: std.zig.system.NativeTargetInfo, | ||
| 1306 | wait_group: *WaitGroup, | ||
| 1307 | ) void { | ||
| 1308 | defer wait_group.finish(); | ||
| 1309 | |||
| 1310 | var prg_node = root_node.start(case.name, case.updates.items.len); | ||
| 1311 | prg_node.activate(); | ||
| 1312 | defer prg_node.end(); | ||
| 1313 | |||
| 1314 | case.result = runOneCase( | ||
| 1315 | gpa, | ||
| 1316 | &prg_node, | ||
| 1317 | case.*, | ||
| 1318 | zig_lib_directory, | ||
| 1319 | thread_pool, | ||
| 1320 | global_cache_directory, | ||
| 1321 | host, | ||
| 1322 | ); | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | fn runOneCase( | 1293 | fn runOneCase( |
| 1326 | allocator: Allocator, | 1294 | allocator: Allocator, |
| 1327 | root_node: *std.Progress.Node, | 1295 | root_node: *std.Progress.Node, |
src/type.zig+17-52| ... | @@ -3000,9 +3000,17 @@ pub const Type = extern union { | ... | @@ -3000,9 +3000,17 @@ pub const Type = extern union { |
| 3000 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | 3000 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 3001 | }; | 3001 | }; |
| 3002 | if (struct_obj.layout == .Packed) { | 3002 | if (struct_obj.layout == .Packed) { |
| 3003 | var buf: Type.Payload.Bits = undefined; | 3003 | switch (strat) { |
| 3004 | const int_ty = struct_obj.packedIntegerType(target, &buf); | 3004 | .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty), |
| 3005 | return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) }; | 3005 | .lazy => |arena| { |
| 3006 | if (!struct_obj.haveLayout()) { | ||
| 3007 | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; | ||
| 3008 | } | ||
| 3009 | }, | ||
| 3010 | .eager => {}, | ||
| 3011 | } | ||
| 3012 | assert(struct_obj.haveLayout()); | ||
| 3013 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(target) }; | ||
| 3006 | } | 3014 | } |
| 3007 | 3015 | ||
| 3008 | const fields = ty.structFields(); | 3016 | const fields = ty.structFields(); |
| ... | @@ -3192,17 +3200,16 @@ pub const Type = extern union { | ... | @@ -3192,17 +3200,16 @@ pub const Type = extern union { |
| 3192 | .Packed => { | 3200 | .Packed => { |
| 3193 | const struct_obj = ty.castTag(.@"struct").?.data; | 3201 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3194 | switch (strat) { | 3202 | switch (strat) { |
| 3195 | .sema_kit => |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty), | 3203 | .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty), |
| 3196 | .lazy => |arena| { | 3204 | .lazy => |arena| { |
| 3197 | if (!struct_obj.haveFieldTypes()) { | 3205 | if (!struct_obj.haveLayout()) { |
| 3198 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | 3206 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; |
| 3199 | } | 3207 | } |
| 3200 | }, | 3208 | }, |
| 3201 | .eager => {}, | 3209 | .eager => {}, |
| 3202 | } | 3210 | } |
| 3203 | var buf: Type.Payload.Bits = undefined; | 3211 | assert(struct_obj.haveLayout()); |
| 3204 | const int_ty = struct_obj.packedIntegerType(target, &buf); | 3212 | return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(target) }; |
| 3205 | return AbiSizeAdvanced{ .scalar = int_ty.abiSize(target) }; | ||
| 3206 | }, | 3213 | }, |
| 3207 | else => { | 3214 | else => { |
| 3208 | switch (strat) { | 3215 | switch (strat) { |
| ... | @@ -5771,50 +5778,6 @@ pub const Type = extern union { | ... | @@ -5771,50 +5778,6 @@ pub const Type = extern union { |
| 5771 | } | 5778 | } |
| 5772 | } | 5779 | } |
| 5773 | 5780 | ||
| 5774 | pub fn getNodeOffset(ty: Type) i32 { | ||
| 5775 | switch (ty.tag()) { | ||
| 5776 | .enum_full, .enum_nonexhaustive => { | ||
| 5777 | const enum_full = ty.cast(Payload.EnumFull).?.data; | ||
| 5778 | return enum_full.node_offset; | ||
| 5779 | }, | ||
| 5780 | .enum_numbered => return ty.castTag(.enum_numbered).?.data.node_offset, | ||
| 5781 | .enum_simple => { | ||
| 5782 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 5783 | return enum_simple.node_offset; | ||
| 5784 | }, | ||
| 5785 | .@"struct" => { | ||
| 5786 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 5787 | return struct_obj.node_offset; | ||
| 5788 | }, | ||
| 5789 | .error_set => { | ||
| 5790 | const error_set = ty.castTag(.error_set).?.data; | ||
| 5791 | return error_set.node_offset; | ||
| 5792 | }, | ||
| 5793 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 5794 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 5795 | return union_obj.node_offset; | ||
| 5796 | }, | ||
| 5797 | .@"opaque" => { | ||
| 5798 | const opaque_obj = ty.cast(Payload.Opaque).?.data; | ||
| 5799 | return opaque_obj.node_offset; | ||
| 5800 | }, | ||
| 5801 | .atomic_order, | ||
| 5802 | .atomic_rmw_op, | ||
| 5803 | .calling_convention, | ||
| 5804 | .address_space, | ||
| 5805 | .float_mode, | ||
| 5806 | .reduce_op, | ||
| 5807 | .call_options, | ||
| 5808 | .prefetch_options, | ||
| 5809 | .export_options, | ||
| 5810 | .extern_options, | ||
| 5811 | .type_info, | ||
| 5812 | => unreachable, // These need to be resolved earlier. | ||
| 5813 | |||
| 5814 | else => unreachable, | ||
| 5815 | } | ||
| 5816 | } | ||
| 5817 | |||
| 5818 | /// This enum does not directly correspond to `std.builtin.TypeId` because | 5781 | /// This enum does not directly correspond to `std.builtin.TypeId` because |
| 5819 | /// it has extra enum tags in it, as a way of using less memory. For example, | 5782 | /// it has extra enum tags in it, as a way of using less memory. For example, |
| 5820 | /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types | 5783 | /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types |
| ... | @@ -6340,6 +6303,8 @@ pub const Type = extern union { | ... | @@ -6340,6 +6303,8 @@ pub const Type = extern union { |
| 6340 | pub const @"anyopaque" = initTag(.anyopaque); | 6303 | pub const @"anyopaque" = initTag(.anyopaque); |
| 6341 | pub const @"null" = initTag(.@"null"); | 6304 | pub const @"null" = initTag(.@"null"); |
| 6342 | 6305 | ||
| 6306 | pub const err_int = Type.u16; | ||
| 6307 | |||
| 6343 | pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type { | 6308 | pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type { |
| 6344 | const target = mod.getTarget(); | 6309 | const target = mod.getTarget(); |
| 6345 | 6310 |
src/value.zig+10-38| ... | @@ -1194,6 +1194,16 @@ pub const Value = extern union { | ... | @@ -1194,6 +1194,16 @@ pub const Value = extern union { |
| 1194 | return switch (self.tag()) { | 1194 | return switch (self.tag()) { |
| 1195 | .bool_true, .one => true, | 1195 | .bool_true, .one => true, |
| 1196 | .bool_false, .zero => false, | 1196 | .bool_false, .zero => false, |
| 1197 | .int_u64 => switch (self.castTag(.int_u64).?.data) { | ||
| 1198 | 0 => false, | ||
| 1199 | 1 => true, | ||
| 1200 | else => unreachable, | ||
| 1201 | }, | ||
| 1202 | .int_i64 => switch (self.castTag(.int_i64).?.data) { | ||
| 1203 | 0 => false, | ||
| 1204 | 1 => true, | ||
| 1205 | else => unreachable, | ||
| 1206 | }, | ||
| 1197 | else => unreachable, | 1207 | else => unreachable, |
| 1198 | }; | 1208 | }; |
| 1199 | } | 1209 | } |
| ... | @@ -3472,44 +3482,6 @@ pub const Value = extern union { | ... | @@ -3472,44 +3482,6 @@ pub const Value = extern union { |
| 3472 | return fromBigInt(allocator, result_q.toConst()); | 3482 | return fromBigInt(allocator, result_q.toConst()); |
| 3473 | } | 3483 | } |
| 3474 | 3484 | ||
| 3475 | pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { | ||
| 3476 | if (ty.zigTypeTag() == .Vector) { | ||
| 3477 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | ||
| 3478 | for (result_data) |*scalar, i| { | ||
| 3479 | scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); | ||
| 3480 | } | ||
| 3481 | return Value.Tag.aggregate.create(allocator, result_data); | ||
| 3482 | } | ||
| 3483 | return intRemScalar(lhs, rhs, allocator, target); | ||
| 3484 | } | ||
| 3485 | |||
| 3486 | pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { | ||
| 3487 | // TODO is this a performance issue? maybe we should try the operation without | ||
| 3488 | // resorting to BigInt first. | ||
| 3489 | var lhs_space: Value.BigIntSpace = undefined; | ||
| 3490 | var rhs_space: Value.BigIntSpace = undefined; | ||
| 3491 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | ||
| 3492 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | ||
| 3493 | const limbs_q = try allocator.alloc( | ||
| 3494 | std.math.big.Limb, | ||
| 3495 | lhs_bigint.limbs.len, | ||
| 3496 | ); | ||
| 3497 | const limbs_r = try allocator.alloc( | ||
| 3498 | std.math.big.Limb, | ||
| 3499 | // TODO: consider reworking Sema to re-use Values rather than | ||
| 3500 | // always producing new Value objects. | ||
| 3501 | rhs_bigint.limbs.len, | ||
| 3502 | ); | ||
| 3503 | const limbs_buffer = try allocator.alloc( | ||
| 3504 | std.math.big.Limb, | ||
| 3505 | std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len), | ||
| 3506 | ); | ||
| 3507 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | ||
| 3508 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | ||
| 3509 | result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); | ||
| 3510 | return fromBigInt(allocator, result_r.toConst()); | ||
| 3511 | } | ||
| 3512 | |||
| 3513 | pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { | 3485 | pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { |
| 3514 | if (ty.zigTypeTag() == .Vector) { | 3486 | if (ty.zigTypeTag() == .Vector) { |
| 3515 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 3487 | const result_data = try allocator.alloc(Value, ty.vectorLen()); |
test/behavior.zig+2| ... | @@ -84,6 +84,7 @@ test { | ... | @@ -84,6 +84,7 @@ test { |
| 84 | _ = @import("behavior/bugs/11213.zig"); | 84 | _ = @import("behavior/bugs/11213.zig"); |
| 85 | _ = @import("behavior/bugs/12003.zig"); | 85 | _ = @import("behavior/bugs/12003.zig"); |
| 86 | _ = @import("behavior/bugs/12033.zig"); | 86 | _ = @import("behavior/bugs/12033.zig"); |
| 87 | _ = @import("behavior/bugs/12430.zig"); | ||
| 87 | _ = @import("behavior/byteswap.zig"); | 88 | _ = @import("behavior/byteswap.zig"); |
| 88 | _ = @import("behavior/byval_arg_var.zig"); | 89 | _ = @import("behavior/byval_arg_var.zig"); |
| 89 | _ = @import("behavior/call.zig"); | 90 | _ = @import("behavior/call.zig"); |
| ... | @@ -165,6 +166,7 @@ test { | ... | @@ -165,6 +166,7 @@ test { |
| 165 | 166 | ||
| 166 | if (builtin.zig_backend != .stage1) { | 167 | if (builtin.zig_backend != .stage1) { |
| 167 | _ = @import("behavior/decltest.zig"); | 168 | _ = @import("behavior/decltest.zig"); |
| 169 | _ = @import("behavior/packed_struct_explicit_backing_int.zig"); | ||
| 168 | } | 170 | } |
| 169 | 171 | ||
| 170 | if (builtin.os.tag != .wasi) { | 172 | if (builtin.os.tag != .wasi) { |
test/behavior/bugs/12430.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test { | ||
| 4 | const T = comptime b: { | ||
| 5 | break :b @Type(.{ .Int = .{ | ||
| 6 | .signedness = .unsigned, | ||
| 7 | .bits = 8, | ||
| 8 | } }); | ||
| 9 | }; | ||
| 10 | try std.testing.expect(T == u8); | ||
| 11 | } | ||
test/behavior/call.zig+15| ... | @@ -246,3 +246,18 @@ test "function call with 40 arguments" { | ... | @@ -246,3 +246,18 @@ test "function call with 40 arguments" { |
| 246 | }; | 246 | }; |
| 247 | try S.doTheTest(39); | 247 | try S.doTheTest(39); |
| 248 | } | 248 | } |
| 249 | |||
| 250 | test "arguments to comptime parameters generated in comptime blocks" { | ||
| 251 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 252 | |||
| 253 | const S = struct { | ||
| 254 | fn fortyTwo() i32 { | ||
| 255 | return 42; | ||
| 256 | } | ||
| 257 | |||
| 258 | fn foo(comptime x: i32) void { | ||
| 259 | if (x != 42) @compileError("bad"); | ||
| 260 | } | ||
| 261 | }; | ||
| 262 | S.foo(S.fortyTwo()); | ||
| 263 | } |
test/behavior/cast.zig+5| ... | @@ -1431,6 +1431,11 @@ test "coerce between pointers of compatible differently-named floats" { | ... | @@ -1431,6 +1431,11 @@ test "coerce between pointers of compatible differently-named floats" { |
| 1431 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1431 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1432 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1432 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1433 | 1433 | ||
| 1434 | if (builtin.os.tag == .windows) { | ||
| 1435 | // https://github.com/ziglang/zig/issues/12396 | ||
| 1436 | return error.SkipZigTest; | ||
| 1437 | } | ||
| 1438 | |||
| 1434 | const F = switch (@typeInfo(c_longdouble).Float.bits) { | 1439 | const F = switch (@typeInfo(c_longdouble).Float.bits) { |
| 1435 | 16 => f16, | 1440 | 16 => f16, |
| 1436 | 32 => f32, | 1441 | 32 => f32, |
test/behavior/eval.zig+17| ... | @@ -1293,3 +1293,20 @@ test "mutate through pointer-like optional at comptime" { | ... | @@ -1293,3 +1293,20 @@ test "mutate through pointer-like optional at comptime" { |
| 1293 | try expect(payload_ptr.*.* == 16); | 1293 | try expect(payload_ptr.*.* == 16); |
| 1294 | } | 1294 | } |
| 1295 | } | 1295 | } |
| 1296 | |||
| 1297 | test "repeated value is correctly expanded" { | ||
| 1298 | const S = struct { x: [4]i8 = std.mem.zeroes([4]i8) }; | ||
| 1299 | const M = struct { x: [4]S = std.mem.zeroes([4]S) }; | ||
| 1300 | |||
| 1301 | comptime { | ||
| 1302 | var res = M{}; | ||
| 1303 | for (.{ 1, 2, 3 }) |i| res.x[i].x[i] = i; | ||
| 1304 | |||
| 1305 | try expectEqual(M{ .x = .{ | ||
| 1306 | .{ .x = .{ 0, 0, 0, 0 } }, | ||
| 1307 | .{ .x = .{ 0, 1, 0, 0 } }, | ||
| 1308 | .{ .x = .{ 0, 0, 2, 0 } }, | ||
| 1309 | .{ .x = .{ 0, 0, 0, 3 } }, | ||
| 1310 | } }, res); | ||
| 1311 | } | ||
| 1312 | } |
test/behavior/math.zig+15| ... | @@ -1721,3 +1721,18 @@ fn testAbsFloat() !void { | ... | @@ -1721,3 +1721,18 @@ fn testAbsFloat() !void { |
| 1721 | fn testAbsFloatOne(in: f32, out: f32) !void { | 1721 | fn testAbsFloatOne(in: f32, out: f32) !void { |
| 1722 | try expect(@fabs(@as(f32, in)) == @as(f32, out)); | 1722 | try expect(@fabs(@as(f32, in)) == @as(f32, out)); |
| 1723 | } | 1723 | } |
| 1724 | |||
| 1725 | test "mod lazy values" { | ||
| 1726 | { | ||
| 1727 | const X = struct { x: u32 }; | ||
| 1728 | const x = @sizeOf(X); | ||
| 1729 | const y = 1 % x; | ||
| 1730 | _ = y; | ||
| 1731 | } | ||
| 1732 | { | ||
| 1733 | const X = struct { x: u32 }; | ||
| 1734 | const x = @sizeOf(X); | ||
| 1735 | const y = x % 1; | ||
| 1736 | _ = y; | ||
| 1737 | } | ||
| 1738 | } |
test/behavior/packed_struct_explicit_backing_int.zig created+53| ... | @@ -0,0 +1,53 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | const native_endian = builtin.cpu.arch.endian(); | ||
| 6 | |||
| 7 | test "packed struct explicit backing integer" { | ||
| 8 | assert(builtin.zig_backend != .stage1); | ||
| 9 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 10 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 11 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 12 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 13 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 14 | |||
| 15 | const S1 = packed struct { a: u8, b: u8, c: u8 }; | ||
| 16 | |||
| 17 | const S2 = packed struct(i24) { d: u8, e: u8, f: u8 }; | ||
| 18 | |||
| 19 | const S3 = packed struct { x: S1, y: S2 }; | ||
| 20 | const S3Padded = packed struct(u64) { s3: S3, pad: u16 }; | ||
| 21 | |||
| 22 | try expectEqual(48, @bitSizeOf(S3)); | ||
| 23 | try expectEqual(@sizeOf(u48), @sizeOf(S3)); | ||
| 24 | |||
| 25 | try expectEqual(3, @offsetOf(S3, "y")); | ||
| 26 | try expectEqual(24, @bitOffsetOf(S3, "y")); | ||
| 27 | |||
| 28 | if (native_endian == .Little) { | ||
| 29 | const s3 = @bitCast(S3Padded, @as(u64, 0xe952d5c71ff4)).s3; | ||
| 30 | try expectEqual(@as(u8, 0xf4), s3.x.a); | ||
| 31 | try expectEqual(@as(u8, 0x1f), s3.x.b); | ||
| 32 | try expectEqual(@as(u8, 0xc7), s3.x.c); | ||
| 33 | try expectEqual(@as(u8, 0xd5), s3.y.d); | ||
| 34 | try expectEqual(@as(u8, 0x52), s3.y.e); | ||
| 35 | try expectEqual(@as(u8, 0xe9), s3.y.f); | ||
| 36 | } | ||
| 37 | |||
| 38 | const S4 = packed struct { a: i32, b: i8 }; | ||
| 39 | const S5 = packed struct(u80) { a: i32, b: i8, c: S4 }; | ||
| 40 | const S6 = packed struct(i80) { a: i32, b: S4, c: i8 }; | ||
| 41 | |||
| 42 | const expectedBitSize = 80; | ||
| 43 | const expectedByteSize = @sizeOf(u80); | ||
| 44 | try expectEqual(expectedBitSize, @bitSizeOf(S5)); | ||
| 45 | try expectEqual(expectedByteSize, @sizeOf(S5)); | ||
| 46 | try expectEqual(expectedBitSize, @bitSizeOf(S6)); | ||
| 47 | try expectEqual(expectedByteSize, @sizeOf(S6)); | ||
| 48 | |||
| 49 | try expectEqual(5, @offsetOf(S5, "c")); | ||
| 50 | try expectEqual(40, @bitOffsetOf(S5, "c")); | ||
| 51 | try expectEqual(9, @offsetOf(S6, "c")); | ||
| 52 | try expectEqual(72, @bitOffsetOf(S6, "c")); | ||
| 53 | } | ||
test/behavior/type.zig+5| ... | @@ -513,6 +513,11 @@ test "Type.Fn" { | ... | @@ -513,6 +513,11 @@ test "Type.Fn" { |
| 513 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | 513 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 514 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 514 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 515 | 515 | ||
| 516 | if (true) { | ||
| 517 | // https://github.com/ziglang/zig/issues/12360 | ||
| 518 | return error.SkipZigTest; | ||
| 519 | } | ||
| 520 | |||
| 516 | const some_opaque = opaque {}; | 521 | const some_opaque = opaque {}; |
| 517 | const some_ptr = *some_opaque; | 522 | const some_ptr = *some_opaque; |
| 518 | const T = fn (c_int, some_ptr) callconv(.C) void; | 523 | const T = fn (c_int, some_ptr) callconv(.C) void; |
test/behavior/type_info.zig+3-1| ... | @@ -293,6 +293,7 @@ test "type info: struct info" { | ... | @@ -293,6 +293,7 @@ test "type info: struct info" { |
| 293 | fn testStruct() !void { | 293 | fn testStruct() !void { |
| 294 | const unpacked_struct_info = @typeInfo(TestStruct); | 294 | const unpacked_struct_info = @typeInfo(TestStruct); |
| 295 | try expect(unpacked_struct_info.Struct.is_tuple == false); | 295 | try expect(unpacked_struct_info.Struct.is_tuple == false); |
| 296 | try expect(unpacked_struct_info.Struct.backing_integer == null); | ||
| 296 | try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32)); | 297 | try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32)); |
| 297 | try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4); | 298 | try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4); |
| 298 | try expect(mem.eql(u8, "foobar", @ptrCast(*const *const [6:0]u8, unpacked_struct_info.Struct.fields[1].default_value.?).*)); | 299 | try expect(mem.eql(u8, "foobar", @ptrCast(*const *const [6:0]u8, unpacked_struct_info.Struct.fields[1].default_value.?).*)); |
| ... | @@ -315,6 +316,7 @@ fn testPackedStruct() !void { | ... | @@ -315,6 +316,7 @@ fn testPackedStruct() !void { |
| 315 | try expect(struct_info == .Struct); | 316 | try expect(struct_info == .Struct); |
| 316 | try expect(struct_info.Struct.is_tuple == false); | 317 | try expect(struct_info.Struct.is_tuple == false); |
| 317 | try expect(struct_info.Struct.layout == .Packed); | 318 | try expect(struct_info.Struct.layout == .Packed); |
| 319 | try expect(struct_info.Struct.backing_integer == u128); | ||
| 318 | try expect(struct_info.Struct.fields.len == 4); | 320 | try expect(struct_info.Struct.fields.len == 4); |
| 319 | try expect(struct_info.Struct.fields[0].alignment == 0); | 321 | try expect(struct_info.Struct.fields[0].alignment == 0); |
| 320 | try expect(struct_info.Struct.fields[2].field_type == f32); | 322 | try expect(struct_info.Struct.fields[2].field_type == f32); |
| ... | @@ -326,7 +328,7 @@ fn testPackedStruct() !void { | ... | @@ -326,7 +328,7 @@ fn testPackedStruct() !void { |
| 326 | } | 328 | } |
| 327 | 329 | ||
| 328 | const TestPackedStruct = packed struct { | 330 | const TestPackedStruct = packed struct { |
| 329 | fieldA: usize, | 331 | fieldA: u64, |
| 330 | fieldB: void, | 332 | fieldB: void, |
| 331 | fieldC: f32, | 333 | fieldC: f32, |
| 332 | fieldD: u32 = 4, | 334 | fieldD: u32 = 4, |
test/behavior/vector.zig+17| ... | @@ -807,6 +807,23 @@ test "vector reduce operation" { | ... | @@ -807,6 +807,23 @@ test "vector reduce operation" { |
| 807 | comptime try S.doTheTest(); | 807 | comptime try S.doTheTest(); |
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | test "vector @reduce comptime" { | ||
| 811 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 812 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 813 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 814 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 815 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 816 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 817 | |||
| 818 | const value = @Vector(4, i32){ 1, -1, 1, -1 }; | ||
| 819 | const result = value > @splat(4, @as(i32, 0)); | ||
| 820 | // result is { true, false, true, false }; | ||
| 821 | comptime try expect(@TypeOf(result) == @Vector(4, bool)); | ||
| 822 | const is_all_true = @reduce(.And, result); | ||
| 823 | comptime try expect(@TypeOf(is_all_true) == bool); | ||
| 824 | try expect(is_all_true == false); | ||
| 825 | } | ||
| 826 | |||
| 810 | test "mask parameter of @shuffle is comptime scope" { | 827 | test "mask parameter of @shuffle is comptime scope" { |
| 811 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 828 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 812 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 829 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
test/cases/compile_errors/calling_function_with_naked_calling_convention.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | foo(); | ||
| 3 | } | ||
| 4 | fn foo() callconv(.Naked) void { } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=llvm | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // :2:5: error: unable to call function with naked calling convention | ||
| 11 | // :4:1: note: function declared here | ||
test/cases/compile_errors/compile_time_null_ptr_cast.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | comptime { | ||
| 2 | var opt_ptr: ?*i32 = null; | ||
| 3 | const ptr = @ptrCast(*i32, opt_ptr); | ||
| 4 | _ = ptr; | ||
| 5 | } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // backend=llvm | ||
| 9 | // target=native | ||
| 10 | // | ||
| 11 | // :3:32: error: null pointer casted to type *i32 | ||
test/cases/compile_errors/compile_time_undef_ptr_cast.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | comptime { | ||
| 2 | var undef_ptr: *i32 = undefined; | ||
| 3 | const ptr = @ptrCast(*i32, undef_ptr); | ||
| 4 | _ = ptr; | ||
| 5 | } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // backend=llvm | ||
| 9 | // target=native | ||
| 10 | // | ||
| 11 | // :3:32: error: use of undefined value here causes undefined behavior | ||
test/cases/compile_errors/exact division failure.zig	 created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | comptime { | ||
| 2 | const x = @divExact(10, 3); | ||
| 3 | _ = x; | ||
| 4 | } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=llvm | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // :2:15: error: exact division produced remainder | ||
test/cases/compile_errors/float exact division failure.zig	 created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | comptime { | ||
| 2 | const x = @divExact(10.0, 3.0); | ||
| 3 | _ = x; | ||
| 4 | } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=llvm | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // :2:15: error: exact division produced remainder | ||
test/cases/compile_errors/int_literal_passed_as_variadic_arg.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | extern fn printf([*:0]const u8, ...) c_int; | ||
| 2 | |||
| 3 | pub export fn entry() void { | ||
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | ||
| 5 | } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // backend=stage2 | ||
| 9 | // target=native | ||
| 10 | // | ||
| 11 | // :4:33: error: integer and float literals in var args function must be casted | ||
test/cases/compile_errors/member_function_arg_mismatch.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const S = struct { | ||
| 2 | a: u32, | ||
| 3 | fn foo(_: *S, _: u32, _: bool) void {} | ||
| 4 | }; | ||
| 5 | pub export fn entry() void { | ||
| 6 | var s: S = undefined; | ||
| 7 | s.foo(true); | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :7:6: error: member function expected 2 argument(s), found 1 | ||
| 15 | // :3:5: note: function declared here | ||
test/cases/compile_errors/non_constant_expression_in_array_size.zig+1-1| ... | @@ -11,4 +11,4 @@ export fn entry() usize { return @offsetOf(Foo, "y"); } | ... | @@ -11,4 +11,4 @@ export fn entry() usize { return @offsetOf(Foo, "y"); } |
| 11 | // target=native | 11 | // target=native |
| 12 | // | 12 | // |
| 13 | // :5:25: error: cannot load runtime value in comptime block | 13 | // :5:25: error: cannot load runtime value in comptime block |
| 14 | // :2:15: note: called from here | 14 | // :2:12: note: called from here |
test/cases/compile_errors/not_an_enum_type.zig+1-1| ... | @@ -17,4 +17,4 @@ const ExpectedVarDeclOrFn = struct {}; | ... | @@ -17,4 +17,4 @@ const ExpectedVarDeclOrFn = struct {}; |
| 17 | // target=native | 17 | // target=native |
| 18 | // | 18 | // |
| 19 | // :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type' | 19 | // :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type' |
| 20 | // :8:1: note: enum declared here | 20 | // :8:15: note: enum declared here |
test/cases/compile_errors/packed_struct_backing_int_wrong.zig created+55| ... | @@ -0,0 +1,55 @@ | ||
| 1 | export fn entry1() void { | ||
| 2 | _ = @sizeOf(packed struct(u32) { | ||
| 3 | x: u1, | ||
| 4 | y: u24, | ||
| 5 | z: u4, | ||
| 6 | }); | ||
| 7 | } | ||
| 8 | export fn entry2() void { | ||
| 9 | _ = @sizeOf(packed struct(i31) { | ||
| 10 | x: u4, | ||
| 11 | y: u24, | ||
| 12 | z: u4, | ||
| 13 | }); | ||
| 14 | } | ||
| 15 | |||
| 16 | export fn entry3() void { | ||
| 17 | _ = @sizeOf(packed struct(void) { | ||
| 18 | x: void, | ||
| 19 | }); | ||
| 20 | } | ||
| 21 | |||
| 22 | export fn entry4() void { | ||
| 23 | _ = @sizeOf(packed struct(void) {}); | ||
| 24 | } | ||
| 25 | |||
| 26 | export fn entry5() void { | ||
| 27 | _ = @sizeOf(packed struct(noreturn) {}); | ||
| 28 | } | ||
| 29 | |||
| 30 | export fn entry6() void { | ||
| 31 | _ = @sizeOf(packed struct(f64) { | ||
| 32 | x: u32, | ||
| 33 | y: f32, | ||
| 34 | }); | ||
| 35 | } | ||
| 36 | |||
| 37 | export fn entry7() void { | ||
| 38 | _ = @sizeOf(packed struct(*u32) { | ||
| 39 | x: u4, | ||
| 40 | y: u24, | ||
| 41 | z: u4, | ||
| 42 | }); | ||
| 43 | } | ||
| 44 | |||
| 45 | // error | ||
| 46 | // backend=llvm | ||
| 47 | // target=native | ||
| 48 | // | ||
| 49 | // :2:31: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 29 | ||
| 50 | // :9:31: error: backing integer type 'i31' has bit size 31 but the struct fields have a total bit size of 32 | ||
| 51 | // :17:31: error: expected backing integer type, found 'void' | ||
| 52 | // :23:31: error: expected backing integer type, found 'void' | ||
| 53 | // :27:31: error: expected backing integer type, found 'noreturn' | ||
| 54 | // :31:31: error: expected backing integer type, found 'f64' | ||
| 55 | // :38:31: error: expected backing integer type, found '*u32' | ||
test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | const Tag = @Type(.{ | ||
| 2 | .Enum = .{ | ||
| 3 | .layout = .Auto, | ||
| 4 | .tag_type = u1, | ||
| 5 | .fields = &.{ | ||
| 6 | .{ .name = "signed", .value = 0 }, | ||
| 7 | .{ .name = "unsigned", .value = 1 }, | ||
| 8 | }, | ||
| 9 | .decls = &.{}, | ||
| 10 | .is_exhaustive = true, | ||
| 11 | }, | ||
| 12 | }); | ||
| 13 | const Tagged = @Type(.{ | ||
| 14 | .Union = .{ | ||
| 15 | .layout = .Auto, | ||
| 16 | .tag_type = Tag, | ||
| 17 | .fields = &.{ | ||
| 18 | .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) }, | ||
| 19 | .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) }, | ||
| 20 | .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) }, | ||
| 21 | }, | ||
| 22 | .decls = &.{}, | ||
| 23 | }, | ||
| 24 | }); | ||
| 25 | export fn entry() void { | ||
| 26 | var tagged = Tagged{ .signed = -1 }; | ||
| 27 | tagged = .{ .unsigned = 1 }; | ||
| 28 | } | ||
| 29 | |||
| 30 | // error | ||
| 31 | // backend=stage2 | ||
| 32 | // target=native | ||
| 33 | // | ||
| 34 | // :13:16: error: no field named 'arst' in enum 'tmp.Tag' | ||
| 35 | // :1:13: note: enum declared here | ||
test/cases/compile_errors/shlExact_shifts_out_1_bits.zig created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | comptime { | ||
| 2 | const x = @shlExact(@as(u8, 0b01010101), 2); | ||
| 3 | _ = x; | ||
| 4 | } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=llvm | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // :2:15: error: operation caused overflow | ||
test/cases/compile_errors/shrExact_shifts_out_1_bits.zig created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | comptime { | ||
| 2 | const x = @shrExact(@as(u8, 0b10101010), 2); | ||
| 3 | _ = x; | ||
| 4 | } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=llvm | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // :2:15: error: exact shift shifted out 1 bits | ||
test/cases/compile_errors/signed_integer_division.zig created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | export fn foo(a: i32, b: i32) i32 { | ||
| 2 | return a / b; | ||
| 3 | } | ||
| 4 | |||
| 5 | // error | ||
| 6 | // backend=stage2 | ||
| 7 | // target=native | ||
| 8 | // | ||
| 9 | // :2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact | ||
test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | foo(); | ||
| 3 | } | ||
| 4 | fn foo() callconv(.Naked) void { } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=stage1 | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // tmp.zig:2:5: error: unable to call function with naked calling convention | ||
| 11 | // tmp.zig:4:1: note: declared here | ||
test/cases/compile_errors/stage1/obj/shlExact_shifts_out_1_bits.zig deleted-10| ... | @@ -1,10 +0,0 @@ | ||
| 1 | comptime { | ||
| 2 | const x = @shlExact(@as(u8, 0b01010101), 2); | ||
| 3 | _ = x; | ||
| 4 | } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=stage1 | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // tmp.zig:2:15: error: operation caused overflow | ||
test/cases/compile_errors/stage1/obj/shrExact_shifts_out_1_bits.zig deleted-10| ... | @@ -1,10 +0,0 @@ | ||
| 1 | comptime { | ||
| 2 | const x = @shrExact(@as(u8, 0b10101010), 2); | ||
| 3 | _ = x; | ||
| 4 | } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=stage1 | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // tmp.zig:2:15: error: exact shift shifted out 1 bits | ||
test/cases/compile_errors/stage1/obj/signed_integer_division.zig deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | export fn foo(a: i32, b: i32) i32 { | ||
| 2 | return a / b; | ||
| 3 | } | ||
| 4 | |||
| 5 | // error | ||
| 6 | // backend=stage1 | ||
| 7 | // target=native | ||
| 8 | // | ||
| 9 | // tmp.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact | ||
test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | const Foo = struct { | ||
| 2 | fn method(self: *const Foo, a: i32) void {_ = self; _ = a;} | ||
| 3 | }; | ||
| 4 | fn f(foo: *const Foo) void { | ||
| 5 | |||
| 6 | foo.method(1, 2); | ||
| 7 | } | ||
| 8 | export fn entry() usize { return @sizeOf(@TypeOf(f)); } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage1 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // tmp.zig:6:15: error: expected 2 argument(s), found 3 | ||
test/cases/compile_errors/tagName_on_invalid_value_of_non-exhaustive_enum.zig+1-1| ... | @@ -9,4 +9,4 @@ test "enum" { | ... | @@ -9,4 +9,4 @@ test "enum" { |
| 9 | // is_test=1 | 9 | // is_test=1 |
| 10 | // | 10 | // |
| 11 | // :3:9: error: no field with value '5' in enum 'test.enum.E' | 11 | // :3:9: error: no field with value '5' in enum 'test.enum.E' |
| 12 | // :1:1: note: declared here | 12 | // :2:15: note: declared here |
test/cases/compile_errors/wrong_number_of_arguments.zig+2-1| ... | @@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; } | ... | @@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; } |
| 7 | // backend=stage2 | 7 | // backend=stage2 |
| 8 | // target=native | 8 | // target=native |
| 9 | // | 9 | // |
| 10 | // :2:6: error: expected 3 argument(s), found 1 | 10 | // :2:5: error: expected 3 argument(s), found 1 |
| 11 | // :4:1: note: function declared here |
test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const Foo = struct { | ||
| 2 | fn method(self: *const Foo, a: i32) void {_ = self; _ = a;} | ||
| 3 | }; | ||
| 4 | fn f(foo: *const Foo) void { | ||
| 5 | |||
| 6 | foo.method(1, 2); | ||
| 7 | } | ||
| 8 | export fn entry() usize { return @sizeOf(@TypeOf(&f)); } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :6:8: error: member function expected 1 argument(s), found 2 | ||
| 15 | // :2:5: note: function declared here | ||
test/cases/error_in_nested_declaration.zig created+31| ... | @@ -0,0 +1,31 @@ | ||
| 1 | const S = struct { | ||
| 2 | b: u32, | ||
| 3 | c: i32, | ||
| 4 | a: struct { | ||
| 5 | pub fn str(_: @This(), extra: []u32) []i32 { | ||
| 6 | return @bitCast([]i32, extra); | ||
| 7 | } | ||
| 8 | }, | ||
| 9 | }; | ||
| 10 | |||
| 11 | pub export fn entry() void { | ||
| 12 | var s: S = undefined; | ||
| 13 | _ = s.a.str(undefined); | ||
| 14 | } | ||
| 15 | |||
| 16 | const S2 = struct { | ||
| 17 | a: [*c]anyopaque, | ||
| 18 | }; | ||
| 19 | |||
| 20 | pub export fn entry2() void { | ||
| 21 | var s: S2 = undefined; | ||
| 22 | _ = s; | ||
| 23 | } | ||
| 24 | |||
| 25 | // error | ||
| 26 | // backend=llvm | ||
| 27 | // target=native | ||
| 28 | // | ||
| 29 | // :17:12: error: C pointers cannot point to opaque types | ||
| 30 | // :6:29: error: cannot @bitCast to '[]i32' | ||
| 31 | // :6:29: note: use @ptrCast to cast from '[]u32' | ||
test/cases/safety/zero casted to error.zig	 created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { | ||
| 4 | _ = stack_trace; | ||
| 5 | if (std.mem.eql(u8, message, "invalid error code")) { | ||
| 6 | std.process.exit(0); | ||
| 7 | } | ||
| 8 | std.process.exit(1); | ||
| 9 | } | ||
| 10 | pub fn main() !void { | ||
| 11 | bar(0) catch {}; | ||
| 12 | return error.TestFailed; | ||
| 13 | } | ||
| 14 | fn bar(x: u16) anyerror { | ||
| 15 | return @intToError(x); | ||
| 16 | } | ||
| 17 | // run | ||
| 18 | // backend=llvm | ||
| 19 | // target=native | ||
test/link.zig+5| ... | @@ -3,6 +3,11 @@ const builtin = @import("builtin"); | ... | @@ -3,6 +3,11 @@ const builtin = @import("builtin"); |
| 3 | const tests = @import("tests.zig"); | 3 | const tests = @import("tests.zig"); |
| 4 | 4 | ||
| 5 | pub fn addCases(cases: *tests.StandaloneContext) void { | 5 | pub fn addCases(cases: *tests.StandaloneContext) void { |
| 6 | if (builtin.os.tag == .windows) { | ||
| 7 | // https://github.com/ziglang/zig/issues/12421 | ||
| 8 | return; | ||
| 9 | } | ||
| 10 | |||
| 6 | cases.addBuildFile("test/link/bss/build.zig", .{ | 11 | cases.addBuildFile("test/link/bss/build.zig", .{ |
| 7 | .build_modes = false, // we only guarantee zerofill for undefined in Debug | 12 | .build_modes = false, // we only guarantee zerofill for undefined in Debug |
| 8 | }); | 13 | }); |
test/stack_traces.zig+6| ... | @@ -3,6 +3,11 @@ const os = std.os; | ... | @@ -3,6 +3,11 @@ const os = std.os; |
| 3 | const tests = @import("tests.zig"); | 3 | const tests = @import("tests.zig"); |
| 4 | 4 | ||
| 5 | pub fn addCases(cases: *tests.StackTracesContext) void { | 5 | pub fn addCases(cases: *tests.StackTracesContext) void { |
| 6 | if (@import("builtin").os.tag == .windows) { | ||
| 7 | // https://github.com/ziglang/zig/issues/12422 | ||
| 8 | return; | ||
| 9 | } | ||
| 10 | |||
| 6 | cases.addCase(.{ | 11 | cases.addCase(.{ |
| 7 | .name = "return", | 12 | .name = "return", |
| 8 | .source = | 13 | .source = |
| ... | @@ -22,6 +27,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { | ... | @@ -22,6 +27,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { |
| 22 | .ReleaseSafe = .{ | 27 | .ReleaseSafe = .{ |
| 23 | .exclude_os = .{ | 28 | .exclude_os = .{ |
| 24 | .windows, // segfault | 29 | .windows, // segfault |
| 30 | .linux, // defeated by aggressive inlining | ||
| 25 | }, | 31 | }, |
| 26 | .expect = | 32 | .expect = |
| 27 | \\error: TheSkyIsFalling | 33 | \\error: TheSkyIsFalling |
test/standalone.zig+5-2| ... | @@ -34,13 +34,16 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -34,13 +34,16 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 34 | if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12194 | 34 | if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12194 |
| 35 | cases.addBuildFile("test/standalone/issue_9812/build.zig", .{}); | 35 | cases.addBuildFile("test/standalone/issue_9812/build.zig", .{}); |
| 36 | } | 36 | } |
| 37 | cases.addBuildFile("test/standalone/issue_11595/build.zig", .{}); | 37 | if (builtin.os.tag != .windows) { |
| 38 | // https://github.com/ziglang/zig/issues/12419 | ||
| 39 | cases.addBuildFile("test/standalone/issue_11595/build.zig", .{}); | ||
| 40 | } | ||
| 38 | if (builtin.os.tag != .wasi) { | 41 | if (builtin.os.tag != .wasi) { |
| 39 | cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{}); | 42 | cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{}); |
| 40 | } | 43 | } |
| 41 | // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481 | 44 | // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481 |
| 42 | if (builtin.cpu.arch == .x86_64) { | 45 | if (builtin.cpu.arch == .x86_64) { |
| 43 | if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12222 | 46 | if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) { // https://github.com/ziglang/zig/issues/12222 |
| 44 | cases.addBuildFile("test/c_abi/build.zig", .{}); | 47 | cases.addBuildFile("test/c_abi/build.zig", .{}); |
| 45 | } | 48 | } |
| 46 | } | 49 | } |
test/tests.zig+7| ... | @@ -641,6 +641,13 @@ pub fn addPkgTests( | ... | @@ -641,6 +641,13 @@ pub fn addPkgTests( |
| 641 | } else false; | 641 | } else false; |
| 642 | if (!want_this_mode) continue; | 642 | if (!want_this_mode) continue; |
| 643 | 643 | ||
| 644 | if (test_target.backend) |backend| { | ||
| 645 | if (backend == .stage2_c and builtin.os.tag == .windows) { | ||
| 646 | // https://github.com/ziglang/zig/issues/12415 | ||
| 647 | continue; | ||
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 644 | const libc_prefix = if (test_target.target.getOs().requiresLibC()) | 651 | const libc_prefix = if (test_target.target.getOs().requiresLibC()) |
| 645 | "" | 652 | "" |
| 646 | else if (test_target.link_libc) | 653 | else if (test_target.link_libc) |
tools/update_clang_options.zig+13-9| ... | @@ -386,11 +386,15 @@ const known_options = [_]KnownOpt{ | ... | @@ -386,11 +386,15 @@ const known_options = [_]KnownOpt{ |
| 386 | }, | 386 | }, |
| 387 | .{ | 387 | .{ |
| 388 | .name = "MM", | 388 | .name = "MM", |
| 389 | .ident = "dep_file_mm", | 389 | .ident = "dep_file_to_stdout", |
| 390 | }, | ||
| 391 | .{ | ||
| 392 | .name = "M", | ||
| 393 | .ident = "dep_file_to_stdout", | ||
| 390 | }, | 394 | }, |
| 391 | .{ | 395 | .{ |
| 392 | .name = "user-dependencies", | 396 | .name = "user-dependencies", |
| 393 | .ident = "dep_file_mm", | 397 | .ident = "dep_file_to_stdout", |
| 394 | }, | 398 | }, |
| 395 | .{ | 399 | .{ |
| 396 | .name = "MMD", | 400 | .name = "MMD", |
| ... | @@ -497,7 +501,7 @@ const cpu_targets = struct { | ... | @@ -497,7 +501,7 @@ const cpu_targets = struct { |
| 497 | pub const riscv = std.Target.riscv; | 501 | pub const riscv = std.Target.riscv; |
| 498 | pub const sparc = std.Target.sparc; | 502 | pub const sparc = std.Target.sparc; |
| 499 | pub const spirv = std.Target.spirv; | 503 | pub const spirv = std.Target.spirv; |
| 500 | pub const systemz = std.Target.systemz; | 504 | pub const s390x = std.Target.s390x; |
| 501 | pub const ve = std.Target.ve; | 505 | pub const ve = std.Target.ve; |
| 502 | pub const wasm = std.Target.wasm; | 506 | pub const wasm = std.Target.wasm; |
| 503 | pub const x86 = std.Target.x86; | 507 | pub const x86 = std.Target.x86; |
| ... | @@ -647,9 +651,9 @@ pub fn main() anyerror!void { | ... | @@ -647,9 +651,9 @@ pub fn main() anyerror!void { |
| 647 | \\ .name = "{s}", | 651 | \\ .name = "{s}", |
| 648 | \\ .syntax = {s}, | 652 | \\ .syntax = {s}, |
| 649 | \\ .zig_equivalent = .{s}, | 653 | \\ .zig_equivalent = .{s}, |
| 650 | \\ .pd1 = {s}, | 654 | \\ .pd1 = {}, |
| 651 | \\ .pd2 = {s}, | 655 | \\ .pd2 = {}, |
| 652 | \\ .psl = {s}, | 656 | \\ .psl = {}, |
| 653 | \\}}, | 657 | \\}}, |
| 654 | \\ | 658 | \\ |
| 655 | , .{ name, final_syntax, ident, pd1, pd2, pslash }); | 659 | , .{ name, final_syntax, ident, pd1, pd2, pslash }); |
| ... | @@ -677,9 +681,9 @@ pub fn main() anyerror!void { | ... | @@ -677,9 +681,9 @@ pub fn main() anyerror!void { |
| 677 | \\ .name = "{s}", | 681 | \\ .name = "{s}", |
| 678 | \\ .syntax = {s}, | 682 | \\ .syntax = {s}, |
| 679 | \\ .zig_equivalent = .other, | 683 | \\ .zig_equivalent = .other, |
| 680 | \\ .pd1 = {s}, | 684 | \\ .pd1 = {}, |
| 681 | \\ .pd2 = {s}, | 685 | \\ .pd2 = {}, |
| 682 | \\ .psl = {s}, | 686 | \\ .psl = {}, |
| 683 | \\}}, | 687 | \\}}, |
| 684 | \\ | 688 | \\ |
| 685 | , .{ name, syntax, pd1, pd2, pslash }); | 689 | , .{ name, syntax, pd1, pd2, pslash }); |