authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-08-16 16:52:26+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-16 16:52:26+02:00
log7f7d58ee895d0e29850ed1823ba91e672edc03a6
tree7bd7515a24e5eafa8c4a95332908e6e5e41ffa47
parent5929da37a117dfe67983155b39d4ee39e11f7ebc
parentb3922289be1ffaf194b55face332892280981356
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge branch 'master' into autodoc-links


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)"
4343
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 953 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
7280
73 cd -81 cd -
7482
...@@ -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"
8593
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 is101 # 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>&1103 #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1
104 #CheckLastExitCode
89105
90 & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1106 & "$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>&1108 & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1
109 CheckLastExitCode
92 name: test110 name: test
93 displayName: 'Test'111 displayName: 'Test'
94112
95 - pwsh: |113 - pwsh: |
96 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"114 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"
97115
116 function CheckLastExitCode {
117 if (!$?) {
118 exit 1
119 }
120 return 0
121 }
122
98 & "$ZIGINSTALLDIR\bin\zig.exe" build docs123 & "$ZIGINSTALLDIR\bin\zig.exe" build docs
124 CheckLastExitCode
99 timeoutInMinutes: 60125 timeoutInMinutes: 60
100 name: doc126 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"
103103
104# Upload new stdlib autodocs 104# Upload new stdlib autodocs
105mkdir -p docs_to_upload/documentation/master/std/105mkdir -p docs_to_upload/documentation/master/std/
106cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html106
107cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js107gzip -c -9 "$ZIGDIR/docs/std/index.html" > docs_to_upload/documentation/master/std/index.html
108cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js108gzip -c -9 "$ZIGDIR/docs/std/data.js" > docs_to_upload/documentation/master/std/data.js
109cp "$LANGREF" docs_to_upload/documentation/master/index.html109gzip -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/110gzip -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/
111119
112git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git120git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git
113cd www.ziglang.org121cd 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");
4444 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");
5556
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 }
126127
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();
165166
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 }
31563164
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 }
32833304
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);
33953416
3396 matchedItemsHTML += "<li><a href=\""+ href +"\">"+ text + "</a></li>";3417 matchedItemsHTML += "<li><a href=\"" + href + "\">" + text + "</a></li>";
3397 }3418 }
33983419
3399 // Replace the search results using our newly constructed HTML string3420 // 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();
34053426
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 }
223223
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 }
594618
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);
901948
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);
904959
...@@ -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);
943998
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);
9461009
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());
276276
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));
281281
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}
869871
870pub noinline fn returnError(maybe_st: ?*StackTrace) void {872pub 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}
876877
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;
814pub const empty_sigset: sigset_t = 0;814pub const empty_sigset: sigset_t = 0;
815815
816pub const SIG = struct {816pub 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);
821821
822 /// block specified signal set822 /// 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 {
609pub const BADSIG = SIG.ERR;609pub const BADSIG = SIG.ERR;
610610
611pub const SIG = struct {611pub 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));
615615
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;
672672
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));
676676
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 {
910const NSIG = 32;910const NSIG = 32;
911911
912pub const SIG = struct {912pub 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));
916916
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 {
982const NSIG = 33;982const NSIG = 33;
983983
984pub const SIG = struct {984pub 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);
990990
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 {
879const NSIG = 75;879const NSIG = 75;
880880
881pub const SIG = struct {881pub 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);
886886
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);
356356
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}
361363
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 },
3232
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 },
4143
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)
5355
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.
55pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {57pub 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}
6962
...@@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool {...@@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool {
193pub fn autoHash(hasher: anytype, key: anytype) void {186pub 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 }
199192
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}
361354
355test "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
362test "testHash struct" {361test "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 {
475475
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,
955954
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;
19471947
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;
19911991
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;
20342034
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};
20392039
2040pub const kernel_rwf = u32;2040pub 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_DFL786 // 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}
790790
791test "dup & dup2" {791test "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};
522525
...@@ -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 comma2967 /// 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 trailing2972 /// 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 }
33573357
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 /// ContainerDeclType3361 /// ContainerDeclType
3360 /// <- KEYWORD_struct3362 /// <- 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}
15091513
1514test "tokenizer - newline in char literal" {
1515 try testTokenize(
1516 \\'
1517 \\'
1518 , &.{ .invalid, .invalid });
1519}
1520
1521test "tokenizer - newline in string literal" {
1522 try testTokenize(
1523 \\"
1524 \\"
1525 , &.{ .invalid, .string_literal });
1526}
1527
1510test "tokenizer - code point literal with unicode escapes" {1528test "tokenizer - code point literal with unicode escapes" {
1511 // Valid unicode escapes1529 // 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,
675675
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 which682 /// 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,
10661071
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;
30733072
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();
42174230
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();
42574272
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);
42604304
...@@ -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();
44474495
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;
45734621
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);
48134859
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);
48154874
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();
48184877
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(
50385097
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", .{});
50405099
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);
50715141
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
65736643
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", .{});
65756645
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;
65776657
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();
66436728
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);
66466732
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);
66556742
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: on7655 // zig fmt: on
75707656
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);
81548265
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) {
81638301 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 }
81768303 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 location8310 return rvalue(gz, rl, call_inst, node); // TODO function call with result location
8179}8311}
81808312
...@@ -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;
1116711301
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);
1117011304
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
11812fn 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(
20792078
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 want2088 // TODO: consider toggling need_type to true if we ever want
2085 // to show discrepancies between the types of provided2089 // to show discrepancies between the types of provided
2086 // arguments and the types declared in the function2090 // 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 }
20912095
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;
25342538
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) = .{};
25372552
...@@ -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 }
10431043
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 };
10461050
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 generic84/// 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 dispatch85/// 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.
88monomorphed_funcs: MonomorphedFuncsSet = .{},87monomorphed_funcs: MonomorphedFuncsSet = .{},
89/// The set of all comptime function calls that have been cached so that future calls88/// 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 here91/// Contains the values from `@setAlignStack`. A sparse table is used here
93/// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while92/// 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.
96align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{},94align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{},
9795
98/// We optimize memory usage for a compilation with no compile errors by storing the96/// 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 {
853pub const ErrorSet = struct {853pub 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 }
872870
...@@ -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,
900896
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 }
959960
...@@ -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 {
10291030
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};
10551044
...@@ -1060,8 +1049,6 @@ pub const Struct = struct {...@@ -1060,8 +1049,6 @@ pub const Struct = struct {
1060pub const EnumSimple = struct {1049pub 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,
10671054
...@@ -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 {
1083pub const EnumNumbered = struct {1070pub 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 {
1113pub const EnumFull = struct {1098pub 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,
11621143
...@@ -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 }
12091190
...@@ -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 {
1410pub const Opaque = struct {1391pub 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,
14171396
...@@ -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 }
14261405
...@@ -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 here4094 // 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 below4323 .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 below4325 .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) = .{},
78err: ?*Module.ErrorMsg = null,78err: ?*Module.ErrorMsg = null,
7979
80const std = @import("std");80const std = @import("std");
81const math = std.math;
81const mem = std.mem;82const mem = std.mem;
82const Allocator = std.mem.Allocator;83const Allocator = std.mem.Allocator;
83const assert = std.debug.assert;84const 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: on954 // 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
18181818
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 };
18231823
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}
18721872
...@@ -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 }
19071907
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;
22412241
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}
22442254
...@@ -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(
2294fn createAnonymousDeclTypeNamed(2303fn 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);
23082319
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(
27632772
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(
28272835
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}
44464453
4447fn 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
4484fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4454fn 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}
54525422
5423fn 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
5453fn zirCall(5436fn 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;
54665449
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;
54695452
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;
54725456
5473 const func_type = sema.typeOf(func);5457 const func_type = sema.typeOf(func);
54745458
...@@ -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 }
54935554
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 here5646 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 }
59736052
...@@ -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;
67286807
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 },
67426821
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,
67456824
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 }
67506829
...@@ -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 }
67616840
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}
67656844
6766fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {6845fn 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();
67766855
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(
1020110283
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 },
1021510295
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 }
1118511265
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 remainder11351 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 remainder11360 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))) and11853 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}
1182011911
11912fn 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
11931fn 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
11821fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11966fn 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
1416214307
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());
1416414309
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);
1449414653
14654 return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
14655}
14656
14657fn 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);
1450514678
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 } } });
1451014683
...@@ -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}
1488015059
15060fn 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
15118fn 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
14881fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {15127fn 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);
1488315129
...@@ -14923,27 +15169,15 @@ fn analyzeRet(...@@ -14923,27 +15169,15 @@ fn analyzeRet(
14923 return always_noreturn;15169 return always_noreturn;
14924 }15170 }
1492515171
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;
1492915173
14930 if (sema.fn_ret_ty.isError() and15174 if (sema.wantErrorReturnTracing()) {
14931 sema.mod.comp.bin_file.options.error_return_tracing and15175 // 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 }
1494515180
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}
1602516259
16026fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {16260fn 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))).?);
1611316348
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);
1628316523
16284 // Decls16524 // 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 }
1628816528
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 else16535 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);
1644216685
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 }
1687617118
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 }
1709617373
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 else17403 else
17134 operand;17404 operand;
1713517405
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 }
2385024135
23851 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);24136 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
2385224137
...@@ -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}
2542525710
25711fn 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
25426fn analyzeIsNonErrComptimeOnly(25732fn 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);
2543725743
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 }
2544425756
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}
2551725829
25830fn 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
25518fn analyzeSlice(25845fn 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;
2691727249
26918 // In case of querying the ABI alignment of this struct, we will ask27250 // 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 anything27264 // otherwise it's a tuple; no need to resolve anything
26933}27265}
2693427266
27267fn 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
27354fn 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
26935fn resolveUnionLayout(27370fn 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;
2724127676
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);
2724427679
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;
2725627691
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;
2726127707
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);
2736427813
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);
2742627875
...@@ -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);
2743827887
...@@ -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);
2745127900
...@@ -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;
2750427953
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);
2750727956
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);
2773228181
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);
2776328212
...@@ -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);
2777528224
...@@ -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);
2778828237
...@@ -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),
2824428691
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 value494 /// 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,
15751561
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,
19831971
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 };
27962779
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 unusedResultExpr2785 // 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_node3085 /// 0. src_node: i32, // if has_src_node
3101 /// 1. fields_len: u32, // if has_fields_len3086 /// 1. fields_len: u32, // if has_fields_len
3102 /// 2. decls_len: u32, // if has_decls_len3087 /// 2. decls_len: u32, // if has_decls_len
3103 /// 3. decl_bits: u32 // for every 8 decls3088 /// 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 pub3093 /// 0b000X: whether corresponding decl is pub
3106 /// 0b00X0: whether corresponding decl is exported3094 /// 0b00X0: whether corresponding decl is exported
3107 /// 0b0X00: whether corresponding decl has an align expression3095 /// 0b0X00: whether corresponding decl has an align expression
3108 /// 0bX000: whether corresponding decl has a linksection or an address space expression3096 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3109 /// 4. decl: { // for every decls_len3097 /// 7. decl: { // for every decls_len
3110 /// src_hash: [4]u32, // hash of source bytes3098 /// src_hash: [4]u32, // hash of source bytes
3111 /// line: u32, // line number of decl, relative to parent3099 /// line: u32, // line number of decl, relative to parent
3112 /// name: u32, // null terminated string index3100 /// 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 fields3115 /// 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 expression3117 /// 0b000X: whether corresponding field has an align expression
3130 /// 0b00X0: whether corresponding field has a default expression3118 /// 0b00X0: whether corresponding field has a default expression
3131 /// 0b0X00: whether corresponding field is comptime3119 /// 0b0X00: whether corresponding field is comptime
3132 /// 0bX000: whether corresponding field has a type expression3120 /// 0bX000: whether corresponding field has a type expression
3133 /// 6. fields: { // for every fields_len3121 /// 9. fields: { // for every fields_len
3134 /// field_name: u32,3122 /// field_name: u32,
3135 /// doc_comment: u32, // 0 if no doc comment3123 /// 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 set3126 /// align_body_len: u32, // if corresponding bit is set
3139 /// init_body_len: u32, // if corresponding bit is set3127 /// init_body_len: u32, // if corresponding bit is set
3140 /// }3128 /// }
3141 /// 7. bodies: { // for every fields_len3129 /// 10. bodies: { // for every fields_len
3142 /// field_type_body_inst: Inst, // for each field_type_body_len3130 /// field_type_body_inst: Inst, // for each field_type_body_len
3143 /// align_body_inst: Inst, // for each align_body_len3131 /// align_body_inst: Inst, // for each align_body_len
3144 /// init_body_inst: Inst, // for each init_body_len3132 /// 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 };
31583147
...@@ -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;
36213610
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", .{}),
779779
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", .{}),
781782
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 };
333358
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 }
337362
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();
357383
...@@ -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", .{}),
770797
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", .{}),
772800
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 register2012 .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 address2289 => 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);
22672299
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, #off2430 // 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}
33493378
3379fn 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
3411fn 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.
3352fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {3477fn 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}
33713496
3372fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void {3497fn 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 };
34103533
...@@ -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 }
35263649
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 });
35413667
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);
35443673
3545 // Make space for the arguments passed via the stack3674 // 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);
56555788
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 }
56605793
...@@ -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.*);
56905824
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`.
34prev_di_pc: usize,34prev_di_pc: usize,
3535
36/// The amount of stack space consumed by all stack arguments as well36/// The amount of stack space consumed by the saved callee-saved
37/// as the saved callee-saved registers37/// registers in bytes
38prologue_stack_space: u32,38saved_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.
42stack_size: u32,
3943
40/// The branch type of every branch44/// The branch type of every branch
41branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},45branch_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;
503508
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) orelse512 const operand = Instruction.Operand.fromU32(raw_offset) orelse
508 return emit.fail("TODO mirLoadStack larger offsets", .{});513 return emit.fail("TODO mirLoadStack larger offsets", .{});
509514
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", .{});
518523
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", .{});
544537
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", .{}),
695695
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", .{}),
697698
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"),
707707
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"),
709710
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;
29const WValue = union(enum) {29const WValue = union(enum) {
30 /// May be referenced but is unused30 /// 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 variable34 /// Index of the local variable
33 local: u32,35 local: u32,
34 /// An immediate 32bit value36 /// 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 offset60 /// 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,
6163
...@@ -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};
75109
76/// Wasm ops, but without input/output/signedness information110/// 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.
602stack_alignment: u32 = 16,636stack_alignment: u32 = 16,
603637
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.
642free_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.
645free_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.
648free_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.
651free_locals_f64: std.ArrayListUnmanaged(u32) = .{},
652
604const InnerError = error{653const 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`
760fn emitWValue(self: *Self, value: WValue) InnerError!void {809fn emitWValue(self: *Self, value: WValue) InnerError!void {
761 switch (value) {810 switch (value) {
762 .none => {}, // no-op811 .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 tag831/// Returns a corresponding `Wvalue` with `local` as active tag
783fn allocLocal(self: *Self, ty: Type) InnerError!WValue {832fn 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.
854fn 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 pointer1205 // Reserve a local to store the current stack pointer
1136 // We can later use this local to set the stack pointer back to the value1206 // 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 value1209 // 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}
11421212
1143/// Reads the stack pointer from `Context.initial_stack_value` and writes it1213/// 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_rt1339 // TODO: We should probably lower this to a call to compiler_rt
1270 // But for now, we implement it manually1340 // But for now, we implement it manually
1271 const offset = try self.allocLocal(Type.usize); // local for counter1341 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 done1344 // 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)}),
16261699
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 {
1653fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {1726fn 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}
16591735
...@@ -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 {
17271803
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 }
17331809
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}
18481924
1849fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {1925fn 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 first1959 // 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());
18851964
1886 // retrieve length from rhs, and store that alongside lhs as well1965 // 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 }
19342017
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}
19372021
2022/// Loads an operand from the linear memory section.
2023/// NOTE: Leaves the value on the stack.
1938fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {2024fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
1939 // load local's value from memory by its stack position2025 // 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 );
19542040
1955 // store the result in a local2041 return WValue{ .stack = {} };
1956 const result = try self.allocLocal(ty);
1957 try self.addLabel(.local_set, result.local);
1958 return result;
1959}2042}
19602043
1961fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2044fn 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);
20272110
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}
20302114
2115/// Performs a binary operation on the given `WValue`'s
2116/// NOTE: THis leaves the value on top of the stack.
2031fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2117fn 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
20542141
2055 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2142 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20562143
2057 // save the result in a temporary2144 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}
20622146
2147/// Performs a binary operation for 16-bit floats.
2148/// NOTE: Leaves the result value on the stack
2063fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue {2149fn 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));
20712154
2072 // re-use temporary local2155 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}
20762157
2077fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2158fn 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 }
20852166
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);
20942178
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);
21022187
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 }
21172202
2118 return self.wrapBinOp(lhs, rhs, ty, op);2203 return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty);
2119}2204}
21202205
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
2121fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2209fn 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}
21462213
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.
2149fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {2217fn 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;
21582225
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);
21622229
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;
21832251
2184 try self.addLabel(.local_set, result_local.local);2252 return WValue{ .stack = {} };
2185 return result_local;
2186}2253}
21872254
2188fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {2255fn 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}
25992666
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.
2600fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {2670fn 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));
26412712
2642 const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i322713 return WValue{ .stack = {} };
2643 try self.addLabel(.local_set, cmp_tmp.local);
2644 return cmp_tmp;
2645}2714}
26462715
2716/// Compares 16-bit floats
2717/// NOTE: The result value remains on top of the stack.
2647fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue {2718fn 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));
26662734
2667 const result = try self.allocLocal(Type.initTag(.i32)); // bool is always i322735 return WValue{ .stack = {} };
2668 try self.addLabel(.local_set, result.local);
2669 return result;
2670}2736}
26712737
2672fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2738fn 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 }
28312899
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}
28342903
2835fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2904fn 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}
30443115
3045fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {3116fn 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 }
30613132
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}
30643136
3065fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3137fn 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 }
31273199
3128 return self.intcast(operand, operand_ty, ty);3200 return (try self.intcast(operand, operand_ty, ty)).toLocal(self, ty);
3129}3201}
31303202
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 <= 1283205/// Asserts type's bitsize <= 128
3206/// NOTE: May leave the result on the top of the stack.
3134fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {3207fn 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 local3227 // 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);
31563230
3157 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it3231 // 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;
31673236
3168 // store msb first3237 // 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());
31703239
3171 // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value3240 // 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'd3246 // 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);
31813251
3182 const result = try self.allocLocal(wanted);3252 return WValue{ .stack = {} };
3183 try self.addLabel(.local_set, result.local);
3184 return result;
3185}3253}
31863254
3187fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue {3255fn 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
31903258
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}
31953264
3265/// For a given type and operand, checks if it's considered `null`.
3266/// NOTE: Leaves the result on the stack
3196fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {3267fn 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));
32113282
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}
32163285
3217fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3286fn 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 }
32313300
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}
32343304
3235fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3305fn 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);
33343404
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}
33373408
3338fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3409fn 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);
33473418
3348 // load pointer onto stack3419 // 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);
33513421
3352 // calculate index into slice3422 // 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}
33663438
3367fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3439fn 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);
33763448
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);
33793450
3380 // calculate index into slice3451 // 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);
33853456
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}
33973469
3398fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3470fn 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 }
34093481
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}
34183490
3419fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3491fn 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 {
34663538
3467 // load pointer onto the stack3539 // 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);
34803551
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}
34883562
3489fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3563fn 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 {
34993573
3500 // load pointer onto the stack3574 // 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);
35133586
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_rt3673 // TODO: We should probably lower this to a call to compiler_rt
3601 // But for now, we implement it manually3674 // But for now, we implement it manually
3602 const offset = try self.allocLocal(Type.usize); // local for counter3675 const offset = try self.ensureAllocLocal(Type.usize); // local for counter
3603 // outer block to jump to when loop is done3676 // 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);
36583731
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);
36613734
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}
36673743
3668fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3744fn 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));
36883764 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}
36943767
3695fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3768fn 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));
38893962
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 validated3963 // 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);
38963967
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 early3971 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);
39023973
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}
39223989
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 > 1283992/// TODO: Lower this to compiler_rt call when bitsize > 128
3925fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3993fn 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 }
39303999
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);
39354004
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");
39414012
...@@ -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);
39534024 _ = 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 }
39604030
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}
39654033
3966fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4034fn 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}
40054074
4006fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4075fn 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);
40124081
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}
40154085
4086/// Extends a float from a given `Type` to a larger wanted `Type`
4087/// NOTE: Leaves the result on the stack
4016fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {4088fn 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);
40194091
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) f324097 // 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}
40604129
4130/// Truncates a float from a given `Type` to its wanted `Type`
4131/// NOTE: The result value remains on the stack
4061fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {4132fn 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);
40644135
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;
40794146
4080 // call __truncsfhf2(f32) f164147 // 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 {
41594226
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
42684332
4269 // for signed integers, we first apply signed shifts by the difference in bits4333 // 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;
42774341
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
42824348
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 32bit4354 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 else4360 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);
42964364
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 }
43014378
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 }
43124389
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);
43174398
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);
43204403
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);
43284414
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 signed4422 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;
43444427
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);
43494432
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);
43544437
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);
43594442
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 };
43794462
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)
43844469
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);
43934483
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);
43984488
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 {
44124502
4413 // We store the bit if it's overflowed or not in this. As it's zero-initialized4503 // 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);
44474539
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 else4559 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);
44764568
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);
44814573
...@@ -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);
44994591
4500 const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
4501
4502 // operands to select from4592 // 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);
45064596
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);
45294619
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 }
45434634
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}
45474638
4548fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4639fn 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);
45774667
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);
46394728
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}
47824872
4783fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4873fn 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);
48154905
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);
48274917
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);
48374931
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}
48624956
4863fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4957fn 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);
48704964
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;
48844978
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);
48954984
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 }
49415034
4942 if (is_f16) {5035 if (is_f16) {
4943 // we can re-use temporary local5036 _ = 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 }
49485039
...@@ -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 }
49635054
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}
49795069
5070/// Retrieves the absolute value of a signed integer
5071/// NOTE: Leaves the result value on the stack.
4980fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {5072fn 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}
50125103
5013fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {5104fn 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));
50355126
5036 if (is_f16) {5127 if (is_f16) {
5037 // re-use temporary to save locals5128 _ = 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 }
50415130
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 }
50665155
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 };
50765166
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 }
50915179
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;
51025190
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;
51055197
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 };
51185210
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 local5220 try self.addLabel(.local_set, bin_result.local); // re-use local
51275221
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 local5226 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 local5244 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);
51725264
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);
51775270
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 };
52155306
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);
52205313
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 }
52275320
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 }
52395331
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}
52595350
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.
5263fn callIntrinsic(5356fn 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(
52895382
5290 // Lower all arguments to the stack before we call our function5383 // 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", .{}),
777777
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", .{}),
779780
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();
43734375
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},
35flagpd1("I-"),35flagpd1("I-"),
36flagpd1("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", .{}),
19551955
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: on1958 // 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 }
724724
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, generating729 // 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 bitcast2265 // 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 replace2266 // 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 }
23332377
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 }
23362388
...@@ -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;
26802732
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;
33313393
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),
41864248
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),
41884251
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 }
78907986
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;
78938036
...@@ -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,
94179565
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 }
94339583
...@@ -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}
96169778
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;
128128
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;
131134
...@@ -245,6 +248,9 @@ pub const Value = opaque {...@@ -245,6 +248,9 @@ pub const Value = opaque {
245248
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};
249255
250pub const Type = opaque {256pub 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 };
439440
440 /// Called from within the CodeGen to lower a local variable instantion as an unnamed441 /// 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 }
103103
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}
53165316
5317fn filterDataInCode(5317fn 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,
53245324
...@@ -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}
58275827
5828pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize {5828pub 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");
58315831
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};
220220
221pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context: RelocContext) !void {221pub 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();
224224
src/link/MachO/DebugSymbols.zig+8-8
...@@ -63,17 +63,16 @@ pub const Reloc = struct {...@@ -63,17 +63,16 @@ pub const Reloc = struct {
63pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {63pub 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 reworking69 // 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;
286285
286 self.updateDwarfSegment();
287 try self.writeLinkeditSegmentData(&ncmds, lc_writer);287 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
288 self.updateDwarfSegment();288 self.updateDwarfSegment();
289289
src/link/MachO/Object.zig+13-12
...@@ -24,7 +24,7 @@ mtime: u64,...@@ -24,7 +24,7 @@ mtime: u64,
24contents: []align(@alignOf(u64)) const u8,24contents: []align(@alignOf(u64)) const u8,
2525
26header: macho.mach_header_64 = undefined,26header: macho.mach_header_64 = undefined,
27in_symtab: []const macho.nlist_64 = undefined,27in_symtab: []align(1) const macho.nlist_64 = undefined,
28in_strtab: []const u8 = undefined,28in_strtab: []const u8 = undefined,
2929
30symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},30symtab: 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}
197198
198fn filterRelocs(199fn 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,
205206
...@@ -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)
303304
304 // Read section's list of relocations305 // 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];
309310
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}
540541
541pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {542pub 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 => { // -MM1660 .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;
42304232
4231fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {4233fn 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),
247248
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 {
247246
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 }
607606
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..];
11621152
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 {
12381245
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 }
12441270
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;
11171117
1118 bool auto_enum, is_root; // union(enum)1118 bool auto_enum, is_root; // union(enum)
1119 bool unsupported_explicit_backing_int;
1119};1120};
11201121
1121struct AstNodeErrorSetField {1122struct 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) {
30343034
3035 AstNode *decl_node = struct_type->data.structure.decl_node;3035 AstNode *decl_node = struct_type->data.structure.decl_node;
30363036
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);
1864218642
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;
1864518645
18646 // layout: ContainerLayout18646 // 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.StructField18660 // fields: []Type.StructField
18652 ensure_field_index(result->type, "fields", 1);18661 ensure_field_index(result->type, "fields", 2);
1865318662
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);
1866518674
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);
1866718676
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.Declaration18721 // 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 }
1871918728
18720 // is_tuple: bool18729 // 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);
1872518734
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);
1931519324
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);
1932419340
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 }
1933619352
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;
1934019356
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}
29032903
2904// ContainerDeclType2904// ContainerDeclType
2905// <- KEYWORD_struct2905// <- 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_opaque2908// / KEYWORD_opaque
2909static AstNode *ast_parse_container_decl_type(ParseContext *pc) {2909static 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 }
29172926
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();
12261226
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 to1227 // 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.?);
12461242
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 }
12691262
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 }
12831278
...@@ -1295,33 +1290,6 @@ pub const TestContext = struct {...@@ -1295,33 +1290,6 @@ pub const TestContext = struct {
1295 }1290 }
1296 }1291 }
12971292
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 }
30073015
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 }
57735780
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` because5781 /// 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 types5783 /// 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");
63426305
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();
63456310
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 }
34743484
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 {
165166
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 }
169171
170 if (builtin.os.tag != .wasi) {172 if (builtin.os.tag != .wasi) {
test/behavior/bugs/12430.zig created+11
...@@ -0,0 +1,11 @@
1const std = @import("std");
2
3test {
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
250test "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; // TODO1431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1432 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1432 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14331433
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
1297test "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 {
1721fn testAbsFloatOne(in: f32, out: f32) !void {1721fn 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
1725test "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 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const expectEqual = std.testing.expectEqual;
5const native_endian = builtin.cpu.arch.endian();
6
7test "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; // TODO514 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
515515
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" {
293fn testStruct() !void {293fn 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}
327329
328const TestPackedStruct = packed struct {330const 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}
809809
810test "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
810test "mask parameter of @shuffle is comptime scope" {827test "mask parameter of @shuffle is comptime scope" {
811 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO828 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
812 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO829 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 @@
1export fn entry() void {
2 foo();
3}
4fn 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 @@
1comptime {
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 @@
1comptime {
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 @@
1comptime {
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 @@
1comptime {
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 @@
1extern fn printf([*:0]const u8, ...) c_int;
2
3pub 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 @@
1const S = struct {
2 a: u32,
3 fn foo(_: *S, _: u32, _: bool) void {}
4};
5pub 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=native11// target=native
12//12//
13// :5:25: error: cannot load runtime value in comptime block13// :5:25: error: cannot load runtime value in comptime block
14// :2:15: note: called from here14// :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=native17// 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 here20// :8:15: note: enum declared here
test/cases/compile_errors/packed_struct_backing_int_wrong.zig created+55
...@@ -0,0 +1,55 @@
1export fn entry1() void {
2 _ = @sizeOf(packed struct(u32) {
3 x: u1,
4 y: u24,
5 z: u4,
6 });
7}
8export fn entry2() void {
9 _ = @sizeOf(packed struct(i31) {
10 x: u4,
11 y: u24,
12 z: u4,
13 });
14}
15
16export fn entry3() void {
17 _ = @sizeOf(packed struct(void) {
18 x: void,
19 });
20}
21
22export fn entry4() void {
23 _ = @sizeOf(packed struct(void) {});
24}
25
26export fn entry5() void {
27 _ = @sizeOf(packed struct(noreturn) {});
28}
29
30export fn entry6() void {
31 _ = @sizeOf(packed struct(f64) {
32 x: u32,
33 y: f32,
34 });
35}
36
37export 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 @@
1const 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});
13const 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});
25export 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 @@
1comptime {
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 @@
1comptime {
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 @@
1export 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 @@
1export fn entry() void {
2 foo();
3}
4fn 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 @@
1comptime {
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 @@
1comptime {
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 @@
1export 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 @@
1const Foo = struct {
2 fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
3};
4fn f(foo: *const Foo) void {
5
6 foo.method(1, 2);
7}
8export 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=19// 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 here12// :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=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:6: error: expected 3 argument(s), found 110// :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 @@
1const Foo = struct {
2 fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
3};
4fn f(foo: *const Foo) void {
5
6 foo.method(1, 2);
7}
8export 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 @@
1const 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
11pub export fn entry() void {
12 var s: S = undefined;
13 _ = s.a.str(undefined);
14}
15
16const S2 = struct {
17 a: [*c]anyopaque,
18};
19
20pub 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 @@
1const std = @import("std");
2
3pub 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}
10pub fn main() !void {
11 bar(0) catch {};
12 return error.TestFailed;
13}
14fn 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");
3const tests = @import("tests.zig");3const tests = @import("tests.zig");
44
5pub fn addCases(cases: *tests.StandaloneContext) void {5pub 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 Debug12 .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;
3const tests = @import("tests.zig");3const tests = @import("tests.zig");
44
5pub fn addCases(cases: *tests.StackTracesContext) void {5pub 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, // segfault29 .windows, // segfault
30 .linux, // defeated by aggressive inlining
25 },31 },
26 .expect = 32 .expect =
27 \\error: TheSkyIsFalling33 \\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/1219434 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/148144 // 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/1222246 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;
643643
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 });