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:
2727 vmImage: 'windows-2019'
2828 variables:
2929 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'
3131 ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip'
3232 steps:
3333 - pwsh: |
......@@ -41,6 +41,13 @@ jobs:
4141 Set-Variable -Name ZIGINSTALLDIR -Value "${ZIGBUILDDIR}\dist"
4242 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
4451 # Make the `zig version` number consistent.
4552 # This will affect the `zig build` command below which uses `git describe`.
4653 git config core.abbrev 9
......@@ -69,6 +76,7 @@ jobs:
6976 -Dstrip `
7077 -Duse-zig-libcxx `
7178 -Dtarget=$(TARGET)
79 CheckLastExitCode
7280
7381 cd -
7482
......@@ -83,19 +91,37 @@ jobs:
8391 - pwsh: |
8492 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"
8593
94 function CheckLastExitCode {
95 if (!$?) {
96 exit 1
97 }
98 return 0
99 }
100
86101 # Sadly, stage2 is omitted from this build to save memory on the CI server. Once self-hosted is
87102 # built with itself and does not gobble as much memory, we can enable these tests.
88103 #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1
104 #CheckLastExitCode
89105
90106 & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1
107 CheckLastExitCode
91108 & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1
109 CheckLastExitCode
92110 name: test
93111 displayName: 'Test'
94112
95113 - pwsh: |
96114 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"
97115
116 function CheckLastExitCode {
117 if (!$?) {
118 exit 1
119 }
120 return 0
121 }
122
98123 & "$ZIGINSTALLDIR\bin\zig.exe" build docs
124 CheckLastExitCode
99125 timeoutInMinutes: 60
100126 name: doc
101127 displayName: 'Documentation'
ci/srht/update_download_page+13-5
......@@ -103,11 +103,19 @@ cd "$HOME"
103103
104104# Upload new stdlib autodocs
105105mkdir -p docs_to_upload/documentation/master/std/
106cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html
107cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js
108cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js
109cp "$LANGREF" docs_to_upload/documentation/master/index.html
110$S3CMD put -P --no-mime-magic --recursive --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/
106
107gzip -c -9 "$ZIGDIR/docs/std/index.html" > docs_to_upload/documentation/master/std/index.html
108gzip -c -9 "$ZIGDIR/docs/std/data.js" > docs_to_upload/documentation/master/std/data.js
109gzip -c -9 "$ZIGDIR/docs/std/main.js" > docs_to_upload/documentation/master/std/main.js
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
112120git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git
113121cd www.ziglang.org
lib/docs/index.html+17-9
......@@ -169,8 +169,8 @@
169169 width: 100%;
170170 margin-bottom: 0.8rem;
171171 padding: 0.5rem;
172 font-size: 1rem;
173172 font-family: var(--ui);
173 font-size: 1rem;
174174 color: var(--tx-color);
175175 background-color: var(--search-bg-color);
176176 border-top: 0;
......@@ -339,8 +339,8 @@
339339 kbd {
340340 display: inline-block;
341341 padding: 0.3em 0.2em;
342 font-size: 1.2em;
343 font-size: var(--mono);
342 font-family: var(--mono);
343 font-size: 1em;
344344 line-height: 0.8em;
345345 vertical-align: middle;
346346 color: #000;
......@@ -612,7 +612,7 @@
612612 </div>
613613 </nav>
614614 </div>
615 <div class="flex-right">
615 <div id="docs" class="flex-right">
616616 <div class="wrap">
617617 <section class="docs">
618618 <div style="position: relative">
......@@ -654,7 +654,13 @@
654654 </div>
655655 <div id="sectSearchNoResults" class="hidden">
656656 <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>
658664 </div>
659665 <div id="sectFields" class="hidden">
660666 <h2>Fields</h2>
......@@ -716,11 +722,13 @@
716722 <div class="modal">
717723 <h1>Keyboard Shortcuts</h1>
718724 <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>
720725 <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>
722 <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl>
723 <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl>
726 <div style="margin-left: 1em">
727 <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</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>
724732 </div>
725733 </div>
726734 </div>
lib/docs/main.js+45-24
......@@ -41,7 +41,7 @@ var zigAnalysis;
4141 const domSearch = document.getElementById("search");
4242 const domSectSearchResults = document.getElementById("sectSearchResults");
4343 const domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink");
44
44 const domDocs = document.getElementById("docs");
4545 const domListSearchResults = document.getElementById("listSearchResults");
4646 const domSectSearchNoResults = document.getElementById("sectSearchNoResults");
4747 const domSectInfo = document.getElementById("sectInfo");
......@@ -52,6 +52,7 @@ var zigAnalysis;
5252 const domHelpModal = document.getElementById("helpModal");
5353 const domSearchPlaceholder = document.getElementById("searchPlaceholder");
5454 const sourceFileUrlTemplate = "/src-viewer/{{file}}#L{{line}}"
55 const domLangRefLink = document.getElementById("langRefLink");
5556
5657 let lineCounter = 1;
5758 let searchTimer = null;
......@@ -118,10 +119,10 @@ var zigAnalysis;
118119 });
119120 domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false);
120121 function onClickSearchShowAllResults(ev) {
121 ev.preventDefault();
122 ev.stopPropagation();
123 searchTrimResults = false;
124 onHashChange();
122 ev.preventDefault();
123 ev.stopPropagation();
124 searchTrimResults = false;
125 onHashChange();
125126 }
126127
127128 domPrivDeclsBox.addEventListener(
......@@ -163,6 +164,13 @@ var zigAnalysis;
163164 window.addEventListener("keydown", onWindowKeyDown, false);
164165 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
166174 function renderTitle() {
167175 let list = curNav.pkgNames.concat(curNav.declNames);
168176 let suffix = " - Zig";
......@@ -3154,6 +3162,23 @@ var zigAnalysis;
31543162 domSearch.blur();
31553163 }
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
31573182 function onSearchKeyDown(ev) {
31583183 switch (getKeyString(ev)) {
31593184 case "Enter":
......@@ -3170,19 +3195,15 @@ var zigAnalysis;
31703195 ev.stopPropagation();
31713196 return;
31723197 case "Esc":
3173 domSearch.value = "";
3174 domSearch.blur();
3175 curSearchIndex = -1;
3176 ev.preventDefault();
3177 ev.stopPropagation();
3178 startSearch();
3179 return;
3198 onEscape(ev);
3199 return
31803200 case "Up":
31813201 moveSearchCursor(-1);
31823202 ev.preventDefault();
31833203 ev.stopPropagation();
31843204 return;
31853205 case "Down":
3206 // TODO: make the page scroll down if the search cursor is out of the screen
31863207 moveSearchCursor(1);
31873208 ev.preventDefault();
31883209 ev.stopPropagation();
......@@ -3251,19 +3272,18 @@ var zigAnalysis;
32513272 function onWindowKeyDown(ev) {
32523273 switch (getKeyString(ev)) {
32533274 case "Esc":
3254 if (!domHelpModal.classList.contains("hidden")) {
3255 domHelpModal.classList.add("hidden");
3275 onEscape(ev);
3276 break;
3277 case "s":
3278 if (domHelpModal.classList.contains("hidden")) {
3279 domSearch.focus();
3280 domSearch.select();
3281 domDocs.scrollTo(0, 0);
32563282 ev.preventDefault();
32573283 ev.stopPropagation();
3284 startAsyncSearch();
32583285 }
32593286 break;
3260 case "s":
3261 domSearch.focus();
3262 domSearch.select();
3263 ev.preventDefault();
3264 ev.stopPropagation();
3265 startAsyncSearch();
3266 break;
32673287 case "?":
32683288 ev.preventDefault();
32693289 ev.stopPropagation();
......@@ -3279,6 +3299,7 @@ var zigAnalysis;
32793299 domHelpModal.style.top =
32803300 window.innerHeight / 2 - domHelpModal.clientHeight / 2 + "px";
32813301 domHelpModal.focus();
3302 domSearch.blur();
32823303 }
32833304
32843305 function clearAsyncSearch() {
......@@ -3304,7 +3325,7 @@ var zigAnalysis;
33043325 list.sort();
33053326 return list;
33063327 }
3307
3328
33083329 function renderSearch() {
33093330 let matchedItems = [];
33103331 let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
......@@ -3393,13 +3414,13 @@ var zigAnalysis;
33933414 const text = lastPkgName + "." + match.path.declNames.join(".");
33943415 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>";
33973418 }
33983419
33993420 // Replace the search results using our newly constructed HTML string
34003421 domListSearchResults.innerHTML = matchedItemsHTML;
34013422 if (searchTrimmed) {
3402 domSectSearchAllResultsLink.classList.remove("hidden");
3423 domSectSearchAllResultsLink.classList.remove("hidden");
34033424 }
34043425 renderSearchCursor();
34053426
lib/std/array_list.zig+63
......@@ -221,6 +221,30 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
221221 mem.copy(T, self.items[old_len..], items);
222222 }
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
224248 pub const Writer = if (T != u8)
225249 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
226250 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
......@@ -592,6 +616,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
592616 mem.copy(T, self.items[old_len..], items);
593617 }
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
595642 pub const WriterContext = struct {
596643 self: *Self,
597644 allocator: Allocator,
......@@ -899,6 +946,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
899946 try testing.expect(list.pop() == 1);
900947 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
902957 list.appendSlice(&[_]i32{}) catch unreachable;
903958 try testing.expect(list.items.len == 9);
904959
......@@ -941,6 +996,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
941996 try testing.expect(list.pop() == 1);
942997 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
9441007 list.appendSlice(a, &[_]i32{}) catch unreachable;
9451008 try testing.expect(list.items.len == 9);
9461009
lib/std/bounded_array.zig+1-1
......@@ -275,7 +275,7 @@ test "BoundedArray" {
275275 try testing.expectEqualSlices(u8, &x, a.constSlice());
276276
277277 var a2 = a;
278 try testing.expectEqualSlices(u8, a.constSlice(), a.constSlice());
278 try testing.expectEqualSlices(u8, a.constSlice(), a2.constSlice());
279279 a2.set(0, 0);
280280 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) {
294294 /// therefore must be kept in sync with the compiler implementation.
295295 pub const Struct = struct {
296296 layout: ContainerLayout,
297 /// Only valid if layout is .Packed
298 backing_integer: ?type = null,
297299 fields: []const StructField,
298300 decls: []const Declaration,
299301 is_tuple: bool,
......@@ -867,10 +869,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
867869 std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len });
868870}
869871
870pub noinline fn returnError(maybe_st: ?*StackTrace) void {
872pub noinline fn returnError(st: *StackTrace) void {
871873 @setCold(true);
872874 @setRuntimeSafety(false);
873 const st = maybe_st orelse return;
874875 addErrRetTraceAddr(st, @returnAddress());
875876}
876877
lib/std/c/darwin.zig+4-4
......@@ -814,10 +814,10 @@ pub const sigset_t = u32;
814814pub const empty_sigset: sigset_t = 0;
815815
816816pub const SIG = struct {
817 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
818 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
819 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
820 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 5);
817 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
818 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
819 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
820 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 5);
821821
822822 /// block specified signal set
823823 pub const _BLOCK = 1;
lib/std/c/dragonfly.zig+3-3
......@@ -609,9 +609,9 @@ pub const S = struct {
609609pub const BADSIG = SIG.ERR;
610610
611611pub const SIG = struct {
612 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
613 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
614 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
612 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
613 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
614 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
615615
616616 pub const BLOCK = 1;
617617 pub const UNBLOCK = 2;
lib/std/c/freebsd.zig+3-3
......@@ -670,9 +670,9 @@ pub const SIG = struct {
670670 pub const UNBLOCK = 2;
671671 pub const SETMASK = 3;
672672
673 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
674 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
675 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
673 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
674 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
675 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
676676
677677 pub const WORDS = 4;
678678 pub const MAXSIG = 128;
lib/std/c/netbsd.zig+3-3
......@@ -910,9 +910,9 @@ pub const winsize = extern struct {
910910const NSIG = 32;
911911
912912pub const SIG = struct {
913 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
914 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
915 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
913 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
914 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
915 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
916916
917917 pub const WORDS = 4;
918918 pub const MAXSIG = 128;
lib/std/c/openbsd.zig+5-5
......@@ -982,11 +982,11 @@ pub const winsize = extern struct {
982982const NSIG = 33;
983983
984984pub const SIG = struct {
985 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
986 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
987 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
988 pub const CATCH = @intToPtr(?Sigaction.sigaction_fn, 2);
989 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 3);
985 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
986 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
987 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
988 pub const CATCH = @intToPtr(?Sigaction.handler_fn, 2);
989 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 3);
990990
991991 pub const HUP = 1;
992992 pub const INT = 2;
lib/std/c/solaris.zig+4-4
......@@ -879,10 +879,10 @@ pub const winsize = extern struct {
879879const NSIG = 75;
880880
881881pub const SIG = struct {
882 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
883 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
884 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
885 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 2);
882 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
883 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
884 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
885 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 2);
886886
887887 pub const WORDS = 4;
888888 pub const MAXSIG = 75;
lib/std/crypto/25519/ed25519.zig+3-1
......@@ -355,7 +355,9 @@ test "ed25519 batch verification" {
355355 try Ed25519.verifyBatch(2, signature_batch);
356356
357357 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));
359361 }
360362}
361363
lib/std/debug.zig+1-1
......@@ -1787,7 +1787,7 @@ fn resetSegfaultHandler() void {
17871787 return;
17881788 }
17891789 var act = os.Sigaction{
1790 .handler = .{ .sigaction = os.SIG.DFL },
1790 .handler = .{ .handler = os.SIG.DFL },
17911791 .mask = os.empty_sigset,
17921792 .flags = 0,
17931793 };
lib/std/fs.zig+4-2
......@@ -877,8 +877,9 @@ pub const IterableDir = struct {
877877 /// a reference to the path.
878878 pub fn next(self: *Walker) !?WalkerEntry {
879879 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`
881881 var top = &self.stack.items[self.stack.items.len - 1];
882 var containing = top;
882883 var dirname_len = top.dirname_len;
883884 if (try top.iter.next()) |base| {
884885 self.name_buffer.shrinkRetainingCapacity(dirname_len);
......@@ -899,10 +900,11 @@ pub const IterableDir = struct {
899900 .dirname_len = self.name_buffer.items.len,
900901 });
901902 top = &self.stack.items[self.stack.items.len - 1];
903 containing = &self.stack.items[self.stack.items.len - 2];
902904 }
903905 }
904906 return WalkerEntry{
905 .dir = top.iter.dir,
907 .dir = containing.iter.dir,
906908 .basename = self.name_buffer.items[dirname_len..],
907909 .path = self.name_buffer.items,
908910 .kind = base.kind,
lib/std/fs/test.zig+3
......@@ -1058,6 +1058,9 @@ test "walker" {
10581058 std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)});
10591059 return err;
10601060 };
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();
10611064 num_walked += 1;
10621065 }
10631066 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)
3030 .DeepRecursive => hash(hasher, key.*, .DeepRecursive),
3131 },
3232
33 .Slice => switch (strat) {
34 .Shallow => {
35 hashPointer(hasher, key.ptr, .Shallow);
36 hash(hasher, key.len, .Shallow);
37 },
38 .Deep => hashArray(hasher, key, .Shallow),
39 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
33 .Slice => {
34 switch (strat) {
35 .Shallow => {
36 hashPointer(hasher, key.ptr, .Shallow);
37 },
38 .Deep => hashArray(hasher, key, .Shallow),
39 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
40 }
41 hash(hasher, key.len, .Shallow);
4042 },
4143
4244 .Many,
......@@ -53,17 +55,8 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)
5355
5456/// Helper function to hash a set of contiguous objects, from an array or slice.
5557pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
56 switch (strat) {
57 .Shallow => {
58 for (key) |element| {
59 hash(hasher, element, .Shallow);
60 }
61 },
62 else => {
63 for (key) |element| {
64 hash(hasher, element, strat);
65 }
66 },
58 for (key) |element| {
59 hash(hasher, element, strat);
6760 }
6861}
6962
......@@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool {
193186pub fn autoHash(hasher: anytype, key: anytype) void {
194187 const Key = @TypeOf(key);
195188 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) ++
197 ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead.");
189 @compileError("std.hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++
190 ") because the intent is unclear. Consider using std.hash.autoHashStrat or providing your own hash function instead.");
198191 }
199192
200193 hash(hasher, key, .Shallow);
......@@ -359,6 +352,12 @@ test "testHash array" {
359352 try testing.expectEqual(h, hasher.final());
360353}
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
362361test "testHash struct" {
363362 const Foo = struct {
364363 a: u32 = 1,
lib/std/os.zig+7-4
......@@ -475,10 +475,9 @@ pub fn abort() noreturn {
475475
476476 // Install default handler so that the tkill below will terminate.
477477 const sigact = Sigaction{
478 .handler = .{ .sigaction = SIG.DFL },
479 .mask = undefined,
480 .flags = undefined,
481 .restorer = undefined,
478 .handler = .{ .handler = SIG.DFL },
479 .mask = empty_sigset,
480 .flags = 0,
482481 };
483482 sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) {
484483 error.OperationNotSupported => unreachable,
......@@ -953,6 +952,10 @@ pub const WriteError = error{
953952 OperationAborted,
954953 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
956959 /// This error occurs when no global event loop is configured,
957960 /// and reading from the file descriptor would block.
958961 WouldBlock,
lib/std/os/linux.zig+9-9
......@@ -1945,9 +1945,9 @@ pub const SIG = if (is_mips) struct {
19451945 pub const SYS = 31;
19461946 pub const UNUSED = SIG.SYS;
19471947
1948 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
1949 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
1950 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
1948 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
1949 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
1950 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
19511951} else if (is_sparc) struct {
19521952 pub const BLOCK = 1;
19531953 pub const UNBLOCK = 2;
......@@ -1989,9 +1989,9 @@ pub const SIG = if (is_mips) struct {
19891989 pub const PWR = LOST;
19901990 pub const IO = SIG.POLL;
19911991
1992 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
1993 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
1994 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
1992 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
1993 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
1994 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
19951995} else struct {
19961996 pub const BLOCK = 0;
19971997 pub const UNBLOCK = 1;
......@@ -2032,9 +2032,9 @@ pub const SIG = if (is_mips) struct {
20322032 pub const SYS = 31;
20332033 pub const UNUSED = SIG.SYS;
20342034
2035 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
2036 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
2037 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
2035 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
2036 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
2037 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
20382038};
20392039
20402040pub const kernel_rwf = u32;
lib/std/os/test.zig+1-1
......@@ -785,7 +785,7 @@ test "sigaction" {
785785 try testing.expect(signal_test_failed == false);
786786 // Check if the handler has been correctly reset to SIG_DFL
787787 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);
789789}
790790
791791test "dup & dup2" {
lib/std/os/windows.zig+4
......@@ -517,6 +517,9 @@ pub const WriteFileError = error{
517517 OperationAborted,
518518 BrokenPipe,
519519 NotOpenForWriting,
520 /// The process cannot access the file because another process has locked
521 /// a portion of the file.
522 LockViolation,
520523 Unexpected,
521524};
522525
......@@ -597,6 +600,7 @@ pub fn WriteFile(
597600 .IO_PENDING => unreachable,
598601 .BROKEN_PIPE => return error.BrokenPipe,
599602 .INVALID_HANDLE => return error.NotOpenForWriting,
603 .LOCK_VIOLATION => return error.LockViolation,
600604 else => |err| return unexpectedError(err),
601605 }
602606 }
lib/std/zig/Ast.zig+1-1
......@@ -2967,7 +2967,7 @@ pub const Node = struct {
29672967 /// Same as ContainerDeclTwo except there is known to be a trailing comma
29682968 /// or semicolon before the rbrace.
29692969 container_decl_two_trailing,
2970 /// `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
2970 /// `struct(lhs)` / `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
29712971 container_decl_arg,
29722972 /// Same as container_decl_arg but there is known to be a trailing
29732973 /// comma or semicolon before the rbrace.
lib/std/zig/parse.zig+6-4
......@@ -3356,16 +3356,18 @@ const Parser = struct {
33563356 }
33573357
33583358 /// Caller must have already verified the first token.
3359 /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
3360 ///
33593361 /// ContainerDeclType
3360 /// <- KEYWORD_struct
3362 /// <- KEYWORD_struct (LPAREN Expr RPAREN)?
3363 /// / KEYWORD_opaque
33613364 /// / KEYWORD_enum (LPAREN Expr RPAREN)?
33623365 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
3363 /// / KEYWORD_opaque
33643366 fn parseContainerDeclAuto(p: *Parser) !Node.Index {
33653367 const main_token = p.nextToken();
33663368 const arg_expr = switch (p.token_tags[main_token]) {
3367 .keyword_struct, .keyword_opaque => null_node,
3368 .keyword_enum => blk: {
3369 .keyword_opaque => null_node,
3370 .keyword_struct, .keyword_enum => blk: {
33693371 if (p.eatToken(.l_paren)) |_| {
33703372 const expr = try p.expectExpr();
33713373 _ = try p.expectToken(.r_paren);
lib/std/zig/parser_test.zig+7
......@@ -3064,6 +3064,13 @@ test "zig fmt: struct declaration" {
30643064 \\ c: u8,
30653065 \\};
30663066 \\
3067 \\const Ps = packed struct(u32) {
3068 \\ a: u1,
3069 \\ b: u2,
3070 \\
3071 \\ c: u29,
3072 \\};
3073 \\
30673074 \\const Es = extern struct {
30683075 \\ a: u8,
30693076 \\ b: u8,
lib/std/zig/tokenizer.zig+18
......@@ -797,6 +797,10 @@ pub const Tokenizer = struct {
797797 remaining_code_units = 3;
798798 state = .char_literal_unicode;
799799 },
800 '\n' => {
801 result.tag = .invalid;
802 break;
803 },
800804 else => {
801805 state = .char_literal_end;
802806 },
......@@ -1507,6 +1511,20 @@ test "tokenizer - code point literal with hex escape" {
15071511 , &.{ .invalid, .invalid });
15081512}
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
15101528test "tokenizer - code point literal with unicode escapes" {
15111529 // Valid unicode escapes
15121530 try testTokenize(
src/Air.zig+5
......@@ -673,6 +673,10 @@ pub const Inst = struct {
673673 /// Uses the `un_op` field.
674674 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
676680 /// Constructs a vector, tuple, struct, or array value out of runtime-known elements.
677681 /// Some of the elements may be comptime-known.
678682 /// 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 {
10621066 .is_err_ptr,
10631067 .is_non_err_ptr,
10641068 .is_named_enum_value,
1069 .error_set_has_value,
10651070 => return Type.bool,
10661071
10671072 .const_ty => return Type.type,
src/AstGen.zig+180-28
......@@ -152,6 +152,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
152152 0,
153153 tree.containerDeclRoot(),
154154 .Auto,
155 0,
155156 )) |struct_decl_ref| {
156157 assert(refToIndex(struct_decl_ref).? == 0);
157158 } else |err| switch (err) {
......@@ -2454,7 +2455,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
24542455 .trunc,
24552456 .round,
24562457 .tag_name,
2457 .reify,
24582458 .type_name,
24592459 .frame_type,
24602460 .frame_size,
......@@ -2501,7 +2501,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25012501 .closure_get,
25022502 .array_base_ptr,
25032503 .field_base_ptr,
2504 .param_type,
25052504 .ret_ptr,
25062505 .ret_type,
25072506 .@"try",
......@@ -3071,6 +3070,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {
30713070 const line = astgen.source_line - gz.decl_line;
30723071 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
30743086 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
30753087 .dbg_stmt = .{
30763088 .line = line,
......@@ -4212,15 +4224,18 @@ fn structDeclInner(
42124224 node: Ast.Node.Index,
42134225 container_decl: Ast.full.ContainerDecl,
42144226 layout: std.builtin.Type.ContainerLayout,
4227 backing_int_node: Ast.Node.Index,
42154228) InnerError!Zir.Inst.Ref {
42164229 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) {
42194232 try gz.setStruct(decl_inst, .{
42204233 .src_node = node,
42214234 .layout = layout,
42224235 .fields_len = 0,
42234236 .decls_len = 0,
4237 .backing_int_ref = .none,
4238 .backing_int_body_len = 0,
42244239 .known_non_opv = false,
42254240 .known_comptime_only = false,
42264241 });
......@@ -4255,6 +4270,35 @@ fn structDeclInner(
42554270 };
42564271 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
42584302 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
42594303 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);
42604304
......@@ -4279,7 +4323,7 @@ fn structDeclInner(
42794323 var known_non_opv = false;
42804324 var known_comptime_only = false;
42814325 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)) {
42834327 .decl => continue,
42844328 .field => |field| field,
42854329 };
......@@ -4367,6 +4411,8 @@ fn structDeclInner(
43674411 .layout = layout,
43684412 .fields_len = field_count,
43694413 .decls_len = decl_count,
4414 .backing_int_ref = backing_int_ref,
4415 .backing_int_body_len = @intCast(u32, backing_int_body_len),
43704416 .known_non_opv = known_non_opv,
43714417 .known_comptime_only = known_comptime_only,
43724418 });
......@@ -4375,7 +4421,9 @@ fn structDeclInner(
43754421 const decls_slice = wip_members.declsSlice();
43764422 const fields_slice = wip_members.fieldsSlice();
43774423 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]);
43794427 astgen.extra.appendSliceAssumeCapacity(decls_slice);
43804428 astgen.extra.appendSliceAssumeCapacity(fields_slice);
43814429 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
......@@ -4446,7 +4494,7 @@ fn unionDeclInner(
44464494 defer wip_members.deinit();
44474495
44484496 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)) {
44504498 .decl => continue,
44514499 .field => |field| field,
44524500 };
......@@ -4571,9 +4619,7 @@ fn containerDecl(
45714619 else => unreachable,
45724620 } else std.builtin.Type.ContainerLayout.Auto;
45734621
4574 assert(container_decl.ast.arg == 0);
4575
4576 const result = try structDeclInner(gz, scope, node, container_decl, layout);
4622 const result = try structDeclInner(gz, scope, node, container_decl, layout, container_decl.ast.arg);
45774623 return rvalue(gz, rl, result, node);
45784624 },
45794625 .keyword_union => {
......@@ -4733,7 +4779,7 @@ fn containerDecl(
47334779 for (container_decl.ast.members) |member_node| {
47344780 if (member_node == counts.nonexhaustive_node)
47354781 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)) {
47374783 .decl => continue,
47384784 .field => |field| field,
47394785 };
......@@ -4811,13 +4857,26 @@ fn containerDecl(
48114857 };
48124858 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
48144873 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
48154874
48164875 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0);
48174876 defer wip_members.deinit();
48184877
48194878 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);
48214880 if (res == .field) {
48224881 return astgen.failNode(member_node, "opaque types cannot have fields", .{});
48234882 }
......@@ -5038,6 +5097,16 @@ fn tryExpr(
50385097
50395098 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
50415110 const operand_rl: ResultLoc = switch (rl) {
50425111 .ref => .ref,
50435112 else => .none,
......@@ -5067,6 +5136,7 @@ fn tryExpr(
50675136 };
50685137 const err_code = try else_scope.addUnNode(err_tag, operand, node);
50695138 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
5139 try emitDbgStmt(&else_scope, try_line, try_column);
50705140 _ = try else_scope.addUnNode(.ret_node, err_code, node);
50715141
50725142 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
65736643
65746644 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
65766656 const defer_outer = &astgen.fn_block.?.base;
65776657
65786658 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
65916671 const defer_counts = countDefers(astgen, defer_outer, scope);
65926672 if (!defer_counts.need_err_code) {
65936673 try genDefers(gz, defer_outer, scope, .both_sans_err);
6674 try emitDbgStmt(gz, ret_line, ret_column);
65946675 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
65956676 return Zir.Inst.Ref.unreachable_value;
65966677 }
65976678 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
65986679 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6680 try emitDbgStmt(gz, ret_line, ret_column);
65996681 _ = try gz.addUnNode(.ret_node, err_code, node);
66006682 return Zir.Inst.Ref.unreachable_value;
66016683 }
......@@ -6614,6 +6696,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66146696 .never => {
66156697 // Returning a value that cannot be an error; skip error defers.
66166698 try genDefers(gz, defer_outer, scope, .normal_only);
6699 try emitDbgStmt(gz, ret_line, ret_column);
66176700 try gz.addRet(rl, operand, node);
66186701 return Zir.Inst.Ref.unreachable_value;
66196702 },
......@@ -6621,6 +6704,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66216704 // Value is always an error. Emit both error defers and regular defers.
66226705 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
66236706 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6707 try emitDbgStmt(gz, ret_line, ret_column);
66246708 try gz.addRet(rl, operand, node);
66256709 return Zir.Inst.Ref.unreachable_value;
66266710 },
......@@ -6629,6 +6713,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66296713 if (!defer_counts.have_err) {
66306714 // Only regular defers; no branch needed.
66316715 try genDefers(gz, defer_outer, scope, .normal_only);
6716 try emitDbgStmt(gz, ret_line, ret_column);
66326717 try gz.addRet(rl, operand, node);
66336718 return Zir.Inst.Ref.unreachable_value;
66346719 }
......@@ -6642,6 +6727,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66426727 defer then_scope.unstack();
66436728
66446729 try genDefers(&then_scope, defer_outer, scope, .normal_only);
6730 try emitDbgStmt(&then_scope, ret_line, ret_column);
66456731 try then_scope.addRet(rl, operand, node);
66466732
66476733 var else_scope = gz.makeSubBlock(scope);
......@@ -6651,6 +6737,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66516737 .both = try else_scope.addUnNode(.err_union_code, result, node),
66526738 };
66536739 try genDefers(&else_scope, defer_outer, scope, which_ones);
6740 try emitDbgStmt(&else_scope, ret_line, ret_column);
66546741 try else_scope.addRet(rl, operand, node);
66556742
66566743 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);
......@@ -7553,7 +7640,6 @@ fn builtinCall(
75537640 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc),
75547641 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round),
75557642 .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),
75577643 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name),
75587644 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type),
75597645 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size),
......@@ -7568,6 +7654,31 @@ fn builtinCall(
75687654 .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate),
75697655 // 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 },
75717682 .panic => {
75727683 try emitDbgNode(gz, node);
75737684 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(
81528263 assert(callee != .none);
81538264 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
81558293 const payload_index = try addExtra(astgen, Zir.Inst.Call{
81568294 .callee = callee,
81578295 .flags = .{
......@@ -8159,22 +8297,16 @@ fn callExpr(
81598297 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
81608298 },
81618299 });
8162 var extra_index = try reserveExtra(astgen, call.ast.params.len);
8163
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;
8300 if (call.ast.params.len != 0) {
8301 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
81758302 }
8176
8177 const call_inst = try gz.addPlNodePayloadIndex(.call, node, payload_index);
8303 gz.astgen.instructions.set(call_index, .{
8304 .tag = .call,
8305 .data = .{ .pl_node = .{
8306 .src_node = gz.nodeIndexToRelative(node),
8307 .payload_index = payload_index,
8308 } },
8309 });
81788310 return rvalue(gz, rl, call_inst, node); // TODO function call with result location
81798311}
81808312
......@@ -11158,6 +11290,8 @@ const GenZir = struct {
1115811290 src_node: Ast.Node.Index,
1115911291 fields_len: u32,
1116011292 decls_len: u32,
11293 backing_int_ref: Zir.Inst.Ref,
11294 backing_int_body_len: u32,
1116111295 layout: std.builtin.Type.ContainerLayout,
1116211296 known_non_opv: bool,
1116311297 known_comptime_only: bool,
......@@ -11165,7 +11299,7 @@ const GenZir = struct {
1116511299 const astgen = gz.astgen;
1116611300 const gpa = astgen.gpa;
1116711301
11168 try astgen.extra.ensureUnusedCapacity(gpa, 4);
11302 try astgen.extra.ensureUnusedCapacity(gpa, 6);
1116911303 const payload_index = @intCast(u32, astgen.extra.items.len);
1117011304
1117111305 if (args.src_node != 0) {
......@@ -11178,6 +11312,12 @@ const GenZir = struct {
1117811312 if (args.decls_len != 0) {
1117911313 astgen.extra.appendAssumeCapacity(args.decls_len);
1118011314 }
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 }
1118111321 astgen.instructions.set(inst, .{
1118211322 .tag = .extended,
1118311323 .data = .{ .extended = .{
......@@ -11186,6 +11326,7 @@ const GenZir = struct {
1118611326 .has_src_node = args.src_node != 0,
1118711327 .has_fields_len = args.fields_len != 0,
1118811328 .has_decls_len = args.decls_len != 0,
11329 .has_backing_int = args.backing_int_ref != .none,
1118911330 .known_non_opv = args.known_non_opv,
1119011331 .known_comptime_only = args.known_comptime_only,
1119111332 .name_strategy = gz.anon_name_strategy,
......@@ -11667,3 +11808,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
1166711808 }
1166811809 return @intCast(u32, count);
1166911810}
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(
12201220 .trunc,
12211221 .round,
12221222 .tag_name,
1223 .reify,
12241223 .type_name,
12251224 .frame_type,
12261225 .frame_size,
......@@ -2079,14 +2078,19 @@ fn walkInstruction(
20792078
20802079 const args_len = extra.data.flags.args_len;
20812080 var args = try self.arena.alloc(DocData.Expr, args_len);
2082 const arg_refs = file.zir.refSlice(extra.end, args_len);
2083 for (arg_refs) |ref, idx| {
2081 const body = file.zir.extra[extra.end..];
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;
20842088 // TODO: consider toggling need_type to true if we ever want
20852089 // to show discrepancies between the types of provided
20862090 // arguments and the types declared in the function
20872091 // signature for its parameters.
20882092 const wr = try self.walkRef(file, parent_scope, ref, false);
2089 args[idx] = wr.expr;
2093 args[i] = wr.expr;
20902094 }
20912095
20922096 const cte_slot_index = self.comptime_exprs.items.len;
......@@ -2532,6 +2536,17 @@ fn walkInstruction(
25322536 break :blk decls_len;
25332537 } 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
25352550 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
25362551 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
25372552
......@@ -2605,6 +2620,7 @@ fn walkInstruction(
26052620 },
26062621 .error_to_int,
26072622 .int_to_error,
2623 .reify,
26082624 => {
26092625 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
26102626 const bin_index = self.exprs.items.len;
src/Compilation.zig+4
......@@ -1041,6 +1041,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
10411041 }
10421042 }
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
10441048 break :blk build_options.is_stage1;
10451049 };
10461050
src/Liveness.zig+2
......@@ -267,6 +267,7 @@ pub fn categorizeOperand(
267267 .byte_swap,
268268 .bit_reverse,
269269 .splat,
270 .error_set_has_value,
270271 => {
271272 const o = air_datas[inst].ty_op;
272273 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
......@@ -842,6 +843,7 @@ fn analyzeInst(
842843 .byte_swap,
843844 .bit_reverse,
844845 .splat,
846 .error_set_has_value,
845847 => {
846848 const o = inst_datas[inst].ty_op;
847849 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) = .{},
8484/// The set of all the generic function instantiations. This is used so that when a generic
8585/// function is called twice with the same comptime parameter arguments, both calls dispatch
8686/// to the same function.
87/// TODO: remove functions from this set when they are destroyed.
8887monomorphed_funcs: MonomorphedFuncsSet = .{},
8988/// The set of all comptime function calls that have been cached so that future calls
9089/// with the same parameters will get the same return value.
......@@ -92,7 +91,6 @@ memoized_calls: MemoizedCallSet = .{},
9291/// Contains the values from `@setAlignStack`. A sparse table is used here
9392/// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while
9493/// functions are many.
95/// TODO: remove functions from this set when they are destroyed.
9694align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{},
9795
9896/// We optimize memory usage for a compilation with no compile errors by storing the
......@@ -560,6 +558,8 @@ pub const Decl = struct {
560558 gpa.destroy(extern_fn);
561559 }
562560 if (decl.getFunction()) |func| {
561 _ = mod.align_stack_fns.remove(func);
562 _ = mod.monomorphed_funcs.remove(func);
563563 func.deinit(gpa);
564564 gpa.destroy(func);
565565 }
......@@ -853,8 +853,6 @@ pub const EmitH = struct {
853853pub const ErrorSet = struct {
854854 /// The Decl that corresponds to the error set itself.
855855 owner_decl: Decl.Index,
856 /// Offset from Decl node index, points to the error set AST node.
857 node_offset: i32,
858856 /// The string bytes are stored in the owner Decl arena.
859857 /// These must be in sorted order. See sortNames.
860858 names: NameMap,
......@@ -866,7 +864,7 @@ pub const ErrorSet = struct {
866864 return .{
867865 .file_scope = owner_decl.getFileScope(),
868866 .parent_decl_node = owner_decl.src_node,
869 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
867 .lazy = LazySrcLoc.nodeOffset(0),
870868 };
871869 }
872870
......@@ -893,12 +891,15 @@ pub const Struct = struct {
893891 namespace: Namespace,
894892 /// The Decl that corresponds to the struct itself.
895893 owner_decl: Decl.Index,
896 /// Offset from `owner_decl`, points to the struct AST node.
897 node_offset: i32,
898894 /// Index of the struct_decl ZIR instruction.
899895 zir_index: Zir.Inst.Index,
900896
901897 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),
902903 status: enum {
903904 none,
904905 field_types_wip,
......@@ -953,7 +954,7 @@ pub const Struct = struct {
953954 return .{
954955 .file_scope = owner_decl.getFileScope(),
955956 .parent_decl_node = owner_decl.src_node,
956 .lazy = LazySrcLoc.nodeOffset(s.node_offset),
957 .lazy = LazySrcLoc.nodeOffset(0),
957958 };
958959 }
959960
......@@ -968,7 +969,7 @@ pub const Struct = struct {
968969 });
969970 return s.srcLoc(mod);
970971 };
971 const node = owner_decl.relativeToNodeIndex(s.node_offset);
972 const node = owner_decl.relativeToNodeIndex(0);
972973 const node_tags = tree.nodes.items(.tag);
973974 switch (node_tags[node]) {
974975 .container_decl,
......@@ -1029,7 +1030,7 @@ pub const Struct = struct {
10291030
10301031 pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 {
10311032 assert(s.layout == .Packed);
1032 assert(s.haveFieldTypes());
1033 assert(s.haveLayout());
10331034 var bit_sum: u64 = 0;
10341035 for (s.fields.values()) |field, i| {
10351036 if (i == index) {
......@@ -1037,19 +1038,7 @@ pub const Struct = struct {
10371038 }
10381039 bit_sum += field.ty.bitSize(target);
10391040 }
1040 return @intCast(u16, bit_sum);
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);
1041 unreachable; // index out of bounds
10531042 }
10541043};
10551044
......@@ -1060,8 +1049,6 @@ pub const Struct = struct {
10601049pub const EnumSimple = struct {
10611050 /// The Decl that corresponds to the enum itself.
10621051 owner_decl: Decl.Index,
1063 /// Offset from `owner_decl`, points to the enum decl AST node.
1064 node_offset: i32,
10651052 /// Set of field names in declaration order.
10661053 fields: NameMap,
10671054
......@@ -1072,7 +1059,7 @@ pub const EnumSimple = struct {
10721059 return .{
10731060 .file_scope = owner_decl.getFileScope(),
10741061 .parent_decl_node = owner_decl.src_node,
1075 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1062 .lazy = LazySrcLoc.nodeOffset(0),
10761063 };
10771064 }
10781065};
......@@ -1083,8 +1070,6 @@ pub const EnumSimple = struct {
10831070pub const EnumNumbered = struct {
10841071 /// The Decl that corresponds to the enum itself.
10851072 owner_decl: Decl.Index,
1086 /// Offset from `owner_decl`, points to the enum decl AST node.
1087 node_offset: i32,
10881073 /// An integer type which is used for the numerical value of the enum.
10891074 /// Whether zig chooses this type or the user specifies it, it is stored here.
10901075 tag_ty: Type,
......@@ -1103,7 +1088,7 @@ pub const EnumNumbered = struct {
11031088 return .{
11041089 .file_scope = owner_decl.getFileScope(),
11051090 .parent_decl_node = owner_decl.src_node,
1106 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1091 .lazy = LazySrcLoc.nodeOffset(0),
11071092 };
11081093 }
11091094};
......@@ -1113,8 +1098,6 @@ pub const EnumNumbered = struct {
11131098pub const EnumFull = struct {
11141099 /// The Decl that corresponds to the enum itself.
11151100 owner_decl: Decl.Index,
1116 /// Offset from `owner_decl`, points to the enum decl AST node.
1117 node_offset: i32,
11181101 /// An integer type which is used for the numerical value of the enum.
11191102 /// Whether zig chooses this type or the user specifies it, it is stored here.
11201103 tag_ty: Type,
......@@ -1137,7 +1120,7 @@ pub const EnumFull = struct {
11371120 return .{
11381121 .file_scope = owner_decl.getFileScope(),
11391122 .parent_decl_node = owner_decl.src_node,
1140 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1123 .lazy = LazySrcLoc.nodeOffset(0),
11411124 };
11421125 }
11431126};
......@@ -1155,8 +1138,6 @@ pub const Union = struct {
11551138 namespace: Namespace,
11561139 /// The Decl that corresponds to the union itself.
11571140 owner_decl: Decl.Index,
1158 /// Offset from `owner_decl`, points to the union decl AST node.
1159 node_offset: i32,
11601141 /// Index of the union_decl ZIR instruction.
11611142 zir_index: Zir.Inst.Index,
11621143
......@@ -1203,7 +1184,7 @@ pub const Union = struct {
12031184 return .{
12041185 .file_scope = owner_decl.getFileScope(),
12051186 .parent_decl_node = owner_decl.src_node,
1206 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1187 .lazy = LazySrcLoc.nodeOffset(0),
12071188 };
12081189 }
12091190
......@@ -1218,7 +1199,7 @@ pub const Union = struct {
12181199 });
12191200 return u.srcLoc(mod);
12201201 };
1221 const node = owner_decl.relativeToNodeIndex(u.node_offset);
1202 const node = owner_decl.relativeToNodeIndex(0);
12221203 const node_tags = tree.nodes.items(.tag);
12231204 var buf: [2]Ast.Node.Index = undefined;
12241205 switch (node_tags[node]) {
......@@ -1410,8 +1391,6 @@ pub const Union = struct {
14101391pub const Opaque = struct {
14111392 /// The Decl that corresponds to the opaque itself.
14121393 owner_decl: Decl.Index,
1413 /// Offset from `owner_decl`, points to the opaque decl AST node.
1414 node_offset: i32,
14151394 /// Represents the declarations inside this opaque.
14161395 namespace: Namespace,
14171396
......@@ -1420,7 +1399,7 @@ pub const Opaque = struct {
14201399 return .{
14211400 .file_scope = owner_decl.getFileScope(),
14221401 .parent_decl_node = owner_decl.src_node,
1423 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1402 .lazy = LazySrcLoc.nodeOffset(0),
14241403 };
14251404 }
14261405
......@@ -4115,6 +4094,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
41154094 // The exports this Decl performs will be re-discovered, so we remove them here
41164095 // prior to re-analysis.
41174096 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
41184103 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
41194104 for (decl.dependencies.keys()) |dep_index| {
41204105 const dep = mod.declPtr(dep_index);
......@@ -4337,7 +4322,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
43374322 struct_obj.* = .{
43384323 .owner_decl = undefined, // set below
43394324 .fields = .{},
4340 .node_offset = 0, // it's the struct for the root file
43414325 .zir_index = undefined, // set below
43424326 .layout = .Auto,
43434327 .status = .none,
src/Sema.zig+617-170
......@@ -78,6 +78,7 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
7878err: ?*Module.ErrorMsg = null,
7979
8080const std = @import("std");
81const math = std.math;
8182const mem = std.mem;
8283const Allocator = std.mem.Allocator;
8384const assert = std.debug.assert;
......@@ -772,7 +773,6 @@ fn analyzeBodyInner(
772773 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
773774 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
774775 .optional_type => try sema.zirOptionalType(block, inst),
775 .param_type => try sema.zirParamType(block, inst),
776776 .ptr_type => try sema.zirPtrType(block, inst),
777777 .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst),
778778 .ref => try sema.zirRef(block, inst),
......@@ -816,7 +816,6 @@ fn analyzeBodyInner(
816816 .embed_file => try sema.zirEmbedFile(block, inst),
817817 .error_name => try sema.zirErrorName(block, inst),
818818 .tag_name => try sema.zirTagName(block, inst),
819 .reify => try sema.zirReify(block, inst),
820819 .type_name => try sema.zirTypeName(block, inst),
821820 .frame_type => try sema.zirFrameType(block, inst),
822821 .frame_size => try sema.zirFrameSize(block, inst),
......@@ -951,6 +950,7 @@ fn analyzeBodyInner(
951950 .select => try sema.zirSelect( block, extended),
952951 .error_to_int => try sema.zirErrorToInt( block, extended),
953952 .int_to_error => try sema.zirIntToError( block, extended),
953 .reify => try sema.zirReify( block, extended, inst),
954954 // zig fmt: on
955955 .fence => {
956956 try sema.zirFence(block, extended);
......@@ -1818,10 +1818,10 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS
18181818
18191819 const tree = try sema.getAstTree(block);
18201820 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);
18221822 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", .{});
18251825 break :msg msg;
18261826 };
18271827 return sema.failWithOwnedErrorMsg(msg);
......@@ -1866,7 +1866,7 @@ fn addFieldErrNote(
18661866 const decl_index = container_ty.getOwnerDecl();
18671867 const decl = mod.declPtr(decl_index);
18681868 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);
18701870 try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args);
18711871}
18721872
......@@ -1906,8 +1906,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
19061906 }
19071907
19081908 const mod = sema.mod;
1909 sema.err = err_msg;
1910
19111909 {
19121910 errdefer err_msg.destroy(mod.gpa);
19131911 if (err_msg.src_loc.lazy == .unneeded) {
......@@ -1925,8 +1923,10 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
19251923 const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index);
19261924 if (gop.found_existing) {
19271925 // If there are multiple errors for the same Decl, prefer the first one added.
1926 sema.err = null;
19281927 err_msg.destroy(mod.gpa);
19291928 } else {
1929 sema.err = err_msg;
19301930 gop.value_ptr.* = err_msg;
19311931 }
19321932 return error.AnalysisFail;
......@@ -2239,6 +2239,16 @@ pub fn analyzeStructDecl(
22392239 break :blk decls_len;
22402240 } 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
22422252 _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
22432253}
22442254
......@@ -2262,7 +2272,7 @@ fn zirStructDecl(
22622272 const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
22632273 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
22642274 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, .{
22662276 .ty = Type.type,
22672277 .val = struct_val,
22682278 }, small.name_strategy, "struct", inst);
......@@ -2272,7 +2282,6 @@ fn zirStructDecl(
22722282 struct_obj.* = .{
22732283 .owner_decl = new_decl_index,
22742284 .fields = .{},
2275 .node_offset = src.node_offset.x,
22762285 .zir_index = inst,
22772286 .layout = small.layout,
22782287 .status = .none,
......@@ -2294,6 +2303,7 @@ fn zirStructDecl(
22942303fn createAnonymousDeclTypeNamed(
22952304 sema: *Sema,
22962305 block: *Block,
2306 src: LazySrcLoc,
22972307 typed_value: TypedValue,
22982308 name_strategy: Zir.Inst.NameStrategy,
22992309 anon_prefix: []const u8,
......@@ -2303,7 +2313,8 @@ fn createAnonymousDeclTypeNamed(
23032313 const namespace = block.namespace;
23042314 const src_scope = block.wip_capture_scope;
23052315 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);
23072318 errdefer mod.destroyDecl(new_decl_index);
23082319
23092320 switch (name_strategy) {
......@@ -2378,7 +2389,7 @@ fn createAnonymousDeclTypeNamed(
23782389 },
23792390 else => {},
23802391 };
2381 return sema.createAnonymousDeclTypeNamed(block, typed_value, .anon, anon_prefix, null);
2392 return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null);
23822393 },
23832394 }
23842395}
......@@ -2442,7 +2453,7 @@ fn zirEnumDecl(
24422453 };
24432454 const enum_ty = Type.initPayload(&enum_ty_payload.base);
24442455 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, .{
24462457 .ty = Type.type,
24472458 .val = enum_val,
24482459 }, small.name_strategy, "enum", inst);
......@@ -2456,7 +2467,6 @@ fn zirEnumDecl(
24562467 .tag_ty_inferred = true,
24572468 .fields = .{},
24582469 .values = .{},
2459 .node_offset = src.node_offset.x,
24602470 .namespace = .{
24612471 .parent = block.namespace,
24622472 .ty = enum_ty,
......@@ -2684,7 +2694,7 @@ fn zirUnionDecl(
26842694 const union_ty = Type.initPayload(&union_payload.base);
26852695 const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
26862696 const mod = sema.mod;
2687 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
2697 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
26882698 .ty = Type.type,
26892699 .val = union_val,
26902700 }, small.name_strategy, "union", inst);
......@@ -2695,7 +2705,6 @@ fn zirUnionDecl(
26952705 .owner_decl = new_decl_index,
26962706 .tag_ty = Type.initTag(.@"null"),
26972707 .fields = .{},
2698 .node_offset = src.node_offset.x,
26992708 .zir_index = inst,
27002709 .layout = small.layout,
27012710 .status = .none,
......@@ -2753,7 +2762,7 @@ fn zirOpaqueDecl(
27532762 };
27542763 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
27552764 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, .{
27572766 .ty = Type.type,
27582767 .val = opaque_val,
27592768 }, small.name_strategy, "opaque", inst);
......@@ -2763,7 +2772,6 @@ fn zirOpaqueDecl(
27632772
27642773 opaque_obj.* = .{
27652774 .owner_decl = new_decl_index,
2766 .node_offset = src.node_offset.x,
27672775 .namespace = .{
27682776 .parent = block.namespace,
27692777 .ty = opaque_ty,
......@@ -2802,7 +2810,7 @@ fn zirErrorSetDecl(
28022810 const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);
28032811 const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty);
28042812 const mod = sema.mod;
2805 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
2813 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
28062814 .ty = Type.type,
28072815 .val = error_set_val,
28082816 }, name_strategy, "error", inst);
......@@ -2827,7 +2835,6 @@ fn zirErrorSetDecl(
28272835
28282836 error_set.* = .{
28292837 .owner_decl = new_decl_index,
2830 .node_offset = inst_data.src_node,
28312838 .names = names,
28322839 };
28332840 try new_decl.finalizeNewArena(&new_decl_arena);
......@@ -4444,43 +4451,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
44444451 return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store);
44454452}
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
44844454fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
44854455 const tracy = trace(@src());
44864456 defer tracy.end();
......@@ -5450,6 +5420,19 @@ fn lookupInNamespace(
54505420 return null;
54515421}
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
54535436fn zirCall(
54545437 sema: *Sema,
54555438 block: *Block,
......@@ -5462,13 +5445,14 @@ fn zirCall(
54625445 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
54635446 const call_src = inst_data.src();
54645447 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
54675450 const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier);
54685451 const ensure_result_used = extra.data.flags.ensure_result_used;
54695452
54705453 var func = try sema.resolveInst(extra.data.callee);
54715454 var resolved_args: []Air.Inst.Ref = undefined;
5455 var arg_index: u32 = 0;
54725456
54735457 const func_type = sema.typeOf(func);
54745458
......@@ -5479,16 +5463,93 @@ fn zirCall(
54795463 const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);
54805464 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
54815465 func = bound_data.func_inst;
5482 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len + 1);
5483 resolved_args[0] = bound_data.arg0_inst;
5484 for (args) |zir_arg, i| {
5485 resolved_args[i + 1] = try sema.resolveInst(zir_arg);
5486 }
5466 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
5467 resolved_args[arg_index] = bound_data.arg0_inst;
5468 arg_index += 1;
54875469 } else {
5488 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len);
5489 for (args) |zir_arg, i| {
5490 resolved_args[i] = try sema.resolveInst(zir_arg);
5470 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
5471 }
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;
54915497 }
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);
54925553 }
54935554
54945555 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
......@@ -5582,13 +5643,20 @@ fn analyzeCall(
55825643 const func_ty_info = func_ty.fnInfo();
55835644 const cc = func_ty_info.cc;
55845645 if (cc == .Naked) {
5585 // TODO add error note: declared here
5586 return sema.fail(
5587 block,
5588 func_src,
5589 "unable to call function with naked calling convention",
5590 .{},
5591 );
5646 const decl_src = try sema.funcDeclSrc(block, func_src, func);
5647 const msg = msg: {
5648 const msg = try sema.errMsg(
5649 block,
5650 func_src,
5651 "unable to call function with naked calling convention",
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);
55925660 }
55935661 const fn_params_len = func_ty_info.param_types.len;
55945662 if (func_ty_info.is_var_args) {
......@@ -5967,7 +6035,18 @@ fn analyzeCall(
59676035 else => |e| return e,
59686036 };
59696037 } 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 };
59716050 }
59726051 }
59736052
......@@ -6272,6 +6351,7 @@ fn instantiateGenericCall(
62726351 new_decl.is_exported = fn_owner_decl.is_exported;
62736352 new_decl.has_align = fn_owner_decl.has_align;
62746353 new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace;
6354 new_decl.@"linksection" = fn_owner_decl.@"linksection";
62756355 new_decl.@"addrspace" = fn_owner_decl.@"addrspace";
62766356 new_decl.zir_decl_index = fn_owner_decl.zir_decl_index;
62776357 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
67246804 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
67256805 const uncasted_operand = try sema.resolveInst(extra.operand);
67266806 const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src);
6727 const result_ty = Type.u16;
67286807
67296808 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
67306809 if (val.isUndef()) {
6731 return sema.addConstUndef(result_ty);
6810 return sema.addConstUndef(Type.err_int);
67326811 }
67336812 switch (val.tag()) {
67346813 .@"error" => {
......@@ -6737,14 +6816,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
67376816 .base = .{ .tag = .int_u64 },
67386817 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
67396818 };
6740 return sema.addConstant(result_ty, Value.initPayload(&payload.base));
6819 return sema.addConstant(Type.err_int, Value.initPayload(&payload.base));
67416820 },
67426821
67436822 // This is not a valid combination with the type `anyerror`.
67446823 .the_only_possible_value => unreachable,
67456824
67466825 // 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),
67486827 }
67496828 }
67506829
......@@ -6753,14 +6832,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
67536832 if (!op_ty.isAnyError()) {
67546833 const names = op_ty.errorSetNames();
67556834 switch (names.len) {
6756 0 => return sema.addConstant(result_ty, Value.zero),
6757 1 => return sema.addIntUnsigned(result_ty, sema.mod.global_error_set.get(names[0]).?),
6835 0 => return sema.addConstant(Type.err_int, Value.zero),
6836 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?),
67586837 else => {},
67596838 }
67606839 }
67616840
67626841 try sema.requireRuntimeBlock(block, src, operand_src);
6763 return block.addBitCast(result_ty, operand);
6842 return block.addBitCast(Type.err_int, operand);
67646843}
67656844
67666845fn 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
67716850 const src = LazySrcLoc.nodeOffset(extra.node);
67726851 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
67736852 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);
67756854 const target = sema.mod.getTarget();
67766855
67776856 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
......@@ -6788,7 +6867,10 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
67886867 try sema.requireRuntimeBlock(block, src, operand_src);
67896868 if (block.wantSafety()) {
67906869 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);
67926874 }
67936875 return block.addInst(.{
67946876 .tag = .bitcast,
......@@ -10201,16 +10283,14 @@ fn zirShl(
1020110283
1020210284 const val = switch (air_tag) {
1020310285 .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);
1020510287 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
10206 break :val shifted;
10288 break :val shifted.wrapped_result;
1020710289 }
10208 const int_info = scalar_ty.intInfo(target);
10209 const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits, target);
10210 if (try sema.compare(block, src, truncated, .eq, shifted, lhs_ty)) {
10211 break :val shifted;
10290 if (shifted.overflowed.compareWithZero(.eq)) {
10291 break :val shifted.wrapped_result;
1021210292 }
10213 return sema.addConstUndef(lhs_ty);
10293 return sema.fail(block, src, "operation caused overflow", .{});
1021410294 },
1021510295
1021610296 .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
......@@ -10363,7 +10443,7 @@ fn zirShr(
1036310443 // Detect if any ones would be shifted out.
1036410444 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);
1036510445 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", .{});
1036710447 }
1036810448 }
1036910449 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
1118311263 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
1118411264 }
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) {
1118711272 .Optimized => Air.Inst.Tag.div_float_optimized,
1118811273 .Strict => Air.Inst.Tag.div_float,
1118911274 };
......@@ -11263,13 +11348,19 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1126311348 if (maybe_lhs_val) |lhs_val| {
1126411349 if (maybe_rhs_val) |rhs_val| {
1126511350 if (is_int) {
11266 // TODO: emit compile error if there is a remainder
11351 const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target);
11352 if (modulus_val.compareWithZero(.neq)) {
11353 return sema.fail(block, src, "exact division produced remainder", .{});
11354 }
1126711355 return sema.addConstant(
1126811356 resolved_type,
1126911357 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),
1127011358 );
1127111359 } else {
11272 // TODO: emit compile error if there is a remainder
11360 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target);
11361 if (modulus_val.compareWithZero(.neq)) {
11362 return sema.fail(block, src, "exact division produced remainder", .{});
11363 }
1127311364 return sema.addConstant(
1127411365 resolved_type,
1127511366 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.
1175611847 return sema.failWithDivideByZero(block, rhs_src);
1175711848 }
1175811849 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);
1176011851 // If this answer could possibly be different by doing `intMod`,
1176111852 // we must emit a compile error. Otherwise, it's OK.
1176211853 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.
1181811909 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
1181911910}
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
1182111966fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1182211967 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1182311968 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
1198212127 if (maybe_lhs_val) |lhs_val| {
1198312128 return sema.addConstant(
1198412129 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),
1198612131 );
1198712132 }
1198812133 break :rs lhs_src;
......@@ -14162,13 +14307,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1416214307
1416314308 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);
1416614323 field_values.* = .{
1416714324 // layout: ContainerLayout,
1416814325 try Value.Tag.enum_field_index.create(
1416914326 sema.arena,
1417014327 @enumToInt(layout),
1417114328 ),
14329 // backing_integer: ?type,
14330 backing_integer_val,
1417214331 // fields: []const StructField,
1417314332 fields_val,
1417414333 // decls: []const Declaration,
......@@ -14492,6 +14651,20 @@ fn zirBoolBr(
1449214651 const rhs_result = try sema.resolveBody(rhs_block, body, inst);
1449314652 _ = 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
1449514668 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
1449614669 then_block.instructions.items.len + else_block.instructions.items.len +
1449714670 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);
......@@ -14504,7 +14677,7 @@ fn zirBoolBr(
1450414677 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
1450514678
1450614679 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
14507 .operand = lhs,
14680 .operand = cond,
1450814681 .payload = cond_br_payload,
1450914682 } } });
1451014683
......@@ -14874,10 +15047,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
1487415047 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
1487515048 return sema.analyzeRet(block, operand, src);
1487615049 }
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
1487715056 _ = try block.addUnOp(.ret_load, ret_ptr);
1487815057 return always_noreturn;
1487915058}
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
1488115127fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
1488215128 assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
1488315129
......@@ -14923,27 +15169,15 @@ fn analyzeRet(
1492315169 return always_noreturn;
1492415170 }
1492515171
14926 // TODO implement this feature in all the backends and then delete this check.
14927 const backend_supports_error_return_tracing =
14928 sema.mod.comp.bin_file.options.use_llvm;
15172 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
1492915173
14930 if (sema.fn_ret_ty.isError() and
14931 sema.mod.comp.bin_file.options.error_return_tracing and
14932 backend_supports_error_return_tracing)
14933 ret_err: {
14934 if (try sema.resolveMaybeUndefVal(block, src, operand)) |ret_val| {
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);
15174 if (sema.wantErrorReturnTracing()) {
15175 // Avoid adding a frame to the error return trace in case the value is comptime-known
15176 // to be not an error.
15177 const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
15178 return retWithErrTracing(sema, block, src, is_non_err, .ret, operand);
1494415179 }
1494515180
14946 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
1494715181 _ = try block.addUnOp(.ret, operand);
1494815182 return always_noreturn;
1494915183}
......@@ -16023,13 +16257,14 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1602316257 return block.addUnOp(.tag_name, casted_operand);
1602416258}
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 {
1602716261 const mod = sema.mod;
16028 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16029 const src = inst_data.src();
16262 const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small);
16263 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
16264 const src = LazySrcLoc.nodeOffset(extra.node);
1603016265 const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type");
16031 const uncasted_operand = try sema.resolveInst(inst_data.operand);
16032 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
16266 const uncasted_operand = try sema.resolveInst(extra.operand);
16267 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
1603316268 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
1603416269 const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known");
1603516270 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
1610916344 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
1611016345 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
1611116346 }
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
1611416349 var buffer: Value.ToTypeBuffer = undefined;
1611516350 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
1627416509 const struct_val = union_val.val.castTag(.aggregate).?.data;
1627516510 // layout: containerlayout,
1627616511 const layout_val = struct_val[0];
16512 // backing_int: ?type,
16513 const backing_int_val = struct_val[1];
1627716514 // fields: []const enumfield,
16278 const fields_val = struct_val[1];
16515 const fields_val = struct_val[2];
1627916516 // decls: []const declaration,
16280 const decls_val = struct_val[2];
16517 const decls_val = struct_val[3];
1628116518 // 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
1628416524 // Decls
1628516525 if (decls_val.sliceLen(mod) > 0) {
1628616526 return sema.fail(block, src, "reified structs must have no decls", .{});
1628716527 }
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
1628916533 return if (is_tuple_val.toBool())
1629016534 try sema.reifyTuple(block, src, fields_val)
1629116535 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);
1629316537 },
1629416538 .Enum => {
1629516539 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
1633516579 };
1633616580 const enum_ty = Type.initPayload(&enum_ty_payload.base);
1633716581 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, .{
1633916583 .ty = Type.type,
1634016584 .val = enum_val,
16341 }, .anon, "enum", null);
16585 }, name_strategy, "enum", inst);
1634216586 const new_decl = mod.declPtr(new_decl_index);
1634316587 new_decl.owns_tv = true;
1634416588 errdefer mod.abortAnonDecl(new_decl_index);
......@@ -16349,7 +16593,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1634916593 .tag_ty_inferred = false,
1635016594 .fields = .{},
1635116595 .values = .{},
16352 .node_offset = src.node_offset.x,
1635316596 .namespace = .{
1635416597 .parent = block.namespace,
1635516598 .ty = enum_ty,
......@@ -16432,17 +16675,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1643216675 };
1643316676 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
1643416677 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, .{
1643616679 .ty = Type.type,
1643716680 .val = opaque_val,
16438 }, .anon, "opaque", null);
16681 }, name_strategy, "opaque", inst);
1643916682 const new_decl = mod.declPtr(new_decl_index);
1644016683 new_decl.owns_tv = true;
1644116684 errdefer mod.abortAnonDecl(new_decl_index);
1644216685
1644316686 opaque_obj.* = .{
1644416687 .owner_decl = new_decl_index,
16445 .node_offset = src.node_offset.x,
1644616688 .namespace = .{
1644716689 .parent = block.namespace,
1644816690 .ty = opaque_ty,
......@@ -16491,10 +16733,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1649116733 };
1649216734 const union_ty = Type.initPayload(&union_payload.base);
1649316735 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, .{
1649516737 .ty = Type.type,
1649616738 .val = new_union_val,
16497 }, .anon, "union", null);
16739 }, name_strategy, "union", inst);
1649816740 const new_decl = mod.declPtr(new_decl_index);
1649916741 new_decl.owns_tv = true;
1650016742 errdefer mod.abortAnonDecl(new_decl_index);
......@@ -16502,7 +16744,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1650216744 .owner_decl = new_decl_index,
1650316745 .tag_ty = Type.initTag(.@"null"),
1650416746 .fields = .{},
16505 .node_offset = src.node_offset.x,
1650616747 .zir_index = inst,
1650716748 .layout = layout,
1650816749 .status = .have_field_types,
......@@ -16785,8 +17026,10 @@ fn reifyStruct(
1678517026 block: *Block,
1678617027 inst: Zir.Inst.Index,
1678717028 src: LazySrcLoc,
16788 layout_val: Value,
17029 layout: std.builtin.Type.ContainerLayout,
17030 backing_int_val: Value,
1678917031 fields_val: Value,
17032 name_strategy: Zir.Inst.NameStrategy,
1679017033) CompileError!Air.Inst.Ref {
1679117034 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
1679217035 errdefer new_decl_arena.deinit();
......@@ -16796,19 +17039,18 @@ fn reifyStruct(
1679617039 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
1679717040 const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
1679817041 const mod = sema.mod;
16799 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
17042 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
1680017043 .ty = Type.type,
1680117044 .val = new_struct_val,
16802 }, .anon, "struct", null);
17045 }, name_strategy, "struct", inst);
1680317046 const new_decl = mod.declPtr(new_decl_index);
1680417047 new_decl.owns_tv = true;
1680517048 errdefer mod.abortAnonDecl(new_decl_index);
1680617049 struct_obj.* = .{
1680717050 .owner_decl = new_decl_index,
1680817051 .fields = .{},
16809 .node_offset = src.node_offset.x,
1681017052 .zir_index = inst,
16811 .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout),
17053 .layout = layout,
1681217054 .status = .have_field_types,
1681317055 .known_non_opv = false,
1681417056 .namespace = .{
......@@ -16874,6 +17116,41 @@ fn reifyStruct(
1687417116 };
1687517117 }
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
1687717154 try new_decl.finalizeNewArena(&new_decl_arena);
1687817155 return sema.analyzeDeclVal(block, src, new_decl_index);
1687917156}
......@@ -17095,17 +17372,10 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1709517372 }
1709617373
1709717374 try sema.requireRuntimeBlock(block, src, operand_src);
17098 if (block.wantSafety() and !dest_ty.isAnyError()) {
17099 const err_int_inst = try block.addBitCast(Type.u16, operand);
17100 // TODO: Output a switch instead of chained OR's.
17101 var found_match: Air.Inst.Ref = undefined;
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);
17375 if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) {
17376 const err_int_inst = try block.addBitCast(Type.err_int, operand);
17377 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
17378 try sema.addSafetyCheck(block, ok, .invalid_error_code);
1710917379 }
1711017380 return block.addBitCast(dest_ty, operand);
1711117381}
......@@ -17133,6 +17403,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1713317403 else
1713417404 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
1713617415 const dest_elem_ty = dest_ty.elemType2();
1713717416 try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);
1713817417 const dest_align = dest_ty.ptrAlignment(target);
......@@ -23464,7 +23743,10 @@ fn coerceVarArgParam(
2346423743 inst_src: LazySrcLoc,
2346523744) !Air.Inst.Ref {
2346623745 const inst_ty = sema.typeOf(inst);
23746 if (block.is_typeof) return inst;
23747
2346723748 switch (inst_ty.zigTypeTag()) {
23749 // TODO consider casting to c_int/f64 if they fit
2346823750 .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}),
2346923751 else => {},
2347023752 }
......@@ -23846,7 +24128,10 @@ fn beginComptimePtrMutation(
2384624128 const array_len_including_sentinel =
2384724129 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
2384824130 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
2385124136 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
2385224137
......@@ -25423,6 +25708,27 @@ fn analyzeIsNull(
2542325708 return block.addUnOp(air_tag, operand);
2542425709}
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
2542625732fn analyzeIsNonErrComptimeOnly(
2542725733 sema: *Sema,
2542825734 block: *Block,
......@@ -25436,10 +25742,16 @@ fn analyzeIsNonErrComptimeOnly(
2543625742 assert(ot == .ErrorUnion);
2543725743
2543825744 if (Air.refToIndex(operand)) |operand_inst| {
25439 const air_tags = sema.air_instructions.items(.tag);
25440 if (air_tags[operand_inst] == .wrap_errunion_payload) {
25441 return Air.Inst.Ref.bool_true;
25745 switch (sema.air_instructions.items(.tag)[operand_inst]) {
25746 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
25747 .wrap_errunion_err => return Air.Inst.Ref.bool_false,
25748 else => {},
2544225749 }
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;
2544325755 }
2544425756
2544525757 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand);
......@@ -25515,6 +25827,21 @@ fn analyzeIsNonErr(
2551525827 }
2551625828}
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
2551825845fn analyzeSlice(
2551925846 sema: *Sema,
2552025847 block: *Block,
......@@ -26913,6 +27240,11 @@ fn resolveStructLayout(
2691327240 else => return err,
2691427241 };
2691527242 }
27243
27244 if (struct_obj.layout == .Packed) {
27245 try semaBackingIntType(sema.mod, struct_obj);
27246 }
27247
2691627248 struct_obj.status = .have_layout;
2691727249
2691827250 // In case of querying the ABI alignment of this struct, we will ask
......@@ -26932,6 +27264,109 @@ fn resolveStructLayout(
2693227264 // otherwise it's a tuple; no need to resolve anything
2693327265}
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
2693527370fn resolveUnionLayout(
2693627371 sema: *Sema,
2693727372 block: *Block,
......@@ -27239,7 +27674,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2723927674 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
2724027675 var extra_index: usize = extended.operand;
2724127676
27242 const src = LazySrcLoc.nodeOffset(struct_obj.node_offset);
27677 const src = LazySrcLoc.nodeOffset(0);
2724327678 extra_index += @boolToInt(small.has_src_node);
2724427679
2724527680 const fields_len = if (small.has_fields_len) blk: {
......@@ -27254,12 +27689,26 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2725427689 break :decls_len decls_len;
2725527690 } 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
2725727703 // Skip over decls.
2725827704 var decls_it = zir.declIteratorInner(extra_index, decls_len);
2725927705 while (decls_it.next()) |_| {}
2726027706 extra_index = decls_it.extra_index;
2726127707
2726227708 if (fields_len == 0) {
27709 if (struct_obj.layout == .Packed) {
27710 try semaBackingIntType(mod, struct_obj);
27711 }
2726327712 struct_obj.status = .have_layout;
2726427713 return;
2726527714 }
......@@ -27358,12 +27807,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2735827807 if (gop.found_existing) {
2735927808 const msg = msg: {
2736027809 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);
2736227811 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
2736327812 errdefer msg.destroy(gpa);
2736427813
2736527814 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);
2736727816 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
2736827817 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
2736927818 break :msg msg;
......@@ -27420,7 +27869,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2742027869 if (field_ty.zigTypeTag() == .Opaque) {
2742127870 const msg = msg: {
2742227871 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);
2742427873 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
2742527874 errdefer msg.destroy(sema.gpa);
2742627875
......@@ -27432,7 +27881,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2743227881 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
2743327882 const msg = msg: {
2743427883 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);
2743627885 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
2743727886 errdefer msg.destroy(sema.gpa);
2743827887
......@@ -27445,7 +27894,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2744527894 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) {
2744627895 const msg = msg: {
2744727896 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);
2744927898 const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
2745027899 errdefer msg.destroy(sema.gpa);
2745127900
......@@ -27502,7 +27951,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2750227951 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
2750327952 var extra_index: usize = extended.operand;
2750427953
27505 const src = LazySrcLoc.nodeOffset(union_obj.node_offset);
27954 const src = LazySrcLoc.nodeOffset(0);
2750627955 extra_index += @boolToInt(small.has_src_node);
2750727956
2750827957 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 {
2772628175 if (gop.found_existing) {
2772728176 const msg = msg: {
2772828177 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);
2773028179 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
2773128180 errdefer msg.destroy(gpa);
2773228181
2773328182 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);
2773528184 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
2773628185 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
2773728186 break :msg msg;
......@@ -27744,7 +28193,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2774428193 if (!enum_has_field) {
2774528194 const msg = msg: {
2774628195 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);
2774828197 const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
2774928198 errdefer msg.destroy(sema.gpa);
2775028199 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
......@@ -27757,7 +28206,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2775728206 if (field_ty.zigTypeTag() == .Opaque) {
2775828207 const msg = msg: {
2775928208 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);
2776128210 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
2776228211 errdefer msg.destroy(sema.gpa);
2776328212
......@@ -27769,7 +28218,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2776928218 if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) {
2777028219 const msg = msg: {
2777128220 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);
2777328222 const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2777428223 errdefer msg.destroy(sema.gpa);
2777528224
......@@ -27782,7 +28231,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2778228231 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {
2778328232 const msg = msg: {
2778428233 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);
2778628235 const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2778728236 errdefer msg.destroy(sema.gpa);
2778828237
......@@ -27874,7 +28323,6 @@ fn generateUnionTagTypeNumbered(
2787428323 .tag_ty = int_ty,
2787528324 .fields = .{},
2787628325 .values = .{},
27877 .node_offset = 0,
2787828326 };
2787928327 // Here we pre-allocate the maps using the decl arena.
2788028328 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
2793228380 enum_obj.* = .{
2793328381 .owner_decl = new_decl_index,
2793428382 .fields = .{},
27935 .node_offset = 0,
2793628383 };
2793728384 // Here we pre-allocate the maps using the decl arena.
2793828385 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
......@@ -28243,7 +28690,7 @@ fn enumFieldSrcLoc(
2824328690 => tree.containerDeclArg(enum_node),
2824428691
2824528692 // Container was constructed with `@Type`.
28246 else => return LazySrcLoc.nodeOffset(node_offset),
28693 else => return LazySrcLoc.nodeOffset(0),
2824728694 };
2824828695 var it_index: usize = 0;
2824928696 for (container_decl.ast.members) |member_node| {
src/Zir.zig+27-28
......@@ -490,14 +490,6 @@ pub const Inst = struct {
490490 /// Merge two error sets into one, `E1 || E2`.
491491 /// Uses the `pl_node` field with payload `Bin`.
492492 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,
501493 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
502494 /// stores it in a memory location, and returns a const pointer to it. If the value
503495 /// is `comptime`, the memory location is global static constant data. Otherwise,
......@@ -839,8 +831,6 @@ pub const Inst = struct {
839831 round,
840832 /// Implement builtin `@tagName`. Uses `un_node`.
841833 tag_name,
842 /// Implement builtin `@Type`. Uses `un_node`.
843 reify,
844834 /// Implement builtin `@typeName`. Uses `un_node`.
845835 type_name,
846836 /// Implement builtin `@Frame`. Uses `un_node`.
......@@ -1097,7 +1087,6 @@ pub const Inst = struct {
10971087 .mul,
10981088 .mulwrap,
10991089 .mul_sat,
1100 .param_type,
11011090 .ref,
11021091 .shl,
11031092 .shl_sat,
......@@ -1197,7 +1186,6 @@ pub const Inst = struct {
11971186 .trunc,
11981187 .round,
11991188 .tag_name,
1200 .reify,
12011189 .type_name,
12021190 .frame_type,
12031191 .frame_size,
......@@ -1400,7 +1388,6 @@ pub const Inst = struct {
14001388 .mul,
14011389 .mulwrap,
14021390 .mul_sat,
1403 .param_type,
14041391 .ref,
14051392 .shl,
14061393 .shl_sat,
......@@ -1484,7 +1471,6 @@ pub const Inst = struct {
14841471 .trunc,
14851472 .round,
14861473 .tag_name,
1487 .reify,
14881474 .type_name,
14891475 .frame_type,
14901476 .frame_size,
......@@ -1573,7 +1559,6 @@ pub const Inst = struct {
15731559 .mulwrap = .pl_node,
15741560 .mul_sat = .pl_node,
15751561
1576 .param_type = .param_type,
15771562 .param = .pl_tok,
15781563 .param_comptime = .pl_tok,
15791564 .param_anytype = .str_tok,
......@@ -1759,7 +1744,6 @@ pub const Inst = struct {
17591744 .trunc = .un_node,
17601745 .round = .un_node,
17611746 .tag_name = .un_node,
1762 .reify = .un_node,
17631747 .type_name = .un_node,
17641748 .frame_type = .un_node,
17651749 .frame_size = .un_node,
......@@ -1980,6 +1964,10 @@ pub const Inst = struct {
19801964 /// Implement builtin `@intToError`.
19811965 /// `operand` is payload index to `UnNode`.
19821966 int_to_error,
1967 /// Implement builtin `@Type`.
1968 /// `operand` is payload index to `UnNode`.
1969 /// `small` contains `NameStrategy
1970 reify,
19831971
19841972 pub const InstData = struct {
19851973 opcode: Extended,
......@@ -2541,10 +2529,6 @@ pub const Inst = struct {
25412529 /// Points to a `Block`.
25422530 payload_index: u32,
25432531 },
2544 param_type: struct {
2545 callee: Ref,
2546 param_index: u32,
2547 },
25482532 @"unreachable": struct {
25492533 /// Offset from Decl AST node index.
25502534 /// `Tag` determines which kind of AST node this points to.
......@@ -2615,7 +2599,6 @@ pub const Inst = struct {
26152599 ptr_type,
26162600 int_type,
26172601 bool_br,
2618 param_type,
26192602 @"unreachable",
26202603 @"break",
26212604 switch_capture,
......@@ -2795,7 +2778,9 @@ pub const Inst = struct {
27952778 };
27962779
27972780 /// 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
27992784 pub const Call = struct {
28002785 // Note: Flags *must* come first so that unusedResultExpr
28012786 // can find it when it goes to modify them.
......@@ -3100,13 +3085,16 @@ pub const Inst = struct {
31003085 /// 0. src_node: i32, // if has_src_node
31013086 /// 1. fields_len: u32, // if has_fields_len
31023087 /// 2. decls_len: u32, // if has_decls_len
3103 /// 3. decl_bits: u32 // for every 8 decls
3088 /// 3. backing_int_body_len: u32, // if has_backing_int
3089 /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3090 /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3091 /// 6. decl_bits: u32 // for every 8 decls
31043092 /// - sets of 4 bits:
31053093 /// 0b000X: whether corresponding decl is pub
31063094 /// 0b00X0: whether corresponding decl is exported
31073095 /// 0b0X00: whether corresponding decl has an align expression
31083096 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3109 /// 4. decl: { // for every decls_len
3097 /// 7. decl: { // for every decls_len
31103098 /// src_hash: [4]u32, // hash of source bytes
31113099 /// line: u32, // line number of decl, relative to parent
31123100 /// name: u32, // null terminated string index
......@@ -3124,13 +3112,13 @@ pub const Inst = struct {
31243112 /// address_space: Ref,
31253113 /// }
31263114 /// }
3127 /// 5. flags: u32 // for every 8 fields
3115 /// 8. flags: u32 // for every 8 fields
31283116 /// - sets of 4 bits:
31293117 /// 0b000X: whether corresponding field has an align expression
31303118 /// 0b00X0: whether corresponding field has a default expression
31313119 /// 0b0X00: whether corresponding field is comptime
31323120 /// 0bX000: whether corresponding field has a type expression
3133 /// 6. fields: { // for every fields_len
3121 /// 9. fields: { // for every fields_len
31343122 /// field_name: u32,
31353123 /// doc_comment: u32, // 0 if no doc comment
31363124 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
......@@ -3138,7 +3126,7 @@ pub const Inst = struct {
31383126 /// align_body_len: u32, // if corresponding bit is set
31393127 /// init_body_len: u32, // if corresponding bit is set
31403128 /// }
3141 /// 7. bodies: { // for every fields_len
3129 /// 10. bodies: { // for every fields_len
31423130 /// field_type_body_inst: Inst, // for each field_type_body_len
31433131 /// align_body_inst: Inst, // for each align_body_len
31443132 /// init_body_inst: Inst, // for each init_body_len
......@@ -3148,11 +3136,12 @@ pub const Inst = struct {
31483136 has_src_node: bool,
31493137 has_fields_len: bool,
31503138 has_decls_len: bool,
3139 has_backing_int: bool,
31513140 known_non_opv: bool,
31523141 known_comptime_only: bool,
31533142 name_strategy: NameStrategy,
31543143 layout: std.builtin.Type.ContainerLayout,
3155 _: u7 = undefined,
3144 _: u6 = undefined,
31563145 };
31573146 };
31583147
......@@ -3619,6 +3608,16 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
36193608 break :decls_len decls_len;
36203609 } 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
36223621 return declIteratorInner(zir, extra_index, decls_len);
36233622 },
36243623 .enum_decl => {
src/arch/aarch64/CodeGen.zig+1
......@@ -778,6 +778,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
778778 => return self.fail("TODO implement optimized float mode", .{}),
779779
780780 .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
782783 .wasm_memory_size => unreachable,
783784 .wasm_memory_grow => unreachable,
src/arch/arm/CodeGen.zig+165-30
......@@ -247,6 +247,31 @@ const BigTomb = struct {
247247 log.debug("%{d} => {}", .{ bt.inst, result });
248248 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
249249 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 }
250275 }
251276 bt.function.finishAirBookkeeping();
252277 }
......@@ -332,7 +357,7 @@ pub fn generate(
332357 };
333358
334359 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);
336361 }
337362
338363 var mir = Mir{
......@@ -351,7 +376,8 @@ pub fn generate(
351376 .prev_di_pc = 0,
352377 .prev_di_line = module_fn.lbrace_line,
353378 .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,
355381 };
356382 defer emit.deinit();
357383
......@@ -464,6 +490,7 @@ fn gen(self: *Self) !void {
464490 const total_stack_size = self.max_end_stack + self.saved_regs_stack_space;
465491 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
466492 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;
493 self.max_end_stack = stack_size;
467494 if (Instruction.Operand.fromU32(stack_size)) |op| {
468495 self.mir_instructions.set(sub_reloc, .{
469496 .tag = .sub,
......@@ -769,6 +796,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
769796 => return self.fail("TODO implement optimized float mode", .{}),
770797
771798 .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
773801 .wasm_memory_size => unreachable,
774802 .wasm_memory_grow => unreachable,
......@@ -1812,7 +1840,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
18121840 switch (error_union_mcv) {
18131841 .register => return self.fail("TODO errUnionErr for registers", .{}),
18141842 .stack_argument_offset => |off| {
1815 return MCValue{ .stack_argument_offset = off - err_offset };
1843 return MCValue{ .stack_argument_offset = off + err_offset };
18161844 },
18171845 .stack_offset => |off| {
18181846 return MCValue{ .stack_offset = off - err_offset };
......@@ -1849,7 +1877,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
18491877 switch (error_union_mcv) {
18501878 .register => return self.fail("TODO errUnionPayload for registers", .{}),
18511879 .stack_argument_offset => |off| {
1852 return MCValue{ .stack_argument_offset = off - payload_offset };
1880 return MCValue{ .stack_argument_offset = off + payload_offset };
18531881 },
18541882 .stack_offset => |off| {
18551883 return MCValue{ .stack_offset = off - payload_offset };
......@@ -1983,7 +2011,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
19832011 .dead, .unreach => unreachable,
19842012 .register => unreachable, // a slice doesn't fit in one register
19852013 .stack_argument_offset => |off| {
1986 break :result MCValue{ .stack_argument_offset = off - 4 };
2014 break :result MCValue{ .stack_argument_offset = off + 4 };
19872015 },
19882016 .stack_offset => |off| {
19892017 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
22592287 .register_c_flag,
22602288 .register_v_flag,
22612289 => unreachable, // cannot hold an address
2262 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
2263 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
2290 .immediate => |imm| {
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 },
22642296 .register => |reg| {
22652297 const reg_lock = self.register_manager.lockReg(reg);
22662298 defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
22672299
22682300 switch (dst_mcv) {
2269 .dead => unreachable,
2270 .undef => unreachable,
2271 .cpsr_flags => unreachable,
22722301 .register => |dst_reg| {
22732302 try self.genLdrRegister(dst_reg, reg, elem_ty);
22742303 },
......@@ -2304,7 +2333,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
23042333 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
23052334 }
23062335 },
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
23082337 }
23092338 },
23102339 .memory,
......@@ -2401,7 +2430,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
24012430 // sub src_reg, fp, #off
24022431 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
24032432 },
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) }),
24052434 .stack_argument_offset => |off| {
24062435 _ = try self.addInst(.{
24072436 .tag = .ldr_ptr_stack_argument,
......@@ -2507,7 +2536,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
25072536 switch (mcv) {
25082537 .dead, .unreach => unreachable,
25092538 .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 };
25112540 },
25122541 .stack_offset => |off| {
25132542 break :result MCValue{ .stack_offset = off - struct_field_offset };
......@@ -3347,6 +3376,102 @@ fn genInlineMemcpy(
33473376 // end:
33483377}
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
33503475/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
33513476/// after codegen for this symbol is done.
33523477fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
......@@ -3369,9 +3494,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
33693494 }
33703495}
33713496
3372fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void {
3373 const prologue_stack_space = stack_byte_count + self.saved_regs_stack_space;
3374
3497fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
33753498 const mcv = self.args[arg_index];
33763499 const ty = self.air.instructions.items(.data)[inst].ty;
33773500 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
34043527 // const abi_size = @intCast(u32, ty.abiSize(self.target.*));
34053528 const adjusted_stack_offset = switch (mcv) {
34063529 .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),
34083531 else => unreachable,
34093532 };
34103533
......@@ -3524,7 +3647,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35243647 try self.register_manager.getReg(reg, null);
35253648 }
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: {
35283654 log.debug("airCall: return by reference", .{});
35293655 const ret_ty = fn_ty.fnReturnType();
35303656 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.
35403666 try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset });
35413667
35423668 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
35453674 // Make space for the arguments passed via the stack
35463675 self.max_end_stack += info.stack_byte_count;
......@@ -3559,7 +3688,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35593688 .stack_offset => unreachable,
35603689 .stack_argument_offset => |offset| try self.genSetStackArgument(
35613690 arg_ty,
3562 info.stack_byte_count - offset,
3691 offset,
35633692 arg_mcv,
35643693 ),
35653694 else => unreachable,
......@@ -4621,11 +4750,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
46214750 if (!self.wantSafety())
46224751 return; // The already existing value will do just fine.
46234752 // TODO Upgrade this to a memset call when we have that available.
4624 switch (ty.abiSize(self.target.*)) {
4625 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4626 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4627 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4628 else => return self.fail("TODO implement memset", .{}),
4753 switch (abi_size) {
4754 1 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4755 2 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4756 4 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4757 else => try self.genInlineMemset(
4758 .{ .ptr_stack_offset = stack_offset },
4759 .{ .immediate = 0xaa },
4760 .{ .immediate = abi_size },
4761 ),
46294762 }
46304763 },
46314764 .cpsr_flags,
......@@ -5037,9 +5170,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
50375170 return; // The already existing value will do just fine.
50385171 // TODO Upgrade this to a memset call when we have that available.
50395172 switch (abi_size) {
5040 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
5041 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
5042 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
5173 1 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
5174 2 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
5175 4 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
50435176 else => return self.fail("TODO implement memset", .{}),
50445177 }
50455178 },
......@@ -5653,8 +5786,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
56535786 if (ty.abiAlignment(self.target.*) == 8)
56545787 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);
56555788
5656 nsaa += param_size;
56575789 result.args[i] = .{ .stack_argument_offset = nsaa };
5790 nsaa += param_size;
56585791 }
56595792 }
56605793
......@@ -5687,9 +5820,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
56875820 for (param_types) |ty, i| {
56885821 if (ty.abiSize(self.target.*) > 0) {
56895822 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);
56925826 result.args[i] = .{ .stack_argument_offset = stack_offset };
5827 stack_offset += param_size;
56935828 } else {
56945829 result.args[i] = .{ .none = {} };
56955830 }
src/arch/arm/Emit.zig+19-38
......@@ -33,9 +33,13 @@ prev_di_column: u32,
3333/// Relative to the beginning of `code`.
3434prev_di_pc: usize,
3535
36/// The amount of stack space consumed by all stack arguments as well
37/// as the saved callee-saved registers
38prologue_stack_space: u32,
36/// The amount of stack space consumed by the saved callee-saved
37/// registers in bytes
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
4044/// The branch type of every branch
4145branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},
......@@ -500,14 +504,15 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
500504 const tag = emit.mir.instructions.items(.tag)[inst];
501505 const cond = emit.mir.instructions.items(.cond)[inst];
502506 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;
505510 switch (tag) {
506511 .ldr_ptr_stack_argument => {
507512 const operand = Instruction.Operand.fromU32(raw_offset) orelse
508513 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));
511516 },
512517 .ldr_stack_argument,
513518 .ldrb_stack_argument,
......@@ -516,23 +521,11 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
516521 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
517522 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
518523
519 const ldr = switch (tag) {
520 .ldr_stack_argument => &Instruction.ldr,
521 .ldrb_stack_argument => &Instruction.ldrb,
524 switch (tag) {
525 .ldr_stack_argument => try emit.writeInstruction(Instruction.ldr(cond, rt, .sp, .{ .offset = offset })),
526 .ldrb_stack_argument => try emit.writeInstruction(Instruction.ldrb(cond, rt, .sp, .{ .offset = offset })),
522527 else => unreachable,
523 };
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 ));
528 }
536529 },
537530 .ldrh_stack_argument,
538531 .ldrsb_stack_argument,
......@@ -542,24 +535,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
542535 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
543536 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
544537
545 const ldr = switch (tag) {
546 .ldrh_stack_argument => &Instruction.ldrh,
547 .ldrsb_stack_argument => &Instruction.ldrsb,
548 .ldrsh_stack_argument => &Instruction.ldrsh,
538 switch (tag) {
539 .ldrh_stack_argument => try emit.writeInstruction(Instruction.ldrh(cond, rt, .sp, .{ .offset = offset })),
540 .ldrsb_stack_argument => try emit.writeInstruction(Instruction.ldrsb(cond, rt, .sp, .{ .offset = offset })),
541 .ldrsh_stack_argument => try emit.writeInstruction(Instruction.ldrsh(cond, rt, .sp, .{ .offset = offset })),
549542 else => unreachable,
550 };
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 ));
543 }
563544 },
564545 else => unreachable,
565546 }
src/arch/riscv64/CodeGen.zig+1
......@@ -694,6 +694,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
694694 => return self.fail("TODO implement optimized float mode", .{}),
695695
696696 .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
698699 .wasm_memory_size => unreachable,
699700 .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 {
706706 => @panic("TODO implement optimized float mode"),
707707
708708 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
709 .error_set_has_value => @panic("TODO implement error_set_has_value"),
709710
710711 .wasm_memory_size => unreachable,
711712 .wasm_memory_grow => unreachable,
src/arch/wasm/CodeGen.zig+419-325
......@@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset;
2929const WValue = union(enum) {
3030 /// May be referenced but is unused
3131 none: void,
32 /// The value lives on top of the stack
33 stack: void,
3234 /// Index of the local variable
3335 local: u32,
3436 /// An immediate 32bit value
......@@ -55,7 +57,7 @@ const WValue = union(enum) {
5557 /// In wasm function pointers are indexes into a function table,
5658 /// rather than an address in the data section.
5759 function_index: u32,
58 /// Offset from the bottom of the stack, with the offset
60 /// Offset from the bottom of the virtual stack, with the offset
5961 /// pointing to where the value lives.
6062 stack_offset: u32,
6163
......@@ -71,6 +73,38 @@ const WValue = union(enum) {
7173 else => return 0,
7274 }
7375 }
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 }
74108};
75109
76110/// Wasm ops, but without input/output/signedness information
......@@ -601,6 +635,21 @@ stack_size: u32 = 0,
601635/// However, local variables or the usage of `@setAlignStack` can overwrite this default.
602636stack_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
604653const InnerError = error{
605654 OutOfMemory,
606655 /// An error occurred when trying to lower AIR to MIR.
......@@ -759,7 +808,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {
759808/// Writes the bytecode depending on the given `WValue` in `val`
760809fn emitWValue(self: *Self, value: WValue) InnerError!void {
761810 switch (value) {
762 .none => {}, // no-op
811 .none, .stack => {}, // no-op
763812 .local => |idx| try self.addLabel(.local_get, idx),
764813 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
765814 .imm64 => |val| try self.addImm64(val),
......@@ -781,9 +830,30 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {
781830/// Creates one locals for a given `Type`.
782831/// Returns a corresponding `Wvalue` with `local` as active tag
783832fn 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));
784856 const initial_index = self.local_index;
785 const valtype = genValtype(ty, self.target);
786 try self.locals.append(self.gpa, valtype);
787857 self.local_index += 1;
788858 return WValue{ .local = initial_index };
789859}
......@@ -1135,9 +1205,9 @@ fn initializeStack(self: *Self) !void {
11351205 // Reserve a local to store the current stack pointer
11361206 // We can later use this local to set the stack pointer back to the value
11371207 // we have stored here.
1138 self.initial_stack_value = try self.allocLocal(Type.usize);
1208 self.initial_stack_value = try self.ensureAllocLocal(Type.usize);
11391209 // 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);
11411211}
11421212
11431213/// 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 {
12681338 else => {
12691339 // TODO: We should probably lower this to a call to compiler_rt
12701340 // But for now, we implement it manually
1271 const offset = try self.allocLocal(Type.usize); // local for counter
1341 var offset = try self.ensureAllocLocal(Type.usize); // local for counter
1342 defer offset.free(self);
1343
12721344 // outer block to jump to when loop is done
12731345 try self.startBlock(.block, wasm.block_empty);
12741346 try self.startBlock(.loop, wasm.block_empty);
......@@ -1405,7 +1477,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum
14051477 // do not perform arithmetic when offset is 0.
14061478 if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value;
14071479 const result_ptr: WValue = switch (action) {
1408 .new => try self.allocLocal(Type.usize),
1480 .new => try self.ensureAllocLocal(Type.usize),
14091481 .modify => ptr_value,
14101482 };
14111483 try self.emitWValue(ptr_value);
......@@ -1622,6 +1694,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16221694 .err_return_trace,
16231695 .set_err_return_trace,
16241696 .is_named_enum_value,
1697 .error_set_has_value,
16251698 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
16261699
16271700 .add_optimized,
......@@ -1653,7 +1726,10 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16531726fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
16541727 for (body) |inst| {
16551728 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 }
16571733 }
16581734}
16591735
......@@ -1727,8 +1803,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17271803
17281804 const fn_info = self.decl.ty.fnInfo();
17291805 if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {
1730 const result = try self.load(operand, ret_ty, 0);
1731 try self.emitWValue(result);
1806 // leave on the stack
1807 _ = try self.load(operand, ret_ty, 0);
17321808 }
17331809
17341810 try self.restoreStackPointer();
......@@ -1847,6 +1923,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
18471923}
18481924
18491925fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
1926 assert(!(lhs != .stack and rhs == .stack));
18501927 switch (ty.zigTypeTag()) {
18511928 .ErrorUnion => {
18521929 const pl_ty = ty.errorUnionPayload();
......@@ -1880,20 +1957,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
18801957 .Pointer => {
18811958 if (ty.isSlice()) {
18821959 // 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);
18831962 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
18861965 // retrieve length from rhs, and store that alongside lhs as well
1966 try self.emitWValue(lhs);
18871967 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());
18891969 return;
18901970 }
18911971 },
18921972 .Int => if (ty.intInfo(self.target).bits > 64) {
1973 try self.emitWValue(lhs);
18931974 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);
18941978 const msb = try self.load(rhs, Type.u64, 8);
1895 try self.store(lhs, lsb, Type.u64, 0);
1896 try self.store(lhs, msb, Type.u64, 8);
1979 try self.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset());
18971980 return;
18981981 },
18991982 else => {},
......@@ -1932,9 +2015,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
19322015 return new_local;
19332016 }
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);
19362020}
19372021
2022/// Loads an operand from the linear memory section.
2023/// NOTE: Leaves the value on the stack.
19382024fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
19392025 // load local's value from memory by its stack position
19402026 try self.emitWValue(operand);
......@@ -1952,10 +2038,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
19522038 .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) },
19532039 );
19542040
1955 // store the result in a local
1956 const result = try self.allocLocal(ty);
1957 try self.addLabel(.local_set, result.local);
1958 return result;
2041 return WValue{ .stack = {} };
19592042}
19602043
19612044fn 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 {
20252108 const rhs = try self.resolveInst(bin_op.rhs);
20262109 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);
20292113}
20302114
2115/// Performs a binary operation on the given `WValue`'s
2116/// NOTE: THis leaves the value on top of the stack.
20312117fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2118 assert(!(lhs != .stack and rhs == .stack));
20322119 if (isByRef(ty, self.target)) {
20332120 if (ty.zigTypeTag() == .Int) {
20342121 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
20542141
20552142 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20562143
2057 // save the result in a temporary
2058 const bin_local = try self.allocLocal(ty);
2059 try self.addLabel(.local_set, bin_local.local);
2060 return bin_local;
2144 return WValue{ .stack = {} };
20612145}
20622146
2147/// Performs a binary operation for 16-bit floats.
2148/// NOTE: Leaves the result value on the stack
20632149fn 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
20672150 const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned });
2068 try self.emitWValue(ext_lhs);
2069 try self.emitWValue(ext_rhs);
2151 _ = try self.fpext(lhs, Type.f16, Type.f32);
2152 _ = try self.fpext(rhs, Type.f16, Type.f32);
20702153 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20712154
2072 // re-use temporary local
2073 try self.addLabel(.local_set, ext_lhs.local);
2074 return self.fptrunc(ext_lhs, Type.f32, Type.f16);
2155 return self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
20752156}
20762157
20772158fn 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
20842165 }
20852166
20862167 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
20882175 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
2089 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
20902176 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
2091
20922177 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
20952179 const lt = if (op == .add) blk: {
20962180 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
20982182 break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);
20992183 } else unreachable;
21002184 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
21032188 try self.store(result, high_op_res, Type.u64, 0);
21042189 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 {
21152200 return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});
21162201 }
21172202
2118 return self.wrapBinOp(lhs, rhs, ty, op);
2203 return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty);
21192204}
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
21212209fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2122 const bit_size = ty.intInfo(self.target).bits;
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
2210 const bin_local = try self.binOp(lhs, rhs, ty, op);
21442211 return self.wrapOperand(bin_local, ty);
21452212}
21462213
21472214/// Wraps an operand based on a given type's bitsize.
21482215/// Asserts `Type` is <= 128 bits.
2216/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack.
21492217fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
21502218 assert(ty.abiSize(self.target) <= 16);
2151 const result_local = try self.allocLocal(ty);
21522219 const bitsize = ty.intInfo(self.target).bits;
21532220 const wasm_bits = toWasmBits(bitsize) orelse {
21542221 return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});
......@@ -2157,14 +2224,15 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
21572224 if (wasm_bits == bitsize) return operand;
21582225
21592226 if (wasm_bits == 128) {
2160 const msb = try self.load(operand, Type.u64, 0);
2227 assert(operand != .stack);
21612228 const lsb = try self.load(operand, Type.u64, 8);
21622229
21632230 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());
21652233 const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1;
21662234 try self.emitWValue(result_ptr);
2167 try self.emitWValue(msb);
2235 _ = try self.load(operand, Type.u64, 0);
21682236 try self.addImm64(result);
21692237 try self.addTag(.i64_and);
21702238 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 {
21812249 try self.addTag(.i64_and);
21822250 } else unreachable;
21832251
2184 try self.addLabel(.local_set, result_local.local);
2185 return result_local;
2252 return WValue{ .stack = {} };
21862253}
21872254
21882255fn 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
25942661 const lhs = try self.resolveInst(bin_op.lhs);
25952662 const rhs = try self.resolveInst(bin_op.rhs);
25962663 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
25982665}
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.
26002670fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {
2671 assert(!(lhs != .stack and rhs == .stack));
26012672 if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) {
26022673 var buf: Type.Payload.ElemType = undefined;
26032674 const payload_ty = ty.optionalChild(&buf);
......@@ -2639,15 +2710,12 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper
26392710 });
26402711 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
26412712
2642 const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i32
2643 try self.addLabel(.local_set, cmp_tmp.local);
2644 return cmp_tmp;
2713 return WValue{ .stack = {} };
26452714}
26462715
2716/// Compares 16-bit floats
2717/// NOTE: The result value remains on top of the stack.
26472718fn 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
26512719 const opcode: wasm.Opcode = buildOpcode(.{
26522720 .op = switch (op) {
26532721 .lt => .lt,
......@@ -2660,13 +2728,11 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato
26602728 .valtype1 = .f32,
26612729 .signedness = .unsigned,
26622730 });
2663 try self.emitWValue(ext_lhs);
2664 try self.emitWValue(ext_rhs);
2731 _ = try self.fpext(lhs, Type.f16, Type.f32);
2732 _ = try self.fpext(rhs, Type.f16, Type.f32);
26652733 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
26662734
2667 const result = try self.allocLocal(Type.initTag(.i32)); // bool is always i32
2668 try self.addLabel(.local_set, result.local);
2669 return result;
2735 return WValue{ .stack = {} };
26702736}
26712737
26722738fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -2727,21 +2793,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27272793 switch (wasm_bits) {
27282794 32 => {
27292795 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);
27312797 },
27322798 64 => {
27332799 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);
27352801 },
27362802 128 => {
27372803 const result_ptr = try self.allocStack(operand_ty);
2804 try self.emitWValue(result_ptr);
27382805 const msb = try self.load(operand, Type.u64, 0);
2739 const lsb = try self.load(operand, Type.u64, 8);
2740
27412806 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);
27422811 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);
2744 try self.store(result_ptr, lsb_xor, Type.u64, 8);
2812 try self.store(result_ptr, lsb_xor, Type.u64, 8 + result_ptr.offset());
27452813 return result_ptr;
27462814 },
27472815 else => unreachable,
......@@ -2829,7 +2897,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28292897 }
28302898 }
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);
28332902}
28342903
28352904fn 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)
30393108 if (op_is_ptr or isByRef(payload_ty, self.target)) {
30403109 return self.buildPointerOffset(operand, pl_offset, .new);
30413110 }
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);
30433114}
30443115
30453116fn 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
30593130 return operand;
30603131 }
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);
30633135}
30643136
30653137fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3125,12 +3197,13 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31253197 return self.fail("todo Wasm intcast for bitsize > 128", .{});
31263198 }
31273199
3128 return self.intcast(operand, operand_ty, ty);
3200 return (try self.intcast(operand, operand_ty, ty)).toLocal(self, ty);
31293201}
31303202
31313203/// Upcasts or downcasts an integer based on the given and wanted types,
31323204/// and stores the result in a new operand.
31333205/// Asserts type's bitsize <= 128
3206/// NOTE: May leave the result on the top of the stack.
31343207fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
31353208 const given_info = given.intInfo(self.target);
31363209 const wanted_info = wanted.intInfo(self.target);
......@@ -3153,25 +3226,22 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W
31533226 } else if (wanted_bits == 128) {
31543227 // for 128bit integers we store the integer in the virtual stack, rather than a local
31553228 const stack_ptr = try self.allocStack(wanted);
3229 try self.emitWValue(stack_ptr);
31563230
31573231 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it
31583232 // meaning less store operations are required.
31593233 const lhs = if (op_bits == 32) blk: {
3160 const tmp = try self.intcast(
3161 operand,
3162 given,
3163 if (wanted.isSignedInt()) Type.i64 else Type.u64,
3164 );
3165 break :blk tmp;
3234 break :blk try self.intcast(operand, given, if (wanted.isSignedInt()) Type.i64 else Type.u64);
31663235 } else operand;
31673236
31683237 // 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
31713240 // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value
31723241 if (wanted.isSignedInt()) {
3242 try self.emitWValue(stack_ptr);
31733243 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());
31753245 } else {
31763246 // Ensure memory of lsb is zero'd
31773247 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
31793249 return stack_ptr;
31803250 } else return self.load(operand, wanted, 0);
31813251
3182 const result = try self.allocLocal(wanted);
3183 try self.addLabel(.local_set, result.local);
3184 return result;
3252 return WValue{ .stack = {} };
31853253}
31863254
31873255fn 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
31903258
31913259 const op_ty = self.air.typeOf(un_op);
31923260 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);
31943263}
31953264
3265/// For a given type and operand, checks if it's considered `null`.
3266/// NOTE: Leaves the result on the stack
31963267fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
31973268 try self.emitWValue(operand);
31983269 if (!optional_ty.optionalReprIsPayload()) {
......@@ -3209,9 +3280,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
32093280 try self.addImm32(0);
32103281 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
32113282
3212 const is_null_tmp = try self.allocLocal(Type.initTag(.i32));
3213 try self.addLabel(.local_set, is_null_tmp.local);
3214 return is_null_tmp;
3283 return WValue{ .stack = {} };
32153284}
32163285
32173286fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3229,7 +3298,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32293298 return self.buildPointerOffset(operand, offset, .new);
32303299 }
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);
32333303}
32343304
32353305fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3332,7 +3402,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33323402 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
33333403 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);
33363407}
33373408
33383409fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3346,8 +3417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33463417 const elem_size = elem_ty.abiSize(self.target);
33473418
33483419 // load pointer onto stack
3349 const slice_ptr = try self.load(slice, Type.usize, 0);
3350 try self.addLabel(.local_get, slice_ptr.local);
3420 _ = try self.load(slice, Type.usize, 0);
33513421
33523422 // calculate index into slice
33533423 try self.emitWValue(index);
......@@ -3361,7 +3431,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33613431 if (isByRef(elem_ty, self.target)) {
33623432 return result;
33633433 }
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);
33653437}
33663438
33673439fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3374,8 +3446,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33743446 const slice = try self.resolveInst(bin_op.lhs);
33753447 const index = try self.resolveInst(bin_op.rhs);
33763448
3377 const slice_ptr = try self.load(slice, Type.usize, 0);
3378 try self.addLabel(.local_get, slice_ptr.local);
3449 _ = try self.load(slice, Type.usize, 0);
33793450
33803451 // calculate index into slice
33813452 try self.emitWValue(index);
......@@ -3383,7 +3454,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33833454 try self.addTag(.i32_mul);
33843455 try self.addTag(.i32_add);
33853456
3386 const result = try self.allocLocal(Type.initTag(.i32));
3457 const result = try self.allocLocal(Type.i32);
33873458 try self.addLabel(.local_set, result.local);
33883459 return result;
33893460}
......@@ -3392,7 +3463,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33923463 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
33933464 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
33943465 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);
33963468}
33973469
33983470fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3407,13 +3479,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34073479 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits});
34083480 }
34093481
3410 const result = try self.intcast(operand, op_ty, wanted_ty);
3482 var result = try self.intcast(operand, op_ty, wanted_ty);
34113483 const wanted_bits = wanted_ty.intInfo(self.target).bits;
34123484 const wasm_bits = toWasmBits(wanted_bits).?;
34133485 if (wasm_bits != wanted_bits) {
3414 return self.wrapOperand(result, wanted_ty);
3486 result = try self.wrapOperand(result, wanted_ty);
34153487 }
3416 return result;
3488 return result.toLocal(self, wanted_ty);
34173489}
34183490
34193491fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3466,8 +3538,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34663538
34673539 // load pointer onto the stack
34683540 if (ptr_ty.isSlice()) {
3469 const ptr_local = try self.load(ptr, Type.usize, 0);
3470 try self.addLabel(.local_get, ptr_local.local);
3541 _ = try self.load(ptr, Type.usize, 0);
34713542 } else {
34723543 try self.lowerToStack(ptr);
34733544 }
......@@ -3478,12 +3549,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34783549 try self.addTag(.i32_mul);
34793550 try self.addTag(.i32_add);
34803551
3481 const result = try self.allocLocal(elem_ty);
3552 var result = try self.allocLocal(elem_ty);
34823553 try self.addLabel(.local_set, result.local);
34833554 if (isByRef(elem_ty, self.target)) {
34843555 return result;
34853556 }
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);
34873561}
34883562
34893563fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3499,8 +3573,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34993573
35003574 // load pointer onto the stack
35013575 if (ptr_ty.isSlice()) {
3502 const ptr_local = try self.load(ptr, Type.usize, 0);
3503 try self.addLabel(.local_get, ptr_local.local);
3576 _ = try self.load(ptr, Type.usize, 0);
35043577 } else {
35053578 try self.lowerToStack(ptr);
35063579 }
......@@ -3511,7 +3584,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
35113584 try self.addTag(.i32_mul);
35123585 try self.addTag(.i32_add);
35133586
3514 const result = try self.allocLocal(Type.initTag(.i32));
3587 const result = try self.allocLocal(Type.i32);
35153588 try self.addLabel(.local_set, result.local);
35163589 return result;
35173590}
......@@ -3599,7 +3672,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void
35993672 else => {
36003673 // TODO: We should probably lower this to a call to compiler_rt
36013674 // But for now, we implement it manually
3602 const offset = try self.allocLocal(Type.usize); // local for counter
3675 const offset = try self.ensureAllocLocal(Type.usize); // local for counter
36033676 // outer block to jump to when loop is done
36043677 try self.startBlock(.block, wasm.block_empty);
36053678 try self.startBlock(.loop, wasm.block_empty);
......@@ -3656,13 +3729,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
36563729 try self.addTag(.i32_mul);
36573730 try self.addTag(.i32_add);
36583731
3659 const result = try self.allocLocal(Type.usize);
3732 var result = try self.allocLocal(Type.usize);
36603733 try self.addLabel(.local_set, result.local);
36613734
36623735 if (isByRef(elem_ty, self.target)) {
36633736 return result;
36643737 }
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);
36663742}
36673743
36683744fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3685,11 +3761,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
36853761 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,
36863762 });
36873763 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
3688
3689 const result = try self.allocLocal(dest_ty);
3690 try self.addLabel(.local_set, result.local);
3691
3692 return self.wrapOperand(result, dest_ty);
3764 const wrapped = try self.wrapOperand(.{ .stack = {} }, dest_ty);
3765 return wrapped.toLocal(self, dest_ty);
36933766}
36943767
36953768fn 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
38873960 const payload_ty = operand_ty.optionalChild(&buf);
38883961 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
38933963 // We store the final result in here that will be validated
38943964 // 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
38973968 try self.startBlock(.block, wasm.block_empty);
3898 try self.emitWValue(lhs_is_null);
3899 try self.emitWValue(rhs_is_null);
3969 _ = try self.isNull(lhs, operand_ty, .i32_eq);
3970 _ = try self.isNull(rhs, operand_ty, .i32_eq);
39003971 try self.addTag(.i32_ne); // inverse so we can exit early
39013972 try self.addLabel(.br_if, 0);
39023973
3903 const lhs_pl = try self.load(lhs, payload_ty, offset);
3904 const rhs_pl = try self.load(rhs, payload_ty, offset);
3905
3906 try self.emitWValue(lhs_pl);
3907 try self.emitWValue(rhs_pl);
3974 _ = try self.load(lhs, payload_ty, offset);
3975 _ = try self.load(rhs, payload_ty, offset);
39083976 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) });
39093977 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
39103978 try self.addLabel(.br_if, 0);
......@@ -3916,26 +3984,29 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
39163984 try self.emitWValue(result);
39173985 try self.addImm32(0);
39183986 try self.addTag(if (op == .eq) .i32_ne else .i32_eq);
3919 try self.addLabel(.local_set, result.local);
3920 return result;
3987 return WValue{ .stack = {} };
39213988}
39223989
39233990/// 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.
39243992/// TODO: Lower this to compiler_rt call when bitsize > 128
39253993fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
39263994 assert(operand_ty.abiSize(self.target) >= 16);
3995 assert(!(lhs != .stack and rhs == .stack));
39273996 if (operand_ty.intInfo(self.target).bits > 128) {
39283997 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});
39293998 }
39303999
3931 const lhs_high_bit = try self.load(lhs, Type.u64, 0);
3932 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
3933 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
3934 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
4000 var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
4001 defer lhs_high_bit.free(self);
4002 var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
4003 defer rhs_high_bit.free(self);
39354004
39364005 switch (op) {
39374006 .eq, .neq => {
39384007 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);
39394010 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
39404011 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
39474018 },
39484019 else => {
39494020 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);
3951 const high_bit_cmp = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);
3952 const low_bit_cmp = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);
3953
3954 try self.emitWValue(low_bit_cmp);
3955 try self.emitWValue(high_bit_cmp);
3956 try self.emitWValue(high_bit_eql);
4021 // leave those value on top of the stack for '.select'
4022 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
4023 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
4024 _ = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);
4025 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);
4026 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);
39574027 try self.addTag(.select);
39584028 },
39594029 }
39604030
3961 const result = try self.allocLocal(Type.initTag(.i32));
3962 try self.addLabel(.local_set, result.local);
3963 return result;
4031 return WValue{ .stack = {} };
39644032}
39654033
39664034fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4000,7 +4068,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
40004068 const offset = if (layout.tag_align < layout.payload_align) blk: {
40014069 break :blk @intCast(u32, layout.payload_size);
40024070 } 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);
40044073}
40054074
40064075fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4010,19 +4079,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
40104079 const dest_ty = self.air.typeOfIndex(inst);
40114080 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);
40144084}
40154085
4086/// Extends a float from a given `Type` to a larger wanted `Type`
4087/// NOTE: Leaves the result on the stack
40164088fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
40174089 const given_bits = given.floatBits(self.target);
40184090 const wanted_bits = wanted.floatBits(self.target);
40194091
40204092 if (wanted_bits == 64 and given_bits == 32) {
4021 const result = try self.allocLocal(wanted);
40224093 try self.emitWValue(operand);
40234094 try self.addTag(.f64_promote_f32);
4024 try self.addLabel(.local_set, result.local);
4025 return result;
4095 return WValue{ .stack = {} };
40264096 } else if (given_bits == 16) {
40274097 // call __extendhfsf2(f16) f32
40284098 const f32_result = try self.callIntrinsic(
......@@ -4036,11 +4106,9 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa
40364106 return f32_result;
40374107 }
40384108 if (wanted_bits == 64) {
4039 const result = try self.allocLocal(wanted);
40404109 try self.emitWValue(f32_result);
40414110 try self.addTag(.f64_promote_f32);
4042 try self.addLabel(.local_set, result.local);
4043 return result;
4111 return WValue{ .stack = {} };
40444112 }
40454113 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits});
40464114 } else {
......@@ -4055,26 +4123,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
40554123 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
40564124 const dest_ty = self.air.typeOfIndex(inst);
40574125 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);
40594128}
40604129
4130/// Truncates a float from a given `Type` to its wanted `Type`
4131/// NOTE: The result value remains on the stack
40614132fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
40624133 const given_bits = given.floatBits(self.target);
40634134 const wanted_bits = wanted.floatBits(self.target);
40644135
40654136 if (wanted_bits == 32 and given_bits == 64) {
4066 const result = try self.allocLocal(wanted);
40674137 try self.emitWValue(operand);
40684138 try self.addTag(.f32_demote_f64);
4069 try self.addLabel(.local_set, result.local);
4070 return result;
4139 return WValue{ .stack = {} };
40714140 } else if (wanted_bits == 16) {
40724141 const op: WValue = if (given_bits == 64) blk: {
4073 const tmp = try self.allocLocal(Type.f32);
40744142 try self.emitWValue(operand);
40754143 try self.addTag(.f32_demote_f64);
4076 try self.addLabel(.local_set, tmp.local);
4077 break :blk tmp;
4144 break :blk WValue{ .stack = {} };
40784145 } else operand;
40794146
40804147 // call __truncsfhf2(f32) f16
......@@ -4159,12 +4226,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
41594226
41604227 switch (wasm_bits) {
41614228 128 => {
4162 const msb = try self.load(operand, Type.u64, 0);
4163 const lsb = try self.load(operand, Type.u64, 8);
4164
4165 try self.emitWValue(msb);
4229 _ = try self.load(operand, Type.u64, 0);
41664230 try self.addTag(.i64_popcnt);
4167 try self.emitWValue(lsb);
4231 _ = try self.load(operand, Type.u64, 8);
41684232 try self.addTag(.i64_popcnt);
41694233 try self.addTag(.i64_add);
41704234 try self.addTag(.i32_wrap_i64);
......@@ -4268,24 +4332,26 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
42684332
42694333 // for signed integers, we first apply signed shifts by the difference in bits
42704334 // 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: {
4272 break :blk try self.signAbsValue(lhs_op, lhs_ty);
4335 var lhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4336 break :blk try (try self.signAbsValue(lhs_op, lhs_ty)).toLocal(self, lhs_ty);
42734337 } else lhs_op;
4274 const rhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4275 break :blk try self.signAbsValue(rhs_op, lhs_ty);
4338 var rhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4339 break :blk try (try self.signAbsValue(rhs_op, lhs_ty)).toLocal(self, lhs_ty);
42764340 } else rhs_op;
42774341
4278 const bin_op = try self.binOp(lhs, rhs, lhs_ty, op);
4279 const result = if (wasm_bits != int_info.bits) blk: {
4280 break :blk try self.wrapOperand(bin_op, lhs_ty);
4342 var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty);
4343 defer bin_op.free(self);
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);
42814346 } else bin_op;
4347 defer result.free(self); // no-op when wasm_bits == int_info.bits
42824348
42834349 const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;
42844350 const overflow_bit: WValue = if (is_signed) blk: {
42854351 if (wasm_bits == int_info.bits) {
42864352 const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op);
42874353 const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt);
4288 break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); // result of cmp_zero and lt is always 32bit
4354 break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor);
42894355 }
42904356 const abs = try self.signAbsValue(bin_op, lhs_ty);
42914357 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
42934359 try self.cmp(bin_op, lhs, lhs_ty, cmp_op)
42944360 else
42954361 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
42974365 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
42984366 try self.store(result_ptr, result, lhs_ty, 0);
42994367 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
43024379 return result_ptr;
43034380}
......@@ -4310,52 +4387,58 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type,
43104387 return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits});
43114388 }
43124389
4313 const lhs_high_bit = try self.load(lhs, Type.u64, 0);
4314 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
4315 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
4316 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
4390 var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
4391 defer lhs_high_bit.free(self);
4392 var lhs_low_bit = try (try self.load(lhs, Type.u64, 8)).toLocal(self, Type.u64);
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);
4319 const high_op_res = try self.binOp(lhs_high_bit, rhs_high_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);
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: {
4322 break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt);
4404 var lt = if (op == .add) blk: {
4405 break :blk try (try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32);
43234406 } 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);
43254408 } else unreachable;
4326 const tmp = try self.intcast(lt, Type.u32, Type.u64);
4327 const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op);
4409 defer lt.free(self);
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
43294415 const overflow_bit = if (is_signed) blk: {
4330 const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor);
43314416 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
43324417 const to_wrap = if (op == .add) wrap: {
43334418 break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
43344419 } else xor_low;
4420 const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor);
43354421 const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and");
43364422 break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed
43374423 } 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
43414424 const first_arg = if (op == .sub) arg: {
43424425 break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt);
43434426 } else lt;
43444427
43454428 try self.emitWValue(first_arg);
4346 try self.emitWValue(op_eq);
4347 try self.emitWValue(eq);
4429 _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt);
4430 _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq);
43484431 try self.addTag(.select);
43494432
4350 const overflow_bit = try self.allocLocal(Type.initTag(.u1));
4351 try self.addLabel(.local_set, overflow_bit.local);
4352 break :blk overflow_bit;
4433 break :blk WValue{ .stack = {} };
43534434 };
4435 var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1));
4436 defer overflow_local.free(self);
43544437
43554438 const result_ptr = try self.allocStack(result_ty);
43564439 try self.store(result_ptr, high_op_res, Type.u64, 0);
43574440 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
43604443 return result_ptr;
43614444}
......@@ -4377,24 +4460,31 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
43774460 return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits});
43784461 };
43794462
4380 const shl = try self.binOp(lhs, rhs, lhs_ty, .shl);
4381 const result = if (wasm_bits != int_info.bits) blk: {
4382 break :blk try self.wrapOperand(shl, lhs_ty);
4463 var shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty);
4464 defer shl.free(self);
4465 var result = if (wasm_bits != int_info.bits) blk: {
4466 break :blk try (try self.wrapOperand(shl, lhs_ty)).toLocal(self, lhs_ty);
43834467 } 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
43854470 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);
43864473 const abs = try self.signAbsValue(shl, lhs_ty);
43874474 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);
43894476 } else blk: {
4477 try self.emitWValue(lhs);
43904478 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);
43924480 };
4481 var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1));
4482 defer overflow_local.free(self);
43934483
43944484 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
43954485 try self.store(result_ptr, result, lhs_ty, 0);
43964486 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
43994489 return result_ptr;
44004490}
......@@ -4412,7 +4502,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
44124502
44134503 // We store the bit if it's overflowed or not in this. As it's zero-initialized
44144504 // 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
44164508 const int_info = lhs_ty.intInfo(self.target);
44174509 const wasm_bits = toWasmBits(int_info.bits) orelse {
44184510 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 {
44334525 const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64;
44344526 const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty);
44354527 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);
44374529 if (int_info.signedness == .unsigned) {
44384530 const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
44394531 const wrap = try self.intcast(shr, new_ty, lhs_ty);
4440 const cmp_res = try self.cmp(wrap, zero, lhs_ty, .neq);
4441 try self.emitWValue(cmp_res);
4532 _ = try self.cmp(wrap, zero, lhs_ty, .neq);
44424533 try self.addLabel(.local_set, overflow_bit.local);
44434534 break :blk try self.intcast(bin_op, new_ty, lhs_ty);
44444535 } else {
4445 const down_cast = try self.intcast(bin_op, new_ty, lhs_ty);
4446 const shr = try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr);
4536 const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);
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
44484540 const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
44494541 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);
4451 try self.emitWValue(cmp_res);
4542 _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq);
44524543 try self.addLabel(.local_set, overflow_bit.local);
44534544 break :blk down_cast;
44544545 }
44554546 } else if (int_info.signedness == .signed) blk: {
44564547 const lhs_abs = try self.signAbsValue(lhs, lhs_ty);
44574548 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);
44594550 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);
4460 const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);
4461 try self.emitWValue(cmp_op);
4551 _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);
44624552 try self.addLabel(.local_set, overflow_bit.local);
44634553 break :blk try self.wrapOperand(bin_op, lhs_ty);
44644554 } 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);
44664557 const shift_imm = if (wasm_bits == 32)
44674558 WValue{ .imm32 = int_info.bits }
44684559 else
44694560 WValue{ .imm64 = int_info.bits };
44704561 const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr);
4471 const cmp_op = try self.cmp(shr, zero, lhs_ty, .neq);
4472 try self.emitWValue(cmp_op);
4562 _ = try self.cmp(shr, zero, lhs_ty, .neq);
44734563 try self.addLabel(.local_set, overflow_bit.local);
44744564 break :blk try self.wrapOperand(bin_op, lhs_ty);
44754565 };
4566 var bin_op_local = try bin_op.toLocal(self, lhs_ty);
4567 defer bin_op_local.free(self);
44764568
44774569 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);
44794571 const offset = @intCast(u32, lhs_ty.abiSize(self.target));
44804572 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
44974589 const lhs = try self.resolveInst(bin_op.lhs);
44984590 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
45024592 // operands to select from
45034593 try self.lowerToStack(lhs);
45044594 try self.lowerToStack(rhs);
4505 try self.emitWValue(cmp_result);
4595 _ = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
45064596
45074597 // based on the result from comparison, return operand 0 or 1.
45084598 try self.addTag(.select);
......@@ -4528,21 +4618,22 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
45284618 const rhs = try self.resolveInst(bin_op.rhs);
45294619
45304620 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);
45334621 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);
45344624 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`
4535 const result = try self.callIntrinsic(
4625 var result = try self.callIntrinsic(
45364626 "fmaf",
45374627 &.{ Type.f32, Type.f32, Type.f32 },
45384628 Type.f32,
45394629 &.{ rhs_ext, lhs_ext, addend_ext },
45404630 );
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);
45424633 }
45434634
45444635 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);
45464637}
45474638
45484639fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4571,17 +4662,16 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
45714662 try self.addTag(.i32_wrap_i64);
45724663 },
45734664 128 => {
4574 const msb = try self.load(operand, Type.u64, 0);
4575 const lsb = try self.load(operand, Type.u64, 8);
4576 const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
4665 var lsb = try (try self.load(operand, Type.u64, 8)).toLocal(self, Type.u64);
4666 defer lsb.free(self);
45774667
45784668 try self.emitWValue(lsb);
45794669 try self.addTag(.i64_clz);
4580 try self.emitWValue(msb);
4670 _ = try self.load(operand, Type.u64, 0);
45814671 try self.addTag(.i64_clz);
45824672 try self.emitWValue(.{ .imm64 = 64 });
45834673 try self.addTag(.i64_add);
4584 try self.emitWValue(neq);
4674 _ = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
45854675 try self.addTag(.select);
45864676 try self.addTag(.i32_wrap_i64);
45874677 },
......@@ -4618,28 +4708,27 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
46184708 32 => {
46194709 if (wasm_bits != int_info.bits) {
46204710 const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits);
4621 const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");
4622 try self.emitWValue(bin_op);
4711 // leave value on the stack
4712 _ = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");
46234713 } else try self.emitWValue(operand);
46244714 try self.addTag(.i32_ctz);
46254715 },
46264716 64 => {
46274717 if (wasm_bits != int_info.bits) {
46284718 const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits);
4629 const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");
4630 try self.emitWValue(bin_op);
4719 // leave value on the stack
4720 _ = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");
46314721 } else try self.emitWValue(operand);
46324722 try self.addTag(.i64_ctz);
46334723 try self.addTag(.i32_wrap_i64);
46344724 },
46354725 128 => {
4636 const msb = try self.load(operand, Type.u64, 0);
4637 const lsb = try self.load(operand, Type.u64, 8);
4638 const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
4726 var msb = try (try self.load(operand, Type.u64, 0)).toLocal(self, Type.u64);
4727 defer msb.free(self);
46394728
46404729 try self.emitWValue(msb);
46414730 try self.addTag(.i64_ctz);
4642 try self.emitWValue(lsb);
4731 _ = try self.load(operand, Type.u64, 8);
46434732 if (wasm_bits != int_info.bits) {
46444733 try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));
46454734 try self.addTag(.i64_or);
......@@ -4651,7 +4740,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
46514740 } else {
46524741 try self.addTag(.i64_add);
46534742 }
4654 try self.emitWValue(neq);
4743 _ = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
46554744 try self.addTag(.select);
46564745 try self.addTag(.i32_wrap_i64);
46574746 },
......@@ -4777,7 +4866,8 @@ fn lowerTry(
47774866 if (isByRef(pl_ty, self.target)) {
47784867 return buildPointerOffset(self, err_union, pl_offset, .new);
47794868 }
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);
47814871}
47824872
47834873fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4807,11 +4897,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48074897 const res = if (int_info.signedness == .signed) blk: {
48084898 break :blk try self.wrapOperand(shr_res, Type.u8);
48094899 } else shr_res;
4810 return self.binOp(lhs, res, ty, .@"or");
4900 return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty);
48114901 },
48124902 24 => {
4813 const msb = try self.wrapOperand(operand, Type.u16);
4814 const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);
4903 var msb = try (try self.wrapOperand(operand, Type.u16)).toLocal(self, Type.u16);
4904 defer msb.free(self);
48154905
48164906 const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl);
48174907 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 {
48254915 const rhs_wrap = try self.wrapOperand(msb, Type.u8);
48264916 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);
48284919 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);
48304921 },
48314922 32 => {
48324923 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);
48344926 const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr);
4835 const rhs = try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and");
4836 const tmp_or = try self.binOp(lhs, rhs, ty, .@"or");
4927 var rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty);
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
48384932 const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
48394933 const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr);
48404934 const res = if (int_info.signedness == .signed) blk: {
48414935 break :blk try self.wrapOperand(shr, Type.u16);
48424936 } else shr;
4843 return self.binOp(shl, res, ty, .@"or");
4937 return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty);
48444938 },
48454939 else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),
48464940 }
......@@ -4857,7 +4951,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48574951 if (ty.isSignedInt()) {
48584952 return self.divSigned(lhs, rhs, ty);
48594953 }
4860 return self.binOp(lhs, rhs, ty, .div);
4954 return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty);
48614955}
48624956
48634957fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4869,33 +4963,31 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48694963 const rhs = try self.resolveInst(bin_op.rhs);
48704964
48714965 if (ty.isUnsignedInt()) {
4872 return self.binOp(lhs, rhs, ty, .div);
4966 return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty);
48734967 } else if (ty.isSignedInt()) {
48744968 const int_bits = ty.intInfo(self.target).bits;
48754969 const wasm_bits = toWasmBits(int_bits) orelse {
48764970 return self.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits});
48774971 };
48784972 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);
48804974 } else lhs;
48814975 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);
48834977 } 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
48884979 const zero = switch (wasm_bits) {
48894980 32 => WValue{ .imm32 = 0 },
48904981 64 => WValue{ .imm64 = 0 },
48914982 else => unreachable,
48924983 };
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);
4897 try self.emitWValue(lhs_less_than_zero);
4898 try self.emitWValue(rhs_less_than_zero);
4985 const div_result = try self.allocLocal(ty);
4986 // leave on stack
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);
48994991 switch (wasm_bits) {
49004992 32 => {
49014993 try self.addTag(.i32_xor);
......@@ -4908,7 +5000,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
49085000 else => unreachable,
49095001 }
49105002 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);
49125005 try self.addTag(.select);
49135006 } else {
49145007 const float_bits = ty.floatBits(self.target);
......@@ -4940,9 +5033,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
49405033 }
49415034
49425035 if (is_f16) {
4943 // we can re-use temporary local
4944 try self.addLabel(.local_set, lhs_operand.local);
4945 return self.fptrunc(lhs_operand, Type.f32, Type.f16);
5036 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
49465037 }
49475038 }
49485039
......@@ -4962,10 +5053,9 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
49625053 }
49635054
49645055 if (wasm_bits != int_bits) {
4965 const lhs_abs = try self.signAbsValue(lhs, ty);
4966 const rhs_abs = try self.signAbsValue(rhs, ty);
4967 try self.emitWValue(lhs_abs);
4968 try self.emitWValue(rhs_abs);
5056 // Leave both values on the stack
5057 _ = try self.signAbsValue(lhs, ty);
5058 _ = try self.signAbsValue(rhs, ty);
49695059 } else {
49705060 try self.emitWValue(lhs);
49715061 try self.emitWValue(rhs);
......@@ -4977,6 +5067,8 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
49775067 return result;
49785068}
49795069
5070/// Retrieves the absolute value of a signed integer
5071/// NOTE: Leaves the result value on the stack.
49805072fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
49815073 const int_bits = ty.intInfo(self.target).bits;
49825074 const wasm_bits = toWasmBits(int_bits) orelse {
......@@ -5005,9 +5097,8 @@ fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
50055097 },
50065098 else => unreachable,
50075099 }
5008 const result = try self.allocLocal(ty);
5009 try self.addLabel(.local_set, result.local);
5010 return result;
5100
5101 return WValue{ .stack = {} };
50115102}
50125103
50135104fn 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
50345125 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
50355126
50365127 if (is_f16) {
5037 // re-use temporary to save locals
5038 try self.addLabel(.local_set, op_to_lower.local);
5039 return self.fptrunc(op_to_lower, Type.f32, Type.f16);
5128 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
50405129 }
50415130
50425131 const result = try self.allocLocal(ty);
......@@ -5065,7 +5154,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
50655154 }
50665155
50675156 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);
50695159 if (wasm_bits != int_info.bits and op == .add) {
50705160 const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1);
50715161 const imm_val = switch (wasm_bits) {
......@@ -5074,19 +5164,17 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
50745164 else => unreachable,
50755165 };
50765166
5077 const cmp_result = try self.cmp(bin_result, imm_val, ty, .lt);
50785167 try self.emitWValue(bin_result);
50795168 try self.emitWValue(imm_val);
5080 try self.emitWValue(cmp_result);
5169 _ = try self.cmp(bin_result, imm_val, ty, .lt);
50815170 } else {
5082 const cmp_result = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
50835171 switch (wasm_bits) {
50845172 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0),
50855173 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0),
50865174 else => unreachable,
50875175 }
50885176 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);
50905178 }
50915179
50925180 try self.addTag(.select);
......@@ -5100,8 +5188,12 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
51005188 const wasm_bits = toWasmBits(int_info.bits).?;
51015189 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;
5104 const rhs = if (!is_wasm_bits) try self.signAbsValue(rhs_operand, ty) else rhs_operand;
5191 var lhs = if (!is_wasm_bits) lhs: {
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
51065198 const max_val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits - 1)) - 1);
51075199 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
51165208 else => unreachable,
51175209 };
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);
51205212 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
51225216 try self.emitWValue(bin_result);
51235217 try self.emitWValue(max_wvalue);
5124 try self.emitWValue(cmp_result_lt);
5218 _ = try self.cmp(bin_result, max_wvalue, ty, .lt);
51255219 try self.addTag(.select);
51265220 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);
51295222 try self.emitWValue(bin_result);
51305223 try self.emitWValue(min_wvalue);
5131 try self.emitWValue(cmp_result_gt);
5224 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);
51325225 try self.addTag(.select);
51335226 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);
51355228 } else {
51365229 const zero = switch (wasm_bits) {
51375230 32 => WValue{ .imm32 = 0 },
51385231 64 => WValue{ .imm64 = 0 },
51395232 else => unreachable,
51405233 };
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);
51455234 try self.emitWValue(max_wvalue);
51465235 try self.emitWValue(min_wvalue);
5147 try self.emitWValue(cmp_bin_zero_result);
5236 _ = try self.cmp(bin_result, zero, ty, .lt);
51485237 try self.addTag(.select);
51495238 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.
51515243 try self.addTag(.select);
51525244 try self.addLabel(.local_set, bin_result.local); // re-use local
51535245 return bin_result;
......@@ -5171,9 +5263,10 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
51715263 const result = try self.allocLocal(ty);
51725264
51735265 if (wasm_bits == int_info.bits) {
5174 const shl = try self.binOp(lhs, rhs, ty, .shl);
5175 const shr = try self.binOp(shl, rhs, ty, .shr);
5176 const cmp_result = try self.cmp(lhs, shr, ty, .neq);
5266 var shl = try (try self.binOp(lhs, rhs, ty, .shl)).toLocal(self, ty);
5267 defer shl.free(self);
5268 var shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty);
5269 defer shr.free(self);
51775270
51785271 switch (wasm_bits) {
51795272 32 => blk: {
......@@ -5181,10 +5274,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
51815274 try self.addImm32(-1);
51825275 break :blk;
51835276 }
5184 const less_than_zero = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
51855277 try self.addImm32(std.math.minInt(i32));
51865278 try self.addImm32(std.math.maxInt(i32));
5187 try self.emitWValue(less_than_zero);
5279 _ = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
51885280 try self.addTag(.select);
51895281 },
51905282 64 => blk: {
......@@ -5192,16 +5284,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
51925284 try self.addImm64(@bitCast(u64, @as(i64, -1)));
51935285 break :blk;
51945286 }
5195 const less_than_zero = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
51965287 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
51975288 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);
51995290 try self.addTag(.select);
52005291 },
52015292 else => unreachable,
52025293 }
52035294 try self.emitWValue(shl);
5204 try self.emitWValue(cmp_result);
5295 _ = try self.cmp(lhs, shr, ty, .neq);
52055296 try self.addTag(.select);
52065297 try self.addLabel(.local_set, result.local);
52075298 return result;
......@@ -5213,10 +5304,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
52135304 else => unreachable,
52145305 };
52155306
5216 const shl_res = try self.binOp(lhs, shift_value, ty, .shl);
5217 const shl = try self.binOp(shl_res, rhs, ty, .shl);
5218 const shr = try self.binOp(shl, rhs, ty, .shr);
5219 const cmp_result = try self.cmp(shl_res, shr, ty, .neq);
5307 var shl_res = try (try self.binOp(lhs, shift_value, ty, .shl)).toLocal(self, ty);
5308 defer shl_res.free(self);
5309 var shl = try (try self.binOp(shl_res, rhs, ty, .shl)).toLocal(self, ty);
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
52215314 switch (wasm_bits) {
52225315 32 => blk: {
......@@ -5225,10 +5318,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
52255318 break :blk;
52265319 }
52275320
5228 const less_than_zero = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt);
52295321 try self.addImm32(std.math.minInt(i32));
52305322 try self.addImm32(std.math.maxInt(i32));
5231 try self.emitWValue(less_than_zero);
5323 _ = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt);
52325324 try self.addTag(.select);
52335325 },
52345326 64 => blk: {
......@@ -5237,29 +5329,30 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
52375329 break :blk;
52385330 }
52395331
5240 const less_than_zero = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt);
52415332 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
52425333 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);
52445335 try self.addTag(.select);
52455336 },
52465337 else => unreachable,
52475338 }
52485339 try self.emitWValue(shl);
5249 try self.emitWValue(cmp_result);
5340 _ = try self.cmp(shl_res, shr, ty, .neq);
52505341 try self.addTag(.select);
52515342 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);
52535344 if (is_signed) {
5254 return self.wrapOperand(shift_result, ty);
5345 shift_result = try self.wrapOperand(shift_result, ty);
52555346 }
5256 return shift_result;
5347 return shift_result.toLocal(self, ty);
52575348 }
52585349}
52595350
52605351/// Calls a compiler-rt intrinsic by creating an undefined symbol,
52615352/// then lowering the arguments and calling the symbol as a function call.
52625353/// 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.
52635356fn callIntrinsic(
52645357 self: *Self,
52655358 name: []const u8,
......@@ -5289,6 +5382,7 @@ fn callIntrinsic(
52895382
52905383 // Lower all arguments to the stack before we call our function
52915384 for (args) |arg, arg_i| {
5385 assert(!(want_sret_param and arg == .stack));
52925386 assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime());
52935387 try self.lowerArg(.C, param_types[arg_i], arg);
52945388 }
src/arch/x86_64/CodeGen.zig+48-1
......@@ -776,6 +776,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
776776 => return self.fail("TODO implement optimized float mode", .{}),
777777
778778 .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
780781 .wasm_memory_size => unreachable,
781782 .wasm_memory_grow => unreachable,
......@@ -4370,6 +4371,7 @@ fn genVarDbgInfo(
43704371 .dwarf => |dw| {
43714372 const dbg_info = &dw.dbg_info;
43724373 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
4374 const endian = self.target.cpu.arch.endian();
43734375
43744376 switch (mcv) {
43754377 .register => |reg| {
......@@ -4390,7 +4392,6 @@ fn genVarDbgInfo(
43904392 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
43914393 },
43924394 .memory, .got_load, .direct_load => {
4393 const endian = self.target.cpu.arch.endian();
43944395 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
43954396 const is_ptr = switch (tag) {
43964397 .dbg_var_ptr => true,
......@@ -4425,7 +4426,53 @@ fn genVarDbgInfo(
44254426 else => {},
44264427 }
44274428 },
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 },
44284471 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 });
44294476 log.debug("TODO generate debug info for {}", .{mcv});
44304477 },
44314478 }
src/clang_options_data.zig+10-3
......@@ -33,7 +33,14 @@ flagpd1("H"),
3333 .psl = false,
3434},
3535flagpd1("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},
3744.{
3845 .name = "MD",
3946 .syntax = .flag,
......@@ -53,7 +60,7 @@ flagpd1("M"),
5360.{
5461 .name = "MM",
5562 .syntax = .flag,
56 .zig_equivalent = .dep_file_mm,
63 .zig_equivalent = .dep_file_to_stdout,
5764 .pd1 = true,
5865 .pd2 = false,
5966 .psl = false,
......@@ -1983,7 +1990,7 @@ flagpsl("MT"),
19831990.{
19841991 .name = "user-dependencies",
19851992 .syntax = .flag,
1986 .zig_equivalent = .dep_file_mm,
1993 .zig_equivalent = .dep_file_to_stdout,
19871994 .pd1 = false,
19881995 .pd2 = true,
19891996 .psl = false,
src/codegen/c.zig+1
......@@ -1954,6 +1954,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
19541954 => return f.fail("TODO implement optimized float mode", .{}),
19551955
19561956 .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", .{}),
19571958 // zig fmt: on
19581959 };
19591960 switch (result_value) {
src/codegen/llvm.zig+180-18
......@@ -722,6 +722,10 @@ pub const Object = struct {
722722 dg.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
723723 }
724724
725 if (decl.@"linksection") |section| {
726 llvm_func.setSection(section);
727 }
728
725729 // Remove all the basic blocks of a function in order to start over, generating
726730 // LLVM IR from an empty function body.
727731 while (llvm_func.getFirstBasicBlock()) |bb| {
......@@ -917,6 +921,40 @@ pub const Object = struct {
917921 };
918922 try args.append(loaded);
919923 },
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 },
920958 .as_u16 => {
921959 const param = llvm_func.getParam(llvm_arg_i);
922960 llvm_arg_i += 1;
......@@ -1107,6 +1145,11 @@ pub const Object = struct {
11071145 .hidden => llvm_global.setVisibility(.Hidden),
11081146 .protected => llvm_global.setVisibility(.Protected),
11091147 }
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 }
11101153 if (decl.val.castTag(.variable)) |variable| {
11111154 if (variable.data.is_threadlocal) {
11121155 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
......@@ -1683,8 +1726,7 @@ pub const Object = struct {
16831726 if (ty.castTag(.@"struct")) |payload| {
16841727 const struct_obj = payload.data;
16851728 if (struct_obj.layout == .Packed) {
1686 var buf: Type.Payload.Bits = undefined;
1687 const info = struct_obj.packedIntegerType(target, &buf).intInfo(target);
1729 const info = struct_obj.backing_int_ty.intInfo(target);
16881730 const dwarf_encoding: c_uint = switch (info.signedness) {
16891731 .signed => DW.ATE.signed,
16901732 .unsigned => DW.ATE.unsigned,
......@@ -2184,6 +2226,7 @@ pub const DeclGen = struct {
21842226 const target = dg.module.getTarget();
21852227 var global = try dg.resolveGlobalDecl(decl_index);
21862228 global.setAlignment(decl.getAlignment(target));
2229 if (decl.@"linksection") |section| global.setSection(section);
21872230 assert(decl.has_tv);
21882231 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
21892232 const variable = payload.data;
......@@ -2217,6 +2260,7 @@ pub const DeclGen = struct {
22172260 new_global.setLinkage(global.getLinkage());
22182261 new_global.setUnnamedAddr(global.getUnnamedAddress());
22192262 new_global.setAlignment(global.getAlignment());
2263 if (decl.@"linksection") |section| new_global.setSection(section);
22202264 new_global.setInitializer(llvm_init);
22212265 // replaceAllUsesWith requires the type to be unchanged. So we bitcast
22222266 // the new global to the old type and use that as the thing to replace
......@@ -2331,6 +2375,14 @@ pub const DeclGen = struct {
23312375 dg.addFnAttr(llvm_fn, "noreturn");
23322376 }
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
23342386 return llvm_fn;
23352387 }
23362388
......@@ -2679,9 +2731,7 @@ pub const DeclGen = struct {
26792731 const struct_obj = t.castTag(.@"struct").?.data;
26802732
26812733 if (struct_obj.layout == .Packed) {
2682 var buf: Type.Payload.Bits = undefined;
2683 const int_ty = struct_obj.packedIntegerType(target, &buf);
2684 const int_llvm_ty = try dg.lowerType(int_ty);
2734 const int_llvm_ty = try dg.lowerType(struct_obj.backing_int_ty);
26852735 gop.value_ptr.* = int_llvm_ty;
26862736 return int_llvm_ty;
26872737 }
......@@ -2886,6 +2936,18 @@ pub const DeclGen = struct {
28862936 llvm_params.appendAssumeCapacity(big_int_ty);
28872937 }
28882938 },
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 },
28892951 .as_u16 => {
28902952 try llvm_params.append(dg.context.intType(16));
28912953 },
......@@ -3330,8 +3392,8 @@ pub const DeclGen = struct {
33303392 const struct_obj = tv.ty.castTag(.@"struct").?.data;
33313393
33323394 if (struct_obj.layout == .Packed) {
3333 const big_bits = struct_obj.packedIntegerBits(target);
3334 const int_llvm_ty = dg.context.intType(big_bits);
3395 const big_bits = struct_obj.backing_int_ty.bitSize(target);
3396 const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits));
33353397 const fields = struct_obj.fields.values();
33363398 comptime assert(Type.packed_struct_layout_version == 2);
33373399 var running_int: *const llvm.Value = int_llvm_ty.constNull();
......@@ -4185,6 +4247,7 @@ pub const FuncGen = struct {
41854247 .prefetch => try self.airPrefetch(inst),
41864248
41874249 .is_named_enum_value => try self.airIsNamedEnumValue(inst),
4250 .error_set_has_value => try self.airErrorSetHasValue(inst),
41884251
41894252 .reduce => try self.airReduce(inst, false),
41904253 .reduce_optimized => try self.airReduce(inst, true),
......@@ -4394,6 +4457,39 @@ pub const FuncGen = struct {
43944457 llvm_args.appendAssumeCapacity(load_inst);
43954458 }
43964459 },
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 },
43974493 .as_u16 => {
43984494 const arg = args[it.zig_index - 1];
43994495 const llvm_arg = try self.resolveInst(arg);
......@@ -7888,6 +7984,53 @@ pub const FuncGen = struct {
78887984 }
78897985 }
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
78918034 fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
78928035 if (self.liveness.isUnused(inst)) return null;
78938036
......@@ -8243,8 +8386,8 @@ pub const FuncGen = struct {
82438386 .Struct => {
82448387 if (result_ty.containerLayout() == .Packed) {
82458388 const struct_obj = result_ty.castTag(.@"struct").?.data;
8246 const big_bits = struct_obj.packedIntegerBits(target);
8247 const int_llvm_ty = self.dg.context.intType(big_bits);
8389 const big_bits = struct_obj.backing_int_ty.bitSize(target);
8390 const int_llvm_ty = self.dg.context.intType(@intCast(c_uint, big_bits));
82488391 const fields = struct_obj.fields.values();
82498392 comptime assert(Type.packed_struct_layout_version == 2);
82508393 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.
93599502 llvm_types_index += 1;
93609503 },
93619504 .sse => {
9362 @panic("TODO");
9505 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9506 llvm_types_index += 1;
93639507 },
93649508 .sseup => {
9365 @panic("TODO");
9509 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9510 llvm_types_index += 1;
93669511 },
93679512 .x87 => {
9368 @panic("TODO");
9513 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9514 llvm_types_index += 1;
93699515 },
93709516 .x87up => {
9371 @panic("TODO");
9517 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9518 llvm_types_index += 1;
93729519 },
93739520 .complex_x87 => {
93749521 @panic("TODO");
......@@ -9414,6 +9561,7 @@ const ParamTypeIterator = struct {
94149561 target: std.Target,
94159562 llvm_types_len: u32,
94169563 llvm_types_buffer: [8]u16,
9564 byval_attr: bool,
94179565
94189566 const Lowering = enum {
94199567 no_bits,
......@@ -9421,6 +9569,7 @@ const ParamTypeIterator = struct {
94219569 byref,
94229570 abi_sized_int,
94239571 multiple_llvm_ints,
9572 multiple_llvm_float,
94249573 slice,
94259574 as_u16,
94269575 };
......@@ -9428,6 +9577,7 @@ const ParamTypeIterator = struct {
94289577 pub fn next(it: *ParamTypeIterator) ?Lowering {
94299578 if (it.zig_index >= it.fn_info.param_types.len) return null;
94309579 const ty = it.fn_info.param_types[it.zig_index];
9580 it.byval_attr = false;
94319581 return nextInner(it, ty);
94329582 }
94339583
......@@ -9513,6 +9663,7 @@ const ParamTypeIterator = struct {
95139663 .memory => {
95149664 it.zig_index += 1;
95159665 it.llvm_index += 1;
9666 it.byval_attr = true;
95169667 return .byref;
95179668 },
95189669 .sse => {
......@@ -9532,6 +9683,7 @@ const ParamTypeIterator = struct {
95329683 if (classes[0] == .memory) {
95339684 it.zig_index += 1;
95349685 it.llvm_index += 1;
9686 it.byval_attr = true;
95359687 return .byref;
95369688 }
95379689 var llvm_types_buffer: [8]u16 = undefined;
......@@ -9543,16 +9695,20 @@ const ParamTypeIterator = struct {
95439695 llvm_types_index += 1;
95449696 },
95459697 .sse => {
9546 @panic("TODO");
9698 llvm_types_buffer[llvm_types_index] = 64;
9699 llvm_types_index += 1;
95479700 },
95489701 .sseup => {
9549 @panic("TODO");
9702 llvm_types_buffer[llvm_types_index] = 64;
9703 llvm_types_index += 1;
95509704 },
95519705 .x87 => {
9552 @panic("TODO");
9706 llvm_types_buffer[llvm_types_index] = 80;
9707 llvm_types_index += 1;
95539708 },
95549709 .x87up => {
9555 @panic("TODO");
9710 llvm_types_buffer[llvm_types_index] = 80;
9711 llvm_types_index += 1;
95569712 },
95579713 .complex_x87 => {
95589714 @panic("TODO");
......@@ -9566,11 +9722,16 @@ const ParamTypeIterator = struct {
95669722 it.llvm_index += 1;
95679723 return .abi_sized_int;
95689724 }
9725 if (classes[0] == .sse and classes[1] == .none) {
9726 it.zig_index += 1;
9727 it.llvm_index += 1;
9728 return .byval;
9729 }
95699730 it.llvm_types_buffer = llvm_types_buffer;
95709731 it.llvm_types_len = llvm_types_index;
95719732 it.llvm_index += llvm_types_index;
95729733 it.zig_index += 1;
9573 return .multiple_llvm_ints;
9734 return if (classes[0] == .integer) .multiple_llvm_ints else .multiple_llvm_float;
95749735 },
95759736 },
95769737 .wasm32 => {
......@@ -9611,6 +9772,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
96119772 .target = dg.module.getTarget(),
96129773 .llvm_types_buffer = undefined,
96139774 .llvm_types_len = 0,
9775 .byval_attr = false,
96149776 };
96159777}
96169778
src/codegen/llvm/bindings.zig+6
......@@ -126,6 +126,9 @@ pub const Value = opaque {
126126 pub const setThreadLocalMode = LLVMSetThreadLocalMode;
127127 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
129132 pub const deleteGlobal = LLVMDeleteGlobal;
130133 extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void;
131134
......@@ -245,6 +248,9 @@ pub const Value = opaque {
245248
246249 pub const addFunctionAttr = ZigLLVMAddFunctionAttr;
247250 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;
248254};
249255
250256pub const Type = opaque {
src/link.zig+1
......@@ -435,6 +435,7 @@ pub const File = struct {
435435 EmitFail,
436436 NameTooLong,
437437 CurrentWorkingDirectoryUnlinked,
438 LockViolation,
438439 };
439440
440441 /// 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 {
102102 }
103103
104104 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 });
106106 try self.exprloc_relocs.append(self.gpa, .{
107107 .@"type" = if (is_ptr) .got_load else .direct_load,
108108 .target = target,
......@@ -135,7 +135,7 @@ pub const DeclState = struct {
135135 .@"type" = ty,
136136 .offset = undefined,
137137 });
138 log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() });
138 log.debug("%{d}: {}", .{ sym_index, ty.fmtDebug() });
139139 try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{
140140 .mod = self.mod,
141141 });
......@@ -143,7 +143,7 @@ pub const DeclState = struct {
143143 .mod = self.mod,
144144 }).?;
145145 };
146 log.debug("{x}: @{d} + 0", .{ offset, resolv });
146 log.debug("{x}: %{d} + 0", .{ offset, resolv });
147147 try self.abbrev_relocs.append(self.gpa, .{
148148 .target = resolv,
149149 .atom = atom,
......@@ -1056,6 +1056,7 @@ pub fn commitDeclState(
10561056 break :blk false;
10571057 };
10581058 if (deferred) {
1059 log.debug("resolving %{d} deferred until flush", .{target});
10591060 try self.global_abbrev_relocs.append(gpa, .{
10601061 .target = null,
10611062 .offset = reloc.offset,
......@@ -1063,10 +1064,12 @@ pub fn commitDeclState(
10631064 .addend = reloc.addend,
10641065 });
10651066 } else {
1067 const value = symbol.atom.off + symbol.offset + reloc.addend;
1068 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });
10661069 mem.writeInt(
10671070 u32,
10681071 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
1069 symbol.atom.off + symbol.offset + reloc.addend,
1072 value,
10701073 target_endian,
10711074 );
10721075 }
......@@ -1259,7 +1262,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
12591262 debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;
12601263 }
12611264 debug_info_sect.size = needed_size;
1262 d_sym.debug_line_header_dirty = true;
1265 d_sym.debug_info_header_dirty = true;
12631266 }
12641267 const file_pos = debug_info_sect.offset + atom.off;
12651268 try pwriteDbgInfoNops(
src/link/MachO.zig+3-3
......@@ -5315,10 +5315,10 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
53155315}
53165316
53175317fn filterDataInCode(
5318 dices: []const macho.data_in_code_entry,
5318 dices: []align(1) const macho.data_in_code_entry,
53195319 start_addr: u64,
53205320 end_addr: u64,
5321) []const macho.data_in_code_entry {
5321) []align(1) const macho.data_in_code_entry {
53225322 const Predicate = struct {
53235323 addr: u64,
53245324
......@@ -5825,7 +5825,7 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
58255825 return global;
58265826}
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 {
58295829 if (!@hasDecl(@TypeOf(predicate), "predicate"))
58305830 @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 {
218218 base_offset: i32 = 0,
219219};
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 {
222222 const tracy = trace(@src());
223223 defer tracy.end();
224224
src/link/MachO/DebugSymbols.zig+8-8
......@@ -63,17 +63,16 @@ pub const Reloc = struct {
6363pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {
6464 if (self.linkedit_segment_cmd_index == null) {
6565 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
66 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{
67 self.base.page_size,
68 self.base.page_size * 2,
69 });
66 const fileoff = @intCast(u64, self.base.page_size);
67 const needed_size = @intCast(u64, self.base.page_size) * 2;
68 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ fileoff, needed_size });
7069 // TODO this needs reworking
7170 try self.segments.append(allocator, .{
7271 .segname = makeStaticString("__LINKEDIT"),
73 .vmaddr = self.base.page_size,
74 .vmsize = self.base.page_size,
75 .fileoff = self.base.page_size,
76 .filesize = self.base.page_size,
72 .vmaddr = fileoff,
73 .vmsize = needed_size,
74 .fileoff = fileoff,
75 .filesize = needed_size,
7776 .maxprot = macho.PROT.READ,
7877 .initprot = macho.PROT.READ,
7978 .cmdsize = @sizeOf(macho.segment_command_64),
......@@ -284,6 +283,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
284283 const lc_writer = lc_buffer.writer();
285284 var ncmds: u32 = 0;
286285
286 self.updateDwarfSegment();
287287 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
288288 self.updateDwarfSegment();
289289
src/link/MachO/Object.zig+13-12
......@@ -24,7 +24,7 @@ mtime: u64,
2424contents: []align(@alignOf(u64)) const u8,
2525
2626header: macho.mach_header_64 = undefined,
27in_symtab: []const macho.nlist_64 = undefined,
27in_symtab: []align(1) const macho.nlist_64 = undefined,
2828in_strtab: []const u8 = undefined,
2929
3030symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
......@@ -99,12 +99,13 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
9999 },
100100 .SYMTAB => {
101101 const symtab = cmd.cast(macho.symtab_command).?;
102 // Sadly, SYMTAB may be at an unaligned offset within the object file.
102103 self.in_symtab = @ptrCast(
103 [*]const macho.nlist_64,
104 @alignCast(@alignOf(macho.nlist_64), &self.contents[symtab.symoff]),
104 [*]align(1) const macho.nlist_64,
105 self.contents.ptr + symtab.symoff,
105106 )[0..symtab.nsyms];
106107 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);
108109 },
109110 else => {},
110111 }
......@@ -196,10 +197,10 @@ fn filterSymbolsByAddress(
196197}
197198
198199fn filterRelocs(
199 relocs: []const macho.relocation_info,
200 relocs: []align(1) const macho.relocation_info,
200201 start_addr: u64,
201202 end_addr: u64,
202) []const macho.relocation_info {
203) []align(1) const macho.relocation_info {
203204 const Predicate = struct {
204205 addr: u64,
205206
......@@ -303,8 +304,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
303304
304305 // Read section's list of relocations
305306 const relocs = @ptrCast(
306 [*]const macho.relocation_info,
307 @alignCast(@alignOf(macho.relocation_info), &self.contents[sect.reloff]),
307 [*]align(1) const macho.relocation_info,
308 self.contents.ptr + sect.reloff,
308309 )[0..sect.nreloc];
309310
310311 // Symbols within this section only.
......@@ -472,7 +473,7 @@ fn createAtomFromSubsection(
472473 size: u64,
473474 alignment: u32,
474475 code: ?[]const u8,
475 relocs: []const macho.relocation_info,
476 relocs: []align(1) const macho.relocation_info,
476477 indexes: []const SymbolAtIndex,
477478 match: u8,
478479 sect: macho.section_64,
......@@ -538,7 +539,7 @@ pub fn getSourceSection(self: Object, index: u16) macho.section_64 {
538539 return self.sections.items[index];
539540}
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 {
542543 var it = LoadCommandIterator{
543544 .ncmds = self.header.ncmds,
544545 .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 {
549550 const dice = cmd.cast(macho.linkedit_data_command).?;
550551 const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry));
551552 return @ptrCast(
552 [*]const macho.data_in_code_entry,
553 @alignCast(@alignOf(macho.data_in_code_entry), &self.contents[dice.dataoff]),
553 [*]align(1) const macho.data_in_code_entry,
554 self.contents.ptr + dice.dataoff,
554555 )[0..ndice];
555556 },
556557 else => {},
src/main.zig+5-3
......@@ -718,7 +718,7 @@ fn buildOutputType(
718718 var test_filter: ?[]const u8 = null;
719719 var test_name_prefix: ?[]const u8 = null;
720720 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");
722722 var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR");
723723 var main_pkg_path: ?[]const u8 = null;
724724 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
......@@ -1657,7 +1657,8 @@ fn buildOutputType(
16571657 disable_c_depfile = true;
16581658 try clang_argv.appendSlice(it.other_args);
16591659 },
1660 .dep_file_mm => { // -MM
1660 .dep_file_to_stdout => { // -M, -MM
1661 // "Like -MD, but also implies -E and writes to stdout by default"
16611662 // "Like -MMD, but also implies -E and writes to stdout by default"
16621663 c_out_mode = .preprocessor;
16631664 disable_c_depfile = true;
......@@ -4226,6 +4227,7 @@ const FmtError = error{
42264227 NotOpenForWriting,
42274228 UnsupportedEncoding,
42284229 ConnectionResetByPeer,
4230 LockViolation,
42294231} || fs.File.OpenError;
42304232
42314233fn 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 {
46524654 lib_dir,
46534655 mcpu,
46544656 dep_file,
4655 dep_file_mm,
4657 dep_file_to_stdout,
46564658 framework_dir,
46574659 framework,
46584660 nostdlibinc,
src/print_air.zig+1
......@@ -243,6 +243,7 @@ const Writer = struct {
243243 .popcount,
244244 .byte_swap,
245245 .bit_reverse,
246 .error_set_has_value,
246247 => try w.writeTyOp(s, inst),
247248
248249 .block,
src/print_zir.zig+61-19
......@@ -214,7 +214,6 @@ const Writer = struct {
214214 .trunc,
215215 .round,
216216 .tag_name,
217 .reify,
218217 .type_name,
219218 .frame_type,
220219 .frame_size,
......@@ -247,7 +246,6 @@ const Writer = struct {
247246
248247 .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),
249248 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
250 .param_type => try self.writeParamType(stream, inst),
251249 .ptr_type => try self.writePtrType(stream, inst),
252250 .int => try self.writeInt(stream, inst),
253251 .int_big => try self.writeIntBig(stream, inst),
......@@ -500,6 +498,7 @@ const Writer = struct {
500498 .wasm_memory_size,
501499 .error_to_int,
502500 .int_to_error,
501 .reify,
503502 => {
504503 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
505504 const src = LazySrcLoc.nodeOffset(inst_data.node);
......@@ -605,16 +604,6 @@ const Writer = struct {
605604 try self.writeSrc(stream, inst_data.src());
606605 }
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
618607 fn writePtrType(
619608 self: *Writer,
620609 stream: anytype,
......@@ -1158,7 +1147,8 @@ const Writer = struct {
11581147 fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
11591148 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
11601149 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
11631153 if (extra.data.flags.ensure_result_used) {
11641154 try stream.writeAll("nodiscard ");
......@@ -1166,10 +1156,27 @@ const Writer = struct {
11661156 try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))});
11671157 try self.writeInstRef(stream, extra.data.callee);
11681158 try stream.writeAll(", [");
1169 for (args) |arg, i| {
1170 if (i != 0) try stream.writeAll(", ");
1171 try self.writeInstRef(stream, arg);
1159
1160 self.indent += 2;
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");
11721174 }
1175 self.indent -= 2;
1176 if (args_len != 0) {
1177 try stream.writeByteNTimes(' ', self.indent);
1178 }
1179
11731180 try stream.writeAll("]) ");
11741181 try self.writeSrc(stream, inst_data.src());
11751182 }
......@@ -1238,13 +1245,36 @@ const Writer = struct {
12381245
12391246 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
12401247 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
1241 try stream.print("{s}, {s}, ", .{
1242 @tagName(small.name_strategy), @tagName(small.layout),
1243 });
1248
1249 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
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
12451271 if (decls_len == 0) {
12461272 try stream.writeAll("{}, ");
12471273 } 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
12481278 try stream.writeAll("{\n");
12491279 self.indent += 2;
12501280 extra_index = try self.writeDecls(stream, decls_len, extra_index);
......@@ -1415,6 +1445,10 @@ const Writer = struct {
14151445 if (decls_len == 0) {
14161446 try stream.writeAll("{}, ");
14171447 } 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
14181452 try stream.writeAll("{\n");
14191453 self.indent += 2;
14201454 extra_index = try self.writeDecls(stream, decls_len, extra_index);
......@@ -1662,6 +1696,10 @@ const Writer = struct {
16621696 if (decls_len == 0) {
16631697 try stream.writeAll("{}, ");
16641698 } 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
16651703 try stream.writeAll("{\n");
16661704 self.indent += 2;
16671705 extra_index = try self.writeDecls(stream, decls_len, extra_index);
......@@ -1755,6 +1793,10 @@ const Writer = struct {
17551793 if (decls_len == 0) {
17561794 try stream.writeAll("{})");
17571795 } 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
17581800 try stream.writeAll("{\n");
17591801 self.indent += 2;
17601802 _ = try self.writeDecls(stream, decls_len, extra_index);
src/stage1/all_types.hpp+1
......@@ -1116,6 +1116,7 @@ struct AstNodeContainerDecl {
11161116 ContainerLayout layout;
11171117
11181118 bool auto_enum, is_root; // union(enum)
1119 bool unsupported_explicit_backing_int;
11191120};
11201121
11211122struct AstNodeErrorSetField {
src/stage1/analyze.cpp+6
......@@ -3034,6 +3034,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
30343034
30353035 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
30373043 if (struct_type->data.structure.resolve_loop_flag_zero_bits) {
30383044 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
30393045 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
1864018640 result->special = ConstValSpecialStatic;
1864118641 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);
1864418644 result->data.x_struct.fields = fields;
1864518645
1864618646 // layout: ContainerLayout
......@@ -18648,8 +18648,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
1864818648 fields[0]->special = ConstValSpecialStatic;
1864918649 fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr);
1865018650 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
1865118660 // fields: []Type.StructField
18652 ensure_field_index(result->type, "fields", 1);
18661 ensure_field_index(result->type, "fields", 2);
1865318662
1865418663 ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr);
1865518664 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
1866318672 struct_field_array->data.x_array.special = ConstArraySpecialNone;
1866418673 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
1866818677 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) {
1866918678 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
1871018719 struct_field_val->parent.data.p_array.elem_index = struct_field_index;
1871118720 }
1871218721 // decls: []Type.Declaration
18713 ensure_field_index(result->type, "decls", 2);
18714 if ((err = ir_make_type_info_decls(ira, source_node, fields[2],
18722 ensure_field_index(result->type, "decls", 3);
18723 if ((err = ir_make_type_info_decls(ira, source_node, fields[3],
1871518724 type_entry->data.structure.decls_scope, false)))
1871618725 {
1871718726 return err;
1871818727 }
1871918728
1872018729 // is_tuple: bool
18721 ensure_field_index(result->type, "is_tuple", 3);
18722 fields[3]->special = ConstValSpecialStatic;
18723 fields[3]->type = g->builtin_types.entry_bool;
18724 fields[3]->data.x_bool = is_tuple(type_entry);
18730 ensure_field_index(result->type, "is_tuple", 4);
18731 fields[4]->special = ConstValSpecialStatic;
18732 fields[4]->type = g->builtin_types.entry_bool;
18733 fields[4]->data.x_bool = is_tuple(type_entry);
1872518734
1872618735 break;
1872718736 }
......@@ -19313,7 +19322,14 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1931319322 assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
1931419323 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);
1931719333 if (fields_value == nullptr)
1931819334 return ira->codegen->invalid_inst_gen->value->type;
1931919335 assert(fields_value->special == ConstValSpecialStatic);
......@@ -19322,7 +19338,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1932219338 ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
1932319339 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);
1932619342 if (decls_value == nullptr)
1932719343 return ira->codegen->invalid_inst_gen->value->type;
1932819344 assert(decls_value->special == ConstValSpecialStatic);
......@@ -19335,7 +19351,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1933519351 }
1933619352
1933719353 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)))
1933919355 return ira->codegen->invalid_inst_gen->value->type;
1934019356
1934119357 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) {
29022902}
29032903
29042904// ContainerDeclType
2905// <- KEYWORD_struct
2905// <- KEYWORD_struct (LPAREN Expr RPAREN)?
29062906// / KEYWORD_enum (LPAREN Expr RPAREN)?
29072907// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
29082908// / KEYWORD_opaque
29092909static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
29102910 TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct);
29112911 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 }
29122918 AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);
29132919 res->data.container_decl.init_arg_expr = nullptr;
29142920 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;
29152924 return res;
29162925 }
29172926
src/test.zig+8-40
......@@ -1224,10 +1224,6 @@ pub const TestContext = struct {
12241224 try aux_thread_pool.init(self.gpa);
12251225 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
12311227 // Use the same global cache dir for all the tests, such that we for example don't have to
12321228 // rebuild musl libc for every case (when LLVM backend is enabled).
12331229 var global_tmp = std.testing.tmpDir(.{});
......@@ -1245,9 +1241,6 @@ pub const TestContext = struct {
12451241 defer self.gpa.free(global_cache_directory.path.?);
12461242
12471243 {
1248 var wait_group: WaitGroup = .{};
1249 defer wait_group.wait();
1250
12511244 for (self.cases.items) |*case| {
12521245 if (build_options.skip_non_native) {
12531246 if (case.target.getCpuArch() != builtin.cpu.arch)
......@@ -1267,17 +1260,19 @@ pub const TestContext = struct {
12671260 if (std.mem.indexOf(u8, case.name, test_filter) == null) continue;
12681261 }
12691262
1270 wait_group.start();
1271 try case_thread_pool.spawn(workerRunOneCase, .{
1263 var prg_node = root_node.start(case.name, case.updates.items.len);
1264 prg_node.activate();
1265 defer prg_node.end();
1266
1267 case.result = runOneCase(
12721268 self.gpa,
1273 root_node,
1274 case,
1269 &prg_node,
1270 case.*,
12751271 zig_lib_directory,
12761272 &aux_thread_pool,
12771273 global_cache_directory,
12781274 host,
1279 &wait_group,
1280 });
1275 );
12811276 }
12821277 }
12831278
......@@ -1295,33 +1290,6 @@ pub const TestContext = struct {
12951290 }
12961291 }
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
13251293 fn runOneCase(
13261294 allocator: Allocator,
13271295 root_node: *std.Progress.Node,
src/type.zig+17-52
......@@ -3000,9 +3000,17 @@ pub const Type = extern union {
30003000 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
30013001 };
30023002 if (struct_obj.layout == .Packed) {
3003 var buf: Type.Payload.Bits = undefined;
3004 const int_ty = struct_obj.packedIntegerType(target, &buf);
3005 return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) };
3003 switch (strat) {
3004 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
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) };
30063014 }
30073015
30083016 const fields = ty.structFields();
......@@ -3192,17 +3200,16 @@ pub const Type = extern union {
31923200 .Packed => {
31933201 const struct_obj = ty.castTag(.@"struct").?.data;
31943202 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),
31963204 .lazy => |arena| {
3197 if (!struct_obj.haveFieldTypes()) {
3205 if (!struct_obj.haveLayout()) {
31983206 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };
31993207 }
32003208 },
32013209 .eager => {},
32023210 }
3203 var buf: Type.Payload.Bits = undefined;
3204 const int_ty = struct_obj.packedIntegerType(target, &buf);
3205 return AbiSizeAdvanced{ .scalar = int_ty.abiSize(target) };
3211 assert(struct_obj.haveLayout());
3212 return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(target) };
32063213 },
32073214 else => {
32083215 switch (strat) {
......@@ -5771,50 +5778,6 @@ pub const Type = extern union {
57715778 }
57725779 }
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
58185781 /// This enum does not directly correspond to `std.builtin.TypeId` because
58195782 /// it has extra enum tags in it, as a way of using less memory. For example,
58205783 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
......@@ -6340,6 +6303,8 @@ pub const Type = extern union {
63406303 pub const @"anyopaque" = initTag(.anyopaque);
63416304 pub const @"null" = initTag(.@"null");
63426305
6306 pub const err_int = Type.u16;
6307
63436308 pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type {
63446309 const target = mod.getTarget();
63456310
src/value.zig+10-38
......@@ -1194,6 +1194,16 @@ pub const Value = extern union {
11941194 return switch (self.tag()) {
11951195 .bool_true, .one => true,
11961196 .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 },
11971207 else => unreachable,
11981208 };
11991209 }
......@@ -3472,44 +3482,6 @@ pub const Value = extern union {
34723482 return fromBigInt(allocator, result_q.toConst());
34733483 }
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
35133485 pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
35143486 if (ty.zigTypeTag() == .Vector) {
35153487 const result_data = try allocator.alloc(Value, ty.vectorLen());
test/behavior.zig+2
......@@ -84,6 +84,7 @@ test {
8484 _ = @import("behavior/bugs/11213.zig");
8585 _ = @import("behavior/bugs/12003.zig");
8686 _ = @import("behavior/bugs/12033.zig");
87 _ = @import("behavior/bugs/12430.zig");
8788 _ = @import("behavior/byteswap.zig");
8889 _ = @import("behavior/byval_arg_var.zig");
8990 _ = @import("behavior/call.zig");
......@@ -165,6 +166,7 @@ test {
165166
166167 if (builtin.zig_backend != .stage1) {
167168 _ = @import("behavior/decltest.zig");
169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
168170 }
169171
170172 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" {
246246 };
247247 try S.doTheTest(39);
248248}
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" {
14311431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14321432 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
14341439 const F = switch (@typeInfo(c_longdouble).Float.bits) {
14351440 16 => f16,
14361441 32 => f32,
test/behavior/eval.zig+17
......@@ -1293,3 +1293,20 @@ test "mutate through pointer-like optional at comptime" {
12931293 try expect(payload_ptr.*.* == 16);
12941294 }
12951295}
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 {
17211721fn testAbsFloatOne(in: f32, out: f32) !void {
17221722 try expect(@fabs(@as(f32, in)) == @as(f32, out));
17231723}
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" {
513513 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
514514 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
516521 const some_opaque = opaque {};
517522 const some_ptr = *some_opaque;
518523 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" {
293293fn testStruct() !void {
294294 const unpacked_struct_info = @typeInfo(TestStruct);
295295 try expect(unpacked_struct_info.Struct.is_tuple == false);
296 try expect(unpacked_struct_info.Struct.backing_integer == null);
296297 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
297298 try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4);
298299 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 {
315316 try expect(struct_info == .Struct);
316317 try expect(struct_info.Struct.is_tuple == false);
317318 try expect(struct_info.Struct.layout == .Packed);
319 try expect(struct_info.Struct.backing_integer == u128);
318320 try expect(struct_info.Struct.fields.len == 4);
319321 try expect(struct_info.Struct.fields[0].alignment == 0);
320322 try expect(struct_info.Struct.fields[2].field_type == f32);
......@@ -326,7 +328,7 @@ fn testPackedStruct() !void {
326328}
327329
328330const TestPackedStruct = packed struct {
329 fieldA: usize,
331 fieldA: u64,
330332 fieldB: void,
331333 fieldC: f32,
332334 fieldD: u32 = 4,
test/behavior/vector.zig+17
......@@ -807,6 +807,23 @@ test "vector reduce operation" {
807807 comptime try S.doTheTest();
808808}
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
810827test "mask parameter of @shuffle is comptime scope" {
811828 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
812829 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"); }
1111// target=native
1212//
1313// :5:25: error: cannot load runtime value in comptime block
14// :2:15: note: called from here
14// :2:12: note: called from here
test/cases/compile_errors/not_an_enum_type.zig+1-1
......@@ -17,4 +17,4 @@ const ExpectedVarDeclOrFn = struct {};
1717// target=native
1818//
1919// :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type'
20// :8:1: note: enum declared here
20// :8:15: note: enum declared here
test/cases/compile_errors/packed_struct_backing_int_wrong.zig created+55
......@@ -0,0 +1,55 @@
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" {
99// is_test=1
1010//
1111// :3:9: error: no field with value '5' in enum 'test.enum.E'
12// :1:1: note: declared here
12// :2:15: note: declared here
test/cases/compile_errors/wrong_number_of_arguments.zig+2-1
......@@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; }
77// backend=stage2
88// target=native
99//
10// :2:6: error: expected 3 argument(s), found 1
10// :2:5: error: expected 3 argument(s), found 1
11// :4:1: note: function declared here
test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig created+15
......@@ -0,0 +1,15 @@
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");
33const tests = @import("tests.zig");
44
55pub fn addCases(cases: *tests.StandaloneContext) void {
6 if (builtin.os.tag == .windows) {
7 // https://github.com/ziglang/zig/issues/12421
8 return;
9 }
10
611 cases.addBuildFile("test/link/bss/build.zig", .{
712 .build_modes = false, // we only guarantee zerofill for undefined in Debug
813 });
test/stack_traces.zig+6
......@@ -3,6 +3,11 @@ const os = std.os;
33const tests = @import("tests.zig");
44
55pub 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
611 cases.addCase(.{
712 .name = "return",
813 .source =
......@@ -22,6 +27,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
2227 .ReleaseSafe = .{
2328 .exclude_os = .{
2429 .windows, // segfault
30 .linux, // defeated by aggressive inlining
2531 },
2632 .expect =
2733 \\error: TheSkyIsFalling
test/standalone.zig+5-2
......@@ -34,13 +34,16 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
3434 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12194
3535 cases.addBuildFile("test/standalone/issue_9812/build.zig", .{});
3636 }
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 }
3841 if (builtin.os.tag != .wasi) {
3942 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});
4043 }
4144 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481
4245 if (builtin.cpu.arch == .x86_64) {
43 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12222
46 if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) { // https://github.com/ziglang/zig/issues/12222
4447 cases.addBuildFile("test/c_abi/build.zig", .{});
4548 }
4649 }
test/tests.zig+7
......@@ -641,6 +641,13 @@ pub fn addPkgTests(
641641 } else false;
642642 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
644651 const libc_prefix = if (test_target.target.getOs().requiresLibC())
645652 ""
646653 else if (test_target.link_libc)
tools/update_clang_options.zig+13-9
......@@ -386,11 +386,15 @@ const known_options = [_]KnownOpt{
386386 },
387387 .{
388388 .name = "MM",
389 .ident = "dep_file_mm",
389 .ident = "dep_file_to_stdout",
390 },
391 .{
392 .name = "M",
393 .ident = "dep_file_to_stdout",
390394 },
391395 .{
392396 .name = "user-dependencies",
393 .ident = "dep_file_mm",
397 .ident = "dep_file_to_stdout",
394398 },
395399 .{
396400 .name = "MMD",
......@@ -497,7 +501,7 @@ const cpu_targets = struct {
497501 pub const riscv = std.Target.riscv;
498502 pub const sparc = std.Target.sparc;
499503 pub const spirv = std.Target.spirv;
500 pub const systemz = std.Target.systemz;
504 pub const s390x = std.Target.s390x;
501505 pub const ve = std.Target.ve;
502506 pub const wasm = std.Target.wasm;
503507 pub const x86 = std.Target.x86;
......@@ -647,9 +651,9 @@ pub fn main() anyerror!void {
647651 \\ .name = "{s}",
648652 \\ .syntax = {s},
649653 \\ .zig_equivalent = .{s},
650 \\ .pd1 = {s},
651 \\ .pd2 = {s},
652 \\ .psl = {s},
654 \\ .pd1 = {},
655 \\ .pd2 = {},
656 \\ .psl = {},
653657 \\}},
654658 \\
655659 , .{ name, final_syntax, ident, pd1, pd2, pslash });
......@@ -677,9 +681,9 @@ pub fn main() anyerror!void {
677681 \\ .name = "{s}",
678682 \\ .syntax = {s},
679683 \\ .zig_equivalent = .other,
680 \\ .pd1 = {s},
681 \\ .pd2 = {s},
682 \\ .psl = {s},
684 \\ .pd1 = {},
685 \\ .pd2 = {},
686 \\ .psl = {},
683687 \\}},
684688 \\
685689 , .{ name, syntax, pd1, pd2, pslash });