authorgravatar for michael.dusan@gmail.comMichael Dusan <michael.dusan@gmail.com> 2021-04-11 17:40:19-04:00
committergravatar for michael.dusan@gmail.comMichael Dusan <michael.dusan@gmail.com> 2021-04-11 17:40:19-04:00
log93cf9560b13619159efb3ca12eeeb13d6031ad85
tree4b5857db65268b6e3a41fc436082da7b100647b6
parent86b31394c9d73b0f753918cea4f08ce8d7a26119
parent82a31aac9b955213f47ff3b2a2c7eb932fdbe294
signature Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into llvm12


78 files changed, 6701 insertions(+), 4013 deletions(-)

ci/azure/macos_arm64_script+1-2
...@@ -114,13 +114,12 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then...@@ -114,13 +114,12 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
114 SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)114 SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
115 BYTESIZE=$(wc -c < $TARBALL)115 BYTESIZE=$(wc -c < $TARBALL)
116116
117 JSONFILE="macos-$GITBRANCH.json"117 JSONFILE="tarball.json"
118 touch $JSONFILE118 touch $JSONFILE
119 echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE119 echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
120 echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE120 echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
121 echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE121 echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
122122
123 s3cmd put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE"
124 s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"123 s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"
125124
126 # `set -x` causes these variables to be mangled.125 # `set -x` causes these variables to be mangled.
ci/azure/pipelines.yml+2-1
...@@ -24,7 +24,7 @@ jobs:...@@ -24,7 +24,7 @@ jobs:
24 secureFile: s3cfg24 secureFile: s3cfg
25 - script: ci/azure/macos_arm64_script25 - script: ci/azure/macos_arm64_script
26 name: main26 name: main
27 displayName: 'Build and cross-compile'27 displayName: 'Build'
28- job: BuildLinux28- job: BuildLinux
29 pool:29 pool:
30 vmImage: 'ubuntu-18.04'30 vmImage: 'ubuntu-18.04'
...@@ -66,6 +66,7 @@ jobs:...@@ -66,6 +66,7 @@ jobs:
66- job: OnMasterSuccess66- job: OnMasterSuccess
67 dependsOn:67 dependsOn:
68 - BuildMacOS68 - BuildMacOS
69 - BuildMacOS_arm64
69 - BuildLinux70 - BuildLinux
70 - BuildWindows71 - BuildWindows
71 condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))72 condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
ci/srht/index.html+6
...@@ -199,6 +199,12 @@...@@ -199,6 +199,12 @@
199 <td>{{X86_64_MACOS_BYTESIZE}}</td>199 <td>{{X86_64_MACOS_BYTESIZE}}</td>
200 <td class="code">{{X86_64_MACOS_SHASUM}}</td>200 <td class="code">{{X86_64_MACOS_SHASUM}}</td>
201 </tr>201 </tr>
202 <tr>
203 <td><a href="https://ziglang.org/builds/{{AARCH64_MACOS_TARBALL}}">{{AARCH64_MACOS_TARBALL}}</a></td>
204 <td>Binary</td>
205 <td>{{AARCH64_MACOS_BYTESIZE}}</td>
206 <td class="code">{{AARCH64_MACOS_SHASUM}}</td>
207 </tr>
202 <tr>208 <tr>
203 <td><a href="https://ziglang.org/builds/{{X86_64_FREEBSD_TARBALL}}">{{X86_64_FREEBSD_TARBALL}}</a></td>209 <td><a href="https://ziglang.org/builds/{{X86_64_FREEBSD_TARBALL}}">{{X86_64_FREEBSD_TARBALL}}</a></td>
204 <td>Binary</td>210 <td>Binary</td>
ci/srht/index.json+5
...@@ -19,6 +19,11 @@...@@ -19,6 +19,11 @@
19 "shasum": "{{X86_64_MACOS_SHASUM}}",19 "shasum": "{{X86_64_MACOS_SHASUM}}",
20 "size": "{{X86_64_MACOS_BYTESIZE}}"20 "size": "{{X86_64_MACOS_BYTESIZE}}"
21 },21 },
22 "aarch64-macos": {
23 "tarball": "https://ziglang.org/builds/{{AARCH64_MACOS_TARBALL}}",
24 "shasum": "{{AARCH64_MACOS_SHASUM}}",
25 "size": "{{AARCH64_MACOS_BYTESIZE}}"
26 },
22 "x86_64-windows": {27 "x86_64-windows": {
23 "tarball": "https://ziglang.org/builds/{{X86_64_WINDOWS_TARBALL}}",28 "tarball": "https://ziglang.org/builds/{{X86_64_WINDOWS_TARBALL}}",
24 "shasum": "{{X86_64_WINDOWS_SHASUM}}",29 "shasum": "{{X86_64_WINDOWS_SHASUM}}",
ci/srht/update_download_page+7
...@@ -12,6 +12,7 @@ NATIVE_TARBALL="zig-linux-$(uname -m)-$VERSION.tar.xz"...@@ -12,6 +12,7 @@ NATIVE_TARBALL="zig-linux-$(uname -m)-$VERSION.tar.xz"
12AARCH64_LINUX_JSON_URL="https://ziglang.org/builds/aarch64-linux-$VERSION.json"12AARCH64_LINUX_JSON_URL="https://ziglang.org/builds/aarch64-linux-$VERSION.json"
13X86_64_LINUX_JSON_URL="https://ziglang.org/builds/x86_64-linux-$VERSION.json"13X86_64_LINUX_JSON_URL="https://ziglang.org/builds/x86_64-linux-$VERSION.json"
14X86_64_WINDOWS_JSON_URL="https://ziglang.org/builds/x86_64-windows-$VERSION.json"14X86_64_WINDOWS_JSON_URL="https://ziglang.org/builds/x86_64-windows-$VERSION.json"
15AARCH64_MACOS_JSON_URL="https://ziglang.org/builds/aarch64-macos-$VERSION.json"
15X86_64_MACOS_JSON_URL="https://ziglang.org/builds/x86_64-macos-$VERSION.json"16X86_64_MACOS_JSON_URL="https://ziglang.org/builds/x86_64-macos-$VERSION.json"
16X86_64_FREEBSD_JSON_URL="https://ziglang.org/builds/x86_64-freebsd-$VERSION.json"17X86_64_FREEBSD_JSON_URL="https://ziglang.org/builds/x86_64-freebsd-$VERSION.json"
1718
...@@ -20,6 +21,7 @@ X86_64_FREEBSD_JSON_URL="https://ziglang.org/builds/x86_64-freebsd-$VERSION.json...@@ -20,6 +21,7 @@ X86_64_FREEBSD_JSON_URL="https://ziglang.org/builds/x86_64-freebsd-$VERSION.json
20curl --fail -I "$AARCH64_LINUX_JSON_URL" >/dev/null || exit 021curl --fail -I "$AARCH64_LINUX_JSON_URL" >/dev/null || exit 0
21curl --fail -I "$X86_64_LINUX_JSON_URL" >/dev/null || exit 022curl --fail -I "$X86_64_LINUX_JSON_URL" >/dev/null || exit 0
22curl --fail -I "$X86_64_WINDOWS_JSON_URL" >/dev/null || exit 023curl --fail -I "$X86_64_WINDOWS_JSON_URL" >/dev/null || exit 0
24curl --fail -I "$AARCH64_MACOS_JSON_URL" >/dev/null || exit 0
23curl --fail -I "$X86_64_MACOS_JSON_URL" >/dev/null || exit 025curl --fail -I "$X86_64_MACOS_JSON_URL" >/dev/null || exit 0
24curl --fail -I "$X86_64_FREEBSD_JSON_URL" >/dev/null || exit 026curl --fail -I "$X86_64_FREEBSD_JSON_URL" >/dev/null || exit 0
2527
...@@ -57,6 +59,11 @@ export X86_64_WINDOWS_TARBALL="$(echo "$X86_64_WINDOWS_JSON" | jq .tarball -r)"...@@ -57,6 +59,11 @@ export X86_64_WINDOWS_TARBALL="$(echo "$X86_64_WINDOWS_JSON" | jq .tarball -r)"
57export X86_64_WINDOWS_BYTESIZE="$(echo "$X86_64_WINDOWS_JSON" | jq .size -r)"59export X86_64_WINDOWS_BYTESIZE="$(echo "$X86_64_WINDOWS_JSON" | jq .size -r)"
58export X86_64_WINDOWS_SHASUM="$(echo "$X86_64_WINDOWS_JSON" | jq .shasum -r)"60export X86_64_WINDOWS_SHASUM="$(echo "$X86_64_WINDOWS_JSON" | jq .shasum -r)"
5961
62AARCH64_MACOS_JSON=$(curl --fail "$AARCH64_MACOS_JSON_URL" || exit 1)
63export AARCH64_MACOS_TARBALL="$(echo "$AARCH64_MACOS_JSON" | jq .tarball -r)"
64export AARCH64_MACOS_BYTESIZE="$(echo "$AARCH64_MACOS_JSON" | jq .size -r)"
65export AARCH64_MACOS_SHASUM="$(echo "$AARCH64_MACOS_JSON" | jq .shasum -r)"
66
60X86_64_MACOS_JSON=$(curl --fail "$X86_64_MACOS_JSON_URL" || exit 1)67X86_64_MACOS_JSON=$(curl --fail "$X86_64_MACOS_JSON_URL" || exit 1)
61export X86_64_MACOS_TARBALL="$(echo "$X86_64_MACOS_JSON" | jq .tarball -r)"68export X86_64_MACOS_TARBALL="$(echo "$X86_64_MACOS_JSON" | jq .tarball -r)"
62export X86_64_MACOS_BYTESIZE="$(echo "$X86_64_MACOS_JSON" | jq .size -r)"69export X86_64_MACOS_BYTESIZE="$(echo "$X86_64_MACOS_JSON" | jq .size -r)"
doc/docgen.zig+1-2
...@@ -1023,6 +1023,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any...@@ -1023,6 +1023,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
1023 const builtin_code = try getBuiltinCode(allocator, &env_map, zig_exe);1023 const builtin_code = try getBuiltinCode(allocator, &env_map, zig_exe);
10241024
1025 for (toc.nodes) |node| {1025 for (toc.nodes) |node| {
1026 defer root_node.completeOne();
1026 switch (node) {1027 switch (node) {
1027 .Content => |data| {1028 .Content => |data| {
1028 try out.writeAll(data);1029 try out.writeAll(data);
...@@ -1062,8 +1063,6 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any...@@ -1062,8 +1063,6 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
1062 try tokenizeAndPrint(tokenizer, out, content_tok);1063 try tokenizeAndPrint(tokenizer, out, content_tok);
1063 },1064 },
1064 .Code => |code| {1065 .Code => |code| {
1065 root_node.completeOne();
1066
1067 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];1066 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
1068 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");1067 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
1069 if (!code.is_inline) {1068 if (!code.is_inline) {
doc/langref.html.in+5-1
...@@ -85,7 +85,6 @@...@@ -85,7 +85,6 @@
85 #main-wrapper {85 #main-wrapper {
86 display: flex;86 display: flex;
87 flex-direction: column;87 flex-direction: column;
88 height: 100vh;
89 }88 }
9089
91 #contents-wrapper {90 #contents-wrapper {
...@@ -106,6 +105,11 @@...@@ -106,6 +105,11 @@
106 #main-wrapper {105 #main-wrapper {
107 flex-direction: row;106 flex-direction: row;
108 }107 }
108 #toc {
109 height: 100vh;
110 position: sticky;
111 top: 0;
112 }
109 #contents-wrapper, #toc {113 #contents-wrapper, #toc {
110 overflow: auto;114 overflow: auto;
111 }115 }
lib/std/build.zig+9
...@@ -1939,6 +1939,15 @@ pub const LibExeObjStep = struct {...@@ -1939,6 +1939,15 @@ pub const LibExeObjStep = struct {
1939 out.print("pub const {}: []const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable;1939 out.print("pub const {}: []const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable;
1940 return;1940 return;
1941 },1941 },
1942 ?[:0]const u8 => {
1943 out.print("pub const {}: ?[:0]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;
1944 if (value) |payload| {
1945 out.print("\"{}\";\n", .{std.zig.fmtEscapes(payload)}) catch unreachable;
1946 } else {
1947 out.writeAll("null;\n") catch unreachable;
1948 }
1949 return;
1950 },
1942 ?[]const u8 => {1951 ?[]const u8 => {
1943 out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;1952 out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;
1944 if (value) |payload| {1953 if (value) |payload| {
lib/std/c/netbsd.zig+5-4
...@@ -18,14 +18,14 @@ pub extern "c" fn _lwp_self() lwpid_t;...@@ -18,14 +18,14 @@ pub extern "c" fn _lwp_self() lwpid_t;
1818
19pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;19pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
20pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;20pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
21pub extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int;21pub extern "c" fn __fstat50(fd: fd_t, buf: *libc_stat) c_int;
22pub extern "c" fn __stat50(path: [*:0]const u8, buf: *Stat) c_int;22pub extern "c" fn __stat50(path: [*:0]const u8, buf: *libc_stat) c_int;
23pub extern "c" fn __clock_gettime50(clk_id: c_int, tp: *timespec) c_int;23pub extern "c" fn __clock_gettime50(clk_id: c_int, tp: *timespec) c_int;
24pub extern "c" fn __clock_getres50(clk_id: c_int, tp: *timespec) c_int;24pub extern "c" fn __clock_getres50(clk_id: c_int, tp: *timespec) c_int;
25pub extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;25pub extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;
26pub extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int;26pub extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
27pub extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int;27pub extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int;
28pub extern "c" fn __sigaction14(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;28pub extern "c" fn __sigaction14(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
29pub extern "c" fn __sigprocmask14(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;29pub extern "c" fn __sigprocmask14(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
30pub extern "c" fn __socket30(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;30pub extern "c" fn __socket30(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
31pub extern "c" fn __gettimeofday50(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;31pub extern "c" fn __gettimeofday50(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
...@@ -34,7 +34,6 @@ pub extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int;...@@ -34,7 +34,6 @@ pub extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int;
34pub extern "c" fn __libc_thr_yield() c_int;34pub extern "c" fn __libc_thr_yield() c_int;
3535
36pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int;36pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int;
37pub extern "c" fn malloc_usable_size(?*const c_void) usize;
3837
39pub const pthread_mutex_t = extern struct {38pub const pthread_mutex_t = extern struct {
40 ptm_magic: u32 = 0x33330003,39 ptm_magic: u32 = 0x33330003,
...@@ -93,3 +92,5 @@ pub const pthread_attr_t = extern struct {...@@ -93,3 +92,5 @@ pub const pthread_attr_t = extern struct {
93 pta_flags: i32,92 pta_flags: i32,
94 pta_private: ?*c_void,93 pta_private: ?*c_void,
95};94};
95
96pub const sem_t = ?*opaque {};
lib/std/debug.zig+1-1
...@@ -462,7 +462,7 @@ pub const TTY = struct {...@@ -462,7 +462,7 @@ pub const TTY = struct {
462 // TODO give this a payload of file handle462 // TODO give this a payload of file handle
463 windows_api,463 windows_api,
464464
465 fn setColor(conf: Config, out_stream: anytype, color: Color) void {465 pub fn setColor(conf: Config, out_stream: anytype, color: Color) void {
466 nosuspend switch (conf) {466 nosuspend switch (conf) {
467 .no_color => return,467 .no_color => return,
468 .escape_codes => switch (color) {468 .escape_codes => switch (color) {
lib/std/fs/file.zig+4-4
...@@ -223,15 +223,15 @@ pub const File = struct {...@@ -223,15 +223,15 @@ pub const File = struct {
223 return os.lseek_SET(self.handle, offset);223 return os.lseek_SET(self.handle, offset);
224 }224 }
225225
226 pub const GetPosError = os.SeekError || os.FStatError;226 pub const GetSeekPosError = os.SeekError || os.FStatError;
227227
228 /// TODO: integrate with async I/O228 /// TODO: integrate with async I/O
229 pub fn getPos(self: File) GetPosError!u64 {229 pub fn getPos(self: File) GetSeekPosError!u64 {
230 return os.lseek_CUR_get(self.handle);230 return os.lseek_CUR_get(self.handle);
231 }231 }
232232
233 /// TODO: integrate with async I/O233 /// TODO: integrate with async I/O
234 pub fn getEndPos(self: File) GetPosError!u64 {234 pub fn getEndPos(self: File) GetSeekPosError!u64 {
235 if (builtin.os.tag == .windows) {235 if (builtin.os.tag == .windows) {
236 return windows.GetFileSizeEx(self.handle);236 return windows.GetFileSizeEx(self.handle);
237 }237 }
...@@ -819,7 +819,7 @@ pub const File = struct {...@@ -819,7 +819,7 @@ pub const File = struct {
819 pub const SeekableStream = io.SeekableStream(819 pub const SeekableStream = io.SeekableStream(
820 File,820 File,
821 SeekError,821 SeekError,
822 GetPosError,822 GetSeekPosError,
823 seekTo,823 seekTo,
824 seekBy,824 seekBy,
825 getPos,825 getPos,
lib/std/hash_map.zig-4
...@@ -398,10 +398,6 @@ pub fn HashMapUnmanaged(...@@ -398,10 +398,6 @@ pub fn HashMapUnmanaged(
398 return size * 100 < max_load_percentage * cap;398 return size * 100 < max_load_percentage * cap;
399 }399 }
400400
401 pub fn init(allocator: *Allocator) Self {
402 return .{};
403 }
404
405 pub fn deinit(self: *Self, allocator: *Allocator) void {401 pub fn deinit(self: *Self, allocator: *Allocator) void {
406 self.deallocate(allocator);402 self.deallocate(allocator);
407 self.* = undefined;403 self.* = undefined;
lib/std/io/stream_source.zig+1-2
...@@ -5,7 +5,6 @@...@@ -5,7 +5,6 @@
5// and substantial portions of the software.5// and substantial portions of the software.
6const std = @import("../std.zig");6const std = @import("../std.zig");
7const io = std.io;7const io = std.io;
8const testing = std.testing;
98
10/// Provides `io.Reader`, `io.Writer`, and `io.SeekableStream` for in-memory buffers as9/// Provides `io.Reader`, `io.Writer`, and `io.SeekableStream` for in-memory buffers as
11/// well as files.10/// well as files.
...@@ -19,7 +18,7 @@ pub const StreamSource = union(enum) {...@@ -19,7 +18,7 @@ pub const StreamSource = union(enum) {
19 pub const ReadError = std.fs.File.ReadError;18 pub const ReadError = std.fs.File.ReadError;
20 pub const WriteError = std.fs.File.WriteError;19 pub const WriteError = std.fs.File.WriteError;
21 pub const SeekError = std.fs.File.SeekError;20 pub const SeekError = std.fs.File.SeekError;
22 pub const GetSeekPosError = std.fs.File.GetPosError;21 pub const GetSeekPosError = std.fs.File.GetSeekPosError;
2322
24 pub const Reader = io.Reader(*StreamSource, ReadError, read);23 pub const Reader = io.Reader(*StreamSource, ReadError, read);
25 pub const Writer = io.Writer(*StreamSource, WriteError, write);24 pub const Writer = io.Writer(*StreamSource, WriteError, write);
lib/std/json.zig+2-2
...@@ -1234,7 +1234,7 @@ test "json.validate" {...@@ -1234,7 +1234,7 @@ test "json.validate" {
1234const Allocator = std.mem.Allocator;1234const Allocator = std.mem.Allocator;
1235const ArenaAllocator = std.heap.ArenaAllocator;1235const ArenaAllocator = std.heap.ArenaAllocator;
1236const ArrayList = std.ArrayList;1236const ArrayList = std.ArrayList;
1237const StringHashMap = std.StringHashMap;1237const StringArrayHashMap = std.StringArrayHashMap;
12381238
1239pub const ValueTree = struct {1239pub const ValueTree = struct {
1240 arena: ArenaAllocator,1240 arena: ArenaAllocator,
...@@ -1245,7 +1245,7 @@ pub const ValueTree = struct {...@@ -1245,7 +1245,7 @@ pub const ValueTree = struct {
1245 }1245 }
1246};1246};
12471247
1248pub const ObjectMap = StringHashMap(Value);1248pub const ObjectMap = StringArrayHashMap(Value);
1249pub const Array = ArrayList(Value);1249pub const Array = ArrayList(Value);
12501250
1251/// Represents a JSON value1251/// Represents a JSON value
lib/std/json/test.zig+119-103
...@@ -12,7 +12,7 @@ const std = @import("../std.zig");...@@ -12,7 +12,7 @@ const std = @import("../std.zig");
12const json = std.json;12const json = std.json;
13const testing = std.testing;13const testing = std.testing;
1414
15fn testNonStreaming(comptime s: []const u8) !void {15fn testNonStreaming(s: []const u8) !void {
16 var p = json.Parser.init(testing.allocator, false);16 var p = json.Parser.init(testing.allocator, false);
17 defer p.deinit();17 defer p.deinit();
1818
...@@ -20,44 +20,60 @@ fn testNonStreaming(comptime s: []const u8) !void {...@@ -20,44 +20,60 @@ fn testNonStreaming(comptime s: []const u8) !void {
20 defer tree.deinit();20 defer tree.deinit();
21}21}
2222
23fn ok(comptime s: []const u8) void {23fn ok(s: []const u8) !void {
24 testing.expect(json.validate(s));24 testing.expect(json.validate(s));
2525
26 testNonStreaming(s) catch testing.expect(false);26 try testNonStreaming(s);
27}27}
2828
29fn err(comptime s: []const u8) void {29fn err(s: []const u8) void {
30 testing.expect(!json.validate(s));30 testing.expect(!json.validate(s));
3131
32 testNonStreaming(s) catch return;32 testNonStreaming(s) catch return;
33 testing.expect(false);33 testing.expect(false);
34}34}
3535
36fn utf8Error(comptime s: []const u8) void {36fn utf8Error(s: []const u8) void {
37 testing.expect(!json.validate(s));37 testing.expect(!json.validate(s));
3838
39 testing.expectError(error.InvalidUtf8Byte, testNonStreaming(s));39 testing.expectError(error.InvalidUtf8Byte, testNonStreaming(s));
40}40}
4141
42fn any(comptime s: []const u8) void {42fn any(s: []const u8) void {
43 _ = json.validate(s);43 _ = json.validate(s);
4444
45 testNonStreaming(s) catch {};45 testNonStreaming(s) catch {};
46}46}
4747
48fn anyStreamingErrNonStreaming(comptime s: []const u8) void {48fn anyStreamingErrNonStreaming(s: []const u8) void {
49 _ = json.validate(s);49 _ = json.validate(s);
5050
51 testNonStreaming(s) catch return;51 testNonStreaming(s) catch return;
52 testing.expect(false);52 testing.expect(false);
53}53}
5454
55fn roundTrip(s: []const u8) !void {
56 testing.expect(json.validate(s));
57
58 var p = json.Parser.init(testing.allocator, false);
59 defer p.deinit();
60
61 var tree = try p.parse(s);
62 defer tree.deinit();
63
64 var buf: [256]u8 = undefined;
65 var fbs = std.io.fixedBufferStream(&buf);
66 try tree.root.jsonStringify(.{}, fbs.writer());
67
68 testing.expectEqualStrings(s, fbs.getWritten());
69}
70
55////////////////////////////////////////////////////////////////////////////////////////////////////71////////////////////////////////////////////////////////////////////////////////////////////////////
56//72//
57// Additional tests not part of test JSONTestSuite.73// Additional tests not part of test JSONTestSuite.
5874
59test "y_trailing_comma_after_empty" {75test "y_trailing_comma_after_empty" {
60 ok(76 try roundTrip(
61 \\{"1":[],"2":{},"3":"4"}77 \\{"1":[],"2":{},"3":"4"}
62 );78 );
63}79}
...@@ -65,252 +81,252 @@ test "y_trailing_comma_after_empty" {...@@ -65,252 +81,252 @@ test "y_trailing_comma_after_empty" {
65////////////////////////////////////////////////////////////////////////////////////////////////////81////////////////////////////////////////////////////////////////////////////////////////////////////
6682
67test "y_array_arraysWithSpaces" {83test "y_array_arraysWithSpaces" {
68 ok(84 try ok(
69 \\[[] ]85 \\[[] ]
70 );86 );
71}87}
7288
73test "y_array_empty" {89test "y_array_empty" {
74 ok(90 try roundTrip(
75 \\[]91 \\[]
76 );92 );
77}93}
7894
79test "y_array_empty-string" {95test "y_array_empty-string" {
80 ok(96 try roundTrip(
81 \\[""]97 \\[""]
82 );98 );
83}99}
84100
85test "y_array_ending_with_newline" {101test "y_array_ending_with_newline" {
86 ok(102 try roundTrip(
87 \\["a"]103 \\["a"]
88 );104 );
89}105}
90106
91test "y_array_false" {107test "y_array_false" {
92 ok(108 try roundTrip(
93 \\[false]109 \\[false]
94 );110 );
95}111}
96112
97test "y_array_heterogeneous" {113test "y_array_heterogeneous" {
98 ok(114 try ok(
99 \\[null, 1, "1", {}]115 \\[null, 1, "1", {}]
100 );116 );
101}117}
102118
103test "y_array_null" {119test "y_array_null" {
104 ok(120 try roundTrip(
105 \\[null]121 \\[null]
106 );122 );
107}123}
108124
109test "y_array_with_1_and_newline" {125test "y_array_with_1_and_newline" {
110 ok(126 try ok(
111 \\[1127 \\[1
112 \\]128 \\]
113 );129 );
114}130}
115131
116test "y_array_with_leading_space" {132test "y_array_with_leading_space" {
117 ok(133 try ok(
118 \\ [1]134 \\ [1]
119 );135 );
120}136}
121137
122test "y_array_with_several_null" {138test "y_array_with_several_null" {
123 ok(139 try roundTrip(
124 \\[1,null,null,null,2]140 \\[1,null,null,null,2]
125 );141 );
126}142}
127143
128test "y_array_with_trailing_space" {144test "y_array_with_trailing_space" {
129 ok("[2] ");145 try ok("[2] ");
130}146}
131147
132test "y_number_0e+1" {148test "y_number_0e+1" {
133 ok(149 try ok(
134 \\[0e+1]150 \\[0e+1]
135 );151 );
136}152}
137153
138test "y_number_0e1" {154test "y_number_0e1" {
139 ok(155 try ok(
140 \\[0e1]156 \\[0e1]
141 );157 );
142}158}
143159
144test "y_number_after_space" {160test "y_number_after_space" {
145 ok(161 try ok(
146 \\[ 4]162 \\[ 4]
147 );163 );
148}164}
149165
150test "y_number_double_close_to_zero" {166test "y_number_double_close_to_zero" {
151 ok(167 try ok(
152 \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]168 \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]
153 );169 );
154}170}
155171
156test "y_number_int_with_exp" {172test "y_number_int_with_exp" {
157 ok(173 try ok(
158 \\[20e1]174 \\[20e1]
159 );175 );
160}176}
161177
162test "y_number" {178test "y_number" {
163 ok(179 try ok(
164 \\[123e65]180 \\[123e65]
165 );181 );
166}182}
167183
168test "y_number_minus_zero" {184test "y_number_minus_zero" {
169 ok(185 try ok(
170 \\[-0]186 \\[-0]
171 );187 );
172}188}
173189
174test "y_number_negative_int" {190test "y_number_negative_int" {
175 ok(191 try roundTrip(
176 \\[-123]192 \\[-123]
177 );193 );
178}194}
179195
180test "y_number_negative_one" {196test "y_number_negative_one" {
181 ok(197 try roundTrip(
182 \\[-1]198 \\[-1]
183 );199 );
184}200}
185201
186test "y_number_negative_zero" {202test "y_number_negative_zero" {
187 ok(203 try ok(
188 \\[-0]204 \\[-0]
189 );205 );
190}206}
191207
192test "y_number_real_capital_e" {208test "y_number_real_capital_e" {
193 ok(209 try ok(
194 \\[1E22]210 \\[1E22]
195 );211 );
196}212}
197213
198test "y_number_real_capital_e_neg_exp" {214test "y_number_real_capital_e_neg_exp" {
199 ok(215 try ok(
200 \\[1E-2]216 \\[1E-2]
201 );217 );
202}218}
203219
204test "y_number_real_capital_e_pos_exp" {220test "y_number_real_capital_e_pos_exp" {
205 ok(221 try ok(
206 \\[1E+2]222 \\[1E+2]
207 );223 );
208}224}
209225
210test "y_number_real_exponent" {226test "y_number_real_exponent" {
211 ok(227 try ok(
212 \\[123e45]228 \\[123e45]
213 );229 );
214}230}
215231
216test "y_number_real_fraction_exponent" {232test "y_number_real_fraction_exponent" {
217 ok(233 try ok(
218 \\[123.456e78]234 \\[123.456e78]
219 );235 );
220}236}
221237
222test "y_number_real_neg_exp" {238test "y_number_real_neg_exp" {
223 ok(239 try ok(
224 \\[1e-2]240 \\[1e-2]
225 );241 );
226}242}
227243
228test "y_number_real_pos_exponent" {244test "y_number_real_pos_exponent" {
229 ok(245 try ok(
230 \\[1e+2]246 \\[1e+2]
231 );247 );
232}248}
233249
234test "y_number_simple_int" {250test "y_number_simple_int" {
235 ok(251 try roundTrip(
236 \\[123]252 \\[123]
237 );253 );
238}254}
239255
240test "y_number_simple_real" {256test "y_number_simple_real" {
241 ok(257 try ok(
242 \\[123.456789]258 \\[123.456789]
243 );259 );
244}260}
245261
246test "y_object_basic" {262test "y_object_basic" {
247 ok(263 try roundTrip(
248 \\{"asd":"sdf"}264 \\{"asd":"sdf"}
249 );265 );
250}266}
251267
252test "y_object_duplicated_key_and_value" {268test "y_object_duplicated_key_and_value" {
253 ok(269 try ok(
254 \\{"a":"b","a":"b"}270 \\{"a":"b","a":"b"}
255 );271 );
256}272}
257273
258test "y_object_duplicated_key" {274test "y_object_duplicated_key" {
259 ok(275 try ok(
260 \\{"a":"b","a":"c"}276 \\{"a":"b","a":"c"}
261 );277 );
262}278}
263279
264test "y_object_empty" {280test "y_object_empty" {
265 ok(281 try roundTrip(
266 \\{}282 \\{}
267 );283 );
268}284}
269285
270test "y_object_empty_key" {286test "y_object_empty_key" {
271 ok(287 try roundTrip(
272 \\{"":0}288 \\{"":0}
273 );289 );
274}290}
275291
276test "y_object_escaped_null_in_key" {292test "y_object_escaped_null_in_key" {
277 ok(293 try ok(
278 \\{"foo\u0000bar": 42}294 \\{"foo\u0000bar": 42}
279 );295 );
280}296}
281297
282test "y_object_extreme_numbers" {298test "y_object_extreme_numbers" {
283 ok(299 try ok(
284 \\{ "min": -1.0e+28, "max": 1.0e+28 }300 \\{ "min": -1.0e+28, "max": 1.0e+28 }
285 );301 );
286}302}
287303
288test "y_object" {304test "y_object" {
289 ok(305 try ok(
290 \\{"asd":"sdf", "dfg":"fgh"}306 \\{"asd":"sdf", "dfg":"fgh"}
291 );307 );
292}308}
293309
294test "y_object_long_strings" {310test "y_object_long_strings" {
295 ok(311 try ok(
296 \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}312 \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
297 );313 );
298}314}
299315
300test "y_object_simple" {316test "y_object_simple" {
301 ok(317 try roundTrip(
302 \\{"a":[]}318 \\{"a":[]}
303 );319 );
304}320}
305321
306test "y_object_string_unicode" {322test "y_object_string_unicode" {
307 ok(323 try ok(
308 \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }324 \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }
309 );325 );
310}326}
311327
312test "y_object_with_newlines" {328test "y_object_with_newlines" {
313 ok(329 try ok(
314 \\{330 \\{
315 \\"a": "b"331 \\"a": "b"
316 \\}332 \\}
...@@ -318,311 +334,311 @@ test "y_object_with_newlines" {...@@ -318,311 +334,311 @@ test "y_object_with_newlines" {
318}334}
319335
320test "y_string_1_2_3_bytes_UTF-8_sequences" {336test "y_string_1_2_3_bytes_UTF-8_sequences" {
321 ok(337 try ok(
322 \\["\u0060\u012a\u12AB"]338 \\["\u0060\u012a\u12AB"]
323 );339 );
324}340}
325341
326test "y_string_accepted_surrogate_pair" {342test "y_string_accepted_surrogate_pair" {
327 ok(343 try ok(
328 \\["\uD801\udc37"]344 \\["\uD801\udc37"]
329 );345 );
330}346}
331347
332test "y_string_accepted_surrogate_pairs" {348test "y_string_accepted_surrogate_pairs" {
333 ok(349 try ok(
334 \\["\ud83d\ude39\ud83d\udc8d"]350 \\["\ud83d\ude39\ud83d\udc8d"]
335 );351 );
336}352}
337353
338test "y_string_allowed_escapes" {354test "y_string_allowed_escapes" {
339 ok(355 try ok(
340 \\["\"\\\/\b\f\n\r\t"]356 \\["\"\\\/\b\f\n\r\t"]
341 );357 );
342}358}
343359
344test "y_string_backslash_and_u_escaped_zero" {360test "y_string_backslash_and_u_escaped_zero" {
345 ok(361 try ok(
346 \\["\\u0000"]362 \\["\\u0000"]
347 );363 );
348}364}
349365
350test "y_string_backslash_doublequotes" {366test "y_string_backslash_doublequotes" {
351 ok(367 try roundTrip(
352 \\["\""]368 \\["\""]
353 );369 );
354}370}
355371
356test "y_string_comments" {372test "y_string_comments" {
357 ok(373 try ok(
358 \\["a/*b*/c/*d//e"]374 \\["a/*b*/c/*d//e"]
359 );375 );
360}376}
361377
362test "y_string_double_escape_a" {378test "y_string_double_escape_a" {
363 ok(379 try ok(
364 \\["\\a"]380 \\["\\a"]
365 );381 );
366}382}
367383
368test "y_string_double_escape_n" {384test "y_string_double_escape_n" {
369 ok(385 try roundTrip(
370 \\["\\n"]386 \\["\\n"]
371 );387 );
372}388}
373389
374test "y_string_escaped_control_character" {390test "y_string_escaped_control_character" {
375 ok(391 try ok(
376 \\["\u0012"]392 \\["\u0012"]
377 );393 );
378}394}
379395
380test "y_string_escaped_noncharacter" {396test "y_string_escaped_noncharacter" {
381 ok(397 try ok(
382 \\["\uFFFF"]398 \\["\uFFFF"]
383 );399 );
384}400}
385401
386test "y_string_in_array" {402test "y_string_in_array" {
387 ok(403 try ok(
388 \\["asd"]404 \\["asd"]
389 );405 );
390}406}
391407
392test "y_string_in_array_with_leading_space" {408test "y_string_in_array_with_leading_space" {
393 ok(409 try ok(
394 \\[ "asd"]410 \\[ "asd"]
395 );411 );
396}412}
397413
398test "y_string_last_surrogates_1_and_2" {414test "y_string_last_surrogates_1_and_2" {
399 ok(415 try ok(
400 \\["\uDBFF\uDFFF"]416 \\["\uDBFF\uDFFF"]
401 );417 );
402}418}
403419
404test "y_string_nbsp_uescaped" {420test "y_string_nbsp_uescaped" {
405 ok(421 try ok(
406 \\["new\u00A0line"]422 \\["new\u00A0line"]
407 );423 );
408}424}
409425
410test "y_string_nonCharacterInUTF-8_U+10FFFF" {426test "y_string_nonCharacterInUTF-8_U+10FFFF" {
411 ok(427 try ok(
412 \\["􏿿"]428 \\["􏿿"]
413 );429 );
414}430}
415431
416test "y_string_nonCharacterInUTF-8_U+FFFF" {432test "y_string_nonCharacterInUTF-8_U+FFFF" {
417 ok(433 try ok(
418 \\["￿"]434 \\["￿"]
419 );435 );
420}436}
421437
422test "y_string_null_escape" {438test "y_string_null_escape" {
423 ok(439 try ok(
424 \\["\u0000"]440 \\["\u0000"]
425 );441 );
426}442}
427443
428test "y_string_one-byte-utf-8" {444test "y_string_one-byte-utf-8" {
429 ok(445 try ok(
430 \\["\u002c"]446 \\["\u002c"]
431 );447 );
432}448}
433449
434test "y_string_pi" {450test "y_string_pi" {
435 ok(451 try ok(
436 \\["π"]452 \\["π"]
437 );453 );
438}454}
439455
440test "y_string_reservedCharacterInUTF-8_U+1BFFF" {456test "y_string_reservedCharacterInUTF-8_U+1BFFF" {
441 ok(457 try ok(
442 \\["𛿿"]458 \\["𛿿"]
443 );459 );
444}460}
445461
446test "y_string_simple_ascii" {462test "y_string_simple_ascii" {
447 ok(463 try ok(
448 \\["asd "]464 \\["asd "]
449 );465 );
450}466}
451467
452test "y_string_space" {468test "y_string_space" {
453 ok(469 try roundTrip(
454 \\" "470 \\" "
455 );471 );
456}472}
457473
458test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" {474test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" {
459 ok(475 try ok(
460 \\["\uD834\uDd1e"]476 \\["\uD834\uDd1e"]
461 );477 );
462}478}
463479
464test "y_string_three-byte-utf-8" {480test "y_string_three-byte-utf-8" {
465 ok(481 try ok(
466 \\["\u0821"]482 \\["\u0821"]
467 );483 );
468}484}
469485
470test "y_string_two-byte-utf-8" {486test "y_string_two-byte-utf-8" {
471 ok(487 try ok(
472 \\["\u0123"]488 \\["\u0123"]
473 );489 );
474}490}
475491
476test "y_string_u+2028_line_sep" {492test "y_string_u+2028_line_sep" {
477 ok("[\"\xe2\x80\xa8\"]");493 try ok("[\"\xe2\x80\xa8\"]");
478}494}
479495
480test "y_string_u+2029_par_sep" {496test "y_string_u+2029_par_sep" {
481 ok("[\"\xe2\x80\xa9\"]");497 try ok("[\"\xe2\x80\xa9\"]");
482}498}
483499
484test "y_string_uescaped_newline" {500test "y_string_uescaped_newline" {
485 ok(501 try ok(
486 \\["new\u000Aline"]502 \\["new\u000Aline"]
487 );503 );
488}504}
489505
490test "y_string_uEscape" {506test "y_string_uEscape" {
491 ok(507 try ok(
492 \\["\u0061\u30af\u30EA\u30b9"]508 \\["\u0061\u30af\u30EA\u30b9"]
493 );509 );
494}510}
495511
496test "y_string_unescaped_char_delete" {512test "y_string_unescaped_char_delete" {
497 ok("[\"\x7f\"]");513 try ok("[\"\x7f\"]");
498}514}
499515
500test "y_string_unicode_2" {516test "y_string_unicode_2" {
501 ok(517 try ok(
502 \\["⍂㈴⍂"]518 \\["⍂㈴⍂"]
503 );519 );
504}520}
505521
506test "y_string_unicodeEscapedBackslash" {522test "y_string_unicodeEscapedBackslash" {
507 ok(523 try ok(
508 \\["\u005C"]524 \\["\u005C"]
509 );525 );
510}526}
511527
512test "y_string_unicode_escaped_double_quote" {528test "y_string_unicode_escaped_double_quote" {
513 ok(529 try ok(
514 \\["\u0022"]530 \\["\u0022"]
515 );531 );
516}532}
517533
518test "y_string_unicode" {534test "y_string_unicode" {
519 ok(535 try ok(
520 \\["\uA66D"]536 \\["\uA66D"]
521 );537 );
522}538}
523539
524test "y_string_unicode_U+10FFFE_nonchar" {540test "y_string_unicode_U+10FFFE_nonchar" {
525 ok(541 try ok(
526 \\["\uDBFF\uDFFE"]542 \\["\uDBFF\uDFFE"]
527 );543 );
528}544}
529545
530test "y_string_unicode_U+1FFFE_nonchar" {546test "y_string_unicode_U+1FFFE_nonchar" {
531 ok(547 try ok(
532 \\["\uD83F\uDFFE"]548 \\["\uD83F\uDFFE"]
533 );549 );
534}550}
535551
536test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" {552test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" {
537 ok(553 try ok(
538 \\["\u200B"]554 \\["\u200B"]
539 );555 );
540}556}
541557
542test "y_string_unicode_U+2064_invisible_plus" {558test "y_string_unicode_U+2064_invisible_plus" {
543 ok(559 try ok(
544 \\["\u2064"]560 \\["\u2064"]
545 );561 );
546}562}
547563
548test "y_string_unicode_U+FDD0_nonchar" {564test "y_string_unicode_U+FDD0_nonchar" {
549 ok(565 try ok(
550 \\["\uFDD0"]566 \\["\uFDD0"]
551 );567 );
552}568}
553569
554test "y_string_unicode_U+FFFE_nonchar" {570test "y_string_unicode_U+FFFE_nonchar" {
555 ok(571 try ok(
556 \\["\uFFFE"]572 \\["\uFFFE"]
557 );573 );
558}574}
559575
560test "y_string_utf8" {576test "y_string_utf8" {
561 ok(577 try ok(
562 \\["€𝄞"]578 \\["€𝄞"]
563 );579 );
564}580}
565581
566test "y_string_with_del_character" {582test "y_string_with_del_character" {
567 ok("[\"a\x7fa\"]");583 try ok("[\"a\x7fa\"]");
568}584}
569585
570test "y_structure_lonely_false" {586test "y_structure_lonely_false" {
571 ok(587 try roundTrip(
572 \\false588 \\false
573 );589 );
574}590}
575591
576test "y_structure_lonely_int" {592test "y_structure_lonely_int" {
577 ok(593 try roundTrip(
578 \\42594 \\42
579 );595 );
580}596}
581597
582test "y_structure_lonely_negative_real" {598test "y_structure_lonely_negative_real" {
583 ok(599 try ok(
584 \\-0.1600 \\-0.1
585 );601 );
586}602}
587603
588test "y_structure_lonely_null" {604test "y_structure_lonely_null" {
589 ok(605 try roundTrip(
590 \\null606 \\null
591 );607 );
592}608}
593609
594test "y_structure_lonely_string" {610test "y_structure_lonely_string" {
595 ok(611 try roundTrip(
596 \\"asd"612 \\"asd"
597 );613 );
598}614}
599615
600test "y_structure_lonely_true" {616test "y_structure_lonely_true" {
601 ok(617 try roundTrip(
602 \\true618 \\true
603 );619 );
604}620}
605621
606test "y_structure_string_empty" {622test "y_structure_string_empty" {
607 ok(623 try roundTrip(
608 \\""624 \\""
609 );625 );
610}626}
611627
612test "y_structure_trailing_newline" {628test "y_structure_trailing_newline" {
613 ok(629 try roundTrip(
614 \\["a"]630 \\["a"]
615 );631 );
616}632}
617633
618test "y_structure_true_in_array" {634test "y_structure_true_in_array" {
619 ok(635 try roundTrip(
620 \\[true]636 \\[true]
621 );637 );
622}638}
623639
624test "y_structure_whitespace_array" {640test "y_structure_whitespace_array" {
625 ok(" [] ");641 try ok(" [] ");
626}642}
627643
628////////////////////////////////////////////////////////////////////////////////////////////////////644////////////////////////////////////////////////////////////////////////////////////////////////////
lib/std/math/ln.zig+3-2
...@@ -36,8 +36,9 @@ pub fn ln(x: anytype) @TypeOf(x) {...@@ -36,8 +36,9 @@ pub fn ln(x: anytype) @TypeOf(x) {
36 .ComptimeInt => {36 .ComptimeInt => {
37 return @as(comptime_int, math.floor(ln_64(@as(f64, x))));37 return @as(comptime_int, math.floor(ln_64(@as(f64, x))));
38 },38 },
39 .Int => {39 .Int => |IntType| switch (IntType.signedness) {
40 return @as(T, math.floor(ln_64(@as(f64, x))));40 .signed => return @compileError("ln not implemented for signed integers"),
41 .unsigned => return @as(T, math.floor(ln_64(@as(f64, x)))),
41 },42 },
42 else => @compileError("ln not implemented for " ++ @typeName(T)),43 else => @compileError("ln not implemented for " ++ @typeName(T)),
43 }44 }
lib/std/math/log.zig+6-4
...@@ -31,9 +31,11 @@ pub fn log(comptime T: type, base: T, x: T) T {...@@ -31,9 +31,11 @@ pub fn log(comptime T: type, base: T, x: T) T {
31 .ComptimeInt => {31 .ComptimeInt => {
32 return @as(comptime_int, math.floor(math.ln(@as(f64, x)) / math.ln(float_base)));32 return @as(comptime_int, math.floor(math.ln(@as(f64, x)) / math.ln(float_base)));
33 },33 },
34 .Int => {34
35 // TODO implement integer log without using float math35 // TODO implement integer log without using float math
36 return @floatToInt(T, math.floor(math.ln(@intToFloat(f64, x)) / math.ln(float_base)));36 .Int => |IntType| switch (IntType.signedness) {
37 .signed => return @compileError("log not implemented for signed integers"),
38 .unsigned => return @floatToInt(T, math.floor(math.ln(@intToFloat(f64, x)) / math.ln(float_base))),
37 },39 },
3840
39 .Float => {41 .Float => {
...@@ -53,7 +55,7 @@ pub fn log(comptime T: type, base: T, x: T) T {...@@ -53,7 +55,7 @@ pub fn log(comptime T: type, base: T, x: T) T {
53test "math.log integer" {55test "math.log integer" {
54 expect(log(u8, 2, 0x1) == 0);56 expect(log(u8, 2, 0x1) == 0);
55 expect(log(u8, 2, 0x2) == 1);57 expect(log(u8, 2, 0x2) == 1);
56 expect(log(i16, 2, 0x72) == 6);58 expect(log(u16, 2, 0x72) == 6);
57 expect(log(u32, 2, 0xFFFFFF) == 23);59 expect(log(u32, 2, 0xFFFFFF) == 23);
58 expect(log(u64, 2, 0x7FF0123456789ABC) == 62);60 expect(log(u64, 2, 0x7FF0123456789ABC) == 62);
59}61}
lib/std/math/log10.zig+3-2
...@@ -37,8 +37,9 @@ pub fn log10(x: anytype) @TypeOf(x) {...@@ -37,8 +37,9 @@ pub fn log10(x: anytype) @TypeOf(x) {
37 .ComptimeInt => {37 .ComptimeInt => {
38 return @as(comptime_int, math.floor(log10_64(@as(f64, x))));38 return @as(comptime_int, math.floor(log10_64(@as(f64, x))));
39 },39 },
40 .Int => {40 .Int => |IntType| switch (IntType.signedness) {
41 return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x))));41 .signed => return @compileError("log10 not implemented for signed integers"),
42 .unsigned => return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x)))),
42 },43 },
43 else => @compileError("log10 not implemented for " ++ @typeName(T)),44 else => @compileError("log10 not implemented for " ++ @typeName(T)),
44 }45 }
lib/std/math/log2.zig+3-2
...@@ -43,8 +43,9 @@ pub fn log2(x: anytype) @TypeOf(x) {...@@ -43,8 +43,9 @@ pub fn log2(x: anytype) @TypeOf(x) {
43 }) : (result += 1) {}43 }) : (result += 1) {}
44 return result;44 return result;
45 },45 },
46 .Int => {46 .Int => |IntType| switch (IntType.signedness) {
47 return math.log2_int(T, x);47 .signed => return @compileError("log2 not implemented for signed integers"),
48 .unsigned => return math.log2_int(T, x),
48 },49 },
49 else => @compileError("log2 not implemented for " ++ @typeName(T)),50 else => @compileError("log2 not implemented for " ++ @typeName(T)),
50 }51 }
lib/std/math/sqrt.zig+4-1
...@@ -31,7 +31,10 @@ pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) {...@@ -31,7 +31,10 @@ pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) {
31 }31 }
32 return @as(T, sqrt_int(u128, x));32 return @as(T, sqrt_int(u128, x));
33 },33 },
34 .Int => return sqrt_int(T, x),34 .Int => |IntType| switch (IntType.signedness) {
35 .signed => return @compileError("sqrt not implemented for signed integers"),
36 .unsigned => return sqrt_int(T, x),
37 },
35 else => @compileError("sqrt not implemented for " ++ @typeName(T)),38 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
36 }39 }
37}40}
lib/std/meta.zig+38-1
...@@ -970,12 +970,15 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {...@@ -970,12 +970,15 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
970970
971 if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile)971 if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile)
972 return @intToPtr(DestType, @ptrToInt(target))972 return @intToPtr(DestType, @ptrToInt(target))
973 else if (@typeInfo(dest.child) == .Opaque)
974 // dest.alignment would error out
975 return @ptrCast(DestType, target)
973 else976 else
974 return @ptrCast(DestType, @alignCast(dest.alignment, target));977 return @ptrCast(DestType, @alignCast(dest.alignment, target));
975}978}
976979
977fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {980fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {
978 return switch(@typeInfo(PtrType)){981 return switch (@typeInfo(PtrType)) {
979 .Optional => |opt_info| @typeInfo(opt_info.child).Pointer,982 .Optional => |opt_info| @typeInfo(opt_info.child).Pointer,
980 .Pointer => |ptr_info| ptr_info,983 .Pointer => |ptr_info| ptr_info,
981 else => unreachable,984 else => unreachable,
...@@ -1010,6 +1013,8 @@ test "std.meta.cast" {...@@ -1010,6 +1013,8 @@ test "std.meta.cast" {
10101013
1011 testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*const u8, 2)));1014 testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*const u8, 2)));
1012 testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*volatile u8, 2)));1015 testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*volatile u8, 2)));
1016
1017 testing.expectEqual(@intToPtr(?*c_void, 2), cast(?*c_void, @intToPtr(*u8, 2)));
1013}1018}
10141019
1015/// Given a value returns its size as C's sizeof operator would.1020/// Given a value returns its size as C's sizeof operator would.
...@@ -1297,3 +1302,35 @@ pub fn globalOption(comptime name: []const u8, comptime T: type) ?T {...@@ -1297,3 +1302,35 @@ pub fn globalOption(comptime name: []const u8, comptime T: type) ?T {
1297 return null;1302 return null;
1298 return @as(T, @field(root, name));1303 return @as(T, @field(root, name));
1299}1304}
1305
1306/// This function is for translate-c and is not intended for general use.
1307/// Convert from clang __builtin_shufflevector index to Zig @shuffle index
1308/// clang requires __builtin_shufflevector index arguments to be integer constants.
1309/// negative values for `this_index` indicate "don't care" so we arbitrarily choose 0
1310/// clang enforces that `this_index` is less than the total number of vector elements
1311/// See https://ziglang.org/documentation/master/#shuffle
1312/// See https://clang.llvm.org/docs/LanguageExtensions.html#langext-builtin-shufflevector
1313pub fn shuffleVectorIndex(comptime this_index: c_int, comptime source_vector_len: usize) i32 {
1314 if (this_index <= 0) return 0;
1315
1316 const positive_index = @intCast(usize, this_index);
1317 if (positive_index < source_vector_len) return @intCast(i32, this_index);
1318 const b_index = positive_index - source_vector_len;
1319 return ~@intCast(i32, b_index);
1320}
1321
1322test "shuffleVectorIndex" {
1323 const vector_len: usize = 4;
1324
1325 testing.expect(shuffleVectorIndex(-1, vector_len) == 0);
1326
1327 testing.expect(shuffleVectorIndex(0, vector_len) == 0);
1328 testing.expect(shuffleVectorIndex(1, vector_len) == 1);
1329 testing.expect(shuffleVectorIndex(2, vector_len) == 2);
1330 testing.expect(shuffleVectorIndex(3, vector_len) == 3);
1331
1332 testing.expect(shuffleVectorIndex(4, vector_len) == -1);
1333 testing.expect(shuffleVectorIndex(5, vector_len) == -2);
1334 testing.expect(shuffleVectorIndex(6, vector_len) == -3);
1335 testing.expect(shuffleVectorIndex(7, vector_len) == -4);
1336}
lib/std/os.zig+5-2
...@@ -3254,6 +3254,9 @@ pub const ConnectError = error{...@@ -3254,6 +3254,9 @@ pub const ConnectError = error{
32543254
3255 /// Connection was reset by peer before connect could complete.3255 /// Connection was reset by peer before connect could complete.
3256 ConnectionResetByPeer,3256 ConnectionResetByPeer,
3257
3258 /// Socket is non-blocking and already has a pending connection in progress.
3259 ConnectionPending,
3257} || UnexpectedError;3260} || UnexpectedError;
32583261
3259/// Initiate a connection on a socket.3262/// Initiate a connection on a socket.
...@@ -3294,7 +3297,7 @@ pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) Conne...@@ -3294,7 +3297,7 @@ pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) Conne
3294 EADDRNOTAVAIL => return error.AddressNotAvailable,3297 EADDRNOTAVAIL => return error.AddressNotAvailable,
3295 EAFNOSUPPORT => return error.AddressFamilyNotSupported,3298 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
3296 EAGAIN, EINPROGRESS => return error.WouldBlock,3299 EAGAIN, EINPROGRESS => return error.WouldBlock,
3297 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.3300 EALREADY => return error.ConnectionPending,
3298 EBADF => unreachable, // sockfd is not a valid open file descriptor.3301 EBADF => unreachable, // sockfd is not a valid open file descriptor.
3299 ECONNREFUSED => return error.ConnectionRefused,3302 ECONNREFUSED => return error.ConnectionRefused,
3300 ECONNRESET => return error.ConnectionResetByPeer,3303 ECONNRESET => return error.ConnectionResetByPeer,
...@@ -3325,7 +3328,7 @@ pub fn getsockoptError(sockfd: fd_t) ConnectError!void {...@@ -3325,7 +3328,7 @@ pub fn getsockoptError(sockfd: fd_t) ConnectError!void {
3325 EADDRNOTAVAIL => return error.AddressNotAvailable,3328 EADDRNOTAVAIL => return error.AddressNotAvailable,
3326 EAFNOSUPPORT => return error.AddressFamilyNotSupported,3329 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
3327 EAGAIN => return error.SystemResources,3330 EAGAIN => return error.SystemResources,
3328 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.3331 EALREADY => return error.ConnectionPending,
3329 EBADF => unreachable, // sockfd is not a valid open file descriptor.3332 EBADF => unreachable, // sockfd is not a valid open file descriptor.
3330 ECONNREFUSED => return error.ConnectionRefused,3333 ECONNREFUSED => return error.ConnectionRefused,
3331 EFAULT => unreachable, // The socket structure address is outside the user's address space.3334 EFAULT => unreachable, // The socket structure address is outside the user's address space.
lib/std/os/bits/linux.zig+87
...@@ -21,6 +21,7 @@ pub usingnamespace switch (builtin.arch) {...@@ -21,6 +21,7 @@ pub usingnamespace switch (builtin.arch) {
21 .riscv64 => @import("linux/riscv64.zig"),21 .riscv64 => @import("linux/riscv64.zig"),
22 .sparcv9 => @import("linux/sparc64.zig"),22 .sparcv9 => @import("linux/sparc64.zig"),
23 .mips, .mipsel => @import("linux/mips.zig"),23 .mips, .mipsel => @import("linux/mips.zig"),
24 .powerpc => @import("linux/powerpc.zig"),
24 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),25 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
25 else => struct {},26 else => struct {},
26};27};
...@@ -586,6 +587,92 @@ pub const IP_DEFAULT_MULTICAST_TTL = 1;...@@ -586,6 +587,92 @@ pub const IP_DEFAULT_MULTICAST_TTL = 1;
586pub const IP_DEFAULT_MULTICAST_LOOP = 1;587pub const IP_DEFAULT_MULTICAST_LOOP = 1;
587pub const IP_MAX_MEMBERSHIPS = 20;588pub const IP_MAX_MEMBERSHIPS = 20;
588589
590// IPv6 socket options
591
592pub const IPV6_ADDRFORM = 1;
593pub const IPV6_2292PKTINFO = 2;
594pub const IPV6_2292HOPOPTS = 3;
595pub const IPV6_2292DSTOPTS = 4;
596pub const IPV6_2292RTHDR = 5;
597pub const IPV6_2292PKTOPTIONS = 6;
598pub const IPV6_CHECKSUM = 7;
599pub const IPV6_2292HOPLIMIT = 8;
600pub const IPV6_NEXTHOP = 9;
601pub const IPV6_AUTHHDR = 10;
602pub const IPV6_FLOWINFO = 11;
603
604pub const IPV6_UNICAST_HOPS = 16;
605pub const IPV6_MULTICAST_IF = 17;
606pub const IPV6_MULTICAST_HOPS = 18;
607pub const IPV6_MULTICAST_LOOP = 19;
608pub const IPV6_ADD_MEMBERSHIP = 20;
609pub const IPV6_DROP_MEMBERSHIP = 21;
610pub const IPV6_ROUTER_ALERT = 22;
611pub const IPV6_MTU_DISCOVER = 23;
612pub const IPV6_MTU = 24;
613pub const IPV6_RECVERR = 25;
614pub const IPV6_V6ONLY = 26;
615pub const IPV6_JOIN_ANYCAST = 27;
616pub const IPV6_LEAVE_ANYCAST = 28;
617
618// IPV6_MTU_DISCOVER values
619pub const IPV6_PMTUDISC_DONT = 0;
620pub const IPV6_PMTUDISC_WANT = 1;
621pub const IPV6_PMTUDISC_DO = 2;
622pub const IPV6_PMTUDISC_PROBE = 3;
623pub const IPV6_PMTUDISC_INTERFACE = 4;
624pub const IPV6_PMTUDISC_OMIT = 5;
625
626// Flowlabel
627pub const IPV6_FLOWLABEL_MGR = 32;
628pub const IPV6_FLOWINFO_SEND = 33;
629pub const IPV6_IPSEC_POLICY = 34;
630pub const IPV6_XFRM_POLICY = 35;
631pub const IPV6_HDRINCL = 36;
632
633// Advanced API (RFC3542) (1)
634pub const IPV6_RECVPKTINFO = 49;
635pub const IPV6_PKTINFO = 50;
636pub const IPV6_RECVHOPLIMIT = 51;
637pub const IPV6_HOPLIMIT = 52;
638pub const IPV6_RECVHOPOPTS = 53;
639pub const IPV6_HOPOPTS = 54;
640pub const IPV6_RTHDRDSTOPTS = 55;
641pub const IPV6_RECVRTHDR = 56;
642pub const IPV6_RTHDR = 57;
643pub const IPV6_RECVDSTOPTS = 58;
644pub const IPV6_DSTOPTS = 59;
645pub const IPV6_RECVPATHMTU = 60;
646pub const IPV6_PATHMTU = 61;
647pub const IPV6_DONTFRAG = 62;
648
649// Advanced API (RFC3542) (2)
650pub const IPV6_RECVTCLASS = 66;
651pub const IPV6_TCLASS = 67;
652
653pub const IPV6_AUTOFLOWLABEL = 70;
654
655// RFC5014: Source address selection
656pub const IPV6_ADDR_PREFERENCES = 72;
657
658pub const IPV6_PREFER_SRC_TMP = 0x0001;
659pub const IPV6_PREFER_SRC_PUBLIC = 0x0002;
660pub const IPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x0100;
661pub const IPV6_PREFER_SRC_COA = 0x0004;
662pub const IPV6_PREFER_SRC_HOME = 0x0400;
663pub const IPV6_PREFER_SRC_CGA = 0x0008;
664pub const IPV6_PREFER_SRC_NONCGA = 0x0800;
665
666// RFC5082: Generalized Ttl Security Mechanism
667pub const IPV6_MINHOPCOUNT = 73;
668
669pub const IPV6_ORIGDSTADDR = 74;
670pub const IPV6_RECVORIGDSTADDR = IPV6_ORIGDSTADDR;
671pub const IPV6_TRANSPARENT = 75;
672pub const IPV6_UNICAST_IF = 76;
673pub const IPV6_RECVFRAGSIZE = 77;
674pub const IPV6_FREEBIND = 78;
675
589pub const MSG_OOB = 0x0001;676pub const MSG_OOB = 0x0001;
590pub const MSG_PEEK = 0x0002;677pub const MSG_PEEK = 0x0002;
591pub const MSG_DONTROUTE = 0x0004;678pub const MSG_DONTROUTE = 0x0004;
lib/std/os/bits/linux/powerpc.zig created+635
...@@ -0,0 +1,635 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../../std.zig");
8const linux = std.os.linux;
9const socklen_t = linux.socklen_t;
10const iovec = linux.iovec;
11const iovec_const = linux.iovec_const;
12const uid_t = linux.uid_t;
13const gid_t = linux.gid_t;
14const pid_t = linux.pid_t;
15const stack_t = linux.stack_t;
16const sigset_t = linux.sigset_t;
17pub const SYS = extern enum(usize) {
18 restart_syscall = 0,
19 exit = 1,
20 fork = 2,
21 read = 3,
22 write = 4,
23 open = 5,
24 close = 6,
25 waitpid = 7,
26 creat = 8,
27 link = 9,
28 unlink = 10,
29 execve = 11,
30 chdir = 12,
31 time = 13,
32 mknod = 14,
33 chmod = 15,
34 lchown = 16,
35 @"break" = 17,
36 oldstat = 18,
37 lseek = 19,
38 getpid = 20,
39 mount = 21,
40 umount = 22,
41 setuid = 23,
42 getuid = 24,
43 stime = 25,
44 ptrace = 26,
45 alarm = 27,
46 oldfstat = 28,
47 pause = 29,
48 utime = 30,
49 stty = 31,
50 gtty = 32,
51 access = 33,
52 nice = 34,
53 ftime = 35,
54 sync = 36,
55 kill = 37,
56 rename = 38,
57 mkdir = 39,
58 rmdir = 40,
59 dup = 41,
60 pipe = 42,
61 times = 43,
62 prof = 44,
63 brk = 45,
64 setgid = 46,
65 getgid = 47,
66 signal = 48,
67 geteuid = 49,
68 getegid = 50,
69 acct = 51,
70 umount2 = 52,
71 lock = 53,
72 ioctl = 54,
73 fcntl = 55,
74 mpx = 56,
75 setpgid = 57,
76 ulimit = 58,
77 oldolduname = 59,
78 umask = 60,
79 chroot = 61,
80 ustat = 62,
81 dup2 = 63,
82 getppid = 64,
83 getpgrp = 65,
84 setsid = 66,
85 sigaction = 67,
86 sgetmask = 68,
87 ssetmask = 69,
88 setreuid = 70,
89 setregid = 71,
90 sigsuspend = 72,
91 sigpending = 73,
92 sethostname = 74,
93 setrlimit = 75,
94 getrlimit = 76,
95 getrusage = 77,
96 gettimeofday = 78,
97 settimeofday = 79,
98 getgroups = 80,
99 setgroups = 81,
100 select = 82,
101 symlink = 83,
102 oldlstat = 84,
103 readlink = 85,
104 uselib = 86,
105 swapon = 87,
106 reboot = 88,
107 readdir = 89,
108 mmap = 90,
109 munmap = 91,
110 truncate = 92,
111 ftruncate = 93,
112 fchmod = 94,
113 fchown = 95,
114 getpriority = 96,
115 setpriority = 97,
116 profil = 98,
117 statfs = 99,
118 fstatfs = 100,
119 ioperm = 101,
120 socketcall = 102,
121 syslog = 103,
122 setitimer = 104,
123 getitimer = 105,
124 stat = 106,
125 lstat = 107,
126 fstat = 108,
127 olduname = 109,
128 iopl = 110,
129 vhangup = 111,
130 idle = 112,
131 vm86 = 113,
132 wait4 = 114,
133 swapoff = 115,
134 sysinfo = 116,
135 ipc = 117,
136 fsync = 118,
137 sigreturn = 119,
138 clone = 120,
139 setdomainname = 121,
140 uname = 122,
141 modify_ldt = 123,
142 adjtimex = 124,
143 mprotect = 125,
144 sigprocmask = 126,
145 create_module = 127,
146 init_module = 128,
147 delete_module = 129,
148 get_kernel_syms = 130,
149 quotactl = 131,
150 getpgid = 132,
151 fchdir = 133,
152 bdflush = 134,
153 sysfs = 135,
154 personality = 136,
155 afs_syscall = 137,
156 setfsuid = 138,
157 setfsgid = 139,
158 _llseek = 140,
159 getdents = 141,
160 _newselect = 142,
161 flock = 143,
162 msync = 144,
163 readv = 145,
164 writev = 146,
165 getsid = 147,
166 fdatasync = 148,
167 _sysctl = 149,
168 mlock = 150,
169 munlock = 151,
170 mlockall = 152,
171 munlockall = 153,
172 sched_setparam = 154,
173 sched_getparam = 155,
174 sched_setscheduler = 156,
175 sched_getscheduler = 157,
176 sched_yield = 158,
177 sched_get_priority_max = 159,
178 sched_get_priority_min = 160,
179 sched_rr_get_interval = 161,
180 nanosleep = 162,
181 mremap = 163,
182 setresuid = 164,
183 getresuid = 165,
184 query_module = 166,
185 poll = 167,
186 nfsservctl = 168,
187 setresgid = 169,
188 getresgid = 170,
189 prctl = 171,
190 rt_sigreturn = 172,
191 rt_sigaction = 173,
192 rt_sigprocmask = 174,
193 rt_sigpending = 175,
194 rt_sigtimedwait = 176,
195 rt_sigqueueinfo = 177,
196 rt_sigsuspend = 178,
197 pread64 = 179,
198 pwrite64 = 180,
199 chown = 181,
200 getcwd = 182,
201 capget = 183,
202 capset = 184,
203 sigaltstack = 185,
204 sendfile = 186,
205 getpmsg = 187,
206 putpmsg = 188,
207 vfork = 189,
208 ugetrlimit = 190,
209 readahead = 191,
210 mmap2 = 192,
211 truncate64 = 193,
212 ftruncate64 = 194,
213 stat64 = 195,
214 lstat64 = 196,
215 fstat64 = 197,
216 pciconfig_read = 198,
217 pciconfig_write = 199,
218 pciconfig_iobase = 200,
219 multiplexer = 201,
220 getdents64 = 202,
221 pivot_root = 203,
222 fcntl64 = 204,
223 madvise = 205,
224 mincore = 206,
225 gettid = 207,
226 tkill = 208,
227 setxattr = 209,
228 lsetxattr = 210,
229 fsetxattr = 211,
230 getxattr = 212,
231 lgetxattr = 213,
232 fgetxattr = 214,
233 listxattr = 215,
234 llistxattr = 216,
235 flistxattr = 217,
236 removexattr = 218,
237 lremovexattr = 219,
238 fremovexattr = 220,
239 futex = 221,
240 sched_setaffinity = 222,
241 sched_getaffinity = 223,
242 tuxcall = 225,
243 sendfile64 = 226,
244 io_setup = 227,
245 io_destroy = 228,
246 io_getevents = 229,
247 io_submit = 230,
248 io_cancel = 231,
249 set_tid_address = 232,
250 fadvise64 = 233,
251 exit_group = 234,
252 lookup_dcookie = 235,
253 epoll_create = 236,
254 epoll_ctl = 237,
255 epoll_wait = 238,
256 remap_file_pages = 239,
257 timer_create = 240,
258 timer_settime = 241,
259 timer_gettime = 242,
260 timer_getoverrun = 243,
261 timer_delete = 244,
262 clock_settime = 245,
263 clock_gettime = 246,
264 clock_getres = 247,
265 clock_nanosleep = 248,
266 swapcontext = 249,
267 tgkill = 250,
268 utimes = 251,
269 statfs64 = 252,
270 fstatfs64 = 253,
271 fadvise64_64 = 254,
272 rtas = 255,
273 sys_debug_setcontext = 256,
274 migrate_pages = 258,
275 mbind = 259,
276 get_mempolicy = 260,
277 set_mempolicy = 261,
278 mq_open = 262,
279 mq_unlink = 263,
280 mq_timedsend = 264,
281 mq_timedreceive = 265,
282 mq_notify = 266,
283 mq_getsetattr = 267,
284 kexec_load = 268,
285 add_key = 269,
286 request_key = 270,
287 keyctl = 271,
288 waitid = 272,
289 ioprio_set = 273,
290 ioprio_get = 274,
291 inotify_init = 275,
292 inotify_add_watch = 276,
293 inotify_rm_watch = 277,
294 spu_run = 278,
295 spu_create = 279,
296 pselect6 = 280,
297 ppoll = 281,
298 unshare = 282,
299 splice = 283,
300 tee = 284,
301 vmsplice = 285,
302 openat = 286,
303 mkdirat = 287,
304 mknodat = 288,
305 fchownat = 289,
306 futimesat = 290,
307 fstatat64 = 291,
308 unlinkat = 292,
309 renameat = 293,
310 linkat = 294,
311 symlinkat = 295,
312 readlinkat = 296,
313 fchmodat = 297,
314 faccessat = 298,
315 get_robust_list = 299,
316 set_robust_list = 300,
317 move_pages = 301,
318 getcpu = 302,
319 epoll_pwait = 303,
320 utimensat = 304,
321 signalfd = 305,
322 timerfd_create = 306,
323 eventfd = 307,
324 sync_file_range2 = 308,
325 fallocate = 309,
326 subpage_prot = 310,
327 timerfd_settime = 311,
328 timerfd_gettime = 312,
329 signalfd4 = 313,
330 eventfd2 = 314,
331 epoll_create1 = 315,
332 dup3 = 316,
333 pipe2 = 317,
334 inotify_init1 = 318,
335 perf_event_open = 319,
336 preadv = 320,
337 pwritev = 321,
338 rt_tgsigqueueinfo = 322,
339 fanotify_init = 323,
340 fanotify_mark = 324,
341 prlimit64 = 325,
342 socket = 326,
343 bind = 327,
344 connect = 328,
345 listen = 329,
346 accept = 330,
347 getsockname = 331,
348 getpeername = 332,
349 socketpair = 333,
350 send = 334,
351 sendto = 335,
352 recv = 336,
353 recvfrom = 337,
354 shutdown = 338,
355 setsockopt = 339,
356 getsockopt = 340,
357 sendmsg = 341,
358 recvmsg = 342,
359 recvmmsg = 343,
360 accept4 = 344,
361 name_to_handle_at = 345,
362 open_by_handle_at = 346,
363 clock_adjtime = 347,
364 syncfs = 348,
365 sendmmsg = 349,
366 setns = 350,
367 process_vm_readv = 351,
368 process_vm_writev = 352,
369 finit_module = 353,
370 kcmp = 354,
371 sched_setattr = 355,
372 sched_getattr = 356,
373 renameat2 = 357,
374 seccomp = 358,
375 getrandom = 359,
376 memfd_create = 360,
377 bpf = 361,
378 execveat = 362,
379 switch_endian = 363,
380 userfaultfd = 364,
381 membarrier = 365,
382 mlock2 = 378,
383 copy_file_range = 379,
384 preadv2 = 380,
385 pwritev2 = 381,
386 kexec_file_load = 382,
387 statx = 383,
388 pkey_alloc = 384,
389 pkey_free = 385,
390 pkey_mprotect = 386,
391 rseq = 387,
392 io_pgetevents = 388,
393 semget = 393,
394 semctl = 394,
395 shmget = 395,
396 shmctl = 396,
397 shmat = 397,
398 shmdt = 398,
399 msgget = 399,
400 msgsnd = 400,
401 msgrcv = 401,
402 msgctl = 402,
403 clock_gettime64 = 403,
404 clock_settime64 = 404,
405 clock_adjtime64 = 405,
406 clock_getres_time64 = 406,
407 clock_nanosleep_time64 = 407,
408 timer_gettime64 = 408,
409 timer_settime64 = 409,
410 timerfd_gettime64 = 410,
411 timerfd_settime64 = 411,
412 utimensat_time64 = 412,
413 pselect6_time64 = 413,
414 ppoll_time64 = 414,
415 io_pgetevents_time64 = 416,
416 recvmmsg_time64 = 417,
417 mq_timedsend_time64 = 418,
418 mq_timedreceive_time64 = 419,
419 semtimedop_time64 = 420,
420 rt_sigtimedwait_time64 = 421,
421 futex_time64 = 422,
422 sched_rr_get_interval_time64 = 423,
423 pidfd_send_signal = 424,
424 io_uring_setup = 425,
425 io_uring_enter = 426,
426 io_uring_register = 427,
427 open_tree = 428,
428 move_mount = 429,
429 fsopen = 430,
430 fsconfig = 431,
431 fsmount = 432,
432 fspick = 433,
433 pidfd_open = 434,
434 clone3 = 435,
435 close_range = 436,
436 openat2 = 437,
437 pidfd_getfd = 438,
438 faccessat2 = 439,
439 process_madvise = 440,
440};
441
442pub const O_CREAT = 0o100;
443pub const O_EXCL = 0o200;
444pub const O_NOCTTY = 0o400;
445pub const O_TRUNC = 0o1000;
446pub const O_APPEND = 0o2000;
447pub const O_NONBLOCK = 0o4000;
448pub const O_DSYNC = 0o10000;
449pub const O_SYNC = 0o4010000;
450pub const O_RSYNC = 0o4010000;
451pub const O_DIRECTORY = 0o40000;
452pub const O_NOFOLLOW = 0o100000;
453pub const O_CLOEXEC = 0o2000000;
454
455pub const O_ASYNC = 0o20000;
456pub const O_DIRECT = 0o400000;
457pub const O_LARGEFILE = 0o200000;
458pub const O_NOATIME = 0o1000000;
459pub const O_PATH = 0o10000000;
460pub const O_TMPFILE = 0o20040000;
461pub const O_NDELAY = O_NONBLOCK;
462
463pub const F_DUPFD = 0;
464pub const F_GETFD = 1;
465pub const F_SETFD = 2;
466pub const F_GETFL = 3;
467pub const F_SETFL = 4;
468
469pub const F_SETOWN = 8;
470pub const F_GETOWN = 9;
471pub const F_SETSIG = 10;
472pub const F_GETSIG = 11;
473
474pub const F_GETLK = 12;
475pub const F_SETLK = 13;
476pub const F_SETLKW = 14;
477
478pub const F_SETOWN_EX = 15;
479pub const F_GETOWN_EX = 16;
480
481pub const F_GETOWNER_UIDS = 17;
482
483pub const F_RDLCK = 0;
484pub const F_WRLCK = 1;
485pub const F_UNLCK = 2;
486
487pub const LOCK_SH = 1;
488pub const LOCK_EX = 2;
489pub const LOCK_UN = 8;
490pub const LOCK_NB = 4;
491
492/// stack-like segment
493pub const MAP_GROWSDOWN = 0x0100;
494
495/// ETXTBSY
496pub const MAP_DENYWRITE = 0x0800;
497
498/// mark it as an executable
499pub const MAP_EXECUTABLE = 0x1000;
500
501/// pages are locked
502pub const MAP_LOCKED = 0x0080;
503
504/// don't check for reservations
505pub const MAP_NORESERVE = 0x0040;
506
507pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
508pub const VDSO_CGT_VER = "LINUX_2.6.15";
509
510pub const Flock = extern struct {
511 l_type: i16,
512 l_whence: i16,
513 l_start: off_t,
514 l_len: off_t,
515 l_pid: pid_t,
516};
517
518pub const msghdr = extern struct {
519 msg_name: ?*sockaddr,
520 msg_namelen: socklen_t,
521 msg_iov: [*]iovec,
522 msg_iovlen: usize,
523 msg_control: ?*c_void,
524 msg_controllen: socklen_t,
525 msg_flags: i32,
526};
527
528pub const msghdr_const = extern struct {
529 msg_name: ?*const sockaddr,
530 msg_namelen: socklen_t,
531 msg_iov: [*]iovec_const,
532 msg_iovlen: usize,
533 msg_control: ?*c_void,
534 msg_controllen: socklen_t,
535 msg_flags: i32,
536};
537
538pub const blksize_t = i32;
539pub const nlink_t = u32;
540pub const time_t = isize;
541pub const mode_t = u32;
542pub const off_t = i64;
543pub const ino_t = u64;
544pub const dev_t = u64;
545pub const blkcnt_t = i64;
546
547// The `stat` definition used by the Linux kernel.
548pub const kernel_stat = extern struct {
549 dev: dev_t,
550 ino: ino_t,
551 mode: mode_t,
552 nlink: nlink_t,
553 uid: uid_t,
554 gid: gid_t,
555 rdev: dev_t,
556 __rdev_padding: i16,
557 size: off_t,
558 blksize: blksize_t,
559 blocks: blkcnt_t,
560 __atim32: timespec32,
561 __mtim32: timespec32,
562 __ctim32: timespec32,
563 __unused: [2]u32,
564 atim: timespec,
565 mtim: timespec,
566 ctim: timespec,
567
568 const timespec32 = extern struct {
569 tv_sec: i32,
570 tv_nsec: i32,
571 };
572
573 pub fn atime(self: @This()) timespec {
574 return self.atim;
575 }
576
577 pub fn mtime(self: @This()) timespec {
578 return self.mtim;
579 }
580
581 pub fn ctime(self: @This()) timespec {
582 return self.ctim;
583 }
584};
585
586// The `stat64` definition used by the libc.
587pub const libc_stat = kernel_stat;
588
589pub const timespec = extern struct {
590 tv_sec: time_t,
591 tv_nsec: isize,
592};
593
594pub const timeval = extern struct {
595 tv_sec: time_t,
596 tv_usec: isize,
597};
598
599pub const timezone = extern struct {
600 tz_minuteswest: i32,
601 tz_dsttime: i32,
602};
603
604pub const greg_t = u32;
605pub const gregset_t = [48]greg_t;
606pub const fpregset_t = [33]f64;
607
608pub const vrregset = extern struct {
609 vrregs: [32][4]u32,
610 vrsave: u32,
611 _pad: [2]u32,
612 vscr: u32,
613};
614pub const vrregset_t = vrregset;
615
616pub const mcontext_t = extern struct {
617 gp_regs: gregset_t,
618 fp_regs: fpregset_t,
619 v_regs: vrregset_t align(16),
620};
621
622pub const ucontext_t = extern struct {
623 flags: u32,
624 link: *ucontext_t,
625 stack: stack_t,
626 pad: [7]i32,
627 regs: *mcontext_t,
628 sigmask: sigset_t,
629 pad2: [3]i32,
630 mcontext: mcontext_t,
631};
632
633pub const Elf_Symndx = u32;
634
635pub const MMAP2_UNIT = 4096;
lib/std/os/bits/netbsd.zig+22-4
...@@ -813,10 +813,6 @@ pub const sigset_t = extern struct {...@@ -813,10 +813,6 @@ pub const sigset_t = extern struct {
813 __bits: [_SIG_WORDS]u32,813 __bits: [_SIG_WORDS]u32,
814};814};
815815
816pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
817pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
818pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
819
820pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** _SIG_WORDS };816pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** _SIG_WORDS };
821817
822// XXX x86_64 specific818// XXX x86_64 specific
...@@ -1219,3 +1215,25 @@ pub const rlimit = extern struct {...@@ -1219,3 +1215,25 @@ pub const rlimit = extern struct {
1219pub const SHUT_RD = 0;1215pub const SHUT_RD = 0;
1220pub const SHUT_WR = 1;1216pub const SHUT_WR = 1;
1221pub const SHUT_RDWR = 2;1217pub const SHUT_RDWR = 2;
1218
1219pub const nfds_t = u32;
1220
1221pub const pollfd = extern struct {
1222 fd: fd_t,
1223 events: i16,
1224 revents: i16,
1225};
1226
1227/// Testable events (may be specified in events field).
1228pub const POLLIN = 0x0001;
1229pub const POLLPRI = 0x0002;
1230pub const POLLOUT = 0x0004;
1231pub const POLLRDNORM = 0x0040;
1232pub const POLLWRNORM = POLLOUT;
1233pub const POLLRDBAND = 0x0080;
1234pub const POLLWRBAND = 0x0100;
1235
1236/// Non-testable events (may not be specified in events field).
1237pub const POLLERR = 0x0008;
1238pub const POLLHUP = 0x0010;
1239pub const POLLNVAL = 0x0020;
lib/std/os/linux.zig+1
...@@ -26,6 +26,7 @@ pub usingnamespace switch (builtin.arch) {...@@ -26,6 +26,7 @@ pub usingnamespace switch (builtin.arch) {
26 .riscv64 => @import("linux/riscv64.zig"),26 .riscv64 => @import("linux/riscv64.zig"),
27 .sparcv9 => @import("linux/sparc64.zig"),27 .sparcv9 => @import("linux/sparc64.zig"),
28 .mips, .mipsel => @import("linux/mips.zig"),28 .mips, .mipsel => @import("linux/mips.zig"),
29 .powerpc => @import("linux/powerpc.zig"),
29 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),30 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
30 else => struct {},31 else => struct {},
31};32};
lib/std/os/linux/io_uring.zig+1-1
...@@ -1354,7 +1354,7 @@ test "timeout (after a relative time)" {...@@ -1354,7 +1354,7 @@ test "timeout (after a relative time)" {
1354 .flags = 0,1354 .flags = 0,
1355 }, cqe);1355 }, cqe);
13561356
1357 // Tests should not depend on timings: skip test (result) if outside margin.1357 // Tests should not depend on timings: skip test if outside margin.
1358 if (!std.math.approxEqAbs(f64, ms, @intToFloat(f64, stopped - started), margin)) return error.SkipZigTest;1358 if (!std.math.approxEqAbs(f64, ms, @intToFloat(f64, stopped - started), margin)) return error.SkipZigTest;
1359}1359}
13601360
lib/std/os/linux/powerpc.zig created+133
...@@ -0,0 +1,133 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7usingnamespace @import("../bits.zig");
8
9pub fn syscall0(number: SYS) usize {
10 return asm volatile (
11 \\ sc
12 \\ bns+ 1f
13 \\ neg 3, 3
14 \\ 1:
15 : [ret] "={r3}" (-> usize)
16 : [number] "{r0}" (@enumToInt(number))
17 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
18 );
19}
20
21pub fn syscall1(number: SYS, arg1: usize) usize {
22 return asm volatile (
23 \\ sc
24 \\ bns+ 1f
25 \\ neg 3, 3
26 \\ 1:
27 : [ret] "={r3}" (-> usize)
28 : [number] "{r0}" (@enumToInt(number)),
29 [arg1] "{r3}" (arg1)
30 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
31 );
32}
33
34pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
35 return asm volatile (
36 \\ sc
37 \\ bns+ 1f
38 \\ neg 3, 3
39 \\ 1:
40 : [ret] "={r3}" (-> usize)
41 : [number] "{r0}" (@enumToInt(number)),
42 [arg1] "{r3}" (arg1),
43 [arg2] "{r4}" (arg2)
44 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
45 );
46}
47
48pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
49 return asm volatile (
50 \\ sc
51 \\ bns+ 1f
52 \\ neg 3, 3
53 \\ 1:
54 : [ret] "={r3}" (-> usize)
55 : [number] "{r0}" (@enumToInt(number)),
56 [arg1] "{r3}" (arg1),
57 [arg2] "{r4}" (arg2),
58 [arg3] "{r5}" (arg3)
59 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
60 );
61}
62
63pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
64 return asm volatile (
65 \\ sc
66 \\ bns+ 1f
67 \\ neg 3, 3
68 \\ 1:
69 : [ret] "={r3}" (-> usize)
70 : [number] "{r0}" (@enumToInt(number)),
71 [arg1] "{r3}" (arg1),
72 [arg2] "{r4}" (arg2),
73 [arg3] "{r5}" (arg3),
74 [arg4] "{r6}" (arg4)
75 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
76 );
77}
78
79pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
80 return asm volatile (
81 \\ sc
82 \\ bns+ 1f
83 \\ neg 3, 3
84 \\ 1:
85 : [ret] "={r3}" (-> usize)
86 : [number] "{r0}" (@enumToInt(number)),
87 [arg1] "{r3}" (arg1),
88 [arg2] "{r4}" (arg2),
89 [arg3] "{r5}" (arg3),
90 [arg4] "{r6}" (arg4),
91 [arg5] "{r7}" (arg5)
92 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
93 );
94}
95
96pub fn syscall6(
97 number: SYS,
98 arg1: usize,
99 arg2: usize,
100 arg3: usize,
101 arg4: usize,
102 arg5: usize,
103 arg6: usize,
104) usize {
105 return asm volatile (
106 \\ sc
107 \\ bns+ 1f
108 \\ neg 3, 3
109 \\ 1:
110 : [ret] "={r3}" (-> usize)
111 : [number] "{r0}" (@enumToInt(number)),
112 [arg1] "{r3}" (arg1),
113 [arg2] "{r4}" (arg2),
114 [arg3] "{r5}" (arg3),
115 [arg4] "{r6}" (arg4),
116 [arg5] "{r7}" (arg5),
117 [arg6] "{r8}" (arg6)
118 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
119 );
120}
121
122/// This matches the libc clone function.
123pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
124
125pub const restore = restore_rt;
126
127pub fn restore_rt() callconv(.Naked) void {
128 return asm volatile ("sc"
129 :
130 : [number] "{r0}" (@enumToInt(SYS.rt_sigreturn))
131 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
132 );
133}
lib/std/special/c.zig+65
...@@ -491,6 +491,71 @@ fn clone() callconv(.Naked) void {...@@ -491,6 +491,71 @@ fn clone() callconv(.Naked) void {
491 \\ syscall491 \\ syscall
492 );492 );
493 },493 },
494 .powerpc => {
495 // __clone(func, stack, flags, arg, ptid, tls, ctid)
496 // 3, 4, 5, 6, 7, 8, 9
497
498 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
499 // 0 3, 4, 5, 6, 7
500 asm volatile (
501 \\# store non-volatile regs r30, r31 on stack in order to put our
502 \\# start func and its arg there
503 \\stwu 30, -16(1)
504 \\stw 31, 4(1)
505 \\
506 \\# save r3 (func) into r30, and r6(arg) into r31
507 \\mr 30, 3
508 \\mr 31, 6
509 \\
510 \\# create initial stack frame for new thread
511 \\clrrwi 4, 4, 4
512 \\li 0, 0
513 \\stwu 0, -16(4)
514 \\
515 \\#move c into first arg
516 \\mr 3, 5
517 \\#mr 4, 4
518 \\mr 5, 7
519 \\mr 6, 8
520 \\mr 7, 9
521 \\
522 \\# move syscall number into r0
523 \\li 0, 120
524 \\
525 \\sc
526 \\
527 \\# check for syscall error
528 \\bns+ 1f # jump to label 1 if no summary overflow.
529 \\#else
530 \\neg 3, 3 #negate the result (errno)
531 \\1:
532 \\# compare sc result with 0
533 \\cmpwi cr7, 3, 0
534 \\
535 \\# if not 0, jump to end
536 \\bne cr7, 2f
537 \\
538 \\#else: we're the child
539 \\#call funcptr: move arg (d) into r3
540 \\mr 3, 31
541 \\#move r30 (funcptr) into CTR reg
542 \\mtctr 30
543 \\# call CTR reg
544 \\bctrl
545 \\# mov SYS_exit into r0 (the exit param is already in r3)
546 \\li 0, 1
547 \\sc
548 \\
549 \\2:
550 \\
551 \\# restore stack
552 \\lwz 30, 0(1)
553 \\lwz 31, 4(1)
554 \\addi 1, 1, 16
555 \\
556 \\blr
557 );
558 },
494 .powerpc64, .powerpc64le => {559 .powerpc64, .powerpc64le => {
495 // __clone(func, stack, flags, arg, ptid, tls, ctid)560 // __clone(func, stack, flags, arg, ptid, tls, ctid)
496 // 3, 4, 5, 6, 7, 8, 9561 // 3, 4, 5, 6, 7, 8, 9
lib/std/special/docs/index.html+16-5
...@@ -43,6 +43,8 @@...@@ -43,6 +43,8 @@
4343
44 /* layout */44 /* layout */
45 .canvas {45 .canvas {
46 display: flex;
47 flex-direction: column;
46 width: 100vw;48 width: 100vw;
47 height: 100vh;49 height: 100vh;
48 overflow: hidden;50 overflow: hidden;
...@@ -53,12 +55,21 @@...@@ -53,12 +55,21 @@
53 background-color: var(--bg-color);55 background-color: var(--bg-color);
54 }56 }
5557
58 .banner {
59 background-color: darkred;
60 text-align: center;
61 color: white;
62 padding: 15px 5px;
63 }
64
65 .banner a {
66 color: bisque;
67 text-decoration: underline;
68 }
69
56 .flex-main {70 .flex-main {
57 display: flex;71 display: flex;
58 width: 100%;72 overflow-y: hidden;
59 height: 100%;
60 justify-content: center;
61
62 z-index: 100;73 z-index: 100;
63 }74 }
6475
...@@ -515,7 +526,7 @@...@@ -515,7 +526,7 @@
515 </style>526 </style>
516 </head>527 </head>
517 <body class="canvas">528 <body class="canvas">
518 <div style="background-color: darkred; width: 100vw; text-align: center; color: white; padding: 15px 5px;">These docs are experimental. <a style="color: bisque;text-decoration: underline;" href="https://kristoff.it/blog/zig-new-relationship-llvm/">Progress depends on the self-hosted compiler</a>, <a style="color: bisque;text-decoration: underline;" href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">consider reading the stlib source in the meantime</a>.</div>529 <div class="banner">These docs are experimental. <a href="https://kristoff.it/blog/zig-new-relationship-llvm/">Progress depends on the self-hosted compiler</a>, <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">consider reading the stdlib source in the meantime</a>.</div>
519 <div class="flex-main">530 <div class="flex-main">
520 <div class="flex-filler"></div>531 <div class="flex-filler"></div>
521 <div class="flex-left sidebar">532 <div class="flex-left sidebar">
lib/std/special/docs/main.js+7-1
...@@ -1844,7 +1844,13 @@...@@ -1844,7 +1844,13 @@
1844 var oldHash = location.hash;1844 var oldHash = location.hash;
1845 var parts = oldHash.split("?");1845 var parts = oldHash.split("?");
1846 var newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);1846 var newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);
1847 location.hash = (parts.length === 1) ? (oldHash + newPart2) : (parts[0] + newPart2);1847 var newHash = (oldHash === "" ? "#" : parts[0]) + newPart2;
1848 // create a history entry only once per search
1849 if (parts.length === 1) {
1850 location.assign(newHash);
1851 } else {
1852 location.replace(newHash);
1853 }
1848 }1854 }
1849 function getSearchTerms() {1855 function getSearchTerms() {
1850 var list = curNavSearch.trim().split(/[ \r\n\t]+/);1856 var list = curNavSearch.trim().split(/[ \r\n\t]+/);
lib/std/start.zig+102-27
...@@ -7,7 +7,7 @@...@@ -7,7 +7,7 @@
77
8const root = @import("root");8const root = @import("root");
9const std = @import("std.zig");9const std = @import("std.zig");
10const builtin = std.builtin;10const builtin = @import("builtin");
11const assert = std.debug.assert;11const assert = std.debug.assert;
12const uefi = std.os.uefi;12const uefi = std.os.uefi;
13const tlcsprng = @import("crypto/tlcsprng.zig");13const tlcsprng = @import("crypto/tlcsprng.zig");
...@@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined;...@@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined;
17const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";17const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
1818
19comptime {19comptime {
20 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {20 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
21 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {21 // Until then, we have simplified logic here for self-hosted. TODO remove this once
22 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });22 // self-hosted is capable enough to handle all of the real start.zig logic.
23 if (builtin.zig_is_stage2) {
24 if (builtin.output_mode == .Exe) {
25 if (builtin.link_libc or builtin.object_format == .c) {
26 if (!@hasDecl(root, "main")) {
27 @export(main2, "main");
28 }
29 } else {
30 if (!@hasDecl(root, "_start")) {
31 @export(_start2, "_start");
32 }
33 }
23 }34 }
24 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {35 } else {
25 if (builtin.link_libc and @hasDecl(root, "main")) {36 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
26 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {37 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
27 @export(main, .{ .name = "main", .linkage = .Weak });38 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
28 }39 }
29 } else if (builtin.os.tag == .windows) {40 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
30 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and41 if (builtin.link_libc and @hasDecl(root, "main")) {
31 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))42 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
32 {43 @export(main, .{ .name = "main", .linkage = .Weak });
33 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });44 }
34 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and45 } else if (builtin.os.tag == .windows) {
35 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))46 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
36 {47 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
37 @compileError("WinMain not supported; declare wWinMain or main instead");48 {
38 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and49 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });
39 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))50 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
40 {51 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
41 @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });52 {
53 @compileError("WinMain not supported; declare wWinMain or main instead");
54 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
55 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
56 {
57 @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
58 }
59 } else if (builtin.os.tag == .uefi) {
60 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
61 } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) {
62 if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
63 } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) {
64 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
42 }65 }
43 } else if (builtin.os.tag == .uefi) {
44 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
45 } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) {
46 if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
47 } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) {
48 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
49 }66 }
50 }67 }
51}68}
5269
70// Simplified start code for stage2 until it supports more language features ///
71
72fn main2() callconv(.C) c_int {
73 root.main();
74 return 0;
75}
76
77fn _start2() callconv(.Naked) noreturn {
78 root.main();
79 exit2(0);
80}
81
82fn exit2(code: u8) noreturn {
83 switch (builtin.arch) {
84 .x86_64 => {
85 asm volatile ("syscall"
86 :
87 : [number] "{rax}" (231),
88 [arg1] "{rdi}" (code)
89 : "rcx", "r11", "memory"
90 );
91 },
92 .arm => {
93 asm volatile ("svc #0"
94 :
95 : [number] "{r7}" (1),
96 [arg1] "{r0}" (code)
97 : "memory"
98 );
99 },
100 .aarch64 => {
101 asm volatile ("svc #0"
102 :
103 : [number] "{x8}" (93),
104 [arg1] "{x0}" (code)
105 : "memory", "cc"
106 );
107 },
108 else => @compileError("TODO"),
109 }
110 unreachable;
111}
112
113////////////////////////////////////////////////////////////////////////////////
114
53fn _DllMainCRTStartup(115fn _DllMainCRTStartup(
54 hinstDLL: std.os.windows.HINSTANCE,116 hinstDLL: std.os.windows.HINSTANCE,
55 fdwReason: std.os.windows.DWORD,117 fdwReason: std.os.windows.DWORD,
...@@ -135,6 +197,19 @@ fn _start() callconv(.Naked) noreturn {...@@ -135,6 +197,19 @@ fn _start() callconv(.Naked) noreturn {
135 : [argc] "={sp}" (-> [*]usize)197 : [argc] "={sp}" (-> [*]usize)
136 );198 );
137 },199 },
200 .powerpc => {
201 // Setup the initial stack frame and clear the back chain pointer.
202 argc_argv_ptr = asm volatile (
203 \\ mr 4, 1
204 \\ li 0, 0
205 \\ stwu 1,-16(1)
206 \\ stw 0, 0(1)
207 \\ mtlr 0
208 : [argc] "={r4}" (-> [*]usize)
209 :
210 : "r0"
211 );
212 },
138 .powerpc64le => {213 .powerpc64le => {
139 // Setup the initial stack frame and clear the back chain pointer.214 // Setup the initial stack frame and clear the back chain pointer.
140 // TODO: Support powerpc64 (big endian) on ELFv2.215 // TODO: Support powerpc64 (big endian) on ELFv2.
lib/std/std.zig+1-1
...@@ -92,7 +92,7 @@ pub const zig = @import("zig.zig");...@@ -92,7 +92,7 @@ pub const zig = @import("zig.zig");
92pub const start = @import("start.zig");92pub const start = @import("start.zig");
9393
94// This forces the start.zig file to be imported, and the comptime logic inside that94// This forces the start.zig file to be imported, and the comptime logic inside that
95// file decides whether to export any appropriate start symbols.95// file decides whether to export any appropriate start symbols, and call main.
96comptime {96comptime {
97 _ = start;97 _ = start;
98}98}
lib/std/target.zig+1-1
...@@ -1178,7 +1178,7 @@ pub const Target = struct {...@@ -1178,7 +1178,7 @@ pub const Target = struct {
1178 return switch (arch) {1178 return switch (arch) {
1179 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,1179 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
1180 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,1180 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
1181 .avr => &avr.cpu.avr1,1181 .avr => &avr.cpu.avr2,
1182 .bpfel, .bpfeb => &bpf.cpu.generic,1182 .bpfel, .bpfeb => &bpf.cpu.generic,
1183 .hexagon => &hexagon.cpu.generic,1183 .hexagon => &hexagon.cpu.generic,
1184 .mips, .mipsel => &mips.cpu.mips32,1184 .mips, .mipsel => &mips.cpu.mips32,
lib/std/testing.zig+3-3
...@@ -431,7 +431,7 @@ fn printIndicatorLine(source: []const u8, indicator_index: usize) void {...@@ -431,7 +431,7 @@ fn printIndicatorLine(source: []const u8, indicator_index: usize) void {
431431
432fn printWithVisibleNewlines(source: []const u8) void {432fn printWithVisibleNewlines(source: []const u8) void {
433 var i: usize = 0;433 var i: usize = 0;
434 while (std.mem.indexOf(u8, source[i..], "\n")) |nl| : (i += nl + 1) {434 while (std.mem.indexOfScalar(u8, source[i..], '\n')) |nl| : (i += nl + 1) {
435 printLine(source[i .. i + nl]);435 printLine(source[i .. i + nl]);
436 }436 }
437 print("{s}␃\n", .{source[i..]}); // End of Text symbol (ETX)437 print("{s}␃\n", .{source[i..]}); // End of Text symbol (ETX)
...@@ -439,7 +439,7 @@ fn printWithVisibleNewlines(source: []const u8) void {...@@ -439,7 +439,7 @@ fn printWithVisibleNewlines(source: []const u8) void {
439439
440fn printLine(line: []const u8) void {440fn printLine(line: []const u8) void {
441 if (line.len != 0) switch (line[line.len - 1]) {441 if (line.len != 0) switch (line[line.len - 1]) {
442 ' ', '\t' => print("{s}⏎\n", .{line}), // Carriage return symbol,442 ' ', '\t' => return print("{s}⏎\n", .{line}), // Carriage return symbol,
443 else => {},443 else => {},
444 };444 };
445 print("{s}\n", .{line});445 print("{s}\n", .{line});
...@@ -451,7 +451,7 @@ test {...@@ -451,7 +451,7 @@ test {
451451
452/// Given a type, reference all the declarations inside, so that the semantic analyzer sees them.452/// Given a type, reference all the declarations inside, so that the semantic analyzer sees them.
453pub fn refAllDecls(comptime T: type) void {453pub fn refAllDecls(comptime T: type) void {
454 if (!@import("builtin").is_test) return;454 if (!std.builtin.is_test) return;
455 inline for (std.meta.declarations(T)) |decl| {455 inline for (std.meta.declarations(T)) |decl| {
456 _ = decl;456 _ = decl;
457 }457 }
lib/std/time.zig+6-2
...@@ -271,7 +271,9 @@ test "timestamp" {...@@ -271,7 +271,9 @@ test "timestamp" {
271 sleep(ns_per_ms);271 sleep(ns_per_ms);
272 const time_1 = milliTimestamp();272 const time_1 = milliTimestamp();
273 const interval = time_1 - time_0;273 const interval = time_1 - time_0;
274 testing.expect(interval > 0 and interval < margin);274 testing.expect(interval > 0);
275 // Tests should not depend on timings: skip test if outside margin.
276 if (!(interval < margin)) return error.SkipZigTest;
275}277}
276278
277test "Timer" {279test "Timer" {
...@@ -280,7 +282,9 @@ test "Timer" {...@@ -280,7 +282,9 @@ test "Timer" {
280 var timer = try Timer.start();282 var timer = try Timer.start();
281 sleep(10 * ns_per_ms);283 sleep(10 * ns_per_ms);
282 const time_0 = timer.read();284 const time_0 = timer.read();
283 testing.expect(time_0 > 0 and time_0 < margin);285 testing.expect(time_0 > 0);
286 // Tests should not depend on timings: skip test if outside margin.
287 if (!(time_0 < margin)) return error.SkipZigTest;
284288
285 const time_1 = timer.lap();289 const time_1 = timer.lap();
286 testing.expect(time_1 >= time_0);290 testing.expect(time_1 >= time_0);
lib/std/wasm.zig+6-1
...@@ -5,6 +5,8 @@...@@ -5,6 +5,8 @@
5// and substantial portions of the software.5// and substantial portions of the software.
6const testing = @import("std.zig").testing;6const testing = @import("std.zig").testing;
77
8// TODO: Add support for multi-byte ops (e.g. table operations)
9
8/// Wasm instruction opcodes10/// Wasm instruction opcodes
9///11///
10/// All instructions are defined as per spec:12/// All instructions are defined as per spec:
...@@ -175,7 +177,7 @@ pub const Opcode = enum(u8) {...@@ -175,7 +177,7 @@ pub const Opcode = enum(u8) {
175 i32_reinterpret_f32 = 0xBC,177 i32_reinterpret_f32 = 0xBC,
176 i64_reinterpret_f64 = 0xBD,178 i64_reinterpret_f64 = 0xBD,
177 f32_reinterpret_i32 = 0xBE,179 f32_reinterpret_i32 = 0xBE,
178 i64_reinterpret_i64 = 0xBF,180 f64_reinterpret_i64 = 0xBF,
179 i32_extend8_s = 0xC0,181 i32_extend8_s = 0xC0,
180 i32_extend16_s = 0xC1,182 i32_extend16_s = 0xC1,
181 i64_extend8_s = 0xC2,183 i64_extend8_s = 0xC2,
...@@ -278,3 +280,6 @@ pub const block_empty: u8 = 0x40;...@@ -278,3 +280,6 @@ pub const block_empty: u8 = 0x40;
278// binary constants280// binary constants
279pub const magic = [_]u8{ 0x00, 0x61, 0x73, 0x6D }; // \0asm281pub const magic = [_]u8{ 0x00, 0x61, 0x73, 0x6D }; // \0asm
280pub const version = [_]u8{ 0x01, 0x00, 0x00, 0x00 }; // version 1282pub const version = [_]u8{ 0x01, 0x00, 0x00, 0x00 }; // version 1
283
284// Each wasm page size is 64kB
285pub const page_size = 64 * 1024;
lib/std/zig.zig+32-12
...@@ -18,34 +18,54 @@ pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;...@@ -18,34 +18,54 @@ pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
1818
19pub const SrcHash = [16]u8;19pub const SrcHash = [16]u8;
2020
21/// If the source is small enough, it is used directly as the hash.
22/// If it is long, blake3 hash is computed.
23pub fn hashSrc(src: []const u8) SrcHash {21pub fn hashSrc(src: []const u8) SrcHash {
24 var out: SrcHash = undefined;22 var out: SrcHash = undefined;
25 if (src.len <= @typeInfo(SrcHash).Array.len) {23 std.crypto.hash.Blake3.hash(src, &out, .{});
26 std.mem.copy(u8, &out, src);
27 std.mem.set(u8, out[src.len..], 0);
28 } else {
29 std.crypto.hash.Blake3.hash(src, &out, .{});
30 }
31 return out;24 return out;
32}25}
3326
34pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {27pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash {
28 var out: SrcHash = undefined;
29 var hasher = std.crypto.hash.Blake3.init(.{});
30 hasher.update(&parent_hash);
31 hasher.update(sep);
32 hasher.update(name);
33 hasher.final(&out);
34 return out;
35}
36
37pub const Loc = struct {
38 line: usize,
39 column: usize,
40 /// Does not include the trailing newline.
41 source_line: []const u8,
42};
43
44pub fn findLineColumn(source: []const u8, byte_offset: usize) Loc {
35 var line: usize = 0;45 var line: usize = 0;
36 var column: usize = 0;46 var column: usize = 0;
37 for (source[0..byte_offset]) |byte| {47 var line_start: usize = 0;
38 switch (byte) {48 var i: usize = 0;
49 while (i < byte_offset) : (i += 1) {
50 switch (source[i]) {
39 '\n' => {51 '\n' => {
40 line += 1;52 line += 1;
41 column = 0;53 column = 0;
54 line_start = i + 1;
42 },55 },
43 else => {56 else => {
44 column += 1;57 column += 1;
45 },58 },
46 }59 }
47 }60 }
48 return .{ .line = line, .column = column };61 while (i < source.len and source[i] != '\n') {
62 i += 1;
63 }
64 return .{
65 .line = line,
66 .column = column,
67 .source_line = source[line_start..i],
68 };
49}69}
5070
51pub fn lineDelta(source: []const u8, start: usize, end: usize) isize {71pub fn lineDelta(source: []const u8, start: usize, end: usize) isize {
lib/std/zig/parser_test.zig+107-7
...@@ -1801,17 +1801,21 @@ test "zig fmt: array literal with hint" {...@@ -1801,17 +1801,21 @@ test "zig fmt: array literal with hint" {
1801 );1801 );
1802}1802}
18031803
1804test "zig fmt: array literal veritical column alignment" {1804test "zig fmt: array literal vertical column alignment" {
1805 try testTransform(1805 try testTransform(
1806 \\const a = []u8{1806 \\const a = []u8{
1807 \\ 1000, 200,1807 \\ 1000, 200,
1808 \\ 30, 4,1808 \\ 30, 4,
1809 \\ 50000, 601809 \\ 50000, 60,
1810 \\};1810 \\};
1811 \\const a = []u8{0, 1, 2, 3, 40,1811 \\const a = []u8{0, 1, 2, 3, 40,
1812 \\ 4,5,600,7,1812 \\ 4,5,600,7,
1813 \\ 80,1813 \\ 80,
1814 \\ 9, 10, 11, 0, 13, 14, 15};1814 \\ 9, 10, 11, 0, 13, 14, 15,};
1815 \\const a = [12]u8{
1816 \\ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1817 \\const a = [12]u8{
1818 \\ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, };
1815 \\1819 \\
1816 ,1820 ,
1817 \\const a = []u8{1821 \\const a = []u8{
...@@ -1825,6 +1829,21 @@ test "zig fmt: array literal veritical column alignment" {...@@ -1825,6 +1829,21 @@ test "zig fmt: array literal veritical column alignment" {
1825 \\ 9, 10, 11, 0, 13,1829 \\ 9, 10, 11, 0, 13,
1826 \\ 14, 15,1830 \\ 14, 15,
1827 \\};1831 \\};
1832 \\const a = [12]u8{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1833 \\const a = [12]u8{
1834 \\ 31,
1835 \\ 28,
1836 \\ 31,
1837 \\ 30,
1838 \\ 31,
1839 \\ 30,
1840 \\ 31,
1841 \\ 31,
1842 \\ 30,
1843 \\ 31,
1844 \\ 30,
1845 \\ 31,
1846 \\};
1828 \\1847 \\
1829 );1848 );
1830}1849}
...@@ -2026,10 +2045,7 @@ test "zig fmt: add trailing comma to array literal" {...@@ -2026,10 +2045,7 @@ test "zig fmt: add trailing comma to array literal" {
2026 \\ return []u16{2045 \\ return []u16{
2027 \\ 'm', 's', 'y', 's', '-', // hi2046 \\ 'm', 's', 'y', 's', '-', // hi
2028 \\ };2047 \\ };
2029 \\ return []u16{2048 \\ return []u16{ 'm', 's', 'y', 's', '-' };
2030 \\ 'm', 's', 'y', 's',
2031 \\ '-',
2032 \\ };
2033 \\ return []u16{ 'm', 's', 'y', 's', '-' };2049 \\ return []u16{ 'm', 's', 'y', 's', '-' };
2034 \\}2050 \\}
2035 \\2051 \\
...@@ -4661,6 +4677,90 @@ test "zig fmt: insert trailing comma if there are comments between switch values...@@ -4661,6 +4677,90 @@ test "zig fmt: insert trailing comma if there are comments between switch values
4661 );4677 );
4662}4678}
46634679
4680test "zig fmt: insert trailing comma if comments in array init" {
4681 try testTransform(
4682 \\var a = .{
4683 \\ "foo", //
4684 \\ "bar"
4685 \\};
4686 \\var a = .{
4687 \\ "foo",
4688 \\ "bar" //
4689 \\};
4690 \\var a = .{
4691 \\ "foo",
4692 \\ "//"
4693 \\};
4694 \\var a = .{
4695 \\ "foo",
4696 \\ "//" //
4697 \\};
4698 \\
4699 ,
4700 \\var a = .{
4701 \\ "foo", //
4702 \\ "bar",
4703 \\};
4704 \\var a = .{
4705 \\ "foo",
4706 \\ "bar", //
4707 \\};
4708 \\var a = .{ "foo", "//" };
4709 \\var a = .{
4710 \\ "foo",
4711 \\ "//", //
4712 \\};
4713 \\
4714 );
4715}
4716
4717test "zig fmt: make single-line if no trailing comma" {
4718 try testTransform(
4719 \\test "function call no trailing comma" {
4720 \\ foo(
4721 \\ 1,
4722 \\ 2
4723 \\ );
4724 \\}
4725 \\
4726 ,
4727 \\test "function call no trailing comma" {
4728 \\ foo(1, 2);
4729 \\}
4730 \\
4731 );
4732
4733 try testTransform(
4734 \\test "struct no trailing comma" {
4735 \\ const a = .{
4736 \\ .foo = 1,
4737 \\ .bar = 2
4738 \\ };
4739 \\}
4740 \\
4741 ,
4742 \\test "struct no trailing comma" {
4743 \\ const a = .{ .foo = 1, .bar = 2 };
4744 \\}
4745 \\
4746 );
4747
4748 try testTransform(
4749 \\test "array no trailing comma" {
4750 \\ var stream = multiOutStream(.{
4751 \\ fbs1.outStream(),
4752 \\ fbs2.outStream()
4753 \\ });
4754 \\}
4755 \\
4756 ,
4757 \\test "array no trailing comma" {
4758 \\ var stream = multiOutStream(.{ fbs1.outStream(), fbs2.outStream() });
4759 \\}
4760 \\
4761 );
4762}
4763
4664test "zig fmt: error for invalid bit range" {4764test "zig fmt: error for invalid bit range" {
4665 try testError(4765 try testError(
4666 \\var x: []align(0:0:0)u8 = bar;4766 \\var x: []align(0:0:0)u8 = bar;
lib/std/zig/perf_test.zig+7-3
...@@ -9,6 +9,7 @@ const warn = std.debug.warn;...@@ -9,6 +9,7 @@ const warn = std.debug.warn;
9const Tokenizer = std.zig.Tokenizer;9const Tokenizer = std.zig.Tokenizer;
10const Parser = std.zig.Parser;10const Parser = std.zig.Parser;
11const io = std.io;11const io = std.io;
12const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
1213
13const source = @embedFile("../os.zig");14const source = @embedFile("../os.zig");
14var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;15var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
...@@ -25,12 +26,15 @@ pub fn main() !void {...@@ -25,12 +26,15 @@ pub fn main() !void {
25 const end = timer.read();26 const end = timer.read();
26 memory_used /= iterations;27 memory_used /= iterations;
27 const elapsed_s = @intToFloat(f64, end - start) / std.time.ns_per_s;28 const elapsed_s = @intToFloat(f64, end - start) / std.time.ns_per_s;
28 const bytes_per_sec = @intToFloat(f64, source.len * iterations) / elapsed_s;29 const bytes_per_sec_float = @intToFloat(f64, source.len * iterations) / elapsed_s;
29 const mb_per_sec = bytes_per_sec / (1024 * 1024);30 const bytes_per_sec = @floatToInt(u64, @floor(bytes_per_sec_float));
3031
31 var stdout_file = std.io.getStdOut();32 var stdout_file = std.io.getStdOut();
32 const stdout = stdout_file.writer();33 const stdout = stdout_file.writer();
33 try stdout.print("{:.3} MiB/s, {} KiB used \n", .{ mb_per_sec, memory_used / 1024 });34 try stdout.print("parsing speed: {:.2}/s, {:.2} used \n", .{
35 fmtIntSizeBin(bytes_per_sec),
36 fmtIntSizeBin(memory_used),
37 });
34}38}
3539
36fn testOnce() usize {40fn testOnce() usize {
lib/std/zig/render.zig+35-15
...@@ -1632,9 +1632,10 @@ fn renderArrayInit(...@@ -1632,9 +1632,10 @@ fn renderArrayInit(
1632 }1632 }
1633 }1633 }
16341634
1635 const contains_newlines = !tree.tokensOnSameLine(array_init.ast.lbrace, rbrace);1635 const contains_comment = hasComment(tree, array_init.ast.lbrace, rbrace);
1636 const contains_multiline_string = hasMultilineString(tree, array_init.ast.lbrace, rbrace);
16361637
1637 if (!trailing_comma and !contains_newlines) {1638 if (!trailing_comma and !contains_comment and !contains_multiline_string) {
1638 // Render all on one line, no trailing comma.1639 // Render all on one line, no trailing comma.
1639 if (array_init.ast.elements.len == 1) {1640 if (array_init.ast.elements.len == 1) {
1640 // If there is only one element, we don't use spaces1641 // If there is only one element, we don't use spaces
...@@ -1653,7 +1654,8 @@ fn renderArrayInit(...@@ -1653,7 +1654,8 @@ fn renderArrayInit(
1653 try renderToken(ais, tree, array_init.ast.lbrace, .newline);1654 try renderToken(ais, tree, array_init.ast.lbrace, .newline);
16541655
1655 var expr_index: usize = 0;1656 var expr_index: usize = 0;
1656 while (rowSize(tree, array_init.ast.elements[expr_index..], rbrace)) |row_size| {1657 while (true) {
1658 const row_size = rowSize(tree, array_init.ast.elements[expr_index..], rbrace);
1657 const row_exprs = array_init.ast.elements[expr_index..];1659 const row_exprs = array_init.ast.elements[expr_index..];
1658 // A place to store the width of each expression and its column's maximum1660 // A place to store the width of each expression and its column's maximum
1659 const widths = try gpa.alloc(usize, row_exprs.len + row_size);1661 const widths = try gpa.alloc(usize, row_exprs.len + row_size);
...@@ -1686,7 +1688,7 @@ fn renderArrayInit(...@@ -1686,7 +1688,7 @@ fn renderArrayInit(
1686 const maybe_comma = expr_last_token + 1;1688 const maybe_comma = expr_last_token + 1;
1687 if (token_tags[maybe_comma] == .comma) {1689 if (token_tags[maybe_comma] == .comma) {
1688 if (hasSameLineComment(tree, maybe_comma))1690 if (hasSameLineComment(tree, maybe_comma))
1689 break :sec_end i - this_line_size.? + 1;1691 break :sec_end i - this_line_size + 1;
1690 }1692 }
1691 }1693 }
1692 break :sec_end row_exprs.len;1694 break :sec_end row_exprs.len;
...@@ -2238,17 +2240,36 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp...@@ -2238,17 +2240,36 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
2238 }2240 }
2239}2241}
22402242
2241/// Returns true if there exists a comment between the start of token2243/// Returns true if there exists a comment between any of the tokens from
2242/// `start_token` and the start of token `end_token`. This is used to determine2244/// `start_token` to `end_token`. This is used to determine if e.g. a
2243/// if e.g. a fn_proto should be wrapped and have a trailing comma inserted2245/// fn_proto should be wrapped and have a trailing comma inserted even if
2244/// even if there is none in the source.2246/// there is none in the source.
2245fn hasComment(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool {2247fn hasComment(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool {
2246 const token_starts = tree.tokens.items(.start);2248 const token_starts = tree.tokens.items(.start);
22472249
2248 const start = token_starts[start_token];2250 var i = start_token;
2249 const end = token_starts[end_token];2251 while (i < end_token) : (i += 1) {
2252 const start = token_starts[i] + tree.tokenSlice(i).len;
2253 const end = token_starts[i + 1];
2254 if (mem.indexOf(u8, tree.source[start..end], "//") != null) return true;
2255 }
2256
2257 return false;
2258}
22502259
2251 return mem.indexOf(u8, tree.source[start..end], "//") != null;2260/// Returns true if there exists a multiline string literal between the start
2261/// of token `start_token` and the start of token `end_token`.
2262fn hasMultilineString(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool {
2263 const token_tags = tree.tokens.items(.tag);
2264
2265 for (token_tags[start_token..end_token]) |tag| {
2266 switch (tag) {
2267 .multiline_string_literal_line => return true,
2268 else => continue,
2269 }
2270 }
2271
2272 return false;
2252}2273}
22532274
2254/// Assumes that start is the first byte past the previous token and2275/// Assumes that start is the first byte past the previous token and
...@@ -2500,9 +2521,8 @@ fn nodeCausesSliceOpSpace(tag: ast.Node.Tag) bool {...@@ -2500,9 +2521,8 @@ fn nodeCausesSliceOpSpace(tag: ast.Node.Tag) bool {
2500 };2521 };
2501}2522}
25022523
2503// Returns the number of nodes in `expr` that are on the same line as `rtoken`,2524// Returns the number of nodes in `expr` that are on the same line as `rtoken`.
2504// or null if they all are on the same line.2525fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex) usize {
2505fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex) ?usize {
2506 const token_tags = tree.tokens.items(.tag);2526 const token_tags = tree.tokens.items(.tag);
25072527
2508 const first_token = tree.firstToken(exprs[0]);2528 const first_token = tree.firstToken(exprs[0]);
...@@ -2510,7 +2530,7 @@ fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex...@@ -2510,7 +2530,7 @@ fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex
2510 const maybe_comma = rtoken - 1;2530 const maybe_comma = rtoken - 1;
2511 if (token_tags[maybe_comma] == .comma)2531 if (token_tags[maybe_comma] == .comma)
2512 return 1;2532 return 1;
2513 return null; // no newlines2533 return exprs.len; // no newlines
2514 }2534 }
25152535
2516 var count: usize = 1;2536 var count: usize = 1;
src/AstGen.zig+334-77
...@@ -28,8 +28,6 @@ const BuiltinFn = @import("BuiltinFn.zig");...@@ -28,8 +28,6 @@ const BuiltinFn = @import("BuiltinFn.zig");
28instructions: std.MultiArrayList(zir.Inst) = .{},28instructions: std.MultiArrayList(zir.Inst) = .{},
29string_bytes: ArrayListUnmanaged(u8) = .{},29string_bytes: ArrayListUnmanaged(u8) = .{},
30extra: ArrayListUnmanaged(u32) = .{},30extra: ArrayListUnmanaged(u32) = .{},
31decl_map: std.StringArrayHashMapUnmanaged(void) = .{},
32decls: ArrayListUnmanaged(*Decl) = .{},
33/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert31/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
34/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.32/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
35ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,33ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,
...@@ -110,8 +108,6 @@ pub fn deinit(astgen: *AstGen) void {...@@ -110,8 +108,6 @@ pub fn deinit(astgen: *AstGen) void {
110 astgen.instructions.deinit(gpa);108 astgen.instructions.deinit(gpa);
111 astgen.extra.deinit(gpa);109 astgen.extra.deinit(gpa);
112 astgen.string_bytes.deinit(gpa);110 astgen.string_bytes.deinit(gpa);
113 astgen.decl_map.deinit(gpa);
114 astgen.decls.deinit(gpa);
115}111}
116112
117pub const ResultLoc = union(enum) {113pub const ResultLoc = union(enum) {
...@@ -124,6 +120,9 @@ pub const ResultLoc = union(enum) {...@@ -124,6 +120,9 @@ pub const ResultLoc = union(enum) {
124 /// The expression must generate a pointer rather than a value. For example, the left hand side120 /// The expression must generate a pointer rather than a value. For example, the left hand side
125 /// of an assignment uses this kind of result location.121 /// of an assignment uses this kind of result location.
126 ref,122 ref,
123 /// The callee will accept a ref, but it is not necessary, and the `ResultLoc`
124 /// may be treated as `none` instead.
125 none_or_ref,
127 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.126 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
128 ty: zir.Inst.Ref,127 ty: zir.Inst.Ref,
129 /// The expression must store its result into this typed pointer. The result instruction128 /// The expression must store its result into this typed pointer. The result instruction
...@@ -157,7 +156,7 @@ pub const ResultLoc = union(enum) {...@@ -157,7 +156,7 @@ pub const ResultLoc = union(enum) {
157 var elide_store_to_block_ptr_instructions = false;156 var elide_store_to_block_ptr_instructions = false;
158 switch (rl) {157 switch (rl) {
159 // In this branch there will not be any store_to_block_ptr instructions.158 // In this branch there will not be any store_to_block_ptr instructions.
160 .discard, .none, .ty, .ref => return .{159 .discard, .none, .none_or_ref, .ty, .ref => return .{
161 .tag = .break_operand,160 .tag = .break_operand,
162 .elide_store_to_block_ptr_instructions = false,161 .elide_store_to_block_ptr_instructions = false,
163 },162 },
...@@ -606,8 +605,13 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -606,8 +605,13 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
606605
607 .deref => {606 .deref => {
608 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);607 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
609 const result = try gz.addUnNode(.load, lhs, node);608 switch (rl) {
610 return rvalue(gz, scope, rl, result, node);609 .ref, .none_or_ref => return lhs,
610 else => {
611 const result = try gz.addUnNode(.load, lhs, node);
612 return rvalue(gz, scope, rl, result, node);
613 },
614 }
611 },615 },
612 .address_of => {616 .address_of => {
613 const result = try expr(gz, scope, .ref, node_datas[node].lhs);617 const result = try expr(gz, scope, .ref, node_datas[node].lhs);
...@@ -816,10 +820,34 @@ pub fn structInitExpr(...@@ -816,10 +820,34 @@ pub fn structInitExpr(
816 }820 }
817 switch (rl) {821 switch (rl) {
818 .discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}),822 .discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}),
819 .none => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
820 .ref => unreachable, // struct literal not valid as l-value824 .ref => unreachable, // struct literal not valid as l-value
821 .ty => |ty_inst| {825 .ty => |ty_inst| {
822 return mod.failNode(scope, node, "TODO implement structInitExpr ty", .{});826 const fields_list = try gpa.alloc(zir.Inst.StructInit.Item, struct_init.ast.fields.len);
827 defer gpa.free(fields_list);
828
829 for (struct_init.ast.fields) |field_init, i| {
830 const name_token = tree.firstToken(field_init) - 2;
831 const str_index = try gz.identAsString(name_token);
832
833 const field_ty_inst = try gz.addPlNode(.field_type, field_init, zir.Inst.FieldType{
834 .container_type = ty_inst,
835 .name_start = str_index,
836 });
837 fields_list[i] = .{
838 .field_type = astgen.refToIndex(field_ty_inst).?,
839 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
840 };
841 }
842 const init_inst = try gz.addPlNode(.struct_init, node, zir.Inst.StructInit{
843 .fields_len = @intCast(u32, fields_list.len),
844 });
845 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
846 fields_list.len * @typeInfo(zir.Inst.StructInit.Item).Struct.fields.len);
847 for (fields_list) |field| {
848 _ = gz.astgen.addExtraAssumeCapacity(field);
849 }
850 return rvalue(gz, scope, rl, init_inst, node);
823 },851 },
824 .ptr => |ptr_inst| {852 .ptr => |ptr_inst| {
825 const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);853 const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);
...@@ -1175,13 +1203,6 @@ fn blockExprStmts(...@@ -1175,13 +1203,6 @@ fn blockExprStmts(
1175 // in the above while loop.1203 // in the above while loop.
1176 const zir_tags = gz.astgen.instructions.items(.tag);1204 const zir_tags = gz.astgen.instructions.items(.tag);
1177 switch (zir_tags[inst]) {1205 switch (zir_tags[inst]) {
1178 .@"const" => {
1179 const tv = gz.astgen.instructions.items(.data)[inst].@"const";
1180 break :b switch (tv.ty.zigTypeTag()) {
1181 .NoReturn, .Void => true,
1182 else => false,
1183 };
1184 },
1185 // For some instructions, swap in a slightly different ZIR tag1206 // For some instructions, swap in a slightly different ZIR tag
1186 // so we can avoid a separate ensure_result_used instruction.1207 // so we can avoid a separate ensure_result_used instruction.
1187 .call_none_chkused => unreachable,1208 .call_none_chkused => unreachable,
...@@ -1248,7 +1269,10 @@ fn blockExprStmts(...@@ -1248,7 +1269,10 @@ fn blockExprStmts(
1248 .fn_type_var_args,1269 .fn_type_var_args,
1249 .fn_type_cc,1270 .fn_type_cc,
1250 .fn_type_cc_var_args,1271 .fn_type_cc_var_args,
1272 .has_decl,
1251 .int,1273 .int,
1274 .float,
1275 .float128,
1252 .intcast,1276 .intcast,
1253 .int_type,1277 .int_type,
1254 .is_non_null,1278 .is_non_null,
...@@ -1321,12 +1345,18 @@ fn blockExprStmts(...@@ -1321,12 +1345,18 @@ fn blockExprStmts(
1321 .switch_capture_else,1345 .switch_capture_else,
1322 .switch_capture_else_ref,1346 .switch_capture_else_ref,
1323 .struct_init_empty,1347 .struct_init_empty,
1348 .struct_init,
1349 .field_type,
1324 .struct_decl,1350 .struct_decl,
1325 .struct_decl_packed,1351 .struct_decl_packed,
1326 .struct_decl_extern,1352 .struct_decl_extern,
1327 .union_decl,1353 .union_decl,
1328 .enum_decl,1354 .enum_decl,
1355 .enum_decl_nonexhaustive,
1329 .opaque_decl,1356 .opaque_decl,
1357 .int_to_enum,
1358 .enum_to_int,
1359 .type_info,
1330 => break :b false,1360 => break :b false,
13311361
1332 // ZIR instructions that are always either `noreturn` or `void`.1362 // ZIR instructions that are always either `noreturn` or `void`.
...@@ -1334,6 +1364,7 @@ fn blockExprStmts(...@@ -1334,6 +1364,7 @@ fn blockExprStmts(
1334 .dbg_stmt_node,1364 .dbg_stmt_node,
1335 .ensure_result_used,1365 .ensure_result_used,
1336 .ensure_result_non_error,1366 .ensure_result_non_error,
1367 .@"export",
1337 .set_eval_branch_quota,1368 .set_eval_branch_quota,
1338 .compile_log,1369 .compile_log,
1339 .ensure_err_payload_void,1370 .ensure_err_payload_void,
...@@ -1482,7 +1513,7 @@ fn varDecl(...@@ -1482,7 +1513,7 @@ fn varDecl(
1482 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);1513 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
1483 init_scope.rl_ty_inst = type_inst;1514 init_scope.rl_ty_inst = type_inst;
1484 } else {1515 } else {
1485 const alloc = try init_scope.addUnNode(.alloc_inferred, undefined, node);1516 const alloc = try init_scope.addNode(.alloc_inferred, node);
1486 resolve_inferred_alloc = alloc;1517 resolve_inferred_alloc = alloc;
1487 init_scope.rl_ptr = alloc;1518 init_scope.rl_ptr = alloc;
1488 }1519 }
...@@ -1557,7 +1588,7 @@ fn varDecl(...@@ -1557,7 +1588,7 @@ fn varDecl(
1557 const alloc = try gz.addUnNode(.alloc_mut, type_inst, node);1588 const alloc = try gz.addUnNode(.alloc_mut, type_inst, node);
1558 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };1589 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
1559 } else a: {1590 } else a: {
1560 const alloc = try gz.addUnNode(.alloc_inferred_mut, undefined, node);1591 const alloc = try gz.addNode(.alloc_inferred_mut, node);
1561 resolve_inferred_alloc = alloc;1592 resolve_inferred_alloc = alloc;
1562 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };1593 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
1563 };1594 };
...@@ -1815,15 +1846,18 @@ fn containerDecl(...@@ -1815,15 +1846,18 @@ fn containerDecl(
1815 defer bit_bag.deinit(gpa);1846 defer bit_bag.deinit(gpa);
18161847
1817 var cur_bit_bag: u32 = 0;1848 var cur_bit_bag: u32 = 0;
1818 var member_index: usize = 0;1849 var field_index: usize = 0;
1819 while (true) {1850 for (container_decl.ast.members) |member_node| {
1820 const member_node = container_decl.ast.members[member_index];
1821 const member = switch (node_tags[member_node]) {1851 const member = switch (node_tags[member_node]) {
1822 .container_field_init => tree.containerFieldInit(member_node),1852 .container_field_init => tree.containerFieldInit(member_node),
1823 .container_field_align => tree.containerFieldAlign(member_node),1853 .container_field_align => tree.containerFieldAlign(member_node),
1824 .container_field => tree.containerField(member_node),1854 .container_field => tree.containerField(member_node),
1825 else => unreachable,1855 else => continue,
1826 };1856 };
1857 if (field_index % 16 == 0 and field_index != 0) {
1858 try bit_bag.append(gpa, cur_bit_bag);
1859 cur_bit_bag = 0;
1860 }
1827 if (member.comptime_token) |comptime_token| {1861 if (member.comptime_token) |comptime_token| {
1828 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});1862 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
1829 }1863 }
...@@ -1850,17 +1884,9 @@ fn containerDecl(...@@ -1850,17 +1884,9 @@ fn containerDecl(
1850 fields_data.appendAssumeCapacity(@enumToInt(default_inst));1884 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
1851 }1885 }
18521886
1853 member_index += 1;1887 field_index += 1;
1854 if (member_index < container_decl.ast.members.len) {
1855 if (member_index % 16 == 0) {
1856 try bit_bag.append(gpa, cur_bit_bag);
1857 cur_bit_bag = 0;
1858 }
1859 } else {
1860 break;
1861 }
1862 }1888 }
1863 const empty_slot_count = 16 - ((member_index - 1) % 16);1889 const empty_slot_count = 16 - (field_index % 16);
1864 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);1890 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
18651891
1866 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{1892 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
...@@ -1877,7 +1903,172 @@ fn containerDecl(...@@ -1877,7 +1903,172 @@ fn containerDecl(
1877 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});1903 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});
1878 },1904 },
1879 .keyword_enum => {1905 .keyword_enum => {
1880 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for enum decl", .{});1906 if (container_decl.layout_token) |t| {
1907 return mod.failTok(scope, t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
1908 }
1909 // Count total fields as well as how many have explicitly provided tag values.
1910 const counts = blk: {
1911 var values: usize = 0;
1912 var total_fields: usize = 0;
1913 var decls: usize = 0;
1914 var nonexhaustive_node: ast.Node.Index = 0;
1915 for (container_decl.ast.members) |member_node| {
1916 const member = switch (node_tags[member_node]) {
1917 .container_field_init => tree.containerFieldInit(member_node),
1918 .container_field_align => tree.containerFieldAlign(member_node),
1919 .container_field => tree.containerField(member_node),
1920 else => {
1921 decls += 1;
1922 continue;
1923 },
1924 };
1925 if (member.comptime_token) |comptime_token| {
1926 return mod.failTok(scope, comptime_token, "enum fields cannot be marked comptime", .{});
1927 }
1928 if (member.ast.type_expr != 0) {
1929 return mod.failNode(scope, member.ast.type_expr, "enum fields do not have types", .{});
1930 }
1931 // Alignment expressions in enums are caught by the parser.
1932 assert(member.ast.align_expr == 0);
1933
1934 const name_token = member.ast.name_token;
1935 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {
1936 if (nonexhaustive_node != 0) {
1937 const msg = msg: {
1938 const msg = try mod.errMsg(
1939 scope,
1940 gz.nodeSrcLoc(member_node),
1941 "redundant non-exhaustive enum mark",
1942 .{},
1943 );
1944 errdefer msg.destroy(gpa);
1945 const other_src = gz.nodeSrcLoc(nonexhaustive_node);
1946 try mod.errNote(scope, other_src, msg, "other mark here", .{});
1947 break :msg msg;
1948 };
1949 return mod.failWithOwnedErrorMsg(scope, msg);
1950 }
1951 nonexhaustive_node = member_node;
1952 if (member.ast.value_expr != 0) {
1953 return mod.failNode(scope, member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
1954 }
1955 continue;
1956 }
1957 total_fields += 1;
1958 if (member.ast.value_expr != 0) {
1959 values += 1;
1960 }
1961 }
1962 break :blk .{
1963 .total_fields = total_fields,
1964 .values = values,
1965 .decls = decls,
1966 .nonexhaustive_node = nonexhaustive_node,
1967 };
1968 };
1969 if (counts.total_fields == 0) {
1970 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
1971 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
1972 // must be at least one tag.
1973 return mod.failNode(scope, node, "enum declarations must have at least one tag", .{});
1974 }
1975 if (counts.nonexhaustive_node != 0 and arg_inst == .none) {
1976 const msg = msg: {
1977 const msg = try mod.errMsg(
1978 scope,
1979 gz.nodeSrcLoc(node),
1980 "non-exhaustive enum missing integer tag type",
1981 .{},
1982 );
1983 errdefer msg.destroy(gpa);
1984 const other_src = gz.nodeSrcLoc(counts.nonexhaustive_node);
1985 try mod.errNote(scope, other_src, msg, "marked non-exhaustive here", .{});
1986 break :msg msg;
1987 };
1988 return mod.failWithOwnedErrorMsg(scope, msg);
1989 }
1990 if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {
1991 // No explicitly provided tag values and no top level declarations! In this case,
1992 // we can construct the enum type in AstGen and it will be correctly shared by all
1993 // generic function instantiations and comptime function calls.
1994 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
1995 errdefer new_decl_arena.deinit();
1996 const arena = &new_decl_arena.allocator;
1997
1998 var fields_map: std.StringArrayHashMapUnmanaged(void) = .{};
1999 try fields_map.ensureCapacity(arena, counts.total_fields);
2000 for (container_decl.ast.members) |member_node| {
2001 if (member_node == counts.nonexhaustive_node)
2002 continue;
2003 const member = switch (node_tags[member_node]) {
2004 .container_field_init => tree.containerFieldInit(member_node),
2005 .container_field_align => tree.containerFieldAlign(member_node),
2006 .container_field => tree.containerField(member_node),
2007 else => unreachable, // We checked earlier.
2008 };
2009 const name_token = member.ast.name_token;
2010 const tag_name = try mod.identifierTokenStringTreeArena(
2011 scope,
2012 name_token,
2013 tree,
2014 arena,
2015 );
2016 const gop = fields_map.getOrPutAssumeCapacity(tag_name);
2017 if (gop.found_existing) {
2018 const msg = msg: {
2019 const msg = try mod.errMsg(
2020 scope,
2021 gz.tokSrcLoc(name_token),
2022 "duplicate enum tag",
2023 .{},
2024 );
2025 errdefer msg.destroy(gpa);
2026 // Iterate to find the other tag. We don't eagerly store it in a hash
2027 // map because in the hot path there will be no compile error and we
2028 // don't need to waste time with a hash map.
2029 const bad_node = for (container_decl.ast.members) |other_member_node| {
2030 const other_member = switch (node_tags[other_member_node]) {
2031 .container_field_init => tree.containerFieldInit(other_member_node),
2032 .container_field_align => tree.containerFieldAlign(other_member_node),
2033 .container_field => tree.containerField(other_member_node),
2034 else => unreachable, // We checked earlier.
2035 };
2036 const other_tag_name = try mod.identifierTokenStringTreeArena(
2037 scope,
2038 other_member.ast.name_token,
2039 tree,
2040 arena,
2041 );
2042 if (mem.eql(u8, tag_name, other_tag_name))
2043 break other_member_node;
2044 } else unreachable;
2045 const other_src = gz.nodeSrcLoc(bad_node);
2046 try mod.errNote(scope, other_src, msg, "other tag here", .{});
2047 break :msg msg;
2048 };
2049 return mod.failWithOwnedErrorMsg(scope, msg);
2050 }
2051 }
2052 const enum_simple = try arena.create(Module.EnumSimple);
2053 enum_simple.* = .{
2054 .owner_decl = astgen.decl,
2055 .node_offset = astgen.decl.nodeIndexToRelative(node),
2056 .fields = fields_map,
2057 };
2058 const enum_ty = try Type.Tag.enum_simple.create(arena, enum_simple);
2059 const enum_val = try Value.Tag.ty.create(arena, enum_ty);
2060 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
2061 .ty = Type.initTag(.type),
2062 .val = enum_val,
2063 });
2064 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2065 const result = try gz.addDecl(.decl_val, decl_index, node);
2066 return rvalue(gz, scope, rl, result, node);
2067 }
2068 // In this case we must generate ZIR code for the tag values, similar to
2069 // how structs are handled above. The new anonymous Decl will be created in
2070 // Sema, not AstGen.
2071 return mod.failNode(scope, node, "TODO AstGen for enum decl with decls or explicitly provided field values", .{});
1881 },2072 },
1882 .keyword_opaque => {2073 .keyword_opaque => {
1883 const result = try gz.addNode(.opaque_decl, node);2074 const result = try gz.addNode(.opaque_decl, node);
...@@ -1893,11 +2084,11 @@ fn errorSetDecl(...@@ -1893,11 +2084,11 @@ fn errorSetDecl(
1893 rl: ResultLoc,2084 rl: ResultLoc,
1894 node: ast.Node.Index,2085 node: ast.Node.Index,
1895) InnerError!zir.Inst.Ref {2086) InnerError!zir.Inst.Ref {
1896 const mod = gz.astgen.mod;2087 const astgen = gz.astgen;
2088 const mod = astgen.mod;
1897 const tree = gz.tree();2089 const tree = gz.tree();
1898 const main_tokens = tree.nodes.items(.main_token);2090 const main_tokens = tree.nodes.items(.main_token);
1899 const token_tags = tree.tokens.items(.tag);2091 const token_tags = tree.tokens.items(.tag);
1900 const arena = gz.astgen.arena;
19012092
1902 // Count how many fields there are.2093 // Count how many fields there are.
1903 const error_token = main_tokens[node];2094 const error_token = main_tokens[node];
...@@ -1914,6 +2105,11 @@ fn errorSetDecl(...@@ -1914,6 +2105,11 @@ fn errorSetDecl(
1914 } else unreachable; // TODO should not need else unreachable here2105 } else unreachable; // TODO should not need else unreachable here
1915 };2106 };
19162107
2108 const gpa = mod.gpa;
2109 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
2110 errdefer new_decl_arena.deinit();
2111 const arena = &new_decl_arena.allocator;
2112
1917 const fields = try arena.alloc([]const u8, count);2113 const fields = try arena.alloc([]const u8, count);
1918 {2114 {
1919 var tok_i = error_token + 2;2115 var tok_i = error_token + 2;
...@@ -1922,7 +2118,7 @@ fn errorSetDecl(...@@ -1922,7 +2118,7 @@ fn errorSetDecl(
1922 switch (token_tags[tok_i]) {2118 switch (token_tags[tok_i]) {
1923 .doc_comment, .comma => {},2119 .doc_comment, .comma => {},
1924 .identifier => {2120 .identifier => {
1925 fields[field_i] = try mod.identifierTokenString(scope, tok_i);2121 fields[field_i] = try mod.identifierTokenStringTreeArena(scope, tok_i, tree, arena);
1926 field_i += 1;2122 field_i += 1;
1927 },2123 },
1928 .r_brace => break,2124 .r_brace => break,
...@@ -1932,18 +2128,19 @@ fn errorSetDecl(...@@ -1932,18 +2128,19 @@ fn errorSetDecl(
1932 }2128 }
1933 const error_set = try arena.create(Module.ErrorSet);2129 const error_set = try arena.create(Module.ErrorSet);
1934 error_set.* = .{2130 error_set.* = .{
1935 .owner_decl = gz.astgen.decl,2131 .owner_decl = astgen.decl,
1936 .node_offset = gz.astgen.decl.nodeIndexToRelative(node),2132 .node_offset = astgen.decl.nodeIndexToRelative(node),
1937 .names_ptr = fields.ptr,2133 .names_ptr = fields.ptr,
1938 .names_len = @intCast(u32, fields.len),2134 .names_len = @intCast(u32, fields.len),
1939 };2135 };
1940 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);2136 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
1941 const typed_value = try arena.create(TypedValue);2137 const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
1942 typed_value.* = .{2138 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1943 .ty = Type.initTag(.type),2139 .ty = Type.initTag(.type),
1944 .val = try Value.Tag.ty.create(arena, error_set_ty),2140 .val = error_set_val,
1945 };2141 });
1946 const result = try gz.addConst(typed_value);2142 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2143 const result = try gz.addDecl(.decl_val, decl_index, node);
1947 return rvalue(gz, scope, rl, result, node);2144 return rvalue(gz, scope, rl, result, node);
1948}2145}
19492146
...@@ -1980,7 +2177,7 @@ fn orelseCatchExpr(...@@ -1980,7 +2177,7 @@ fn orelseCatchExpr(
1980 // TODO handle catch2177 // TODO handle catch
1981 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {2178 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
1982 .ref => .ref,2179 .ref => .ref,
1983 .discard, .none, .block_ptr, .inferred_ptr => .none,2180 .discard, .none, .none_or_ref, .block_ptr, .inferred_ptr => .none,
1984 .ty => |elem_ty| blk: {2181 .ty => |elem_ty| blk: {
1985 const wrapped_ty = try block_scope.addUnNode(.optional_type, elem_ty, node);2182 const wrapped_ty = try block_scope.addUnNode(.optional_type, elem_ty, node);
1986 break :blk .{ .ty = wrapped_ty };2183 break :blk .{ .ty = wrapped_ty };
...@@ -2156,7 +2353,7 @@ pub fn fieldAccess(...@@ -2156,7 +2353,7 @@ pub fn fieldAccess(
2156 .field_name_start = str_index,2353 .field_name_start = str_index,
2157 }),2354 }),
2158 else => return rvalue(gz, scope, rl, try gz.addPlNode(.field_val, node, zir.Inst.Field{2355 else => return rvalue(gz, scope, rl, try gz.addPlNode(.field_val, node, zir.Inst.Field{
2159 .lhs = try expr(gz, scope, .none, object_node),2356 .lhs = try expr(gz, scope, .none_or_ref, object_node),
2160 .field_name_start = str_index,2357 .field_name_start = str_index,
2161 }), node),2358 }), node),
2162 }2359 }
...@@ -2179,7 +2376,7 @@ fn arrayAccess(...@@ -2179,7 +2376,7 @@ fn arrayAccess(
2179 ),2376 ),
2180 else => return rvalue(gz, scope, rl, try gz.addBin(2377 else => return rvalue(gz, scope, rl, try gz.addBin(
2181 .elem_val,2378 .elem_val,
2182 try expr(gz, scope, .none, node_datas[node].lhs),2379 try expr(gz, scope, .none_or_ref, node_datas[node].lhs),
2183 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),2380 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
2184 ), node),2381 ), node),
2185 }2382 }
...@@ -3188,8 +3385,13 @@ fn switchExpr(...@@ -3188,8 +3385,13 @@ fn switchExpr(
3188 switch (strat.tag) {3385 switch (strat.tag) {
3189 .break_operand => {3386 .break_operand => {
3190 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus3387 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus
3191 // this is always true.3388 // `elide_store_to_block_ptr_instructions` will either be true,
3192 assert(strat.elide_store_to_block_ptr_instructions);3389 // or all prongs are noreturn.
3390 if (!strat.elide_store_to_block_ptr_instructions) {
3391 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
3392 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
3393 return astgen.indexToRef(switch_block);
3394 }
31933395
3194 // There will necessarily be a store_to_block_ptr for3396 // There will necessarily be a store_to_block_ptr for
3195 // all prongs, except for prongs that ended with a noreturn instruction.3397 // all prongs, except for prongs that ended with a noreturn instruction.
...@@ -3418,7 +3620,8 @@ fn identifier(...@@ -3418,7 +3620,8 @@ fn identifier(
3418 const tracy = trace(@src());3620 const tracy = trace(@src());
3419 defer tracy.end();3621 defer tracy.end();
34203622
3421 const mod = gz.astgen.mod;3623 const astgen = gz.astgen;
3624 const mod = astgen.mod;
3422 const tree = gz.tree();3625 const tree = gz.tree();
3423 const main_tokens = tree.nodes.items(.main_token);3626 const main_tokens = tree.nodes.items(.main_token);
34243627
...@@ -3451,7 +3654,7 @@ fn identifier(...@@ -3451,7 +3654,7 @@ fn identifier(
3451 const result = try gz.add(.{3654 const result = try gz.add(.{
3452 .tag = .int_type,3655 .tag = .int_type,
3453 .data = .{ .int_type = .{3656 .data = .{ .int_type = .{
3454 .src_node = gz.astgen.decl.nodeIndexToRelative(ident),3657 .src_node = astgen.decl.nodeIndexToRelative(ident),
3455 .signedness = signedness,3658 .signedness = signedness,
3456 .bit_count = bit_count,3659 .bit_count = bit_count,
3457 } },3660 } },
...@@ -3474,9 +3677,13 @@ fn identifier(...@@ -3474,9 +3677,13 @@ fn identifier(
3474 .local_ptr => {3677 .local_ptr => {
3475 const local_ptr = s.cast(Scope.LocalPtr).?;3678 const local_ptr = s.cast(Scope.LocalPtr).?;
3476 if (mem.eql(u8, local_ptr.name, ident_name)) {3679 if (mem.eql(u8, local_ptr.name, ident_name)) {
3477 if (rl == .ref) return local_ptr.ptr;3680 switch (rl) {
3478 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);3681 .ref, .none_or_ref => return local_ptr.ptr,
3479 return rvalue(gz, scope, rl, loaded, ident);3682 else => {
3683 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
3684 return rvalue(gz, scope, rl, loaded, ident);
3685 },
3686 }
3480 }3687 }
3481 s = local_ptr.parent;3688 s = local_ptr.parent;
3482 },3689 },
...@@ -3485,15 +3692,15 @@ fn identifier(...@@ -3485,15 +3692,15 @@ fn identifier(
3485 };3692 };
3486 }3693 }
34873694
3488 const gop = try gz.astgen.decl_map.getOrPut(mod.gpa, ident_name);3695 const decl = mod.lookupDeclName(scope, ident_name) orelse {
3489 if (!gop.found_existing) {3696 // TODO insert a "dependency on the non-existence of a decl" here to make this
3490 const decl = mod.lookupDeclName(scope, ident_name) orelse3697 // compile error go away when the decl is introduced. This data should be in a global
3491 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});3698 // sparse map since it is only relevant when a compile error occurs.
3492 try gz.astgen.decls.append(mod.gpa, decl);3699 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
3493 }3700 };
3494 const decl_index = @intCast(u32, gop.index);3701 const decl_index = try mod.declareDeclDependency(astgen.decl, decl);
3495 switch (rl) {3702 switch (rl) {
3496 .ref => return gz.addDecl(.decl_ref, decl_index, ident),3703 .ref, .none_or_ref => return gz.addDecl(.decl_ref, decl_index, ident),
3497 else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),3704 else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),
3498 }3705 }
3499}3706}
...@@ -3626,12 +3833,23 @@ fn floatLiteral(...@@ -3626,12 +3833,23 @@ fn floatLiteral(
3626 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {3833 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
3627 error.InvalidCharacter => unreachable, // validated by tokenizer3834 error.InvalidCharacter => unreachable, // validated by tokenizer
3628 };3835 };
3629 const typed_value = try arena.create(TypedValue);3836 // If the value fits into a f32 without losing any precision, store it that way.
3630 typed_value.* = .{3837 @setFloatMode(.Strict);
3631 .ty = Type.initTag(.comptime_float),3838 const smaller_float = @floatCast(f32, float_number);
3632 .val = try Value.Tag.float_128.create(arena, float_number),3839 const bigger_again: f128 = smaller_float;
3633 };3840 if (bigger_again == float_number) {
3634 const result = try gz.addConst(typed_value);3841 const result = try gz.addFloat(smaller_float, node);
3842 return rvalue(gz, scope, rl, result, node);
3843 }
3844 // We need to use 128 bits. Break the float into 4 u32 values so we can
3845 // put it into the `extra` array.
3846 const int_bits = @bitCast(u128, float_number);
3847 const result = try gz.addPlNode(.float128, node, zir.Inst.Float128{
3848 .piece0 = @truncate(u32, int_bits),
3849 .piece1 = @truncate(u32, int_bits >> 32),
3850 .piece2 = @truncate(u32, int_bits >> 64),
3851 .piece3 = @truncate(u32, int_bits >> 96),
3852 });
3635 return rvalue(gz, scope, rl, result, node);3853 return rvalue(gz, scope, rl, result, node);
3636}3854}
36373855
...@@ -3697,7 +3915,7 @@ fn as(...@@ -3697,7 +3915,7 @@ fn as(
3697) InnerError!zir.Inst.Ref {3915) InnerError!zir.Inst.Ref {
3698 const dest_type = try typeExpr(gz, scope, lhs);3916 const dest_type = try typeExpr(gz, scope, lhs);
3699 switch (rl) {3917 switch (rl) {
3700 .none, .discard, .ref, .ty => {3918 .none, .none_or_ref, .discard, .ref, .ty => {
3701 const result = try expr(gz, scope, .{ .ty = dest_type }, rhs);3919 const result = try expr(gz, scope, .{ .ty = dest_type }, rhs);
3702 return rvalue(gz, scope, rl, result, node);3920 return rvalue(gz, scope, rl, result, node);
3703 },3921 },
...@@ -3781,7 +3999,7 @@ fn bitCast(...@@ -3781,7 +3999,7 @@ fn bitCast(
3781 });3999 });
3782 return rvalue(gz, scope, rl, result, node);4000 return rvalue(gz, scope, rl, result, node);
3783 },4001 },
3784 .ref => unreachable, // `@bitCast` is not allowed as an r-value.4002 .ref, .none_or_ref => unreachable, // `@bitCast` is not allowed as an r-value.
3785 .ptr => |result_ptr| {4003 .ptr => |result_ptr| {
3786 const casted_result_ptr = try gz.addUnNode(.bitcast_result_ptr, result_ptr, node);4004 const casted_result_ptr = try gz.addUnNode(.bitcast_result_ptr, result_ptr, node);
3787 return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);4005 return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);
...@@ -3882,11 +4100,11 @@ fn builtinCall(...@@ -3882,11 +4100,11 @@ fn builtinCall(
3882 return rvalue(gz, scope, rl, result, node);4100 return rvalue(gz, scope, rl, result, node);
3883 },4101 },
3884 .breakpoint => {4102 .breakpoint => {
3885 const result = try gz.add(.{4103 _ = try gz.add(.{
3886 .tag = .breakpoint,4104 .tag = .breakpoint,
3887 .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(node) },4105 .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(node) },
3888 });4106 });
3889 return rvalue(gz, scope, rl, result, node);4107 return rvalue(gz, scope, rl, .void_value, node);
3890 },4108 },
3891 .import => {4109 .import => {
3892 const target = try expr(gz, scope, .none, params[0]);4110 const target = try expr(gz, scope, .none, params[0]);
...@@ -3943,6 +4161,50 @@ fn builtinCall(...@@ -3943,6 +4161,50 @@ fn builtinCall(
3943 .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),4161 .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),
3944 .TypeOf => return typeOf(gz, scope, rl, node, params),4162 .TypeOf => return typeOf(gz, scope, rl, node, params),
39454163
4164 .int_to_enum => {
4165 const result = try gz.addPlNode(.int_to_enum, node, zir.Inst.Bin{
4166 .lhs = try typeExpr(gz, scope, params[0]),
4167 .rhs = try expr(gz, scope, .none, params[1]),
4168 });
4169 return rvalue(gz, scope, rl, result, node);
4170 },
4171
4172 .enum_to_int => {
4173 const operand = try expr(gz, scope, .none, params[0]);
4174 const result = try gz.addUnNode(.enum_to_int, operand, node);
4175 return rvalue(gz, scope, rl, result, node);
4176 },
4177
4178 .@"export" => {
4179 // TODO: @export is supposed to be able to export things other than functions.
4180 // Instead of `comptimeExpr` here we need `decl_ref`.
4181 const fn_to_export = try comptimeExpr(gz, scope, .none, params[0]);
4182 // TODO: the second parameter here is supposed to be
4183 // `std.builtin.ExportOptions`, not a string.
4184 const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
4185 _ = try gz.addPlNode(.@"export", node, zir.Inst.Bin{
4186 .lhs = fn_to_export,
4187 .rhs = export_name,
4188 });
4189 return rvalue(gz, scope, rl, .void_value, node);
4190 },
4191
4192 .has_decl => {
4193 const container_type = try typeExpr(gz, scope, params[0]);
4194 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
4195 const result = try gz.addPlNode(.has_decl, node, zir.Inst.Bin{
4196 .lhs = container_type,
4197 .rhs = name,
4198 });
4199 return rvalue(gz, scope, rl, result, node);
4200 },
4201
4202 .type_info => {
4203 const operand = try typeExpr(gz, scope, params[0]);
4204 const result = try gz.addUnNode(.type_info, operand, node);
4205 return rvalue(gz, scope, rl, result, node);
4206 },
4207
3946 .add_with_overflow,4208 .add_with_overflow,
3947 .align_cast,4209 .align_cast,
3948 .align_of,4210 .align_of,
...@@ -3969,17 +4231,13 @@ fn builtinCall(...@@ -3969,17 +4231,13 @@ fn builtinCall(
3969 .div_floor,4231 .div_floor,
3970 .div_trunc,4232 .div_trunc,
3971 .embed_file,4233 .embed_file,
3972 .enum_to_int,
3973 .error_name,4234 .error_name,
3974 .error_return_trace,4235 .error_return_trace,
3975 .err_set_cast,4236 .err_set_cast,
3976 .@"export",
3977 .fence,4237 .fence,
3978 .field_parent_ptr,4238 .field_parent_ptr,
3979 .float_to_int,4239 .float_to_int,
3980 .has_decl,
3981 .has_field,4240 .has_field,
3982 .int_to_enum,
3983 .int_to_float,4241 .int_to_float,
3984 .int_to_ptr,4242 .int_to_ptr,
3985 .memcpy,4243 .memcpy,
...@@ -4023,7 +4281,6 @@ fn builtinCall(...@@ -4023,7 +4281,6 @@ fn builtinCall(
4023 .This,4281 .This,
4024 .truncate,4282 .truncate,
4025 .Type,4283 .Type,
4026 .type_info,
4027 .type_name,4284 .type_name,
4028 .union_init,4285 .union_init,
4029 => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{4286 => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{
...@@ -4354,7 +4611,7 @@ fn rvalue(...@@ -4354,7 +4611,7 @@ fn rvalue(
4354 src_node: ast.Node.Index,4611 src_node: ast.Node.Index,
4355) InnerError!zir.Inst.Ref {4612) InnerError!zir.Inst.Ref {
4356 switch (rl) {4613 switch (rl) {
4357 .none => return result,4614 .none, .none_or_ref => return result,
4358 .discard => {4615 .discard => {
4359 // Emit a compile error for discarding error values.4616 // Emit a compile error for discarding error values.
4360 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);4617 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
src/BuiltinFn.zig+1-1
...@@ -484,7 +484,7 @@ pub const list = list: {...@@ -484,7 +484,7 @@ pub const list = list: {
484 "@intToEnum",484 "@intToEnum",
485 .{485 .{
486 .tag = .int_to_enum,486 .tag = .int_to_enum,
487 .param_count = 1,487 .param_count = 2,
488 },488 },
489 },489 },
490 .{490 .{
src/Compilation.zig+132-58
...@@ -272,32 +272,57 @@ pub const AllErrors = struct {...@@ -272,32 +272,57 @@ pub const AllErrors = struct {
272 line: u32,272 line: u32,
273 column: u32,273 column: u32,
274 byte_offset: u32,274 byte_offset: u32,
275 /// Does not include the trailing newline.
276 source_line: ?[]const u8,
275 notes: []Message = &.{},277 notes: []Message = &.{},
276 },278 },
277 plain: struct {279 plain: struct {
278 msg: []const u8,280 msg: []const u8,
279 },281 },
280282
281 pub fn renderToStdErr(msg: Message) void {283 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
282 return msg.renderToStdErrInner("error");284 const stderr_mutex = std.debug.getStderrMutex();
285 const held = std.debug.getStderrMutex().acquire();
286 defer held.release();
287 const stderr = std.io.getStdErr();
288 return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red) catch return;
283 }289 }
284290
285 fn renderToStdErrInner(msg: Message, kind: []const u8) void {291 fn renderToStdErrInner(
292 msg: Message,
293 ttyconf: std.debug.TTY.Config,
294 stderr_file: std.fs.File,
295 kind: []const u8,
296 color: std.debug.TTY.Color,
297 ) anyerror!void {
298 const stderr = stderr_file.writer();
286 switch (msg) {299 switch (msg) {
287 .src => |src| {300 .src => |src| {
288 std.debug.print("{s}:{d}:{d}: {s}: {s}\n", .{301 ttyconf.setColor(stderr, .Bold);
302 try stderr.print("{s}:{d}:{d}: ", .{
289 src.src_path,303 src.src_path,
290 src.line + 1,304 src.line + 1,
291 src.column + 1,305 src.column + 1,
292 kind,
293 src.msg,
294 });306 });
307 ttyconf.setColor(stderr, color);
308 try stderr.writeAll(kind);
309 ttyconf.setColor(stderr, .Bold);
310 try stderr.print(" {s}\n", .{src.msg});
311 ttyconf.setColor(stderr, .Reset);
312 if (src.source_line) |line| {
313 try stderr.writeAll(line);
314 try stderr.writeByte('\n');
315 try stderr.writeByteNTimes(' ', src.column);
316 ttyconf.setColor(stderr, .Green);
317 try stderr.writeAll("^\n");
318 ttyconf.setColor(stderr, .Reset);
319 }
295 for (src.notes) |note| {320 for (src.notes) |note| {
296 note.renderToStdErrInner("note");321 try note.renderToStdErrInner(ttyconf, stderr_file, "note:", .Cyan);
297 }322 }
298 },323 },
299 .plain => |plain| {324 .plain => |plain| {
300 std.debug.print("{s}: {s}\n", .{ kind, plain.msg });325 try stderr.print("{s}: {s}\n", .{ kind, plain.msg });
301 },326 },
302 }327 }
303 }328 }
...@@ -327,6 +352,7 @@ pub const AllErrors = struct {...@@ -327,6 +352,7 @@ pub const AllErrors = struct {
327 .byte_offset = byte_offset,352 .byte_offset = byte_offset,
328 .line = @intCast(u32, loc.line),353 .line = @intCast(u32, loc.line),
329 .column = @intCast(u32, loc.column),354 .column = @intCast(u32, loc.column),
355 .source_line = try arena.allocator.dupe(u8, loc.source_line),
330 },356 },
331 };357 };
332 }358 }
...@@ -342,6 +368,7 @@ pub const AllErrors = struct {...@@ -342,6 +368,7 @@ pub const AllErrors = struct {
342 .line = @intCast(u32, loc.line),368 .line = @intCast(u32, loc.line),
343 .column = @intCast(u32, loc.column),369 .column = @intCast(u32, loc.column),
344 .notes = notes,370 .notes = notes,
371 .source_line = try arena.allocator.dupe(u8, loc.source_line),
345 },372 },
346 });373 });
347 }374 }
...@@ -906,38 +933,56 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -906,38 +933,56 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
906 artifact_sub_dir,933 artifact_sub_dir,
907 };934 };
908935
909 // TODO when we implement serialization and deserialization of incremental compilation metadata,936 // If we rely on stage1, we must not redundantly add these packages.
910 // this is where we would load it. We have open a handle to the directory where937 const use_stage1 = build_options.is_stage1 and use_llvm;
911 // the output either already is, or will be.938 if (!use_stage1) {
939 const builtin_pkg = try Package.createWithDir(
940 gpa,
941 zig_cache_artifact_directory,
942 null,
943 "builtin.zig",
944 );
945 errdefer builtin_pkg.destroy(gpa);
946
947 const std_pkg = try Package.createWithDir(
948 gpa,
949 options.zig_lib_directory,
950 "std",
951 "std.zig",
952 );
953 errdefer std_pkg.destroy(gpa);
954
955 try root_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);
956 try root_pkg.add(gpa, "root", root_pkg);
957 try root_pkg.addAndAdopt(gpa, "std", std_pkg);
958
959 try std_pkg.add(gpa, "builtin", builtin_pkg);
960 try std_pkg.add(gpa, "root", root_pkg);
961 }
962
963 // TODO when we implement serialization and deserialization of incremental
964 // compilation metadata, this is where we would load it. We have open a handle
965 // to the directory where the output either already is, or will be.
912 // However we currently do not have serialization of such metadata, so for now966 // However we currently do not have serialization of such metadata, so for now
913 // we set up an empty Module that does the entire compilation fresh.967 // we set up an empty Module that does the entire compilation fresh.
914968
915 const root_scope = rs: {969 const root_scope = try gpa.create(Module.Scope.File);
916 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {970 errdefer gpa.destroy(root_scope);
917 const root_scope = try gpa.create(Module.Scope.File);971
918 const struct_ty = try Type.Tag.empty_struct.create(972 const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container);
919 gpa,973 root_scope.* = .{
920 &root_scope.root_container,974 // TODO this is duped so it can be freed in Container.deinit
921 );975 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
922 root_scope.* = .{976 .source = .{ .unloaded = {} },
923 // TODO this is duped so it can be freed in Container.deinit977 .tree = undefined,
924 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),978 .status = .never_loaded,
925 .source = .{ .unloaded = {} },979 .pkg = root_pkg,
926 .tree = undefined,980 .root_container = .{
927 .status = .never_loaded,981 .file_scope = root_scope,
928 .pkg = root_pkg,982 .decls = .{},
929 .root_container = .{983 .ty = struct_ty,
930 .file_scope = root_scope,984 .parent_name_hash = root_pkg.namespace_hash,
931 .decls = .{},985 },
932 .ty = struct_ty,
933 },
934 };
935 break :rs root_scope;
936 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
937 return error.ZirFilesUnsupported;
938 } else {
939 unreachable;
940 }
941 };986 };
942987
943 const module = try arena.create(Module);988 const module = try arena.create(Module);
...@@ -1339,16 +1384,17 @@ pub fn update(self: *Compilation) !void {...@@ -1339,16 +1384,17 @@ pub fn update(self: *Compilation) !void {
1339 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);1384 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
1340 }1385 }
13411386
1342 const use_stage1 = build_options.omit_stage2 or build_options.is_stage1 and self.bin_file.options.use_llvm;1387 const use_stage1 = build_options.omit_stage2 or
1388 (build_options.is_stage1 and self.bin_file.options.use_llvm);
1343 if (!use_stage1) {1389 if (!use_stage1) {
1344 if (self.bin_file.options.module) |module| {1390 if (self.bin_file.options.module) |module| {
1345 module.compile_log_text.shrinkAndFree(module.gpa, 0);1391 module.compile_log_text.shrinkAndFree(module.gpa, 0);
1346 module.generation += 1;1392 module.generation += 1;
13471393
1348 // TODO Detect which source files changed.1394 // TODO Detect which source files changed.
1349 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;1395 // Until then we simulate a full cache miss. Source files could have been loaded
1350 // to force a refresh we unload now.1396 // for any reason; to force a refresh we unload now.
1351 module.root_scope.unload(module.gpa);1397 module.unloadFile(module.root_scope);
1352 module.failed_root_src_file = null;1398 module.failed_root_src_file = null;
1353 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {1399 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
1354 error.AnalysisFail => {1400 error.AnalysisFail => {
...@@ -1362,7 +1408,7 @@ pub fn update(self: *Compilation) !void {...@@ -1362,7 +1408,7 @@ pub fn update(self: *Compilation) !void {
13621408
1363 // TODO only analyze imports if they are still referenced1409 // TODO only analyze imports if they are still referenced
1364 for (module.import_table.items()) |entry| {1410 for (module.import_table.items()) |entry| {
1365 entry.value.unload(module.gpa);1411 module.unloadFile(entry.value);
1366 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {1412 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
1367 error.AnalysisFail => {1413 error.AnalysisFail => {
1368 assert(self.totalErrorCount() != 0);1414 assert(self.totalErrorCount() != 0);
...@@ -1377,14 +1423,17 @@ pub fn update(self: *Compilation) !void {...@@ -1377,14 +1423,17 @@ pub fn update(self: *Compilation) !void {
13771423
1378 if (!use_stage1) {1424 if (!use_stage1) {
1379 if (self.bin_file.options.module) |module| {1425 if (self.bin_file.options.module) |module| {
1380 // Process the deletion set.1426 // Process the deletion set. We use a while loop here because the
1381 while (module.deletion_set.popOrNull()) |decl| {1427 // deletion set may grow as we call `deleteDecl` within this loop,
1382 if (decl.dependants.items().len != 0) {1428 // and more unreferenced Decls are revealed.
1383 decl.deletion_flag = false;1429 var entry_i: usize = 0;
1384 continue;1430 while (entry_i < module.deletion_set.entries.items.len) : (entry_i += 1) {
1385 }1431 const decl = module.deletion_set.entries.items[entry_i].key;
1386 try module.deleteDecl(decl);1432 assert(decl.deletion_flag);
1433 assert(decl.dependants.items().len == 0);
1434 try module.deleteDecl(decl, null);
1387 }1435 }
1436 module.deletion_set.shrinkRetainingCapacity(0);
1388 }1437 }
1389 }1438 }
13901439
...@@ -1429,11 +1478,25 @@ pub fn totalErrorCount(self: *Compilation) usize {...@@ -1429,11 +1478,25 @@ pub fn totalErrorCount(self: *Compilation) usize {
1429 var total: usize = self.failed_c_objects.items().len;1478 var total: usize = self.failed_c_objects.items().len;
14301479
1431 if (self.bin_file.options.module) |module| {1480 if (self.bin_file.options.module) |module| {
1432 total += module.failed_decls.count() +1481 total += module.failed_exports.items().len +
1433 module.emit_h_failed_decls.count() +
1434 module.failed_exports.items().len +
1435 module.failed_files.items().len +1482 module.failed_files.items().len +
1436 @boolToInt(module.failed_root_src_file != null);1483 @boolToInt(module.failed_root_src_file != null);
1484 // Skip errors for Decls within files that failed parsing.
1485 // When a parse error is introduced, we keep all the semantic analysis for
1486 // the previous parse success, including compile errors, but we cannot
1487 // emit them until the file succeeds parsing.
1488 for (module.failed_decls.items()) |entry| {
1489 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1490 continue;
1491 }
1492 total += 1;
1493 }
1494 for (module.emit_h_failed_decls.items()) |entry| {
1495 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1496 continue;
1497 }
1498 total += 1;
1499 }
1437 }1500 }
14381501
1439 // The "no entry point found" error only counts if there are no other errors.1502 // The "no entry point found" error only counts if there are no other errors.
...@@ -1472,6 +1535,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1472,6 +1535,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1472 .byte_offset = 0,1535 .byte_offset = 0,
1473 .line = err_msg.line,1536 .line = err_msg.line,
1474 .column = err_msg.column,1537 .column = err_msg.column,
1538 .source_line = null, // TODO
1475 },1539 },
1476 });1540 });
1477 }1541 }
...@@ -1480,9 +1544,19 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1480,9 +1544,19 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1480 try AllErrors.add(module, &arena, &errors, entry.value.*);1544 try AllErrors.add(module, &arena, &errors, entry.value.*);
1481 }1545 }
1482 for (module.failed_decls.items()) |entry| {1546 for (module.failed_decls.items()) |entry| {
1547 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1548 // Skip errors for Decls within files that had a parse failure.
1549 // We'll try again once parsing succeeds.
1550 continue;
1551 }
1483 try AllErrors.add(module, &arena, &errors, entry.value.*);1552 try AllErrors.add(module, &arena, &errors, entry.value.*);
1484 }1553 }
1485 for (module.emit_h_failed_decls.items()) |entry| {1554 for (module.emit_h_failed_decls.items()) |entry| {
1555 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1556 // Skip errors for Decls within files that had a parse failure.
1557 // We'll try again once parsing succeeds.
1558 continue;
1559 }
1486 try AllErrors.add(module, &arena, &errors, entry.value.*);1560 try AllErrors.add(module, &arena, &errors, entry.value.*);
1487 }1561 }
1488 for (module.failed_exports.items()) |entry| {1562 for (module.failed_exports.items()) |entry| {
...@@ -2437,7 +2511,7 @@ pub fn addCCArgs(...@@ -2437,7 +2511,7 @@ pub fn addCCArgs(
2437 try argv.append("-fPIC");2511 try argv.append("-fPIC");
2438 }2512 }
2439 },2513 },
2440 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig, .zir => {},2514 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig => {},
2441 }2515 }
2442 if (out_dep_path) |p| {2516 if (out_dep_path) |p| {
2443 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });2517 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
...@@ -2511,7 +2585,6 @@ pub const FileExt = enum {...@@ -2511,7 +2585,6 @@ pub const FileExt = enum {
2511 object,2585 object,
2512 static_library,2586 static_library,
2513 zig,2587 zig,
2514 zir,
2515 unknown,2588 unknown,
25162589
2517 pub fn clangSupportsDepFile(ext: FileExt) bool {2590 pub fn clangSupportsDepFile(ext: FileExt) bool {
...@@ -2525,7 +2598,6 @@ pub const FileExt = enum {...@@ -2525,7 +2598,6 @@ pub const FileExt = enum {
2525 .object,2598 .object,
2526 .static_library,2599 .static_library,
2527 .zig,2600 .zig,
2528 .zir,
2529 .unknown,2601 .unknown,
2530 => false,2602 => false,
2531 };2603 };
...@@ -2597,8 +2669,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {...@@ -2597,8 +2669,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
2597 return .h;2669 return .h;
2598 } else if (mem.endsWith(u8, filename, ".zig")) {2670 } else if (mem.endsWith(u8, filename, ".zig")) {
2599 return .zig;2671 return .zig;
2600 } else if (mem.endsWith(u8, filename, ".zir")) {
2601 return .zir;
2602 } else if (hasSharedLibraryExt(filename)) {2672 } else if (hasSharedLibraryExt(filename)) {
2603 return .shared_library;2673 return .shared_library;
2604 } else if (hasStaticLibraryExt(filename)) {2674 } else if (hasStaticLibraryExt(filename)) {
...@@ -2619,7 +2689,6 @@ test "classifyFileExt" {...@@ -2619,7 +2689,6 @@ test "classifyFileExt" {
2619 std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));2689 std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));
2620 std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));2690 std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));
2621 std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));2691 std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
2622 std.testing.expectEqual(FileExt.zir, classifyFileExt("foo.zir"));
2623}2692}
26242693
2625fn haveFramePointer(comp: *const Compilation) bool {2694fn haveFramePointer(comp: *const Compilation) bool {
...@@ -2814,6 +2883,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8...@@ -2814,6 +2883,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28142883
2815 const target = comp.getTarget();2884 const target = comp.getTarget();
2816 const generic_arch_name = target.cpu.arch.genericName();2885 const generic_arch_name = target.cpu.arch.genericName();
2886 const use_stage1 = build_options.omit_stage2 or
2887 (build_options.is_stage1 and comp.bin_file.options.use_llvm);
28172888
2818 @setEvalBranchQuota(4000);2889 @setEvalBranchQuota(4000);
2819 try buffer.writer().print(2890 try buffer.writer().print(
...@@ -2826,6 +2897,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8...@@ -2826,6 +2897,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
2826 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer2897 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
2827 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.2898 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
2828 \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}");2899 \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}");
2900 \\pub const zig_is_stage2 = {};
2829 \\2901 \\
2830 \\pub const output_mode = OutputMode.{};2902 \\pub const output_mode = OutputMode.{};
2831 \\pub const link_mode = LinkMode.{};2903 \\pub const link_mode = LinkMode.{};
...@@ -2839,6 +2911,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8...@@ -2839,6 +2911,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
2839 \\2911 \\
2840 , .{2912 , .{
2841 build_options.version,2913 build_options.version,
2914 !use_stage1,
2842 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),2915 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
2843 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),2916 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
2844 comp.bin_file.options.is_test,2917 comp.bin_file.options.is_test,
...@@ -3044,6 +3117,7 @@ fn buildOutputFromZig(...@@ -3044,6 +3117,7 @@ fn buildOutputFromZig(
3044 .handle = special_dir,3117 .handle = special_dir,
3045 },3118 },
3046 .root_src_path = src_basename,3119 .root_src_path = src_basename,
3120 .namespace_hash = Package.root_namespace_hash,
3047 };3121 };
3048 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];3122 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
3049 const target = comp.getTarget();3123 const target = comp.getTarget();
src/Module.zig+320-132
...@@ -65,8 +65,8 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},...@@ -65,8 +65,8 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
65/// Keep track of one `@compileLog` callsite per owner Decl.65/// Keep track of one `@compileLog` callsite per owner Decl.
66compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},66compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},
67/// Using a map here for consistency with the other fields here.67/// Using a map here for consistency with the other fields here.
68/// The ErrorMsg memory is owned by the `Scope`, using Module's general purpose allocator.68/// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator.
69failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *ErrorMsg) = .{},69failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{},
70/// Using a map here for consistency with the other fields here.70/// Using a map here for consistency with the other fields here.
71/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.71/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
72failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},72failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
...@@ -75,7 +75,7 @@ next_anon_name_index: usize = 0,...@@ -75,7 +75,7 @@ next_anon_name_index: usize = 0,
7575
76/// Candidates for deletion. After a semantic analysis update completes, this list76/// Candidates for deletion. After a semantic analysis update completes, this list
77/// contains Decls that need to be deleted if they end up having no references to them.77/// contains Decls that need to be deleted if they end up having no references to them.
78deletion_set: ArrayListUnmanaged(*Decl) = .{},78deletion_set: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
7979
80/// Error tags and their values, tag names are duped with mod.gpa.80/// Error tags and their values, tag names are duped with mod.gpa.
81/// Corresponds with `error_name_list`.81/// Corresponds with `error_name_list`.
...@@ -150,9 +150,15 @@ pub const Decl = struct {...@@ -150,9 +150,15 @@ pub const Decl = struct {
150 /// The direct parent container of the Decl.150 /// The direct parent container of the Decl.
151 /// Reference to externally owned memory.151 /// Reference to externally owned memory.
152 container: *Scope.Container,152 container: *Scope.Container,
153 /// The AST Node decl index or ZIR Inst index that contains this declaration.153
154 /// An integer that can be checked against the corresponding incrementing
155 /// generation field of Module. This is used to determine whether `complete` status
156 /// represents pre- or post- re-analysis.
157 generation: u32,
158 /// The AST Node index or ZIR Inst index that contains this declaration.
154 /// Must be recomputed when the corresponding source file is modified.159 /// Must be recomputed when the corresponding source file is modified.
155 src_index: usize,160 src_node: ast.Node.Index,
161
156 /// The most recent value of the Decl after a successful semantic analysis.162 /// The most recent value of the Decl after a successful semantic analysis.
157 typed_value: union(enum) {163 typed_value: union(enum) {
158 never_succeeded: void,164 never_succeeded: void,
...@@ -192,17 +198,12 @@ pub const Decl = struct {...@@ -192,17 +198,12 @@ pub const Decl = struct {
192 /// to require re-analysis.198 /// to require re-analysis.
193 outdated,199 outdated,
194 },200 },
195 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared201 /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared
196 /// when removed.202 /// when removed.
197 deletion_flag: bool,203 deletion_flag: bool,
198 /// Whether the corresponding AST decl has a `pub` keyword.204 /// Whether the corresponding AST decl has a `pub` keyword.
199 is_pub: bool,205 is_pub: bool,
200206
201 /// An integer that can be checked against the corresponding incrementing
202 /// generation field of Module. This is used to determine whether `complete` status
203 /// represents pre- or post- re-analysis.
204 generation: u32,
205
206 /// Represents the position of the code in the output file.207 /// Represents the position of the code in the output file.
207 /// This is populated regardless of semantic analysis and code generation.208 /// This is populated regardless of semantic analysis and code generation.
208 link: link.File.LinkBlock,209 link: link.File.LinkBlock,
...@@ -249,11 +250,11 @@ pub const Decl = struct {...@@ -249,11 +250,11 @@ pub const Decl = struct {
249 }250 }
250251
251 pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index {252 pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index {
252 return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.srcNode()));253 return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.src_node));
253 }254 }
254255
255 pub fn nodeIndexToRelative(decl: Decl, node_index: ast.Node.Index) i32 {256 pub fn nodeIndexToRelative(decl: Decl, node_index: ast.Node.Index) i32 {
256 return @bitCast(i32, node_index) - @bitCast(i32, decl.srcNode());257 return @bitCast(i32, node_index) - @bitCast(i32, decl.src_node);
257 }258 }
258259
259 pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {260 pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {
...@@ -271,14 +272,9 @@ pub const Decl = struct {...@@ -271,14 +272,9 @@ pub const Decl = struct {
271 };272 };
272 }273 }
273274
274 pub fn srcNode(decl: Decl) u32 {
275 const tree = &decl.container.file_scope.tree;
276 return tree.rootDecls()[decl.src_index];
277 }
278
279 pub fn srcToken(decl: Decl) u32 {275 pub fn srcToken(decl: Decl) u32 {
280 const tree = &decl.container.file_scope.tree;276 const tree = &decl.container.file_scope.tree;
281 return tree.firstToken(decl.srcNode());277 return tree.firstToken(decl.src_node);
282 }278 }
283279
284 pub fn srcByteOffset(decl: Decl) u32 {280 pub fn srcByteOffset(decl: Decl) u32 {
...@@ -290,6 +286,18 @@ pub const Decl = struct {...@@ -290,6 +286,18 @@ pub const Decl = struct {
290 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));286 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
291 }287 }
292288
289 pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void {
290 const unqualified_name = mem.spanZ(decl.name);
291 return decl.container.renderFullyQualifiedName(unqualified_name, writer);
292 }
293
294 pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 {
295 var buffer = std.ArrayList(u8).init(gpa);
296 defer buffer.deinit();
297 try decl.renderFullyQualifiedName(buffer.writer());
298 return buffer.toOwnedSlice();
299 }
300
293 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {301 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {
294 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;302 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;
295 return tvm.typed_value;303 return tvm.typed_value;
...@@ -354,6 +362,13 @@ pub const ErrorSet = struct {...@@ -354,6 +362,13 @@ pub const ErrorSet = struct {
354 /// The string bytes are stored in the owner Decl arena.362 /// The string bytes are stored in the owner Decl arena.
355 /// They are in the same order they appear in the AST.363 /// They are in the same order they appear in the AST.
356 names_ptr: [*]const []const u8,364 names_ptr: [*]const []const u8,
365
366 pub fn srcLoc(self: ErrorSet) SrcLoc {
367 return .{
368 .container = .{ .decl = self.owner_decl },
369 .lazy = .{ .node_offset = self.node_offset },
370 };
371 }
357};372};
358373
359/// Represents the data that a struct declaration provides.374/// Represents the data that a struct declaration provides.
...@@ -364,7 +379,7 @@ pub const Struct = struct {...@@ -364,7 +379,7 @@ pub const Struct = struct {
364 /// Represents the declarations inside this struct.379 /// Represents the declarations inside this struct.
365 container: Scope.Container,380 container: Scope.Container,
366381
367 /// Offset from Decl node index, points to the struct AST node.382 /// Offset from `owner_decl`, points to the struct AST node.
368 node_offset: i32,383 node_offset: i32,
369384
370 pub const Field = struct {385 pub const Field = struct {
...@@ -373,6 +388,64 @@ pub const Struct = struct {...@@ -373,6 +388,64 @@ pub const Struct = struct {
373 /// Uses `unreachable_value` to indicate no default.388 /// Uses `unreachable_value` to indicate no default.
374 default_val: Value,389 default_val: Value,
375 };390 };
391
392 pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 {
393 return s.owner_decl.getFullyQualifiedName(gpa);
394 }
395
396 pub fn srcLoc(s: Struct) SrcLoc {
397 return .{
398 .container = .{ .decl = s.owner_decl },
399 .lazy = .{ .node_offset = s.node_offset },
400 };
401 }
402};
403
404/// Represents the data that an enum declaration provides, when the fields
405/// are auto-numbered, and there are no declarations. The integer tag type
406/// is inferred to be the smallest power of two unsigned int that fits
407/// the number of fields.
408pub const EnumSimple = struct {
409 owner_decl: *Decl,
410 /// Set of field names in declaration order.
411 fields: std.StringArrayHashMapUnmanaged(void),
412 /// Offset from `owner_decl`, points to the enum decl AST node.
413 node_offset: i32,
414
415 pub fn srcLoc(self: EnumSimple) SrcLoc {
416 return .{
417 .container = .{ .decl = self.owner_decl },
418 .lazy = .{ .node_offset = self.node_offset },
419 };
420 }
421};
422
423/// Represents the data that an enum declaration provides, when there is
424/// at least one tag value explicitly specified, or at least one declaration.
425pub const EnumFull = struct {
426 owner_decl: *Decl,
427 /// An integer type which is used for the numerical value of the enum.
428 /// Whether zig chooses this type or the user specifies it, it is stored here.
429 tag_ty: Type,
430 /// Set of field names in declaration order.
431 fields: std.StringArrayHashMapUnmanaged(void),
432 /// Maps integer tag value to field index.
433 /// Entries are in declaration order, same as `fields`.
434 /// If this hash map is empty, it means the enum tags are auto-numbered.
435 values: ValueMap,
436 /// Represents the declarations inside this struct.
437 container: Scope.Container,
438 /// Offset from `owner_decl`, points to the enum decl AST node.
439 node_offset: i32,
440
441 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.hash_u32, Value.eql, false);
442
443 pub fn srcLoc(self: EnumFull) SrcLoc {
444 return .{
445 .container = .{ .decl = self.owner_decl },
446 .lazy = .{ .node_offset = self.node_offset },
447 };
448 }
376};449};
377450
378/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.451/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
...@@ -601,6 +674,7 @@ pub const Scope = struct {...@@ -601,6 +674,7 @@ pub const Scope = struct {
601 base: Scope = Scope{ .tag = base_tag },674 base: Scope = Scope{ .tag = base_tag },
602675
603 file_scope: *Scope.File,676 file_scope: *Scope.File,
677 parent_name_hash: NameHash,
604678
605 /// Direct children of the file.679 /// Direct children of the file.
606 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},680 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
...@@ -619,8 +693,12 @@ pub const Scope = struct {...@@ -619,8 +693,12 @@ pub const Scope = struct {
619 }693 }
620694
621 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {695 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
622 // TODO container scope qualified names.696 return std.zig.hashName(cont.parent_name_hash, ".", name);
623 return std.zig.hashSrc(name);697 }
698
699 pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {
700 // TODO this should render e.g. "std.fs.Dir.OpenOptions"
701 return writer.writeAll(name);
624 }702 }
625 };703 };
626704
...@@ -650,10 +728,12 @@ pub const Scope = struct {...@@ -650,10 +728,12 @@ pub const Scope = struct {
650728
651 pub fn unload(file: *File, gpa: *Allocator) void {729 pub fn unload(file: *File, gpa: *Allocator) void {
652 switch (file.status) {730 switch (file.status) {
653 .never_loaded,
654 .unloaded_parse_failure,731 .unloaded_parse_failure,
732 .never_loaded,
655 .unloaded_success,733 .unloaded_success,
656 => {},734 => {
735 file.status = .unloaded_success;
736 },
657737
658 .loaded_success => {738 .loaded_success => {
659 file.tree.deinit(gpa);739 file.tree.deinit(gpa);
...@@ -1018,7 +1098,6 @@ pub const Scope = struct {...@@ -1018,7 +1098,6 @@ pub const Scope = struct {
1018 .instructions = gz.astgen.instructions.toOwnedSlice(),1098 .instructions = gz.astgen.instructions.toOwnedSlice(),
1019 .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),1099 .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),
1020 .extra = gz.astgen.extra.toOwnedSlice(gpa),1100 .extra = gz.astgen.extra.toOwnedSlice(gpa),
1021 .decls = gz.astgen.decls.toOwnedSlice(gpa),
1022 };1101 };
1023 }1102 }
10241103
...@@ -1048,6 +1127,9 @@ pub const Scope = struct {...@@ -1048,6 +1127,9 @@ pub const Scope = struct {
1048 gz.rl_ty_inst = ty_inst;1127 gz.rl_ty_inst = ty_inst;
1049 gz.break_result_loc = parent_rl;1128 gz.break_result_loc = parent_rl;
1050 },1129 },
1130 .none_or_ref => {
1131 gz.break_result_loc = .ref;
1132 },
1051 .discard, .none, .ptr, .ref => {1133 .discard, .none, .ptr, .ref => {
1052 gz.break_result_loc = parent_rl;1134 gz.break_result_loc = parent_rl;
1053 },1135 },
...@@ -1227,6 +1309,16 @@ pub const Scope = struct {...@@ -1227,6 +1309,16 @@ pub const Scope = struct {
1227 });1309 });
1228 }1310 }
12291311
1312 pub fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !zir.Inst.Ref {
1313 return gz.add(.{
1314 .tag = .float,
1315 .data = .{ .float = .{
1316 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
1317 .number = number,
1318 } },
1319 });
1320 }
1321
1230 pub fn addUnNode(1322 pub fn addUnNode(
1231 gz: *GenZir,1323 gz: *GenZir,
1232 tag: zir.Inst.Tag,1324 tag: zir.Inst.Tag,
...@@ -1435,13 +1527,6 @@ pub const Scope = struct {...@@ -1435,13 +1527,6 @@ pub const Scope = struct {
1435 return new_index;1527 return new_index;
1436 }1528 }
14371529
1438 pub fn addConst(gz: *GenZir, typed_value: *TypedValue) !zir.Inst.Ref {
1439 return gz.add(.{
1440 .tag = .@"const",
1441 .data = .{ .@"const" = typed_value },
1442 });
1443 }
1444
1445 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {1530 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
1446 return gz.astgen.indexToRef(try gz.addAsIndex(inst));1531 return gz.astgen.indexToRef(try gz.addAsIndex(inst));
1447 }1532 }
...@@ -1572,6 +1657,7 @@ pub const SrcLoc = struct {...@@ -1572,6 +1657,7 @@ pub const SrcLoc = struct {
1572 .byte_offset,1657 .byte_offset,
1573 .token_offset,1658 .token_offset,
1574 .node_offset,1659 .node_offset,
1660 .node_offset_back2tok,
1575 .node_offset_var_decl_ty,1661 .node_offset_var_decl_ty,
1576 .node_offset_for_cond,1662 .node_offset_for_cond,
1577 .node_offset_builtin_call_arg0,1663 .node_offset_builtin_call_arg0,
...@@ -1633,6 +1719,14 @@ pub const SrcLoc = struct {...@@ -1633,6 +1719,14 @@ pub const SrcLoc = struct {
1633 const token_starts = tree.tokens.items(.start);1719 const token_starts = tree.tokens.items(.start);
1634 return token_starts[tok_index];1720 return token_starts[tok_index];
1635 },1721 },
1722 .node_offset_back2tok => |node_off| {
1723 const decl = src_loc.container.decl;
1724 const node = decl.relativeToNodeIndex(node_off);
1725 const tree = decl.container.file_scope.base.tree();
1726 const tok_index = tree.firstToken(node) - 2;
1727 const token_starts = tree.tokens.items(.start);
1728 return token_starts[tok_index];
1729 },
1636 .node_offset_var_decl_ty => |node_off| {1730 .node_offset_var_decl_ty => |node_off| {
1637 const decl = src_loc.container.decl;1731 const decl = src_loc.container.decl;
1638 const node = decl.relativeToNodeIndex(node_off);1732 const node = decl.relativeToNodeIndex(node_off);
...@@ -1747,7 +1841,10 @@ pub const SrcLoc = struct {...@@ -1747,7 +1841,10 @@ pub const SrcLoc = struct {
1747 const node_datas = tree.nodes.items(.data);1841 const node_datas = tree.nodes.items(.data);
1748 const node_tags = tree.nodes.items(.tag);1842 const node_tags = tree.nodes.items(.tag);
1749 const node = decl.relativeToNodeIndex(node_off);1843 const node = decl.relativeToNodeIndex(node_off);
1750 const tok_index = node_datas[node].rhs;1844 const tok_index = switch (node_tags[node]) {
1845 .field_access => node_datas[node].rhs,
1846 else => tree.firstToken(node) - 2,
1847 };
1751 const token_starts = tree.tokens.items(.start);1848 const token_starts = tree.tokens.items(.start);
1752 return token_starts[tok_index];1849 return token_starts[tok_index];
1753 },1850 },
...@@ -1988,6 +2085,10 @@ pub const LazySrcLoc = union(enum) {...@@ -1988,6 +2085,10 @@ pub const LazySrcLoc = union(enum) {
1988 /// from its containing Decl node AST index.2085 /// from its containing Decl node AST index.
1989 /// The Decl is determined contextually.2086 /// The Decl is determined contextually.
1990 node_offset: i32,2087 node_offset: i32,
2088 /// The source location points to two tokens left of the first token of an AST node,
2089 /// which is this value offset from its containing Decl node AST index.
2090 /// The Decl is determined contextually.
2091 node_offset_back2tok: i32,
1991 /// The source location points to a variable declaration type expression,2092 /// The source location points to a variable declaration type expression,
1992 /// found by taking this AST node index offset from the containing2093 /// found by taking this AST node index offset from the containing
1993 /// Decl AST node, which points to a variable declaration AST node. Next, navigate2094 /// Decl AST node, which points to a variable declaration AST node. Next, navigate
...@@ -2026,10 +2127,10 @@ pub const LazySrcLoc = union(enum) {...@@ -2026,10 +2127,10 @@ pub const LazySrcLoc = union(enum) {
2026 /// to the callee expression.2127 /// to the callee expression.
2027 /// The Decl is determined contextually.2128 /// The Decl is determined contextually.
2028 node_offset_call_func: i32,2129 node_offset_call_func: i32,
2029 /// The source location points to the field name of a field access expression,2130 /// The payload is offset from the containing Decl AST node.
2030 /// found by taking this AST node index offset from the containing2131 /// The source location points to the field name of:
2031 /// Decl AST node, which points to a field access AST node. Next, navigate2132 /// * a field access expression (`a.b`), or
2032 /// to the field name token.2133 /// * the operand ("b" node) of a field initialization expression (`.a = b`)
2033 /// The Decl is determined contextually.2134 /// The Decl is determined contextually.
2034 node_offset_field_name: i32,2135 node_offset_field_name: i32,
2035 /// The source location points to the pointer of a pointer deref expression,2136 /// The source location points to the pointer of a pointer deref expression,
...@@ -2114,6 +2215,7 @@ pub const LazySrcLoc = union(enum) {...@@ -2114,6 +2215,7 @@ pub const LazySrcLoc = union(enum) {
2114 .byte_offset,2215 .byte_offset,
2115 .token_offset,2216 .token_offset,
2116 .node_offset,2217 .node_offset,
2218 .node_offset_back2tok,
2117 .node_offset_var_decl_ty,2219 .node_offset_var_decl_ty,
2118 .node_offset_for_cond,2220 .node_offset_for_cond,
2119 .node_offset_builtin_call_arg0,2221 .node_offset_builtin_call_arg0,
...@@ -2156,6 +2258,7 @@ pub const LazySrcLoc = union(enum) {...@@ -2156,6 +2258,7 @@ pub const LazySrcLoc = union(enum) {
2156 .byte_offset,2258 .byte_offset,
2157 .token_offset,2259 .token_offset,
2158 .node_offset,2260 .node_offset,
2261 .node_offset_back2tok,
2159 .node_offset_var_decl_ty,2262 .node_offset_var_decl_ty,
2160 .node_offset_for_cond,2263 .node_offset_for_cond,
2161 .node_offset_builtin_call_arg0,2264 .node_offset_builtin_call_arg0,
...@@ -2189,6 +2292,20 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail };...@@ -2189,6 +2292,20 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail };
2189pub fn deinit(mod: *Module) void {2292pub fn deinit(mod: *Module) void {
2190 const gpa = mod.gpa;2293 const gpa = mod.gpa;
21912294
2295 // The callsite of `Compilation.create` owns the `root_pkg`, however
2296 // Module owns the builtin and std packages that it adds.
2297 if (mod.root_pkg.table.remove("builtin")) |entry| {
2298 gpa.free(entry.key);
2299 entry.value.destroy(gpa);
2300 }
2301 if (mod.root_pkg.table.remove("std")) |entry| {
2302 gpa.free(entry.key);
2303 entry.value.destroy(gpa);
2304 }
2305 if (mod.root_pkg.table.remove("root")) |entry| {
2306 gpa.free(entry.key);
2307 }
2308
2192 mod.compile_log_text.deinit(gpa);2309 mod.compile_log_text.deinit(gpa);
21932310
2194 mod.zig_cache_artifact_directory.handle.close();2311 mod.zig_cache_artifact_directory.handle.close();
...@@ -2288,7 +2405,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {...@@ -2288,7 +2405,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2288 // We don't perform a deletion here, because this Decl or another one2405 // We don't perform a deletion here, because this Decl or another one
2289 // may end up referencing it before the update is complete.2406 // may end up referencing it before the update is complete.
2290 dep.deletion_flag = true;2407 dep.deletion_flag = true;
2291 try mod.deletion_set.append(mod.gpa, dep);2408 try mod.deletion_set.put(mod.gpa, dep, {});
2292 }2409 }
2293 }2410 }
2294 decl.dependencies.clearRetainingCapacity();2411 decl.dependencies.clearRetainingCapacity();
...@@ -2351,7 +2468,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2351,7 +2468,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
2351 const tree = try mod.getAstTree(decl.container.file_scope);2468 const tree = try mod.getAstTree(decl.container.file_scope);
2352 const node_tags = tree.nodes.items(.tag);2469 const node_tags = tree.nodes.items(.tag);
2353 const node_datas = tree.nodes.items(.data);2470 const node_datas = tree.nodes.items(.data);
2354 const decl_node = tree.rootDecls()[decl.src_index];2471 const decl_node = decl.src_node;
2355 switch (node_tags[decl_node]) {2472 switch (node_tags[decl_node]) {
2356 .fn_decl => {2473 .fn_decl => {
2357 const fn_proto = node_datas[decl_node].lhs;2474 const fn_proto = node_datas[decl_node].lhs;
...@@ -2406,6 +2523,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2406,6 +2523,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
24062523
2407 const block_expr = node_datas[decl_node].lhs;2524 const block_expr = node_datas[decl_node].lhs;
2408 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);2525 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
2526 _ = try gen_scope.addBreak(.break_inline, 0, .void_value);
24092527
2410 const code = try gen_scope.finish();2528 const code = try gen_scope.finish();
2411 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2529 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
...@@ -3087,12 +3205,19 @@ fn astgenAndSemaVarDecl(...@@ -3087,12 +3205,19 @@ fn astgenAndSemaVarDecl(
3087 return type_changed;3205 return type_changed;
3088}3206}
30893207
3090pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {3208/// Returns the depender's index of the dependee.
3091 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.items().len + 1);3209pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 {
3092 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.items().len + 1);3210 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);
3211 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1);
3212
3213 if (dependee.deletion_flag) {
3214 dependee.deletion_flag = false;
3215 mod.deletion_set.removeAssertDiscard(dependee);
3216 }
30933217
3094 depender.dependencies.putAssumeCapacity(dependee, {});
3095 dependee.dependants.putAssumeCapacity(depender, {});3218 dependee.dependants.putAssumeCapacity(depender, {});
3219 const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);
3220 return @intCast(u32, gop.index);
3096}3221}
30973222
3098pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {3223pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
...@@ -3117,17 +3242,19 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {...@@ -3117,17 +3242,19 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
3117 var msg = std.ArrayList(u8).init(mod.gpa);3242 var msg = std.ArrayList(u8).init(mod.gpa);
3118 defer msg.deinit();3243 defer msg.deinit();
31193244
3245 const token_starts = tree.tokens.items(.start);
3246
3120 try tree.renderError(parse_err, msg.writer());3247 try tree.renderError(parse_err, msg.writer());
3121 const err_msg = try mod.gpa.create(ErrorMsg);3248 const err_msg = try mod.gpa.create(ErrorMsg);
3122 err_msg.* = .{3249 err_msg.* = .{
3123 .src_loc = .{3250 .src_loc = .{
3124 .container = .{ .file_scope = root_scope },3251 .container = .{ .file_scope = root_scope },
3125 .lazy = .{ .token_abs = parse_err.token },3252 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
3126 },3253 },
3127 .msg = msg.toOwnedSlice(),3254 .msg = msg.toOwnedSlice(),
3128 };3255 };
31293256
3130 mod.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);3257 mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg);
3131 root_scope.status = .unloaded_parse_failure;3258 root_scope.status = .unloaded_parse_failure;
3132 return error.AnalysisFail;3259 return error.AnalysisFail;
3133 }3260 }
...@@ -3167,7 +3294,15 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3167,7 +3294,15 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3167 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});3294 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
3168 }3295 }
31693296
3170 for (decls) |decl_node, decl_i| switch (node_tags[decl_node]) {3297 // Keep track of decls that are invalidated from the update. Ultimately,
3298 // the goal is to queue up `analyze_decl` tasks in the work queue for
3299 // the outdated decls, but we cannot queue up the tasks until after
3300 // we find out which ones have been deleted, otherwise there would be
3301 // deleted Decl pointers in the work queue.
3302 var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);
3303 defer outdated_decls.deinit();
3304
3305 for (decls) |decl_node| switch (node_tags[decl_node]) {
3171 .fn_decl => {3306 .fn_decl => {
3172 const fn_proto = node_datas[decl_node].lhs;3307 const fn_proto = node_datas[decl_node].lhs;
3173 const body = node_datas[decl_node].rhs;3308 const body = node_datas[decl_node].rhs;
...@@ -3177,8 +3312,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3177,8 +3312,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3177 try mod.semaContainerFn(3312 try mod.semaContainerFn(
3178 container_scope,3313 container_scope,
3179 &deleted_decls,3314 &deleted_decls,
3315 &outdated_decls,
3180 decl_node,3316 decl_node,
3181 decl_i,
3182 tree.*,3317 tree.*,
3183 body,3318 body,
3184 tree.fnProtoSimple(&params, fn_proto),3319 tree.fnProtoSimple(&params, fn_proto),
...@@ -3187,8 +3322,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3187,8 +3322,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3187 .fn_proto_multi => try mod.semaContainerFn(3322 .fn_proto_multi => try mod.semaContainerFn(
3188 container_scope,3323 container_scope,
3189 &deleted_decls,3324 &deleted_decls,
3325 &outdated_decls,
3190 decl_node,3326 decl_node,
3191 decl_i,
3192 tree.*,3327 tree.*,
3193 body,3328 body,
3194 tree.fnProtoMulti(fn_proto),3329 tree.fnProtoMulti(fn_proto),
...@@ -3198,8 +3333,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3198,8 +3333,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3198 try mod.semaContainerFn(3333 try mod.semaContainerFn(
3199 container_scope,3334 container_scope,
3200 &deleted_decls,3335 &deleted_decls,
3336 &outdated_decls,
3201 decl_node,3337 decl_node,
3202 decl_i,
3203 tree.*,3338 tree.*,
3204 body,3339 body,
3205 tree.fnProtoOne(&params, fn_proto),3340 tree.fnProtoOne(&params, fn_proto),
...@@ -3208,8 +3343,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3208,8 +3343,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3208 .fn_proto => try mod.semaContainerFn(3343 .fn_proto => try mod.semaContainerFn(
3209 container_scope,3344 container_scope,
3210 &deleted_decls,3345 &deleted_decls,
3346 &outdated_decls,
3211 decl_node,3347 decl_node,
3212 decl_i,
3213 tree.*,3348 tree.*,
3214 body,3349 body,
3215 tree.fnProto(fn_proto),3350 tree.fnProto(fn_proto),
...@@ -3222,8 +3357,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3222,8 +3357,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3222 try mod.semaContainerFn(3357 try mod.semaContainerFn(
3223 container_scope,3358 container_scope,
3224 &deleted_decls,3359 &deleted_decls,
3360 &outdated_decls,
3225 decl_node,3361 decl_node,
3226 decl_i,
3227 tree.*,3362 tree.*,
3228 0,3363 0,
3229 tree.fnProtoSimple(&params, decl_node),3364 tree.fnProtoSimple(&params, decl_node),
...@@ -3232,8 +3367,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3232,8 +3367,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3232 .fn_proto_multi => try mod.semaContainerFn(3367 .fn_proto_multi => try mod.semaContainerFn(
3233 container_scope,3368 container_scope,
3234 &deleted_decls,3369 &deleted_decls,
3370 &outdated_decls,
3235 decl_node,3371 decl_node,
3236 decl_i,
3237 tree.*,3372 tree.*,
3238 0,3373 0,
3239 tree.fnProtoMulti(decl_node),3374 tree.fnProtoMulti(decl_node),
...@@ -3243,8 +3378,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3243,8 +3378,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3243 try mod.semaContainerFn(3378 try mod.semaContainerFn(
3244 container_scope,3379 container_scope,
3245 &deleted_decls,3380 &deleted_decls,
3381 &outdated_decls,
3246 decl_node,3382 decl_node,
3247 decl_i,
3248 tree.*,3383 tree.*,
3249 0,3384 0,
3250 tree.fnProtoOne(&params, decl_node),3385 tree.fnProtoOne(&params, decl_node),
...@@ -3253,8 +3388,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3253,8 +3388,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3253 .fn_proto => try mod.semaContainerFn(3388 .fn_proto => try mod.semaContainerFn(
3254 container_scope,3389 container_scope,
3255 &deleted_decls,3390 &deleted_decls,
3391 &outdated_decls,
3256 decl_node,3392 decl_node,
3257 decl_i,
3258 tree.*,3393 tree.*,
3259 0,3394 0,
3260 tree.fnProto(decl_node),3395 tree.fnProto(decl_node),
...@@ -3263,32 +3398,32 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3263,32 +3398,32 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3263 .global_var_decl => try mod.semaContainerVar(3398 .global_var_decl => try mod.semaContainerVar(
3264 container_scope,3399 container_scope,
3265 &deleted_decls,3400 &deleted_decls,
3401 &outdated_decls,
3266 decl_node,3402 decl_node,
3267 decl_i,
3268 tree.*,3403 tree.*,
3269 tree.globalVarDecl(decl_node),3404 tree.globalVarDecl(decl_node),
3270 ),3405 ),
3271 .local_var_decl => try mod.semaContainerVar(3406 .local_var_decl => try mod.semaContainerVar(
3272 container_scope,3407 container_scope,
3273 &deleted_decls,3408 &deleted_decls,
3409 &outdated_decls,
3274 decl_node,3410 decl_node,
3275 decl_i,
3276 tree.*,3411 tree.*,
3277 tree.localVarDecl(decl_node),3412 tree.localVarDecl(decl_node),
3278 ),3413 ),
3279 .simple_var_decl => try mod.semaContainerVar(3414 .simple_var_decl => try mod.semaContainerVar(
3280 container_scope,3415 container_scope,
3281 &deleted_decls,3416 &deleted_decls,
3417 &outdated_decls,
3282 decl_node,3418 decl_node,
3283 decl_i,
3284 tree.*,3419 tree.*,
3285 tree.simpleVarDecl(decl_node),3420 tree.simpleVarDecl(decl_node),
3286 ),3421 ),
3287 .aligned_var_decl => try mod.semaContainerVar(3422 .aligned_var_decl => try mod.semaContainerVar(
3288 container_scope,3423 container_scope,
3289 &deleted_decls,3424 &deleted_decls,
3425 &outdated_decls,
3290 decl_node,3426 decl_node,
3291 decl_i,
3292 tree.*,3427 tree.*,
3293 tree.alignedVarDecl(decl_node),3428 tree.alignedVarDecl(decl_node),
3294 ),3429 ),
...@@ -3301,49 +3436,48 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3301,49 +3436,48 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3301 const name_hash = container_scope.fullyQualifiedNameHash(name);3436 const name_hash = container_scope.fullyQualifiedNameHash(name);
3302 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));3437 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
33033438
3304 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);3439 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
3305 container_scope.decls.putAssumeCapacity(new_decl, {});3440 container_scope.decls.putAssumeCapacity(new_decl, {});
3306 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });3441 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
3307 },3442 },
33083443
3309 .container_field_init => try mod.semaContainerField(3444 // Container fields are handled in AstGen.
3310 container_scope,3445 .container_field_init,
3311 &deleted_decls,3446 .container_field_align,
3312 decl_node,3447 .container_field,
3313 decl_i,3448 => continue,
3314 tree.*,
3315 tree.containerFieldInit(decl_node),
3316 ),
3317 .container_field_align => try mod.semaContainerField(
3318 container_scope,
3319 &deleted_decls,
3320 decl_node,
3321 decl_i,
3322 tree.*,
3323 tree.containerFieldAlign(decl_node),
3324 ),
3325 .container_field => try mod.semaContainerField(
3326 container_scope,
3327 &deleted_decls,
3328 decl_node,
3329 decl_i,
3330 tree.*,
3331 tree.containerField(decl_node),
3332 ),
33333449
3334 .test_decl => {3450 .test_decl => {
3335 log.err("TODO: analyze test decl", .{});3451 if (mod.comp.bin_file.options.is_test) {
3452 log.err("TODO: analyze test decl", .{});
3453 }
3336 },3454 },
3337 .@"usingnamespace" => {3455 .@"usingnamespace" => {
3338 log.err("TODO: analyze usingnamespace decl", .{});3456 log.err("TODO: analyze usingnamespace decl", .{});
3339 },3457 },
3340 else => unreachable,3458 else => unreachable,
3341 };3459 };
3342 // Handle explicitly deleted decls from the source code. Not to be confused3460 // Handle explicitly deleted decls from the source code. This is one of two
3343 // with when we delete decls because they are no longer referenced.3461 // places that Decl deletions happen. The other is in `Compilation`, after
3462 // `performAllTheWork`, where we iterate over `Module.deletion_set` and
3463 // delete Decls which are no longer referenced.
3464 // If a Decl is explicitly deleted from source, and also no longer referenced,
3465 // it may be both in this `deleted_decls` set, as well as in the
3466 // `Module.deletion_set`. To avoid deleting it twice, we remove it from the
3467 // deletion set at this time.
3344 for (deleted_decls.items()) |entry| {3468 for (deleted_decls.items()) |entry| {
3345 log.debug("noticed '{s}' deleted from source", .{entry.key.name});3469 const decl = entry.key;
3346 try mod.deleteDecl(entry.key);3470 log.debug("'{s}' deleted from source", .{decl.name});
3471 if (decl.deletion_flag) {
3472 log.debug("'{s}' redundantly in deletion set; removing", .{decl.name});
3473 mod.deletion_set.removeAssertDiscard(decl);
3474 }
3475 try mod.deleteDecl(decl, &outdated_decls);
3476 }
3477 // Finally we can queue up re-analysis tasks after we have processed
3478 // the deleted decls.
3479 for (outdated_decls.items()) |entry| {
3480 try mod.markOutdatedDecl(entry.key);
3347 }3481 }
3348}3482}
33493483
...@@ -3351,8 +3485,8 @@ fn semaContainerFn(...@@ -3351,8 +3485,8 @@ fn semaContainerFn(
3351 mod: *Module,3485 mod: *Module,
3352 container_scope: *Scope.Container,3486 container_scope: *Scope.Container,
3353 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3487 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3488 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3354 decl_node: ast.Node.Index,3489 decl_node: ast.Node.Index,
3355 decl_i: usize,
3356 tree: ast.Tree,3490 tree: ast.Tree,
3357 body_node: ast.Node.Index,3491 body_node: ast.Node.Index,
3358 fn_proto: ast.full.FnProto,3492 fn_proto: ast.full.FnProto,
...@@ -3361,28 +3495,34 @@ fn semaContainerFn(...@@ -3361,28 +3495,34 @@ fn semaContainerFn(
3361 defer tracy.end();3495 defer tracy.end();
33623496
3363 // We will create a Decl for it regardless of analysis status.3497 // We will create a Decl for it regardless of analysis status.
3364 const name_tok = fn_proto.name_token orelse {3498 const name_token = fn_proto.name_token orelse {
3365 // This problem will go away with #1717.3499 // This problem will go away with #1717.
3366 @panic("TODO missing function name");3500 @panic("TODO missing function name");
3367 };3501 };
3368 const name = tree.tokenSlice(name_tok); // TODO use identifierTokenString3502 const name = tree.tokenSlice(name_token); // TODO use identifierTokenString
3369 const name_hash = container_scope.fullyQualifiedNameHash(name);3503 const name_hash = container_scope.fullyQualifiedNameHash(name);
3370 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));3504 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
3371 if (mod.decl_table.get(name_hash)) |decl| {3505 if (mod.decl_table.get(name_hash)) |decl| {
3372 // Update the AST Node index of the decl, even if its contents are unchanged, it may3506 // Update the AST Node index of the decl, even if its contents are unchanged, it may
3373 // have been re-ordered.3507 // have been re-ordered.
3374 decl.src_index = decl_i;3508 const prev_src_node = decl.src_node;
3509 decl.src_node = decl_node;
3375 if (deleted_decls.swapRemove(decl) == null) {3510 if (deleted_decls.swapRemove(decl) == null) {
3376 decl.analysis = .sema_failure;3511 decl.analysis = .sema_failure;
3377 const msg = try ErrorMsg.create(mod.gpa, .{3512 const msg = try ErrorMsg.create(mod.gpa, .{
3378 .container = .{ .file_scope = container_scope.file_scope },3513 .container = .{ .file_scope = container_scope.file_scope },
3379 .lazy = .{ .token_abs = name_tok },3514 .lazy = .{ .token_abs = name_token },
3380 }, "redefinition of '{s}'", .{decl.name});3515 }, "redefinition of '{s}'", .{decl.name});
3381 errdefer msg.destroy(mod.gpa);3516 errdefer msg.destroy(mod.gpa);
3517 const other_src_loc: SrcLoc = .{
3518 .container = .{ .file_scope = decl.container.file_scope },
3519 .lazy = .{ .node_abs = prev_src_node },
3520 };
3521 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});
3382 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);3522 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
3383 } else {3523 } else {
3384 if (!srcHashEql(decl.contents_hash, contents_hash)) {3524 if (!srcHashEql(decl.contents_hash, contents_hash)) {
3385 try mod.markOutdatedDecl(decl);3525 try outdated_decls.put(decl, {});
3386 decl.contents_hash = contents_hash;3526 decl.contents_hash = contents_hash;
3387 } else switch (mod.comp.bin_file.tag) {3527 } else switch (mod.comp.bin_file.tag) {
3388 .coff => {3528 .coff => {
...@@ -3402,7 +3542,7 @@ fn semaContainerFn(...@@ -3402,7 +3542,7 @@ fn semaContainerFn(
3402 }3542 }
3403 }3543 }
3404 } else {3544 } else {
3405 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);3545 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
3406 container_scope.decls.putAssumeCapacity(new_decl, {});3546 container_scope.decls.putAssumeCapacity(new_decl, {});
3407 if (fn_proto.extern_export_token) |maybe_export_token| {3547 if (fn_proto.extern_export_token) |maybe_export_token| {
3408 const token_tags = tree.tokens.items(.tag);3548 const token_tags = tree.tokens.items(.tag);
...@@ -3410,6 +3550,7 @@ fn semaContainerFn(...@@ -3410,6 +3550,7 @@ fn semaContainerFn(
3410 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });3550 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
3411 }3551 }
3412 }3552 }
3553 new_decl.is_pub = fn_proto.visib_token != null;
3413 }3554 }
3414}3555}
34153556
...@@ -3417,8 +3558,8 @@ fn semaContainerVar(...@@ -3417,8 +3558,8 @@ fn semaContainerVar(
3417 mod: *Module,3558 mod: *Module,
3418 container_scope: *Scope.Container,3559 container_scope: *Scope.Container,
3419 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3560 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3561 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3420 decl_node: ast.Node.Index,3562 decl_node: ast.Node.Index,
3421 decl_i: usize,
3422 tree: ast.Tree,3563 tree: ast.Tree,
3423 var_decl: ast.full.VarDecl,3564 var_decl: ast.full.VarDecl,
3424) !void {3565) !void {
...@@ -3432,21 +3573,27 @@ fn semaContainerVar(...@@ -3432,21 +3573,27 @@ fn semaContainerVar(
3432 if (mod.decl_table.get(name_hash)) |decl| {3573 if (mod.decl_table.get(name_hash)) |decl| {
3433 // Update the AST Node index of the decl, even if its contents are unchanged, it may3574 // Update the AST Node index of the decl, even if its contents are unchanged, it may
3434 // have been re-ordered.3575 // have been re-ordered.
3435 decl.src_index = decl_i;3576 const prev_src_node = decl.src_node;
3577 decl.src_node = decl_node;
3436 if (deleted_decls.swapRemove(decl) == null) {3578 if (deleted_decls.swapRemove(decl) == null) {
3437 decl.analysis = .sema_failure;3579 decl.analysis = .sema_failure;
3438 const err_msg = try ErrorMsg.create(mod.gpa, .{3580 const msg = try ErrorMsg.create(mod.gpa, .{
3439 .container = .{ .file_scope = container_scope.file_scope },3581 .container = .{ .file_scope = container_scope.file_scope },
3440 .lazy = .{ .token_abs = name_token },3582 .lazy = .{ .token_abs = name_token },
3441 }, "redefinition of '{s}'", .{decl.name});3583 }, "redefinition of '{s}'", .{decl.name});
3442 errdefer err_msg.destroy(mod.gpa);3584 errdefer msg.destroy(mod.gpa);
3443 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);3585 const other_src_loc: SrcLoc = .{
3586 .container = .{ .file_scope = decl.container.file_scope },
3587 .lazy = .{ .node_abs = prev_src_node },
3588 };
3589 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});
3590 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
3444 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {3591 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
3445 try mod.markOutdatedDecl(decl);3592 try outdated_decls.put(decl, {});
3446 decl.contents_hash = contents_hash;3593 decl.contents_hash = contents_hash;
3447 }3594 }
3448 } else {3595 } else {
3449 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);3596 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
3450 container_scope.decls.putAssumeCapacity(new_decl, {});3597 container_scope.decls.putAssumeCapacity(new_decl, {});
3451 if (var_decl.extern_export_token) |maybe_export_token| {3598 if (var_decl.extern_export_token) |maybe_export_token| {
3452 const token_tags = tree.tokens.items(.tag);3599 const token_tags = tree.tokens.items(.tag);
...@@ -3454,35 +3601,31 @@ fn semaContainerVar(...@@ -3454,35 +3601,31 @@ fn semaContainerVar(
3454 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });3601 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
3455 }3602 }
3456 }3603 }
3604 new_decl.is_pub = var_decl.visib_token != null;
3457 }3605 }
3458}3606}
34593607
3460fn semaContainerField(3608pub fn deleteDecl(
3461 mod: *Module,3609 mod: *Module,
3462 container_scope: *Scope.Container,3610 decl: *Decl,
3463 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3611 outdated_decls: ?*std.AutoArrayHashMap(*Decl, void),
3464 decl_node: ast.Node.Index,
3465 decl_i: usize,
3466 tree: ast.Tree,
3467 field: ast.full.ContainerField,
3468) !void {3612) !void {
3469 const tracy = trace(@src());3613 const tracy = trace(@src());
3470 defer tracy.end();3614 defer tracy.end();
34713615
3472 log.err("TODO: analyze container field", .{});3616 log.debug("deleting decl '{s}'", .{decl.name});
3473}
3474
3475pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
3476 const tracy = trace(@src());
3477 defer tracy.end();
34783617
3479 try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.items.len + decl.dependencies.items().len);3618 if (outdated_decls) |map| {
3619 _ = map.swapRemove(decl);
3620 try map.ensureCapacity(map.count() + decl.dependants.count());
3621 }
3622 try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.count() +
3623 decl.dependencies.count());
34803624
3481 // Remove from the namespace it resides in. In the case of an anonymous Decl it will3625 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
3482 // not be present in the set, and this does nothing.3626 // not be present in the set, and this does nothing.
3483 decl.container.removeDecl(decl);3627 decl.container.removeDecl(decl);
34843628
3485 log.debug("deleting decl '{s}'", .{decl.name});
3486 const name_hash = decl.fullyQualifiedNameHash();3629 const name_hash = decl.fullyQualifiedNameHash();
3487 mod.decl_table.removeAssertDiscard(name_hash);3630 mod.decl_table.removeAssertDiscard(name_hash);
3488 // Remove itself from its dependencies, because we are about to destroy the decl pointer.3631 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
...@@ -3493,16 +3636,22 @@ pub fn deleteDecl(mod: *Module, decl: *Decl) !void {...@@ -3493,16 +3636,22 @@ pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
3493 // We don't recursively perform a deletion here, because during the update,3636 // We don't recursively perform a deletion here, because during the update,
3494 // another reference to it may turn up.3637 // another reference to it may turn up.
3495 dep.deletion_flag = true;3638 dep.deletion_flag = true;
3496 mod.deletion_set.appendAssumeCapacity(dep);3639 mod.deletion_set.putAssumeCapacity(dep, {});
3497 }3640 }
3498 }3641 }
3499 // Anything that depends on this deleted decl certainly needs to be re-analyzed.3642 // Anything that depends on this deleted decl needs to be re-analyzed.
3500 for (decl.dependants.items()) |entry| {3643 for (decl.dependants.items()) |entry| {
3501 const dep = entry.key;3644 const dep = entry.key;
3502 dep.removeDependency(decl);3645 dep.removeDependency(decl);
3503 if (dep.analysis != .outdated) {3646 if (outdated_decls) |map| {
3504 // TODO Move this failure possibility to the top of the function.3647 map.putAssumeCapacity(dep, {});
3505 try mod.markOutdatedDecl(dep);3648 } else if (std.debug.runtime_safety) {
3649 // If `outdated_decls` is `null`, it means we're being called from
3650 // `Compilation` after `performAllTheWork` and we cannot queue up any
3651 // more work. `dep` must necessarily be another Decl that is no longer
3652 // being referenced, and will be in the `deletion_set`. Otherwise,
3653 // something has gone wrong.
3654 assert(mod.deletion_set.contains(dep));
3506 }3655 }
3507 }3656 }
3508 if (mod.failed_decls.swapRemove(decl)) |entry| {3657 if (mod.failed_decls.swapRemove(decl)) |entry| {
...@@ -3638,7 +3787,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {...@@ -3638,7 +3787,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
3638fn allocateNewDecl(3787fn allocateNewDecl(
3639 mod: *Module,3788 mod: *Module,
3640 scope: *Scope,3789 scope: *Scope,
3641 src_index: usize,3790 src_node: ast.Node.Index,
3642 contents_hash: std.zig.SrcHash,3791 contents_hash: std.zig.SrcHash,
3643) !*Decl {3792) !*Decl {
3644 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.3793 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.
...@@ -3654,7 +3803,7 @@ fn allocateNewDecl(...@@ -3654,7 +3803,7 @@ fn allocateNewDecl(
3654 new_decl.* = .{3803 new_decl.* = .{
3655 .name = "",3804 .name = "",
3656 .container = scope.namespace(),3805 .container = scope.namespace(),
3657 .src_index = src_index,3806 .src_node = src_node,
3658 .typed_value = .{ .never_succeeded = {} },3807 .typed_value = .{ .never_succeeded = {} },
3659 .analysis = .unreferenced,3808 .analysis = .unreferenced,
3660 .deletion_flag = false,3809 .deletion_flag = false,
...@@ -3664,7 +3813,7 @@ fn allocateNewDecl(...@@ -3664,7 +3813,7 @@ fn allocateNewDecl(
3664 .elf => .{ .elf = link.File.Elf.TextBlock.empty },3813 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
3665 .macho => .{ .macho = link.File.MachO.TextBlock.empty },3814 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
3666 .c => .{ .c = link.File.C.DeclBlock.empty },3815 .c => .{ .c = link.File.C.DeclBlock.empty },
3667 .wasm => .{ .wasm = {} },3816 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
3668 .spirv => .{ .spirv = {} },3817 .spirv => .{ .spirv = {} },
3669 },3818 },
3670 .fn_link = switch (mod.comp.bin_file.tag) {3819 .fn_link = switch (mod.comp.bin_file.tag) {
...@@ -3672,7 +3821,7 @@ fn allocateNewDecl(...@@ -3672,7 +3821,7 @@ fn allocateNewDecl(
3672 .elf => .{ .elf = link.File.Elf.SrcFn.empty },3821 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
3673 .macho => .{ .macho = link.File.MachO.SrcFn.empty },3822 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
3674 .c => .{ .c = link.File.C.FnBlock.empty },3823 .c => .{ .c = link.File.C.FnBlock.empty },
3675 .wasm => .{ .wasm = null },3824 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
3676 .spirv => .{ .spirv = .{} },3825 .spirv => .{ .spirv = .{} },
3677 },3826 },
3678 .generation = 0,3827 .generation = 0,
...@@ -3685,12 +3834,12 @@ fn createNewDecl(...@@ -3685,12 +3834,12 @@ fn createNewDecl(
3685 mod: *Module,3834 mod: *Module,
3686 scope: *Scope,3835 scope: *Scope,
3687 decl_name: []const u8,3836 decl_name: []const u8,
3688 src_index: usize,3837 src_node: ast.Node.Index,
3689 name_hash: Scope.NameHash,3838 name_hash: Scope.NameHash,
3690 contents_hash: std.zig.SrcHash,3839 contents_hash: std.zig.SrcHash,
3691) !*Decl {3840) !*Decl {
3692 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);3841 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);
3693 const new_decl = try mod.allocateNewDecl(scope, src_index, contents_hash);3842 const new_decl = try mod.allocateNewDecl(scope, src_node, contents_hash);
3694 errdefer mod.gpa.destroy(new_decl);3843 errdefer mod.gpa.destroy(new_decl);
3695 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);3844 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
3696 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);3845 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
...@@ -3903,7 +4052,7 @@ pub fn createAnonymousDecl(...@@ -3903,7 +4052,7 @@ pub fn createAnonymousDecl(
3903 defer mod.gpa.free(name);4052 defer mod.gpa.free(name);
3904 const name_hash = scope.namespace().fullyQualifiedNameHash(name);4053 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
3905 const src_hash: std.zig.SrcHash = undefined;4054 const src_hash: std.zig.SrcHash = undefined;
3906 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);4055 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
3907 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);4056 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
39084057
3909 decl_arena_state.* = decl_arena.state;4058 decl_arena_state.* = decl_arena.state;
...@@ -3939,7 +4088,7 @@ pub fn createContainerDecl(...@@ -3939,7 +4088,7 @@ pub fn createContainerDecl(
3939 defer mod.gpa.free(name);4088 defer mod.gpa.free(name);
3940 const name_hash = scope.namespace().fullyQualifiedNameHash(name);4089 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
3941 const src_hash: std.zig.SrcHash = undefined;4090 const src_hash: std.zig.SrcHash = undefined;
3942 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);4091 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
3943 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);4092 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
39444093
3945 decl_arena_state.* = decl_arena.state;4094 decl_arena_state.* = decl_arena.state;
...@@ -4003,13 +4152,23 @@ pub fn errNote(...@@ -4003,13 +4152,23 @@ pub fn errNote(
4003 parent: *ErrorMsg,4152 parent: *ErrorMsg,
4004 comptime format: []const u8,4153 comptime format: []const u8,
4005 args: anytype,4154 args: anytype,
4155) error{OutOfMemory}!void {
4156 return mod.errNoteNonLazy(src.toSrcLoc(scope), parent, format, args);
4157}
4158
4159pub fn errNoteNonLazy(
4160 mod: *Module,
4161 src_loc: SrcLoc,
4162 parent: *ErrorMsg,
4163 comptime format: []const u8,
4164 args: anytype,
4006) error{OutOfMemory}!void {4165) error{OutOfMemory}!void {
4007 const msg = try std.fmt.allocPrint(mod.gpa, format, args);4166 const msg = try std.fmt.allocPrint(mod.gpa, format, args);
4008 errdefer mod.gpa.free(msg);4167 errdefer mod.gpa.free(msg);
40094168
4010 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);4169 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
4011 parent.notes[parent.notes.len - 1] = .{4170 parent.notes[parent.notes.len - 1] = .{
4012 .src_loc = src.toSrcLoc(scope),4171 .src_loc = src_loc,
4013 .msg = msg,4172 .msg = msg,
4014 };4173 };
4015}4174}
...@@ -4412,7 +4571,29 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)...@@ -4412,7 +4571,29 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
4412 var buf: ArrayListUnmanaged(u8) = .{};4571 var buf: ArrayListUnmanaged(u8) = .{};
4413 defer buf.deinit(mod.gpa);4572 defer buf.deinit(mod.gpa);
4414 try parseStrLit(mod, scope, token, &buf, ident_name, 1);4573 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4415 return buf.toOwnedSlice(mod.gpa);4574 const duped = try scope.arena().dupe(u8, buf.items);
4575 return duped;
4576}
4577
4578/// `scope` is only used for error reporting.
4579/// The string is stored in `arena` regardless of whether it uses @"" syntax.
4580pub fn identifierTokenStringTreeArena(
4581 mod: *Module,
4582 scope: *Scope,
4583 token: ast.TokenIndex,
4584 tree: *const ast.Tree,
4585 arena: *Allocator,
4586) InnerError![]u8 {
4587 const token_tags = tree.tokens.items(.tag);
4588 assert(token_tags[token] == .identifier);
4589 const ident_name = tree.tokenSlice(token);
4590 if (!mem.startsWith(u8, ident_name, "@")) {
4591 return arena.dupe(u8, ident_name);
4592 }
4593 var buf: ArrayListUnmanaged(u8) = .{};
4594 defer buf.deinit(mod.gpa);
4595 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4596 return arena.dupe(u8, buf.items);
4416}4597}
44174598
4418/// Given an identifier token, obtain the string for it (possibly parsing as a string4599/// Given an identifier token, obtain the string for it (possibly parsing as a string
...@@ -4502,3 +4683,10 @@ pub fn parseStrLit(...@@ -4502,3 +4683,10 @@ pub fn parseStrLit(
4502 },4683 },
4503 }4684 }
4504}4685}
4686
4687pub fn unloadFile(mod: *Module, file_scope: *Scope.File) void {
4688 if (file_scope.status == .unloaded_parse_failure) {
4689 mod.failed_files.swapRemove(file_scope).?.value.destroy(mod.gpa);
4690 }
4691 file_scope.unload(mod.gpa);
4692}
src/Package.zig+68-8
...@@ -4,18 +4,29 @@ const std = @import("std");...@@ -4,18 +4,29 @@ const std = @import("std");
4const fs = std.fs;4const fs = std.fs;
5const mem = std.mem;5const mem = std.mem;
6const Allocator = mem.Allocator;6const Allocator = mem.Allocator;
7const assert = std.debug.assert;
78
8const Compilation = @import("Compilation.zig");9const Compilation = @import("Compilation.zig");
10const Module = @import("Module.zig");
911
10pub const Table = std.StringHashMapUnmanaged(*Package);12pub const Table = std.StringHashMapUnmanaged(*Package);
1113
14pub const root_namespace_hash: Module.Scope.NameHash = .{
15 0, 0, 6, 6, 6, 0, 0, 0,
16 6, 9, 0, 0, 0, 4, 2, 0,
17};
18
12root_src_directory: Compilation.Directory,19root_src_directory: Compilation.Directory,
13/// Relative to `root_src_directory`. May contain path separators.20/// Relative to `root_src_directory`. May contain path separators.
14root_src_path: []const u8,21root_src_path: []const u8,
15table: Table = .{},22table: Table = .{},
16parent: ?*Package = null,23parent: ?*Package = null,
24namespace_hash: Module.Scope.NameHash,
25/// Whether to free `root_src_directory` on `destroy`.
26root_src_directory_owned: bool = false,
1727
18/// Allocate a Package. No references to the slices passed are kept.28/// Allocate a Package. No references to the slices passed are kept.
29/// Don't forget to set `namespace_hash` later.
19pub fn create(30pub fn create(
20 gpa: *Allocator,31 gpa: *Allocator,
21 /// Null indicates the current working directory32 /// Null indicates the current working directory
...@@ -38,27 +49,69 @@ pub fn create(...@@ -38,27 +49,69 @@ pub fn create(
38 .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(),49 .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(),
39 },50 },
40 .root_src_path = owned_src_path,51 .root_src_path = owned_src_path,
52 .root_src_directory_owned = true,
53 .namespace_hash = undefined,
41 };54 };
4255
43 return ptr;56 return ptr;
44}57}
4558
46/// Free all memory associated with this package and recursively call destroy59pub fn createWithDir(
47/// on all packages in its table60 gpa: *Allocator,
61 directory: Compilation.Directory,
62 /// Relative to `directory`. If null, means `directory` is the root src dir
63 /// and is owned externally.
64 root_src_dir_path: ?[]const u8,
65 /// Relative to root_src_dir_path
66 root_src_path: []const u8,
67) !*Package {
68 const ptr = try gpa.create(Package);
69 errdefer gpa.destroy(ptr);
70
71 const owned_src_path = try gpa.dupe(u8, root_src_path);
72 errdefer gpa.free(owned_src_path);
73
74 if (root_src_dir_path) |p| {
75 const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});
76 errdefer gpa.free(owned_dir_path);
77
78 ptr.* = .{
79 .root_src_directory = .{
80 .path = owned_dir_path,
81 .handle = try directory.handle.openDir(p, .{}),
82 },
83 .root_src_directory_owned = true,
84 .root_src_path = owned_src_path,
85 .namespace_hash = undefined,
86 };
87 } else {
88 ptr.* = .{
89 .root_src_directory = directory,
90 .root_src_directory_owned = false,
91 .root_src_path = owned_src_path,
92 .namespace_hash = undefined,
93 };
94 }
95 return ptr;
96}
97
98/// Free all memory associated with this package. It does not destroy any packages
99/// inside its table; the caller is responsible for calling destroy() on them.
48pub fn destroy(pkg: *Package, gpa: *Allocator) void {100pub fn destroy(pkg: *Package, gpa: *Allocator) void {
49 gpa.free(pkg.root_src_path);101 gpa.free(pkg.root_src_path);
50102
51 // If root_src_directory.path is null then the handle is the cwd()103 if (pkg.root_src_directory_owned) {
52 // which shouldn't be closed.104 // If root_src_directory.path is null then the handle is the cwd()
53 if (pkg.root_src_directory.path) |p| {105 // which shouldn't be closed.
54 gpa.free(p);106 if (pkg.root_src_directory.path) |p| {
55 pkg.root_src_directory.handle.close();107 gpa.free(p);
108 pkg.root_src_directory.handle.close();
109 }
56 }110 }
57111
58 {112 {
59 var it = pkg.table.iterator();113 var it = pkg.table.iterator();
60 while (it.next()) |kv| {114 while (it.next()) |kv| {
61 kv.value.destroy(gpa);
62 gpa.free(kv.key);115 gpa.free(kv.key);
63 }116 }
64 }117 }
...@@ -72,3 +125,10 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)...@@ -72,3 +125,10 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)
72 const name_dupe = try mem.dupe(gpa, u8, name);125 const name_dupe = try mem.dupe(gpa, u8, name);
73 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);126 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
74}127}
128
129pub fn addAndAdopt(parent: *Package, gpa: *Allocator, name: []const u8, child: *Package) !void {
130 assert(child.parent == null); // make up your mind, who is the parent??
131 child.parent = parent;
132 child.namespace_hash = std.zig.hashName(parent.namespace_hash, ":", name);
133 return parent.add(gpa, name, child);
134}
src/Sema.zig+734-133
...@@ -168,7 +168,6 @@ pub fn analyzeBody(...@@ -168,7 +168,6 @@ pub fn analyzeBody(
168 .cmp_lte => try sema.zirCmp(block, inst, .lte),168 .cmp_lte => try sema.zirCmp(block, inst, .lte),
169 .cmp_neq => try sema.zirCmp(block, inst, .neq),169 .cmp_neq => try sema.zirCmp(block, inst, .neq),
170 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),170 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
171 .@"const" => try sema.zirConst(block, inst),
172 .decl_ref => try sema.zirDeclRef(block, inst),171 .decl_ref => try sema.zirDeclRef(block, inst),
173 .decl_val => try sema.zirDeclVal(block, inst),172 .decl_val => try sema.zirDeclVal(block, inst),
174 .load => try sema.zirLoad(block, inst),173 .load => try sema.zirLoad(block, inst),
...@@ -179,6 +178,8 @@ pub fn analyzeBody(...@@ -179,6 +178,8 @@ pub fn analyzeBody(
179 .elem_val_node => try sema.zirElemValNode(block, inst),178 .elem_val_node => try sema.zirElemValNode(block, inst),
180 .enum_literal => try sema.zirEnumLiteral(block, inst),179 .enum_literal => try sema.zirEnumLiteral(block, inst),
181 .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),180 .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),
181 .enum_to_int => try sema.zirEnumToInt(block, inst),
182 .int_to_enum => try sema.zirIntToEnum(block, inst),
182 .err_union_code => try sema.zirErrUnionCode(block, inst),183 .err_union_code => try sema.zirErrUnionCode(block, inst),
183 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),184 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
184 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),185 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
...@@ -198,9 +199,12 @@ pub fn analyzeBody(...@@ -198,9 +199,12 @@ pub fn analyzeBody(
198 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),199 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
199 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),200 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
200 .fn_type_var_args => try sema.zirFnType(block, inst, true),201 .fn_type_var_args => try sema.zirFnType(block, inst, true),
202 .has_decl => try sema.zirHasDecl(block, inst),
201 .import => try sema.zirImport(block, inst),203 .import => try sema.zirImport(block, inst),
202 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),204 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
203 .int => try sema.zirInt(block, inst),205 .int => try sema.zirInt(block, inst),
206 .float => try sema.zirFloat(block, inst),
207 .float128 => try sema.zirFloat128(block, inst),
204 .int_type => try sema.zirIntType(block, inst),208 .int_type => try sema.zirIntType(block, inst),
205 .intcast => try sema.zirIntcast(block, inst),209 .intcast => try sema.zirIntcast(block, inst),
206 .is_err => try sema.zirIsErr(block, inst),210 .is_err => try sema.zirIsErr(block, inst),
...@@ -255,16 +259,20 @@ pub fn analyzeBody(...@@ -255,16 +259,20 @@ pub fn analyzeBody(
255 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),259 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
256 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),260 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
257 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),261 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
262 .type_info => try sema.zirTypeInfo(block, inst),
258 .typeof => try sema.zirTypeof(block, inst),263 .typeof => try sema.zirTypeof(block, inst),
259 .typeof_elem => try sema.zirTypeofElem(block, inst),264 .typeof_elem => try sema.zirTypeofElem(block, inst),
260 .typeof_peer => try sema.zirTypeofPeer(block, inst),265 .typeof_peer => try sema.zirTypeofPeer(block, inst),
261 .xor => try sema.zirBitwise(block, inst, .xor),266 .xor => try sema.zirBitwise(block, inst, .xor),
262 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),267 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
268 .struct_init => try sema.zirStructInit(block, inst),
269 .field_type => try sema.zirFieldType(block, inst),
263270
264 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),271 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
265 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),272 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
266 .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),273 .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),
267 .enum_decl => try sema.zirEnumDecl(block, inst),274 .enum_decl => try sema.zirEnumDecl(block, inst, false),
275 .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),
268 .union_decl => try sema.zirUnionDecl(block, inst),276 .union_decl => try sema.zirUnionDecl(block, inst),
269 .opaque_decl => try sema.zirOpaqueDecl(block, inst),277 .opaque_decl => try sema.zirOpaqueDecl(block, inst),
270278
...@@ -338,6 +346,10 @@ pub fn analyzeBody(...@@ -338,6 +346,10 @@ pub fn analyzeBody(
338 try sema.zirValidateStructInitPtr(block, inst);346 try sema.zirValidateStructInitPtr(block, inst);
339 continue;347 continue;
340 },348 },
349 .@"export" => {
350 try sema.zirExport(block, inst);
351 continue;
352 },
341353
342 // Special case instructions to handle comptime control flow.354 // Special case instructions to handle comptime control flow.
343 .repeat_inline => {355 .repeat_inline => {
...@@ -498,18 +510,6 @@ fn resolveInstConst(...@@ -498,18 +510,6 @@ fn resolveInstConst(
498 };510 };
499}511}
500512
501fn zirConst(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
502 const tracy = trace(@src());
503 defer tracy.end();
504
505 const tv_ptr = sema.code.instructions.items(.data)[inst].@"const";
506 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
507 // after analysis. This happens, for example, with variable declaration initialization
508 // expressions.
509 const typed_value_copy = try tv_ptr.copy(sema.arena);
510 return sema.mod.constInst(sema.arena, .unneeded, typed_value_copy);
511}
512
513fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {513fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
514 const tracy = trace(@src());514 const tracy = trace(@src());
515 defer tracy.end();515 defer tracy.end();
...@@ -600,6 +600,11 @@ fn zirStructDecl(...@@ -600,6 +600,11 @@ fn zirStructDecl(
600600
601 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);601 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
602 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);602 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
603 const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
604 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
605 .ty = Type.initTag(.type),
606 .val = struct_val,
607 });
603 struct_obj.* = .{608 struct_obj.* = .{
604 .owner_decl = sema.owner_decl,609 .owner_decl = sema.owner_decl,
605 .fields = fields_map,610 .fields = fields_map,
...@@ -607,16 +612,18 @@ fn zirStructDecl(...@@ -607,16 +612,18 @@ fn zirStructDecl(
607 .container = .{612 .container = .{
608 .ty = struct_ty,613 .ty = struct_ty,
609 .file_scope = block.getFileScope(),614 .file_scope = block.getFileScope(),
615 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
610 },616 },
611 };617 };
612 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
613 .ty = Type.initTag(.type),
614 .val = try Value.Tag.ty.create(gpa, struct_ty),
615 });
616 return sema.analyzeDeclVal(block, src, new_decl);618 return sema.analyzeDeclVal(block, src, new_decl);
617}619}
618620
619fn zirEnumDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {621fn zirEnumDecl(
622 sema: *Sema,
623 block: *Scope.Block,
624 inst: zir.Inst.Index,
625 nonexhaustive: bool,
626) InnerError!*Inst {
620 const tracy = trace(@src());627 const tracy = trace(@src());
621 defer tracy.end();628 defer tracy.end();
622629
...@@ -787,8 +794,8 @@ fn zirAllocInferred(...@@ -787,8 +794,8 @@ fn zirAllocInferred(
787 const tracy = trace(@src());794 const tracy = trace(@src());
788 defer tracy.end();795 defer tracy.end();
789796
790 const inst_data = sema.code.instructions.items(.data)[inst].un_node;797 const src_node = sema.code.instructions.items(.data)[inst].node;
791 const src = inst_data.src();798 const src: LazySrcLoc = .{ .node_offset = src_node };
792799
793 const val_payload = try sema.arena.create(Value.Payload.InferredAlloc);800 const val_payload = try sema.arena.create(Value.Payload.InferredAlloc);
794 val_payload.* = .{801 val_payload.* = .{
...@@ -837,12 +844,100 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind...@@ -837,12 +844,100 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind
837 const tracy = trace(@src());844 const tracy = trace(@src());
838 defer tracy.end();845 defer tracy.end();
839846
840 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;847 const gpa = sema.gpa;
841 const src = inst_data.src();848 const mod = sema.mod;
842 const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);849 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
843 const instrs = sema.code.extra[extra.end..][0..extra.data.body_len];850 const struct_init_src = validate_inst.src();
851 const validate_extra = sema.code.extraData(zir.Inst.Block, validate_inst.payload_index);
852 const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
853
854 const struct_obj: *Module.Struct = s: {
855 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
856 const field_ptr_extra = sema.code.extraData(zir.Inst.Field, field_ptr_data.payload_index).data;
857 const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);
858 break :s object_ptr.ty.elemType().castTag(.@"struct").?.data;
859 };
860
861 // Maps field index to field_ptr index of where it was already initialized.
862 const found_fields = try gpa.alloc(zir.Inst.Index, struct_obj.fields.entries.items.len);
863 defer gpa.free(found_fields);
864
865 mem.set(zir.Inst.Index, found_fields, 0);
866
867 for (instrs) |field_ptr| {
868 const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
869 const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };
870 const field_ptr_extra = sema.code.extraData(zir.Inst.Field, field_ptr_data.payload_index).data;
871 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
872 const field_index = struct_obj.fields.getIndex(field_name) orelse
873 return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);
874 if (found_fields[field_index] != 0) {
875 const other_field_ptr = found_fields[field_index];
876 const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
877 const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_ptr_data.src_node };
878 const msg = msg: {
879 const msg = try mod.errMsg(&block.base, field_src, "duplicate field", .{});
880 errdefer msg.destroy(gpa);
881 try mod.errNote(&block.base, other_field_src, msg, "other field here", .{});
882 break :msg msg;
883 };
884 return mod.failWithOwnedErrorMsg(&block.base, msg);
885 }
886 found_fields[field_index] = field_ptr;
887 }
888
889 var root_msg: ?*Module.ErrorMsg = null;
890
891 for (found_fields) |field_ptr, i| {
892 if (field_ptr != 0) continue;
844893
845 log.warn("TODO implement zirValidateStructInitPtr (compile errors for missing/dupe fields)", .{});894 const field_name = struct_obj.fields.entries.items[i].key;
895 const template = "mising struct field: {s}";
896 const args = .{field_name};
897 if (root_msg) |msg| {
898 try mod.errNote(&block.base, struct_init_src, msg, template, args);
899 } else {
900 root_msg = try mod.errMsg(&block.base, struct_init_src, template, args);
901 }
902 }
903 if (root_msg) |msg| {
904 const fqn = try struct_obj.getFullyQualifiedName(gpa);
905 defer gpa.free(fqn);
906 try mod.errNoteNonLazy(
907 struct_obj.srcLoc(),
908 msg,
909 "struct '{s}' declared here",
910 .{fqn},
911 );
912 return mod.failWithOwnedErrorMsg(&block.base, msg);
913 }
914}
915
916fn failWithBadFieldAccess(
917 sema: *Sema,
918 block: *Scope.Block,
919 struct_obj: *Module.Struct,
920 field_src: LazySrcLoc,
921 field_name: []const u8,
922) InnerError {
923 const mod = sema.mod;
924 const gpa = sema.gpa;
925
926 const fqn = try struct_obj.getFullyQualifiedName(gpa);
927 defer gpa.free(fqn);
928
929 const msg = msg: {
930 const msg = try mod.errMsg(
931 &block.base,
932 field_src,
933 "no field named '{s}' in struct '{s}'",
934 .{ field_name, fqn },
935 );
936 errdefer msg.destroy(gpa);
937 try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "struct declared here", .{});
938 break :msg msg;
939 };
940 return mod.failWithOwnedErrorMsg(&block.base, msg);
846}941}
847942
848fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {943fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
...@@ -981,6 +1076,31 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In...@@ -981,6 +1076,31 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In
981 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);1076 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
982}1077}
9831078
1079fn zirFloat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1080 const arena = sema.arena;
1081 const inst_data = sema.code.instructions.items(.data)[inst].float;
1082 const src = inst_data.src();
1083 const number = inst_data.number;
1084
1085 return sema.mod.constInst(arena, src, .{
1086 .ty = Type.initTag(.comptime_float),
1087 .val = try Value.Tag.float_32.create(arena, number),
1088 });
1089}
1090
1091fn zirFloat128(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1092 const arena = sema.arena;
1093 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1094 const extra = sema.code.extraData(zir.Inst.Float128, inst_data.payload_index).data;
1095 const src = inst_data.src();
1096 const number = extra.get();
1097
1098 return sema.mod.constInst(arena, src, .{
1099 .ty = Type.initTag(.comptime_float),
1100 .val = try Value.Tag.float_128.create(arena, number),
1101 });
1102}
1103
984fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {1104fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
985 const tracy = trace(@src());1105 const tracy = trace(@src());
986 defer tracy.end();1106 defer tracy.end();
...@@ -1222,6 +1342,28 @@ fn analyzeBlockBody(...@@ -1222,6 +1342,28 @@ fn analyzeBlockBody(
1222 return &merges.block_inst.base;1342 return &merges.block_inst.base;
1223}1343}
12241344
1345fn zirExport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
1346 const tracy = trace(@src());
1347 defer tracy.end();
1348
1349 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1350 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1351 const src = inst_data.src();
1352 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1353 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1354
1355 // TODO (see corresponding TODO in AstGen) this is supposed to be a `decl_ref`
1356 // instruction, which could reference any decl, which is then supposed to get
1357 // exported, regardless of whether or not it is a function.
1358 const target_fn = try sema.resolveInstConst(block, lhs_src, extra.lhs);
1359 // TODO (see corresponding TODO in AstGen) this is supposed to be
1360 // `std.builtin.ExportOptions`, not a string.
1361 const export_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
1362
1363 const actual_fn = target_fn.val.castTag(.function).?.data;
1364 try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl);
1365}
1366
1225fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {1367fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
1226 const tracy = trace(@src());1368 const tracy = trace(@src());
1227 defer tracy.end();1369 defer tracy.end();
...@@ -1291,22 +1433,16 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE...@@ -1291,22 +1433,16 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
1291}1433}
12921434
1293fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1435fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1294 const tracy = trace(@src());
1295 defer tracy.end();
1296
1297 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1436 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1298 const src = inst_data.src();1437 const src = inst_data.src();
1299 const decl = sema.code.decls[inst_data.payload_index];1438 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
1300 return sema.analyzeDeclRef(block, src, decl);1439 return sema.analyzeDeclRef(block, src, decl);
1301}1440}
13021441
1303fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1442fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1304 const tracy = trace(@src());
1305 defer tracy.end();
1306
1307 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1443 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1308 const src = inst_data.src();1444 const src = inst_data.src();
1309 const decl = sema.code.decls[inst_data.payload_index];1445 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
1310 return sema.analyzeDeclVal(block, src, decl);1446 return sema.analyzeDeclVal(block, src, decl);
1311}1447}
13121448
...@@ -1763,6 +1899,143 @@ fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I...@@ -1763,6 +1899,143 @@ fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I
1763 });1899 });
1764}1900}
17651901
1902fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1903 const mod = sema.mod;
1904 const arena = sema.arena;
1905 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1906 const src = inst_data.src();
1907 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1908 const operand = try sema.resolveInst(inst_data.operand);
1909
1910 const enum_tag: *Inst = switch (operand.ty.zigTypeTag()) {
1911 .Enum => operand,
1912 .Union => {
1913 //if (!operand.ty.unionHasTag()) {
1914 // return mod.fail(
1915 // &block.base,
1916 // operand_src,
1917 // "untagged union '{}' cannot be converted to integer",
1918 // .{dest_ty_src},
1919 // );
1920 //}
1921 return mod.fail(&block.base, operand_src, "TODO zirEnumToInt for tagged unions", .{});
1922 },
1923 else => {
1924 return mod.fail(&block.base, operand_src, "expected enum or tagged union, found {}", .{
1925 operand.ty,
1926 });
1927 },
1928 };
1929
1930 var int_tag_type_buffer: Type.Payload.Bits = undefined;
1931 const int_tag_ty = try enum_tag.ty.intTagType(&int_tag_type_buffer).copy(arena);
1932
1933 if (enum_tag.ty.onePossibleValue()) |opv| {
1934 return mod.constInst(arena, src, .{
1935 .ty = int_tag_ty,
1936 .val = opv,
1937 });
1938 }
1939
1940 if (enum_tag.value()) |enum_tag_val| {
1941 if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| {
1942 const field_index = enum_field_payload.data;
1943 switch (enum_tag.ty.tag()) {
1944 .enum_full => {
1945 const enum_full = enum_tag.ty.castTag(.enum_full).?.data;
1946 if (enum_full.values.count() != 0) {
1947 const val = enum_full.values.entries.items[field_index].key;
1948 return mod.constInst(arena, src, .{
1949 .ty = int_tag_ty,
1950 .val = val,
1951 });
1952 } else {
1953 // Field index and integer values are the same.
1954 const val = try Value.Tag.int_u64.create(arena, field_index);
1955 return mod.constInst(arena, src, .{
1956 .ty = int_tag_ty,
1957 .val = val,
1958 });
1959 }
1960 },
1961 .enum_simple => {
1962 // Field index and integer values are the same.
1963 const val = try Value.Tag.int_u64.create(arena, field_index);
1964 return mod.constInst(arena, src, .{
1965 .ty = int_tag_ty,
1966 .val = val,
1967 });
1968 },
1969 else => unreachable,
1970 }
1971 } else {
1972 // Assume it is already an integer and return it directly.
1973 return mod.constInst(arena, src, .{
1974 .ty = int_tag_ty,
1975 .val = enum_tag_val,
1976 });
1977 }
1978 }
1979
1980 try sema.requireRuntimeBlock(block, src);
1981 return block.addUnOp(src, int_tag_ty, .bitcast, enum_tag);
1982}
1983
1984fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1985 const mod = sema.mod;
1986 const target = mod.getTarget();
1987 const arena = sema.arena;
1988 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1989 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1990 const src = inst_data.src();
1991 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1992 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1993 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
1994 const operand = try sema.resolveInst(extra.rhs);
1995
1996 if (dest_ty.zigTypeTag() != .Enum) {
1997 return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
1998 }
1999
2000 if (dest_ty.isNonexhaustiveEnum()) {
2001 if (operand.value()) |int_val| {
2002 return mod.constInst(arena, src, .{
2003 .ty = dest_ty,
2004 .val = int_val,
2005 });
2006 }
2007 }
2008
2009 if (try sema.resolveDefinedValue(block, operand_src, operand)) |int_val| {
2010 if (!dest_ty.enumHasInt(int_val, target)) {
2011 const msg = msg: {
2012 const msg = try mod.errMsg(
2013 &block.base,
2014 src,
2015 "enum '{}' has no tag with value {}",
2016 .{ dest_ty, int_val },
2017 );
2018 errdefer msg.destroy(sema.gpa);
2019 try mod.errNoteNonLazy(
2020 dest_ty.declSrcLoc(),
2021 msg,
2022 "enum declared here",
2023 .{},
2024 );
2025 break :msg msg;
2026 };
2027 return mod.failWithOwnedErrorMsg(&block.base, msg);
2028 }
2029 return mod.constInst(arena, src, .{
2030 .ty = dest_ty,
2031 .val = int_val,
2032 });
2033 }
2034
2035 try sema.requireRuntimeBlock(block, src);
2036 return block.addUnOp(src, dest_ty, .bitcast, operand);
2037}
2038
1766/// Pointer in, pointer out.2039/// Pointer in, pointer out.
1767fn zirOptionalPayloadPtr(2040fn zirOptionalPayloadPtr(
1768 sema: *Sema,2041 sema: *Sema,
...@@ -2139,7 +2412,10 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro...@@ -2139,7 +2412,10 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro
2139 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;2412 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
2140 const field_name = sema.code.nullTerminatedString(extra.field_name_start);2413 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
2141 const object = try sema.resolveInst(extra.lhs);2414 const object = try sema.resolveInst(extra.lhs);
2142 const object_ptr = try sema.analyzeRef(block, src, object);2415 const object_ptr = if (object.ty.zigTypeTag() == .Pointer)
2416 object
2417 else
2418 try sema.analyzeRef(block, src, object);
2143 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);2419 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
2144 return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);2420 return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
2145}2421}
...@@ -2292,7 +2568,10 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError...@@ -2292,7 +2568,10 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
22922568
2293 const bin_inst = sema.code.instructions.items(.data)[inst].bin;2569 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2294 const array = try sema.resolveInst(bin_inst.lhs);2570 const array = try sema.resolveInst(bin_inst.lhs);
2295 const array_ptr = try sema.analyzeRef(block, sema.src, array);2571 const array_ptr = if (array.ty.zigTypeTag() == .Pointer)
2572 array
2573 else
2574 try sema.analyzeRef(block, sema.src, array);
2296 const elem_index = try sema.resolveInst(bin_inst.rhs);2575 const elem_index = try sema.resolveInst(bin_inst.rhs);
2297 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);2576 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
2298 return sema.analyzeLoad(block, sema.src, result_ptr, sema.src);2577 return sema.analyzeLoad(block, sema.src, result_ptr, sema.src);
...@@ -2307,7 +2586,10 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE...@@ -2307,7 +2586,10 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
2307 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };2586 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
2308 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;2587 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
2309 const array = try sema.resolveInst(extra.lhs);2588 const array = try sema.resolveInst(extra.lhs);
2310 const array_ptr = try sema.analyzeRef(block, src, array);2589 const array_ptr = if (array.ty.zigTypeTag() == .Pointer)
2590 array
2591 else
2592 try sema.analyzeRef(block, src, array);
2311 const elem_index = try sema.resolveInst(extra.rhs);2593 const elem_index = try sema.resolveInst(extra.rhs);
2312 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);2594 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
2313 return sema.analyzeLoad(block, src, result_ptr, src);2595 return sema.analyzeLoad(block, src, result_ptr, src);
...@@ -2492,6 +2774,8 @@ fn analyzeSwitch(...@@ -2492,6 +2774,8 @@ fn analyzeSwitch(
2492 src_node_offset: i32,2774 src_node_offset: i32,
2493) InnerError!*Inst {2775) InnerError!*Inst {
2494 const gpa = sema.gpa;2776 const gpa = sema.gpa;
2777 const mod = sema.mod;
2778
2495 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {2779 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
2496 .none => .{ .body = &.{}, .end = extra_end },2780 .none => .{ .body = &.{}, .end = extra_end },
2497 .under, .@"else" => blk: {2781 .under, .@"else" => blk: {
...@@ -2509,16 +2793,16 @@ fn analyzeSwitch(...@@ -2509,16 +2793,16 @@ fn analyzeSwitch(
2509 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };2793 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
25102794
2511 // Validate usage of '_' prongs.2795 // Validate usage of '_' prongs.
2512 if (special_prong == .under and !operand.ty.isExhaustiveEnum()) {2796 if (special_prong == .under and !operand.ty.isNonexhaustiveEnum()) {
2513 const msg = msg: {2797 const msg = msg: {
2514 const msg = try sema.mod.errMsg(2798 const msg = try mod.errMsg(
2515 &block.base,2799 &block.base,
2516 src,2800 src,
2517 "'_' prong only allowed when switching on non-exhaustive enums",2801 "'_' prong only allowed when switching on non-exhaustive enums",
2518 .{},2802 .{},
2519 );2803 );
2520 errdefer msg.destroy(gpa);2804 errdefer msg.destroy(gpa);
2521 try sema.mod.errNote(2805 try mod.errNote(
2522 &block.base,2806 &block.base,
2523 special_prong_src,2807 special_prong_src,
2524 msg,2808 msg,
...@@ -2527,14 +2811,123 @@ fn analyzeSwitch(...@@ -2527,14 +2811,123 @@ fn analyzeSwitch(
2527 );2811 );
2528 break :msg msg;2812 break :msg msg;
2529 };2813 };
2530 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);2814 return mod.failWithOwnedErrorMsg(&block.base, msg);
2531 }2815 }
25322816
2533 // Validate for duplicate items, missing else prong, and invalid range.2817 // Validate for duplicate items, missing else prong, and invalid range.
2534 switch (operand.ty.zigTypeTag()) {2818 switch (operand.ty.zigTypeTag()) {
2535 .Enum => return sema.mod.fail(&block.base, src, "TODO validate switch .Enum", .{}),2819 .Enum => {
2536 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),2820 var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount());
2537 .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),2821 defer gpa.free(seen_fields);
2822
2823 mem.set(?AstGen.SwitchProngSrc, seen_fields, null);
2824
2825 var extra_index: usize = special.end;
2826 {
2827 var scalar_i: u32 = 0;
2828 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
2829 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
2830 extra_index += 1;
2831 const body_len = sema.code.extra[extra_index];
2832 extra_index += 1;
2833 const body = sema.code.extra[extra_index..][0..body_len];
2834 extra_index += body_len;
2835
2836 try sema.validateSwitchItemEnum(
2837 block,
2838 seen_fields,
2839 item_ref,
2840 src_node_offset,
2841 .{ .scalar = scalar_i },
2842 );
2843 }
2844 }
2845 {
2846 var multi_i: u32 = 0;
2847 while (multi_i < multi_cases_len) : (multi_i += 1) {
2848 const items_len = sema.code.extra[extra_index];
2849 extra_index += 1;
2850 const ranges_len = sema.code.extra[extra_index];
2851 extra_index += 1;
2852 const body_len = sema.code.extra[extra_index];
2853 extra_index += 1;
2854 const items = sema.code.refSlice(extra_index, items_len);
2855 extra_index += items_len + body_len;
2856
2857 for (items) |item_ref, item_i| {
2858 try sema.validateSwitchItemEnum(
2859 block,
2860 seen_fields,
2861 item_ref,
2862 src_node_offset,
2863 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
2864 );
2865 }
2866
2867 try sema.validateSwitchNoRange(block, ranges_len, operand.ty, src_node_offset);
2868 }
2869 }
2870 const all_tags_handled = for (seen_fields) |seen_src| {
2871 if (seen_src == null) break false;
2872 } else true;
2873
2874 switch (special_prong) {
2875 .none => {
2876 if (!all_tags_handled) {
2877 const msg = msg: {
2878 const msg = try mod.errMsg(
2879 &block.base,
2880 src,
2881 "switch must handle all possibilities",
2882 .{},
2883 );
2884 errdefer msg.destroy(sema.gpa);
2885 for (seen_fields) |seen_src, i| {
2886 if (seen_src != null) continue;
2887
2888 const field_name = operand.ty.enumFieldName(i);
2889
2890 // TODO have this point to the tag decl instead of here
2891 try mod.errNote(
2892 &block.base,
2893 src,
2894 msg,
2895 "unhandled enumeration value: '{s}'",
2896 .{field_name},
2897 );
2898 }
2899 try mod.errNoteNonLazy(
2900 operand.ty.declSrcLoc(),
2901 msg,
2902 "enum '{}' declared here",
2903 .{operand.ty},
2904 );
2905 break :msg msg;
2906 };
2907 return mod.failWithOwnedErrorMsg(&block.base, msg);
2908 }
2909 },
2910 .under => {
2911 if (all_tags_handled) return mod.fail(
2912 &block.base,
2913 special_prong_src,
2914 "unreachable '_' prong; all cases already handled",
2915 .{},
2916 );
2917 },
2918 .@"else" => {
2919 if (all_tags_handled) return mod.fail(
2920 &block.base,
2921 special_prong_src,
2922 "unreachable else prong; all cases already handled",
2923 .{},
2924 );
2925 },
2926 }
2927 },
2928
2929 .ErrorSet => return mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),
2930 .Union => return mod.fail(&block.base, src, "TODO validate switch .Union", .{}),
2538 .Int, .ComptimeInt => {2931 .Int, .ComptimeInt => {
2539 var range_set = RangeSet.init(gpa);2932 var range_set = RangeSet.init(gpa);
2540 defer range_set.deinit();2933 defer range_set.deinit();
...@@ -2607,11 +3000,11 @@ fn analyzeSwitch(...@@ -2607,11 +3000,11 @@ fn analyzeSwitch(
2607 var arena = std.heap.ArenaAllocator.init(gpa);3000 var arena = std.heap.ArenaAllocator.init(gpa);
2608 defer arena.deinit();3001 defer arena.deinit();
26093002
2610 const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());3003 const min_int = try operand.ty.minInt(&arena, mod.getTarget());
2611 const max_int = try operand.ty.maxInt(&arena, sema.mod.getTarget());3004 const max_int = try operand.ty.maxInt(&arena, mod.getTarget());
2612 if (try range_set.spans(min_int, max_int)) {3005 if (try range_set.spans(min_int, max_int)) {
2613 if (special_prong == .@"else") {3006 if (special_prong == .@"else") {
2614 return sema.mod.fail(3007 return mod.fail(
2615 &block.base,3008 &block.base,
2616 special_prong_src,3009 special_prong_src,
2617 "unreachable else prong; all cases already handled",3010 "unreachable else prong; all cases already handled",
...@@ -2622,7 +3015,7 @@ fn analyzeSwitch(...@@ -2622,7 +3015,7 @@ fn analyzeSwitch(
2622 }3015 }
2623 }3016 }
2624 if (special_prong != .@"else") {3017 if (special_prong != .@"else") {
2625 return sema.mod.fail(3018 return mod.fail(
2626 &block.base,3019 &block.base,
2627 src,3020 src,
2628 "switch must handle all possibilities",3021 "switch must handle all possibilities",
...@@ -2685,7 +3078,7 @@ fn analyzeSwitch(...@@ -2685,7 +3078,7 @@ fn analyzeSwitch(
2685 switch (special_prong) {3078 switch (special_prong) {
2686 .@"else" => {3079 .@"else" => {
2687 if (true_count + false_count == 2) {3080 if (true_count + false_count == 2) {
2688 return sema.mod.fail(3081 return mod.fail(
2689 &block.base,3082 &block.base,
2690 src,3083 src,
2691 "unreachable else prong; all cases already handled",3084 "unreachable else prong; all cases already handled",
...@@ -2695,7 +3088,7 @@ fn analyzeSwitch(...@@ -2695,7 +3088,7 @@ fn analyzeSwitch(
2695 },3088 },
2696 .under, .none => {3089 .under, .none => {
2697 if (true_count + false_count < 2) {3090 if (true_count + false_count < 2) {
2698 return sema.mod.fail(3091 return mod.fail(
2699 &block.base,3092 &block.base,
2700 src,3093 src,
2701 "switch must handle all possibilities",3094 "switch must handle all possibilities",
...@@ -2707,7 +3100,7 @@ fn analyzeSwitch(...@@ -2707,7 +3100,7 @@ fn analyzeSwitch(
2707 },3100 },
2708 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {3101 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
2709 if (special_prong != .@"else") {3102 if (special_prong != .@"else") {
2710 return sema.mod.fail(3103 return mod.fail(
2711 &block.base,3104 &block.base,
2712 src,3105 src,
2713 "else prong required when switching on type '{}'",3106 "else prong required when switching on type '{}'",
...@@ -2779,7 +3172,7 @@ fn analyzeSwitch(...@@ -2779,7 +3172,7 @@ fn analyzeSwitch(
2779 .AnyFrame,3172 .AnyFrame,
2780 .ComptimeFloat,3173 .ComptimeFloat,
2781 .Float,3174 .Float,
2782 => return sema.mod.fail(&block.base, operand_src, "invalid switch operand type '{}'", .{3175 => return mod.fail(&block.base, operand_src, "invalid switch operand type '{}'", .{
2783 operand.ty,3176 operand.ty,
2784 }),3177 }),
2785 }3178 }
...@@ -3054,7 +3447,7 @@ fn resolveSwitchItemVal(...@@ -3054,7 +3447,7 @@ fn resolveSwitchItemVal(
3054 switch_node_offset: i32,3447 switch_node_offset: i32,
3055 switch_prong_src: AstGen.SwitchProngSrc,3448 switch_prong_src: AstGen.SwitchProngSrc,
3056 range_expand: AstGen.SwitchProngSrc.RangeExpand,3449 range_expand: AstGen.SwitchProngSrc.RangeExpand,
3057) InnerError!Value {3450) InnerError!TypedValue {
3058 const item = try sema.resolveInst(item_ref);3451 const item = try sema.resolveInst(item_ref);
3059 // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc3452 // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc
3060 // because we only have the switch AST node. Only if we know for sure we need to report3453 // because we only have the switch AST node. Only if we know for sure we need to report
...@@ -3064,7 +3457,7 @@ fn resolveSwitchItemVal(...@@ -3064,7 +3457,7 @@ fn resolveSwitchItemVal(
3064 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);3457 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
3065 return sema.failWithUseOfUndef(block, src);3458 return sema.failWithUseOfUndef(block, src);
3066 }3459 }
3067 return val;3460 return TypedValue{ .ty = item.ty, .val = val };
3068 }3461 }
3069 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);3462 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
3070 return sema.failWithNeededComptime(block, src);3463 return sema.failWithNeededComptime(block, src);
...@@ -3079,8 +3472,8 @@ fn validateSwitchRange(...@@ -3079,8 +3472,8 @@ fn validateSwitchRange(
3079 src_node_offset: i32,3472 src_node_offset: i32,
3080 switch_prong_src: AstGen.SwitchProngSrc,3473 switch_prong_src: AstGen.SwitchProngSrc,
3081) InnerError!void {3474) InnerError!void {
3082 const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);3475 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
3083 const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);3476 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
3084 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);3477 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
3085 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);3478 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
3086}3479}
...@@ -3093,11 +3486,46 @@ fn validateSwitchItem(...@@ -3093,11 +3486,46 @@ fn validateSwitchItem(
3093 src_node_offset: i32,3486 src_node_offset: i32,
3094 switch_prong_src: AstGen.SwitchProngSrc,3487 switch_prong_src: AstGen.SwitchProngSrc,
3095) InnerError!void {3488) InnerError!void {
3096 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);3489 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
3097 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);3490 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
3098 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);3491 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
3099}3492}
31003493
3494fn validateSwitchItemEnum(
3495 sema: *Sema,
3496 block: *Scope.Block,
3497 seen_fields: []?AstGen.SwitchProngSrc,
3498 item_ref: zir.Inst.Ref,
3499 src_node_offset: i32,
3500 switch_prong_src: AstGen.SwitchProngSrc,
3501) InnerError!void {
3502 const mod = sema.mod;
3503 const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
3504 const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val) orelse {
3505 const msg = msg: {
3506 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
3507 const msg = try mod.errMsg(
3508 &block.base,
3509 src,
3510 "enum '{}' has no tag with value '{}'",
3511 .{ item_tv.ty, item_tv.val },
3512 );
3513 errdefer msg.destroy(sema.gpa);
3514 try mod.errNoteNonLazy(
3515 item_tv.ty.declSrcLoc(),
3516 msg,
3517 "enum declared here",
3518 .{},
3519 );
3520 break :msg msg;
3521 };
3522 return mod.failWithOwnedErrorMsg(&block.base, msg);
3523 };
3524 const maybe_prev_src = seen_fields[field_index];
3525 seen_fields[field_index] = switch_prong_src;
3526 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
3527}
3528
3101fn validateSwitchDupe(3529fn validateSwitchDupe(
3102 sema: *Sema,3530 sema: *Sema,
3103 block: *Scope.Block,3531 block: *Scope.Block,
...@@ -3106,17 +3534,18 @@ fn validateSwitchDupe(...@@ -3106,17 +3534,18 @@ fn validateSwitchDupe(
3106 src_node_offset: i32,3534 src_node_offset: i32,
3107) InnerError!void {3535) InnerError!void {
3108 const prev_prong_src = maybe_prev_src orelse return;3536 const prev_prong_src = maybe_prev_src orelse return;
3537 const mod = sema.mod;
3109 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);3538 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
3110 const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none);3539 const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none);
3111 const msg = msg: {3540 const msg = msg: {
3112 const msg = try sema.mod.errMsg(3541 const msg = try mod.errMsg(
3113 &block.base,3542 &block.base,
3114 src,3543 src,
3115 "duplicate switch value",3544 "duplicate switch value",
3116 .{},3545 .{},
3117 );3546 );
3118 errdefer msg.destroy(sema.gpa);3547 errdefer msg.destroy(sema.gpa);
3119 try sema.mod.errNote(3548 try mod.errNote(
3120 &block.base,3549 &block.base,
3121 prev_src,3550 prev_src,
3122 msg,3551 msg,
...@@ -3125,7 +3554,7 @@ fn validateSwitchDupe(...@@ -3125,7 +3554,7 @@ fn validateSwitchDupe(
3125 );3554 );
3126 break :msg msg;3555 break :msg msg;
3127 };3556 };
3128 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);3557 return mod.failWithOwnedErrorMsg(&block.base, msg);
3129}3558}
31303559
3131fn validateSwitchItemBool(3560fn validateSwitchItemBool(
...@@ -3137,7 +3566,7 @@ fn validateSwitchItemBool(...@@ -3137,7 +3566,7 @@ fn validateSwitchItemBool(
3137 src_node_offset: i32,3566 src_node_offset: i32,
3138 switch_prong_src: AstGen.SwitchProngSrc,3567 switch_prong_src: AstGen.SwitchProngSrc,
3139) InnerError!void {3568) InnerError!void {
3140 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);3569 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
3141 if (item_val.toBool()) {3570 if (item_val.toBool()) {
3142 true_count.* += 1;3571 true_count.* += 1;
3143 } else {3572 } else {
...@@ -3159,7 +3588,7 @@ fn validateSwitchItemSparse(...@@ -3159,7 +3588,7 @@ fn validateSwitchItemSparse(
3159 src_node_offset: i32,3588 src_node_offset: i32,
3160 switch_prong_src: AstGen.SwitchProngSrc,3589 switch_prong_src: AstGen.SwitchProngSrc,
3161) InnerError!void {3590) InnerError!void {
3162 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);3591 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
3163 const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;3592 const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
3164 return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);3593 return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);
3165}3594}
...@@ -3197,6 +3626,34 @@ fn validateSwitchNoRange(...@@ -3197,6 +3626,34 @@ fn validateSwitchNoRange(
3197 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);3626 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
3198}3627}
31993628
3629fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
3630 const tracy = trace(@src());
3631 defer tracy.end();
3632
3633 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3634 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
3635 const src = inst_data.src();
3636 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
3637 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
3638 const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
3639 const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
3640 const mod = sema.mod;
3641 const arena = sema.arena;
3642
3643 const container_scope = container_type.getContainerScope() orelse return mod.fail(
3644 &block.base,
3645 lhs_src,
3646 "expected struct, enum, union, or opaque, found '{}'",
3647 .{container_type},
3648 );
3649 if (mod.lookupDeclName(&container_scope.base, decl_name)) |decl| {
3650 // TODO if !decl.is_pub and inDifferentFiles() return false
3651 return mod.constBool(arena, src, true);
3652 } else {
3653 return mod.constBool(arena, src, false);
3654 }
3655}
3656
3200fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {3657fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
3201 const tracy = trace(@src());3658 const tracy = trace(@src());
3202 defer tracy.end();3659 defer tracy.end();
...@@ -3448,6 +3905,7 @@ fn analyzeArithmetic(...@@ -3448,6 +3905,7 @@ fn analyzeArithmetic(
3448 .subwrap => .subwrap,3905 .subwrap => .subwrap,
3449 .mul => .mul,3906 .mul => .mul,
3450 .mulwrap => .mulwrap,3907 .mulwrap => .mulwrap,
3908 .div => .div,
3451 else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(zir_tag)}),3909 else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(zir_tag)}),
3452 };3910 };
34533911
...@@ -3539,9 +3997,13 @@ fn zirCmp(...@@ -3539,9 +3997,13 @@ fn zirCmp(
3539 const tracy = trace(@src());3997 const tracy = trace(@src());
3540 defer tracy.end();3998 defer tracy.end();
35413999
4000 const mod = sema.mod;
4001
3542 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;4002 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3543 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;4003 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
3544 const src: LazySrcLoc = inst_data.src();4004 const src: LazySrcLoc = inst_data.src();
4005 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
4006 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
3545 const lhs = try sema.resolveInst(extra.lhs);4007 const lhs = try sema.resolveInst(extra.lhs);
3546 const rhs = try sema.resolveInst(extra.rhs);4008 const rhs = try sema.resolveInst(extra.rhs);
35474009
...@@ -3553,7 +4015,7 @@ fn zirCmp(...@@ -3553,7 +4015,7 @@ fn zirCmp(
3553 const rhs_ty_tag = rhs.ty.zigTypeTag();4015 const rhs_ty_tag = rhs.ty.zigTypeTag();
3554 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {4016 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
3555 // null == null, null != null4017 // null == null, null != null
3556 return sema.mod.constBool(sema.arena, src, op == .eq);4018 return mod.constBool(sema.arena, src, op == .eq);
3557 } else if (is_equality_cmp and4019 } else if (is_equality_cmp and
3558 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or4020 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
3559 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))4021 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
...@@ -3564,23 +4026,23 @@ fn zirCmp(...@@ -3564,23 +4026,23 @@ fn zirCmp(
3564 } else if (is_equality_cmp and4026 } else if (is_equality_cmp and
3565 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))4027 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
3566 {4028 {
3567 return sema.mod.fail(&block.base, src, "TODO implement C pointer cmp", .{});4029 return mod.fail(&block.base, src, "TODO implement C pointer cmp", .{});
3568 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {4030 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
3569 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;4031 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;
3570 return sema.mod.fail(&block.base, src, "comparison of '{}' with null", .{non_null_type});4032 return mod.fail(&block.base, src, "comparison of '{}' with null", .{non_null_type});
3571 } else if (is_equality_cmp and4033 } else if (is_equality_cmp and
3572 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or4034 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
3573 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))4035 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
3574 {4036 {
3575 return sema.mod.fail(&block.base, src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});4037 return mod.fail(&block.base, src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
3576 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {4038 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
3577 if (!is_equality_cmp) {4039 if (!is_equality_cmp) {
3578 return sema.mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});4040 return mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});
3579 }4041 }
3580 if (rhs.value()) |rval| {4042 if (rhs.value()) |rval| {
3581 if (lhs.value()) |lval| {4043 if (lhs.value()) |lval| {
3582 // TODO optimisation oppurtunity: evaluate if std.mem.eql is faster with the names, or calling to Module.getErrorValue to get the values and then compare them is faster4044 // TODO optimisation oppurtunity: evaluate if std.mem.eql is faster with the names, or calling to Module.getErrorValue to get the values and then compare them is faster
3583 return sema.mod.constBool(sema.arena, src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));4045 return mod.constBool(sema.arena, src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));
3584 }4046 }
3585 }4047 }
3586 try sema.requireRuntimeBlock(block, src);4048 try sema.requireRuntimeBlock(block, src);
...@@ -3592,11 +4054,36 @@ fn zirCmp(...@@ -3592,11 +4054,36 @@ fn zirCmp(
3592 return sema.cmpNumeric(block, src, lhs, rhs, op);4054 return sema.cmpNumeric(block, src, lhs, rhs, op);
3593 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {4055 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
3594 if (!is_equality_cmp) {4056 if (!is_equality_cmp) {
3595 return sema.mod.fail(&block.base, src, "{s} operator not allowed for types", .{@tagName(op)});4057 return mod.fail(&block.base, src, "{s} operator not allowed for types", .{@tagName(op)});
3596 }4058 }
3597 return sema.mod.constBool(sema.arena, src, lhs.value().?.eql(rhs.value().?) == (op == .eq));4059 return mod.constBool(sema.arena, src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
3598 }4060 }
3599 return sema.mod.fail(&block.base, src, "TODO implement more cmp analysis", .{});4061
4062 const instructions = &[_]*Inst{ lhs, rhs };
4063 const resolved_type = try sema.resolvePeerTypes(block, src, instructions);
4064 if (!resolved_type.isSelfComparable(is_equality_cmp)) {
4065 return mod.fail(&block.base, src, "operator not allowed for type '{}'", .{resolved_type});
4066 }
4067
4068 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
4069 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
4070 try sema.requireRuntimeBlock(block, src); // TODO try to do it at comptime
4071 const bool_type = Type.initTag(.bool); // TODO handle vectors
4072 const tag: Inst.Tag = switch (op) {
4073 .lt => .cmp_lt,
4074 .lte => .cmp_lte,
4075 .eq => .cmp_eq,
4076 .gte => .cmp_gte,
4077 .gt => .cmp_gt,
4078 .neq => .cmp_neq,
4079 };
4080 return block.addBinOp(src, bool_type, tag, casted_lhs, casted_rhs);
4081}
4082
4083fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4084 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4085 const src = inst_data.src();
4086 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeInfo", .{});
3600}4087}
36014088
3602fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {4089fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
...@@ -3740,7 +4227,7 @@ fn zirBoolBr(...@@ -3740,7 +4227,7 @@ fn zirBoolBr(
3740 _ = try rhs_block.addBr(src, block_inst, rhs_result);4227 _ = try rhs_block.addBr(src, block_inst, rhs_result);
37414228
3742 const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) };4229 const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) };
3743 const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, rhs_block.instructions.items) };4230 const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, else_block.instructions.items) };
3744 _ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body);4231 _ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body);
37454232
3746 block_inst.body = .{4233 block_inst.body = .{
...@@ -4016,6 +4503,18 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In...@@ -4016,6 +4503,18 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
4016 });4503 });
4017}4504}
40184505
4506fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4507 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
4508 const src = inst_data.src();
4509 return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInit", .{});
4510}
4511
4512fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4513 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
4514 const src = inst_data.src();
4515 return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldType", .{});
4516}
4517
4019fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {4518fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
4020 if (sema.func == null) {4519 if (sema.func == null) {
4021 return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});4520 return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
...@@ -4123,22 +4622,25 @@ fn namedFieldPtr(...@@ -4123,22 +4622,25 @@ fn namedFieldPtr(
4123 field_name: []const u8,4622 field_name: []const u8,
4124 field_name_src: LazySrcLoc,4623 field_name_src: LazySrcLoc,
4125) InnerError!*Inst {4624) InnerError!*Inst {
4625 const mod = sema.mod;
4626 const arena = sema.arena;
4627
4126 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {4628 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
4127 .Pointer => object_ptr.ty.elemType(),4629 .Pointer => object_ptr.ty.elemType(),
4128 else => return sema.mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),4630 else => return mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
4129 };4631 };
4130 switch (elem_ty.zigTypeTag()) {4632 switch (elem_ty.zigTypeTag()) {
4131 .Array => {4633 .Array => {
4132 if (mem.eql(u8, field_name, "len")) {4634 if (mem.eql(u8, field_name, "len")) {
4133 return sema.mod.constInst(sema.arena, src, .{4635 return mod.constInst(arena, src, .{
4134 .ty = Type.initTag(.single_const_pointer_to_comptime_int),4636 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
4135 .val = try Value.Tag.ref_val.create(4637 .val = try Value.Tag.ref_val.create(
4136 sema.arena,4638 arena,
4137 try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()),4639 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
4138 ),4640 ),
4139 });4641 });
4140 } else {4642 } else {
4141 return sema.mod.fail(4643 return mod.fail(
4142 &block.base,4644 &block.base,
4143 field_name_src,4645 field_name_src,
4144 "no member named '{s}' in '{}'",4646 "no member named '{s}' in '{}'",
...@@ -4151,15 +4653,15 @@ fn namedFieldPtr(...@@ -4151,15 +4653,15 @@ fn namedFieldPtr(
4151 switch (ptr_child.zigTypeTag()) {4653 switch (ptr_child.zigTypeTag()) {
4152 .Array => {4654 .Array => {
4153 if (mem.eql(u8, field_name, "len")) {4655 if (mem.eql(u8, field_name, "len")) {
4154 return sema.mod.constInst(sema.arena, src, .{4656 return mod.constInst(arena, src, .{
4155 .ty = Type.initTag(.single_const_pointer_to_comptime_int),4657 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
4156 .val = try Value.Tag.ref_val.create(4658 .val = try Value.Tag.ref_val.create(
4157 sema.arena,4659 arena,
4158 try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()),4660 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
4159 ),4661 ),
4160 });4662 });
4161 } else {4663 } else {
4162 return sema.mod.fail(4664 return mod.fail(
4163 &block.base,4665 &block.base,
4164 field_name_src,4666 field_name_src,
4165 "no member named '{s}' in '{}'",4667 "no member named '{s}' in '{}'",
...@@ -4174,7 +4676,7 @@ fn namedFieldPtr(...@@ -4174,7 +4676,7 @@ fn namedFieldPtr(
4174 _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);4676 _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
4175 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);4677 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
4176 const val = result.value().?;4678 const val = result.value().?;
4177 const child_type = try val.toType(sema.arena);4679 const child_type = try val.toType(arena);
4178 switch (child_type.zigTypeTag()) {4680 switch (child_type.zigTypeTag()) {
4179 .ErrorSet => {4681 .ErrorSet => {
4180 // TODO resolve inferred error sets4682 // TODO resolve inferred error sets
...@@ -4188,42 +4690,92 @@ fn namedFieldPtr(...@@ -4188,42 +4690,92 @@ fn namedFieldPtr(
4188 break :blk name;4690 break :blk name;
4189 }4691 }
4190 }4692 }
4191 return sema.mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{4693 return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
4192 field_name,4694 field_name,
4193 child_type,4695 child_type,
4194 });4696 });
4195 } else (try sema.mod.getErrorValue(field_name)).key;4697 } else (try mod.getErrorValue(field_name)).key;
41964698
4197 return sema.mod.constInst(sema.arena, src, .{4699 return mod.constInst(arena, src, .{
4198 .ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One),4700 .ty = try mod.simplePtrType(arena, child_type, false, .One),
4199 .val = try Value.Tag.ref_val.create(4701 .val = try Value.Tag.ref_val.create(
4200 sema.arena,4702 arena,
4201 try Value.Tag.@"error".create(sema.arena, .{4703 try Value.Tag.@"error".create(arena, .{
4202 .name = name,4704 .name = name,
4203 }),4705 }),
4204 ),4706 ),
4205 });4707 });
4206 },4708 },
4207 .Struct => {4709 .Struct, .Opaque, .Union => {
4208 const container_scope = child_type.getContainerScope();4710 if (child_type.getContainerScope()) |container_scope| {
4209 if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| {4711 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4210 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"4712 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))
4211 return sema.analyzeDeclRef(block, src, decl);4713 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
4212 }4714 return sema.analyzeDeclRef(block, src, decl);
4715 }
42134716
4214 if (container_scope.file_scope == sema.mod.root_scope) {4717 // TODO this will give false positives for structs inside the root file
4215 return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});4718 if (container_scope.file_scope == mod.root_scope) {
4216 } else {4719 return mod.fail(
4217 return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });4720 &block.base,
4721 src,
4722 "root source file has no member named '{s}'",
4723 .{field_name},
4724 );
4725 }
4726 }
4727 // TODO add note: declared here
4728 const kw_name = switch (child_type.zigTypeTag()) {
4729 .Struct => "struct",
4730 .Opaque => "opaque",
4731 .Union => "union",
4732 else => unreachable,
4733 };
4734 return mod.fail(&block.base, src, "{s} '{}' has no member named '{s}'", .{
4735 kw_name, child_type, field_name,
4736 });
4737 },
4738 .Enum => {
4739 if (child_type.getContainerScope()) |container_scope| {
4740 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4741 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))
4742 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
4743 return sema.analyzeDeclRef(block, src, decl);
4744 }
4218 }4745 }
4746 const field_index = child_type.enumFieldIndex(field_name) orelse {
4747 const msg = msg: {
4748 const msg = try mod.errMsg(
4749 &block.base,
4750 src,
4751 "enum '{}' has no member named '{s}'",
4752 .{ child_type, field_name },
4753 );
4754 errdefer msg.destroy(sema.gpa);
4755 try mod.errNoteNonLazy(
4756 child_type.declSrcLoc(),
4757 msg,
4758 "enum declared here",
4759 .{},
4760 );
4761 break :msg msg;
4762 };
4763 return mod.failWithOwnedErrorMsg(&block.base, msg);
4764 };
4765 const field_index_u32 = @intCast(u32, field_index);
4766 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
4767 return mod.constInst(arena, src, .{
4768 .ty = try mod.simplePtrType(arena, child_type, false, .One),
4769 .val = try Value.Tag.ref_val.create(arena, enum_val),
4770 });
4219 },4771 },
4220 else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),4772 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
4221 }4773 }
4222 },4774 },
4223 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),4775 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
4224 else => {},4776 else => {},
4225 }4777 }
4226 return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});4778 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
4227}4779}
42284780
4229fn analyzeStructFieldPtr(4781fn analyzeStructFieldPtr(
...@@ -4241,12 +4793,8 @@ fn analyzeStructFieldPtr(...@@ -4241,12 +4793,8 @@ fn analyzeStructFieldPtr(
42414793
4242 const struct_obj = elem_ty.castTag(.@"struct").?.data;4794 const struct_obj = elem_ty.castTag(.@"struct").?.data;
42434795
4244 const field_index = struct_obj.fields.getIndex(field_name) orelse {4796 const field_index = struct_obj.fields.getIndex(field_name) orelse
4245 // TODO note: struct S declared here4797 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
4246 return mod.fail(&block.base, field_name_src, "no field named '{s}' in struct '{}'", .{
4247 field_name, elem_ty,
4248 });
4249 };
4250 const field = struct_obj.fields.entries.items[field_index].value;4798 const field = struct_obj.fields.entries.items[field_index].value;
4251 const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);4799 const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);
4252 // TODO comptime field access4800 // TODO comptime field access
...@@ -4262,37 +4810,51 @@ fn elemPtr(...@@ -4262,37 +4810,51 @@ fn elemPtr(
4262 elem_index: *Inst,4810 elem_index: *Inst,
4263 elem_index_src: LazySrcLoc,4811 elem_index_src: LazySrcLoc,
4264) InnerError!*Inst {4812) InnerError!*Inst {
4265 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {4813 const array_ty = switch (array_ptr.ty.zigTypeTag()) {
4266 .Pointer => array_ptr.ty.elemType(),4814 .Pointer => array_ptr.ty.elemType(),
4267 else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),4815 else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
4268 };4816 };
4269 if (!elem_ty.isIndexable()) {4817 if (!array_ty.isIndexable()) {
4270 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{elem_ty});4818 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{array_ty});
4271 }4819 }
42724820 if (array_ty.isSinglePointer() and array_ty.elemType().zigTypeTag() == .Array) {
4273 if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
4274 // we have to deref the ptr operand to get the actual array pointer4821 // we have to deref the ptr operand to get the actual array pointer
4275 const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);4822 const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);
4276 if (array_ptr_deref.value()) |array_ptr_val| {4823 return sema.elemPtrArray(block, src, array_ptr_deref, elem_index, elem_index_src);
4277 if (elem_index.value()) |index_val| {4824 }
4278 // Both array pointer and index are compile-time known.4825 if (array_ty.zigTypeTag() == .Array) {
4279 const index_u64 = index_val.toUnsignedInt();4826 return sema.elemPtrArray(block, src, array_ptr, elem_index, elem_index_src);
4280 // @intCast here because it would have been impossible to construct a value that
4281 // required a larger index.
4282 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));
4283 const pointee_type = elem_ty.elemType().elemType();
4284
4285 return sema.mod.constInst(sema.arena, src, .{
4286 .ty = try Type.Tag.single_const_pointer.create(sema.arena, pointee_type),
4287 .val = elem_ptr,
4288 });
4289 }
4290 }
4291 }4827 }
42924828
4293 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});4829 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});
4294}4830}
42954831
4832fn elemPtrArray(
4833 sema: *Sema,
4834 block: *Scope.Block,
4835 src: LazySrcLoc,
4836 array_ptr: *Inst,
4837 elem_index: *Inst,
4838 elem_index_src: LazySrcLoc,
4839) InnerError!*Inst {
4840 if (array_ptr.value()) |array_ptr_val| {
4841 if (elem_index.value()) |index_val| {
4842 // Both array pointer and index are compile-time known.
4843 const index_u64 = index_val.toUnsignedInt();
4844 // @intCast here because it would have been impossible to construct a value that
4845 // required a larger index.
4846 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));
4847 const pointee_type = array_ptr.ty.elemType().elemType();
4848
4849 return sema.mod.constInst(sema.arena, src, .{
4850 .ty = try Type.Tag.single_const_pointer.create(sema.arena, pointee_type),
4851 .val = elem_ptr,
4852 });
4853 }
4854 }
4855 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr for arrays", .{});
4856}
4857
4296fn coerce(4858fn coerce(
4297 sema: *Sema,4859 sema: *Sema,
4298 block: *Scope.Block,4860 block: *Scope.Block,
...@@ -4312,10 +4874,13 @@ fn coerce(...@@ -4312,10 +4874,13 @@ fn coerce(
4312 return sema.bitcast(block, dest_type, inst);4874 return sema.bitcast(block, dest_type, inst);
4313 }4875 }
43144876
4877 const mod = sema.mod;
4878 const arena = sema.arena;
4879
4315 // undefined to anything4880 // undefined to anything
4316 if (inst.value()) |val| {4881 if (inst.value()) |val| {
4317 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {4882 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
4318 return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = val });4883 return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = val });
4319 }4884 }
4320 }4885 }
4321 assert(inst.ty.zigTypeTag() != .Undefined);4886 assert(inst.ty.zigTypeTag() != .Undefined);
...@@ -4329,13 +4894,13 @@ fn coerce(...@@ -4329,13 +4894,13 @@ fn coerce(
4329 if (try sema.coerceNum(block, dest_type, inst)) |some|4894 if (try sema.coerceNum(block, dest_type, inst)) |some|
4330 return some;4895 return some;
43314896
4332 const target = sema.mod.getTarget();4897 const target = mod.getTarget();
43334898
4334 switch (dest_type.zigTypeTag()) {4899 switch (dest_type.zigTypeTag()) {
4335 .Optional => {4900 .Optional => {
4336 // null to ?T4901 // null to ?T
4337 if (inst.ty.zigTypeTag() == .Null) {4902 if (inst.ty.zigTypeTag() == .Null) {
4338 return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });4903 return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
4339 }4904 }
43404905
4341 // T to ?T4906 // T to ?T
...@@ -4421,10 +4986,40 @@ fn coerce(...@@ -4421,10 +4986,40 @@ fn coerce(
4421 }4986 }
4422 }4987 }
4423 },4988 },
4989 .Enum => {
4990 // enum literal to enum
4991 if (inst.ty.zigTypeTag() == .EnumLiteral) {
4992 const val = try sema.resolveConstValue(block, inst_src, inst);
4993 const bytes = val.castTag(.enum_literal).?.data;
4994 const field_index = dest_type.enumFieldIndex(bytes) orelse {
4995 const msg = msg: {
4996 const msg = try mod.errMsg(
4997 &block.base,
4998 inst_src,
4999 "enum '{}' has no field named '{s}'",
5000 .{ dest_type, bytes },
5001 );
5002 errdefer msg.destroy(sema.gpa);
5003 try mod.errNoteNonLazy(
5004 dest_type.declSrcLoc(),
5005 msg,
5006 "enum declared here",
5007 .{},
5008 );
5009 break :msg msg;
5010 };
5011 return mod.failWithOwnedErrorMsg(&block.base, msg);
5012 };
5013 return mod.constInst(arena, inst_src, .{
5014 .ty = dest_type,
5015 .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),
5016 });
5017 }
5018 },
4424 else => {},5019 else => {},
4425 }5020 }
44265021
4427 return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty });5022 return mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty });
4428}5023}
44295024
4430const InMemoryCoercionResult = enum {5025const InMemoryCoercionResult = enum {
...@@ -4542,7 +5137,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl...@@ -4542,7 +5137,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
4542}5137}
45435138
4544fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {5139fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
4545 try sema.mod.declareDeclDependency(sema.owner_decl, decl);5140 _ = try sema.mod.declareDeclDependency(sema.owner_decl, decl);
4546 sema.mod.ensureDeclAnalyzed(decl) catch |err| {5141 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
4547 if (sema.func) |func| {5142 if (sema.func) |func| {
4548 func.state = .dependency_failure;5143 func.state = .dependency_failure;
...@@ -4742,9 +5337,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin...@@ -4742,9 +5337,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
4742 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });5337 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
4743 errdefer sema.gpa.free(resolved_path);5338 errdefer sema.gpa.free(resolved_path);
47445339
4745 if (sema.mod.import_table.get(resolved_path)) |some| {5340 if (sema.mod.import_table.get(resolved_path)) |cached_import| {
4746 sema.gpa.free(resolved_path);5341 sema.gpa.free(resolved_path);
4747 return some;5342 return cached_import;
4748 }5343 }
47495344
4750 if (found_pkg == null) {5345 if (found_pkg == null) {
...@@ -4762,6 +5357,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin...@@ -4762,6 +5357,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
4762 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);5357 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);
4763 errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?);5358 errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?);
47645359
5360 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
5361 pkg.namespace_hash
5362 else
5363 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
5364
4765 file_scope.* = .{5365 file_scope.* = .{
4766 .sub_file_path = resolved_path,5366 .sub_file_path = resolved_path,
4767 .source = .{ .unloaded = {} },5367 .source = .{ .unloaded = {} },
...@@ -4772,6 +5372,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin...@@ -4772,6 +5372,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
4772 .file_scope = file_scope,5372 .file_scope = file_scope,
4773 .decls = .{},5373 .decls = .{},
4774 .ty = struct_ty,5374 .ty = struct_ty,
5375 .parent_name_hash = container_name_hash,
4775 },5376 },
4776 };5377 };
4777 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {5378 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
src/clang.zig+27
...@@ -300,6 +300,14 @@ pub const ConstantExpr = opaque {};...@@ -300,6 +300,14 @@ pub const ConstantExpr = opaque {};
300300
301pub const ContinueStmt = opaque {};301pub const ContinueStmt = opaque {};
302302
303pub const ConvertVectorExpr = opaque {
304 pub const getSrcExpr = ZigClangConvertVectorExpr_getSrcExpr;
305 extern fn ZigClangConvertVectorExpr_getSrcExpr(*const ConvertVectorExpr) *const Expr;
306
307 pub const getTypeSourceInfo_getType = ZigClangConvertVectorExpr_getTypeSourceInfo_getType;
308 extern fn ZigClangConvertVectorExpr_getTypeSourceInfo_getType(*const ConvertVectorExpr) QualType;
309};
310
303pub const DecayedType = opaque {311pub const DecayedType = opaque {
304 pub const getDecayedType = ZigClangDecayedType_getDecayedType;312 pub const getDecayedType = ZigClangDecayedType_getDecayedType;
305 extern fn ZigClangDecayedType_getDecayedType(*const DecayedType) QualType;313 extern fn ZigClangDecayedType_getDecayedType(*const DecayedType) QualType;
...@@ -748,6 +756,14 @@ pub const ReturnStmt = opaque {...@@ -748,6 +756,14 @@ pub const ReturnStmt = opaque {
748 extern fn ZigClangReturnStmt_getRetValue(*const ReturnStmt) ?*const Expr;756 extern fn ZigClangReturnStmt_getRetValue(*const ReturnStmt) ?*const Expr;
749};757};
750758
759pub const ShuffleVectorExpr = opaque {
760 pub const getNumSubExprs = ZigClangShuffleVectorExpr_getNumSubExprs;
761 extern fn ZigClangShuffleVectorExpr_getNumSubExprs(*const ShuffleVectorExpr) c_uint;
762
763 pub const getExpr = ZigClangShuffleVectorExpr_getExpr;
764 extern fn ZigClangShuffleVectorExpr_getExpr(*const ShuffleVectorExpr, c_uint) *const Expr;
765};
766
751pub const SourceManager = opaque {767pub const SourceManager = opaque {
752 pub const getSpellingLoc = ZigClangSourceManager_getSpellingLoc;768 pub const getSpellingLoc = ZigClangSourceManager_getSpellingLoc;
753 extern fn ZigClangSourceManager_getSpellingLoc(*const SourceManager, Loc: SourceLocation) SourceLocation;769 extern fn ZigClangSourceManager_getSpellingLoc(*const SourceManager, Loc: SourceLocation) SourceLocation;
...@@ -837,6 +853,9 @@ pub const Type = opaque {...@@ -837,6 +853,9 @@ pub const Type = opaque {
837 pub const isRecordType = ZigClangType_isRecordType;853 pub const isRecordType = ZigClangType_isRecordType;
838 extern fn ZigClangType_isRecordType(*const Type) bool;854 extern fn ZigClangType_isRecordType(*const Type) bool;
839855
856 pub const isVectorType = ZigClangType_isVectorType;
857 extern fn ZigClangType_isVectorType(*const Type) bool;
858
840 pub const isIncompleteOrZeroLengthArrayType = ZigClangType_isIncompleteOrZeroLengthArrayType;859 pub const isIncompleteOrZeroLengthArrayType = ZigClangType_isIncompleteOrZeroLengthArrayType;
841 extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(*const Type, *const ASTContext) bool;860 extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(*const Type, *const ASTContext) bool;
842861
...@@ -937,6 +956,14 @@ pub const VarDecl = opaque {...@@ -937,6 +956,14 @@ pub const VarDecl = opaque {
937 extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType;956 extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType;
938};957};
939958
959pub const VectorType = opaque {
960 pub const getElementType = ZigClangVectorType_getElementType;
961 extern fn ZigClangVectorType_getElementType(*const VectorType) QualType;
962
963 pub const getNumElements = ZigClangVectorType_getNumElements;
964 extern fn ZigClangVectorType_getNumElements(*const VectorType) c_uint;
965};
966
940pub const WhileStmt = opaque {967pub const WhileStmt = opaque {
941 pub const getCond = ZigClangWhileStmt_getCond;968 pub const getCond = ZigClangWhileStmt_getCond;
942 extern fn ZigClangWhileStmt_getCond(*const WhileStmt) *const Expr;969 extern fn ZigClangWhileStmt_getCond(*const WhileStmt) *const Expr;
src/codegen.zig+74-14
...@@ -417,7 +417,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -417,7 +417,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
417 const node_datas = tree.nodes.items(.data);417 const node_datas = tree.nodes.items(.data);
418 const token_starts = tree.tokens.items(.start);418 const token_starts = tree.tokens.items(.start);
419419
420 const fn_decl = tree.rootDecls()[module_fn.owner_decl.src_index];420 const fn_decl = module_fn.owner_decl.src_node;
421 assert(node_tags[fn_decl] == .fn_decl);421 assert(node_tags[fn_decl] == .fn_decl);
422 const block = node_datas[fn_decl].rhs;422 const block = node_datas[fn_decl].rhs;
423 const lbrace_src = token_starts[tree.firstToken(block)];423 const lbrace_src = token_starts[tree.firstToken(block)];
...@@ -855,6 +855,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -855,6 +855,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
855 .not => return self.genNot(inst.castTag(.not).?),855 .not => return self.genNot(inst.castTag(.not).?),
856 .mul => return self.genMul(inst.castTag(.mul).?),856 .mul => return self.genMul(inst.castTag(.mul).?),
857 .mulwrap => return self.genMulWrap(inst.castTag(.mulwrap).?),857 .mulwrap => return self.genMulWrap(inst.castTag(.mulwrap).?),
858 .div => return self.genDiv(inst.castTag(.div).?),
858 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),859 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
859 .ref => return self.genRef(inst.castTag(.ref).?),860 .ref => return self.genRef(inst.castTag(.ref).?),
860 .ret => return self.genRet(inst.castTag(.ret).?),861 .ret => return self.genRet(inst.castTag(.ret).?),
...@@ -1092,6 +1093,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1092,6 +1093,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1092 }1093 }
1093 }1094 }
10941095
1096 fn genDiv(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1097 // No side effects, so if it's unreferenced, do nothing.
1098 if (inst.base.isUnused())
1099 return MCValue.dead;
1100 switch (arch) {
1101 else => return self.fail(inst.base.src, "TODO implement div for {}", .{self.target.cpu.arch}),
1102 }
1103 }
1104
1095 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {1105 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1096 // No side effects, so if it's unreferenced, do nothing.1106 // No side effects, so if it's unreferenced, do nothing.
1097 if (inst.base.isUnused())1107 if (inst.base.isUnused())
...@@ -1735,7 +1745,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1735,7 +1745,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17351745
1736 switch (result) {1746 switch (result) {
1737 .register => |reg| {1747 .register => |reg| {
1738 try self.register_manager.getRegAssumeFree(toCanonicalReg(reg), &inst.base);1748 try self.register_manager.registers.ensureCapacity(self.gpa, self.register_manager.registers.count() + 1);
1749 self.register_manager.getRegAssumeFree(toCanonicalReg(reg), &inst.base);
1739 },1750 },
1740 else => {},1751 else => {},
1741 }1752 }
...@@ -1783,8 +1794,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1783,8 +1794,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1783 switch (mc_arg) {1794 switch (mc_arg) {
1784 .none => continue,1795 .none => continue,
1785 .register => |reg| {1796 .register => |reg| {
1797 try self.register_manager.getRegWithoutTracking(reg);
1786 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);1798 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1787 // TODO interact with the register allocator to mark the instruction as moved.
1788 },1799 },
1789 .stack_offset => {1800 .stack_offset => {
1790 // Here we need to emit instructions like this:1801 // Here we need to emit instructions like this:
...@@ -1925,8 +1936,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1925,8 +1936,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1925 .compare_flags_signed => unreachable,1936 .compare_flags_signed => unreachable,
1926 .compare_flags_unsigned => unreachable,1937 .compare_flags_unsigned => unreachable,
1927 .register => |reg| {1938 .register => |reg| {
1939 try self.register_manager.getRegWithoutTracking(reg);
1928 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);1940 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1929 // TODO interact with the register allocator to mark the instruction as moved.
1930 },1941 },
1931 .stack_offset => {1942 .stack_offset => {
1932 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});1943 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
...@@ -1988,8 +1999,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1988,8 +1999,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1988 .compare_flags_signed => unreachable,1999 .compare_flags_signed => unreachable,
1989 .compare_flags_unsigned => unreachable,2000 .compare_flags_unsigned => unreachable,
1990 .register => |reg| {2001 .register => |reg| {
2002 try self.register_manager.getRegWithoutTracking(reg);
1991 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);2003 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1992 // TODO interact with the register allocator to mark the instruction as moved.
1993 },2004 },
1994 .stack_offset => {2005 .stack_offset => {
1995 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});2006 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
...@@ -2039,8 +2050,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2039,8 +2050,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2039 switch (mc_arg) {2050 switch (mc_arg) {
2040 .none => continue,2051 .none => continue,
2041 .register => |reg| {2052 .register => |reg| {
2053 try self.register_manager.getRegWithoutTracking(reg);
2042 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);2054 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2043 // TODO interact with the register allocator to mark the instruction as moved.
2044 },2055 },
2045 .stack_offset => {2056 .stack_offset => {
2046 // Here we need to emit instructions like this:2057 // Here we need to emit instructions like this:
...@@ -2704,8 +2715,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2704,8 +2715,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2704 const reg_name = input[1 .. input.len - 1];2715 const reg_name = input[1 .. input.len - 1];
2705 const reg = parseRegName(reg_name) orelse2716 const reg = parseRegName(reg_name) orelse
2706 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2717 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2707 const arg = try self.resolveInst(inst.args[i]);2718
2708 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);2719 const arg = inst.args[i];
2720 const arg_mcv = try self.resolveInst(arg);
2721 try self.register_manager.getRegWithoutTracking(reg);
2722 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
2709 }2723 }
27102724
2711 if (mem.eql(u8, inst.asm_source, "svc #0")) {2725 if (mem.eql(u8, inst.asm_source, "svc #0")) {
...@@ -2734,8 +2748,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2734,8 +2748,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2734 const reg_name = input[1 .. input.len - 1];2748 const reg_name = input[1 .. input.len - 1];
2735 const reg = parseRegName(reg_name) orelse2749 const reg = parseRegName(reg_name) orelse
2736 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2750 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2737 const arg = try self.resolveInst(inst.args[i]);2751
2738 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);2752 const arg = inst.args[i];
2753 const arg_mcv = try self.resolveInst(arg);
2754 try self.register_manager.getRegWithoutTracking(reg);
2755 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
2739 }2756 }
27402757
2741 if (mem.eql(u8, inst.asm_source, "svc #0")) {2758 if (mem.eql(u8, inst.asm_source, "svc #0")) {
...@@ -2766,8 +2783,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2766,8 +2783,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2766 const reg_name = input[1 .. input.len - 1];2783 const reg_name = input[1 .. input.len - 1];
2767 const reg = parseRegName(reg_name) orelse2784 const reg = parseRegName(reg_name) orelse
2768 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2785 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2769 const arg = try self.resolveInst(inst.args[i]);2786
2770 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);2787 const arg = inst.args[i];
2788 const arg_mcv = try self.resolveInst(arg);
2789 try self.register_manager.getRegWithoutTracking(reg);
2790 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
2771 }2791 }
27722792
2773 if (mem.eql(u8, inst.asm_source, "ecall")) {2793 if (mem.eql(u8, inst.asm_source, "ecall")) {
...@@ -2796,8 +2816,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2796,8 +2816,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2796 const reg_name = input[1 .. input.len - 1];2816 const reg_name = input[1 .. input.len - 1];
2797 const reg = parseRegName(reg_name) orelse2817 const reg = parseRegName(reg_name) orelse
2798 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2818 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2799 const arg = try self.resolveInst(inst.args[i]);2819
2800 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);2820 const arg = inst.args[i];
2821 const arg_mcv = try self.resolveInst(arg);
2822 try self.register_manager.getRegWithoutTracking(reg);
2823 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
2801 }2824 }
28022825
2803 if (mem.eql(u8, inst.asm_source, "syscall")) {2826 if (mem.eql(u8, inst.asm_source, "syscall")) {
...@@ -3302,6 +3325,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3302,6 +3325,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3302 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());3325 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());
3303 }3326 }
3304 },3327 },
3328 .stack_offset => |unadjusted_off| {
3329 // TODO: maybe addressing from sp instead of fp
3330 const abi_size = ty.abiSize(self.target.*);
3331 const adj_off = unadjusted_off + abi_size;
3332
3333 const rn: Register = switch (arch) {
3334 .aarch64, .aarch64_be => .x29,
3335 .aarch64_32 => .w29,
3336 else => unreachable,
3337 };
3338
3339 const offset = if (math.cast(i9, adj_off)) |imm|
3340 Instruction.LoadStoreOffset.imm_post_index(-imm)
3341 else |_|
3342 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u64), MCValue{ .immediate = adj_off }));
3343
3344 switch (abi_size) {
3345 1, 2 => {
3346 const ldr = switch (abi_size) {
3347 1 => Instruction.ldrb,
3348 2 => Instruction.ldrh,
3349 else => unreachable, // unexpected abi size
3350 };
3351
3352 writeInt(u32, try self.code.addManyAsArray(4), ldr(reg, rn, .{
3353 .offset = offset,
3354 }).toU32());
3355 },
3356 4, 8 => {
3357 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{
3358 .rn = rn,
3359 .offset = offset,
3360 } }).toU32());
3361 },
3362 else => return self.fail(src, "TODO implement genSetReg other types abi_size={}", .{abi_size}),
3363 }
3364 },
3305 else => return self.fail(src, "TODO implement genSetReg for aarch64 {}", .{mcv}),3365 else => return self.fail(src, "TODO implement genSetReg for aarch64 {}", .{mcv}),
3306 },3366 },
3307 .riscv64 => switch (mcv) {3367 .riscv64 => switch (mcv) {
src/codegen/aarch64.zig+209-56
...@@ -200,7 +200,7 @@ test "FloatingPointRegister.toX" {...@@ -200,7 +200,7 @@ test "FloatingPointRegister.toX" {
200200
201/// Represents an instruction in the AArch64 instruction set201/// Represents an instruction in the AArch64 instruction set
202pub const Instruction = union(enum) {202pub const Instruction = union(enum) {
203 MoveWideImmediate: packed struct {203 move_wide_immediate: packed struct {
204 rd: u5,204 rd: u5,
205 imm16: u16,205 imm16: u16,
206 hw: u2,206 hw: u2,
...@@ -208,14 +208,14 @@ pub const Instruction = union(enum) {...@@ -208,14 +208,14 @@ pub const Instruction = union(enum) {
208 opc: u2,208 opc: u2,
209 sf: u1,209 sf: u1,
210 },210 },
211 PCRelativeAddress: packed struct {211 pc_relative_address: packed struct {
212 rd: u5,212 rd: u5,
213 immhi: u19,213 immhi: u19,
214 fixed: u5 = 0b10000,214 fixed: u5 = 0b10000,
215 immlo: u2,215 immlo: u2,
216 op: u1,216 op: u1,
217 },217 },
218 LoadStoreRegister: packed struct {218 load_store_register: packed struct {
219 rt: u5,219 rt: u5,
220 rn: u5,220 rn: u5,
221 offset: u12,221 offset: u12,
...@@ -225,7 +225,7 @@ pub const Instruction = union(enum) {...@@ -225,7 +225,7 @@ pub const Instruction = union(enum) {
225 fixed: u3 = 0b111,225 fixed: u3 = 0b111,
226 size: u2,226 size: u2,
227 },227 },
228 LoadStorePairOfRegisters: packed struct {228 load_store_register_pair: packed struct {
229 rt1: u5,229 rt1: u5,
230 rn: u5,230 rn: u5,
231 rt2: u5,231 rt2: u5,
...@@ -235,20 +235,20 @@ pub const Instruction = union(enum) {...@@ -235,20 +235,20 @@ pub const Instruction = union(enum) {
235 fixed: u5 = 0b101_0_0,235 fixed: u5 = 0b101_0_0,
236 opc: u2,236 opc: u2,
237 },237 },
238 LoadLiteral: packed struct {238 load_literal: packed struct {
239 rt: u5,239 rt: u5,
240 imm19: u19,240 imm19: u19,
241 fixed: u6 = 0b011_0_00,241 fixed: u6 = 0b011_0_00,
242 opc: u2,242 opc: u2,
243 },243 },
244 ExceptionGeneration: packed struct {244 exception_generation: packed struct {
245 ll: u2,245 ll: u2,
246 op2: u3,246 op2: u3,
247 imm16: u16,247 imm16: u16,
248 opc: u3,248 opc: u3,
249 fixed: u8 = 0b1101_0100,249 fixed: u8 = 0b1101_0100,
250 },250 },
251 UnconditionalBranchRegister: packed struct {251 unconditional_branch_register: packed struct {
252 op4: u5,252 op4: u5,
253 rn: u5,253 rn: u5,
254 op3: u6,254 op3: u6,
...@@ -256,15 +256,15 @@ pub const Instruction = union(enum) {...@@ -256,15 +256,15 @@ pub const Instruction = union(enum) {
256 opc: u4,256 opc: u4,
257 fixed: u7 = 0b1101_011,257 fixed: u7 = 0b1101_011,
258 },258 },
259 UnconditionalBranchImmediate: packed struct {259 unconditional_branch_immediate: packed struct {
260 imm26: u26,260 imm26: u26,
261 fixed: u5 = 0b00101,261 fixed: u5 = 0b00101,
262 op: u1,262 op: u1,
263 },263 },
264 NoOperation: packed struct {264 no_operation: packed struct {
265 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,265 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
266 },266 },
267 LogicalShiftedRegister: packed struct {267 logical_shifted_register: packed struct {
268 rd: u5,268 rd: u5,
269 rn: u5,269 rn: u5,
270 imm6: u6,270 imm6: u6,
...@@ -275,7 +275,7 @@ pub const Instruction = union(enum) {...@@ -275,7 +275,7 @@ pub const Instruction = union(enum) {
275 opc: u2,275 opc: u2,
276 sf: u1,276 sf: u1,
277 },277 },
278 AddSubtractImmediate: packed struct {278 add_subtract_immediate: packed struct {
279 rd: u5,279 rd: u5,
280 rn: u5,280 rn: u5,
281 imm12: u12,281 imm12: u12,
...@@ -285,6 +285,20 @@ pub const Instruction = union(enum) {...@@ -285,6 +285,20 @@ pub const Instruction = union(enum) {
285 op: u1,285 op: u1,
286 sf: u1,286 sf: u1,
287 },287 },
288 conditional_branch: struct {
289 cond: u4,
290 o0: u1,
291 imm19: u19,
292 o1: u1,
293 fixed: u7 = 0b0101010,
294 },
295 compare_and_branch: struct {
296 rt: u5,
297 imm19: u19,
298 op: u1,
299 fixed: u6 = 0b011010,
300 sf: u1,
301 },
288302
289 pub const Shift = struct {303 pub const Shift = struct {
290 shift: Type = .lsl,304 shift: Type = .lsl,
...@@ -303,19 +317,73 @@ pub const Instruction = union(enum) {...@@ -303,19 +317,73 @@ pub const Instruction = union(enum) {
303 };317 };
304 };318 };
305319
320 pub const Condition = enum(u4) {
321 /// Integer: Equal
322 /// Floating point: Equal
323 eq,
324 /// Integer: Not equal
325 /// Floating point: Not equal or unordered
326 ne,
327 /// Integer: Carry set
328 /// Floating point: Greater than, equal, or unordered
329 cs,
330 /// Integer: Carry clear
331 /// Floating point: Less than
332 cc,
333 /// Integer: Minus, negative
334 /// Floating point: Less than
335 mi,
336 /// Integer: Plus, positive or zero
337 /// Floating point: Greater than, equal, or unordered
338 pl,
339 /// Integer: Overflow
340 /// Floating point: Unordered
341 vs,
342 /// Integer: No overflow
343 /// Floating point: Ordered
344 vc,
345 /// Integer: Unsigned higher
346 /// Floating point: Greater than, or unordered
347 hi,
348 /// Integer: Unsigned lower or same
349 /// Floating point: Less than or equal
350 ls,
351 /// Integer: Signed greater than or equal
352 /// Floating point: Greater than or equal
353 ge,
354 /// Integer: Signed less than
355 /// Floating point: Less than, or unordered
356 lt,
357 /// Integer: Signed greater than
358 /// Floating point: Greater than
359 gt,
360 /// Integer: Signed less than or equal
361 /// Floating point: Less than, equal, or unordered
362 le,
363 /// Integer: Always
364 /// Floating point: Always
365 al,
366 /// Integer: Always
367 /// Floating point: Always
368 nv,
369 };
370
306 pub fn toU32(self: Instruction) u32 {371 pub fn toU32(self: Instruction) u32 {
307 return switch (self) {372 return switch (self) {
308 .MoveWideImmediate => |v| @bitCast(u32, v),373 .move_wide_immediate => |v| @bitCast(u32, v),
309 .PCRelativeAddress => |v| @bitCast(u32, v),374 .pc_relative_address => |v| @bitCast(u32, v),
310 .LoadStoreRegister => |v| @bitCast(u32, v),375 .load_store_register => |v| @bitCast(u32, v),
311 .LoadStorePairOfRegisters => |v| @bitCast(u32, v),376 .load_store_register_pair => |v| @bitCast(u32, v),
312 .LoadLiteral => |v| @bitCast(u32, v),377 .load_literal => |v| @bitCast(u32, v),
313 .ExceptionGeneration => |v| @bitCast(u32, v),378 .exception_generation => |v| @bitCast(u32, v),
314 .UnconditionalBranchRegister => |v| @bitCast(u32, v),379 .unconditional_branch_register => |v| @bitCast(u32, v),
315 .UnconditionalBranchImmediate => |v| @bitCast(u32, v),380 .unconditional_branch_immediate => |v| @bitCast(u32, v),
316 .NoOperation => |v| @bitCast(u32, v),381 .no_operation => |v| @bitCast(u32, v),
317 .LogicalShiftedRegister => |v| @bitCast(u32, v),382 .logical_shifted_register => |v| @bitCast(u32, v),
318 .AddSubtractImmediate => |v| @bitCast(u32, v),383 .add_subtract_immediate => |v| @bitCast(u32, v),
384 // TODO once packed structs work, this can be refactored
385 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
386 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
319 };387 };
320 }388 }
321389
...@@ -329,7 +397,7 @@ pub const Instruction = union(enum) {...@@ -329,7 +397,7 @@ pub const Instruction = union(enum) {
329 32 => {397 32 => {
330 assert(shift % 16 == 0 and shift <= 16);398 assert(shift % 16 == 0 and shift <= 16);
331 return Instruction{399 return Instruction{
332 .MoveWideImmediate = .{400 .move_wide_immediate = .{
333 .rd = rd.id(),401 .rd = rd.id(),
334 .imm16 = imm16,402 .imm16 = imm16,
335 .hw = @intCast(u2, shift / 16),403 .hw = @intCast(u2, shift / 16),
...@@ -341,7 +409,7 @@ pub const Instruction = union(enum) {...@@ -341,7 +409,7 @@ pub const Instruction = union(enum) {
341 64 => {409 64 => {
342 assert(shift % 16 == 0 and shift <= 48);410 assert(shift % 16 == 0 and shift <= 48);
343 return Instruction{411 return Instruction{
344 .MoveWideImmediate = .{412 .move_wide_immediate = .{
345 .rd = rd.id(),413 .rd = rd.id(),
346 .imm16 = imm16,414 .imm16 = imm16,
347 .hw = @intCast(u2, shift / 16),415 .hw = @intCast(u2, shift / 16),
...@@ -358,7 +426,7 @@ pub const Instruction = union(enum) {...@@ -358,7 +426,7 @@ pub const Instruction = union(enum) {
358 assert(rd.size() == 64);426 assert(rd.size() == 64);
359 const imm21_u = @bitCast(u21, imm21);427 const imm21_u = @bitCast(u21, imm21);
360 return Instruction{428 return Instruction{
361 .PCRelativeAddress = .{429 .pc_relative_address = .{
362 .rd = rd.id(),430 .rd = rd.id(),
363 .immlo = @truncate(u2, imm21_u),431 .immlo = @truncate(u2, imm21_u),
364 .immhi = @truncate(u19, imm21_u >> 2),432 .immhi = @truncate(u19, imm21_u >> 2),
...@@ -487,11 +555,17 @@ pub const Instruction = union(enum) {...@@ -487,11 +555,17 @@ pub const Instruction = union(enum) {
487 /// Which kind of load/store to perform555 /// Which kind of load/store to perform
488 const LoadStoreVariant = enum {556 const LoadStoreVariant = enum {
489 /// 32-bit or 64-bit557 /// 32-bit or 64-bit
490 normal,558 str,
491 /// 16-bit559 /// 16-bit, zero-extended
492 half,560 strh,
493 /// 8-bit561 /// 8-bit, zero-extended
494 byte,562 strb,
563 /// 32-bit or 64-bit
564 ldr,
565 /// 16-bit, zero-extended
566 ldrh,
567 /// 8-bit, zero-extended
568 ldrb,
495 };569 };
496570
497 fn loadStoreRegister(571 fn loadStoreRegister(
...@@ -499,7 +573,6 @@ pub const Instruction = union(enum) {...@@ -499,7 +573,6 @@ pub const Instruction = union(enum) {
499 rn: Register,573 rn: Register,
500 offset: LoadStoreOffset,574 offset: LoadStoreOffset,
501 variant: LoadStoreVariant,575 variant: LoadStoreVariant,
502 load: bool,
503 ) Instruction {576 ) Instruction {
504 const off = offset.toU12();577 const off = offset.toU12();
505 const op1: u2 = blk: {578 const op1: u2 = blk: {
...@@ -512,9 +585,12 @@ pub const Instruction = union(enum) {...@@ -512,9 +585,12 @@ pub const Instruction = union(enum) {
512 }585 }
513 break :blk 0b00;586 break :blk 0b00;
514 };587 };
515 const opc: u2 = if (load) 0b01 else 0b00;588 const opc: u2 = switch (variant) {
589 .ldr, .ldrh, .ldrb => 0b01,
590 .str, .strh, .strb => 0b00,
591 };
516 return Instruction{592 return Instruction{
517 .LoadStoreRegister = .{593 .load_store_register = .{
518 .rt = rt.id(),594 .rt = rt.id(),
519 .rn = rn.id(),595 .rn = rn.id(),
520 .offset = off,596 .offset = off,
...@@ -523,20 +599,20 @@ pub const Instruction = union(enum) {...@@ -523,20 +599,20 @@ pub const Instruction = union(enum) {
523 .v = 0,599 .v = 0,
524 .size = blk: {600 .size = blk: {
525 switch (variant) {601 switch (variant) {
526 .normal => switch (rt.size()) {602 .ldr, .str => switch (rt.size()) {
527 32 => break :blk 0b10,603 32 => break :blk 0b10,
528 64 => break :blk 0b11,604 64 => break :blk 0b11,
529 else => unreachable, // unexpected register size605 else => unreachable, // unexpected register size
530 },606 },
531 .half => break :blk 0b01,607 .ldrh, .strh => break :blk 0b01,
532 .byte => break :blk 0b00,608 .ldrb, .strb => break :blk 0b00,
533 }609 }
534 },610 },
535 },611 },
536 };612 };
537 }613 }
538614
539 fn loadStorePairOfRegisters(615 fn loadStoreRegisterPair(
540 rt1: Register,616 rt1: Register,
541 rt2: Register,617 rt2: Register,
542 rn: Register,618 rn: Register,
...@@ -549,7 +625,7 @@ pub const Instruction = union(enum) {...@@ -549,7 +625,7 @@ pub const Instruction = union(enum) {
549 assert(-256 <= offset and offset <= 252);625 assert(-256 <= offset and offset <= 252);
550 const imm7 = @truncate(u7, @bitCast(u9, offset >> 2));626 const imm7 = @truncate(u7, @bitCast(u9, offset >> 2));
551 return Instruction{627 return Instruction{
552 .LoadStorePairOfRegisters = .{628 .load_store_register_pair = .{
553 .rt1 = rt1.id(),629 .rt1 = rt1.id(),
554 .rn = rn.id(),630 .rn = rn.id(),
555 .rt2 = rt2.id(),631 .rt2 = rt2.id(),
...@@ -564,7 +640,7 @@ pub const Instruction = union(enum) {...@@ -564,7 +640,7 @@ pub const Instruction = union(enum) {
564 assert(-512 <= offset and offset <= 504);640 assert(-512 <= offset and offset <= 504);
565 const imm7 = @truncate(u7, @bitCast(u9, offset >> 3));641 const imm7 = @truncate(u7, @bitCast(u9, offset >> 3));
566 return Instruction{642 return Instruction{
567 .LoadStorePairOfRegisters = .{643 .load_store_register_pair = .{
568 .rt1 = rt1.id(),644 .rt1 = rt1.id(),
569 .rn = rn.id(),645 .rn = rn.id(),
570 .rt2 = rt2.id(),646 .rt2 = rt2.id(),
...@@ -583,7 +659,7 @@ pub const Instruction = union(enum) {...@@ -583,7 +659,7 @@ pub const Instruction = union(enum) {
583 switch (rt.size()) {659 switch (rt.size()) {
584 32 => {660 32 => {
585 return Instruction{661 return Instruction{
586 .LoadLiteral = .{662 .load_literal = .{
587 .rt = rt.id(),663 .rt = rt.id(),
588 .imm19 = imm19,664 .imm19 = imm19,
589 .opc = 0b00,665 .opc = 0b00,
...@@ -592,7 +668,7 @@ pub const Instruction = union(enum) {...@@ -592,7 +668,7 @@ pub const Instruction = union(enum) {
592 },668 },
593 64 => {669 64 => {
594 return Instruction{670 return Instruction{
595 .LoadLiteral = .{671 .load_literal = .{
596 .rt = rt.id(),672 .rt = rt.id(),
597 .imm19 = imm19,673 .imm19 = imm19,
598 .opc = 0b01,674 .opc = 0b01,
...@@ -610,7 +686,7 @@ pub const Instruction = union(enum) {...@@ -610,7 +686,7 @@ pub const Instruction = union(enum) {
610 imm16: u16,686 imm16: u16,
611 ) Instruction {687 ) Instruction {
612 return Instruction{688 return Instruction{
613 .ExceptionGeneration = .{689 .exception_generation = .{
614 .ll = ll,690 .ll = ll,
615 .op2 = op2,691 .op2 = op2,
616 .imm16 = imm16,692 .imm16 = imm16,
...@@ -629,7 +705,7 @@ pub const Instruction = union(enum) {...@@ -629,7 +705,7 @@ pub const Instruction = union(enum) {
629 assert(rn.size() == 64);705 assert(rn.size() == 64);
630706
631 return Instruction{707 return Instruction{
632 .UnconditionalBranchRegister = .{708 .unconditional_branch_register = .{
633 .op4 = op4,709 .op4 = op4,
634 .rn = rn.id(),710 .rn = rn.id(),
635 .op3 = op3,711 .op3 = op3,
...@@ -644,7 +720,7 @@ pub const Instruction = union(enum) {...@@ -644,7 +720,7 @@ pub const Instruction = union(enum) {
644 offset: i28,720 offset: i28,
645 ) Instruction {721 ) Instruction {
646 return Instruction{722 return Instruction{
647 .UnconditionalBranchImmediate = .{723 .unconditional_branch_immediate = .{
648 .imm26 = @bitCast(u26, @intCast(i26, offset >> 2)),724 .imm26 = @bitCast(u26, @intCast(i26, offset >> 2)),
649 .op = op,725 .op = op,
650 },726 },
...@@ -663,7 +739,7 @@ pub const Instruction = union(enum) {...@@ -663,7 +739,7 @@ pub const Instruction = union(enum) {
663 32 => {739 32 => {
664 assert(shift.amount < 32);740 assert(shift.amount < 32);
665 return Instruction{741 return Instruction{
666 .LogicalShiftedRegister = .{742 .logical_shifted_register = .{
667 .rd = rd.id(),743 .rd = rd.id(),
668 .rn = rn.id(),744 .rn = rn.id(),
669 .imm6 = shift.amount,745 .imm6 = shift.amount,
...@@ -677,7 +753,7 @@ pub const Instruction = union(enum) {...@@ -677,7 +753,7 @@ pub const Instruction = union(enum) {
677 },753 },
678 64 => {754 64 => {
679 return Instruction{755 return Instruction{
680 .LogicalShiftedRegister = .{756 .logical_shifted_register = .{
681 .rd = rd.id(),757 .rd = rd.id(),
682 .rn = rn.id(),758 .rn = rn.id(),
683 .imm6 = shift.amount,759 .imm6 = shift.amount,
...@@ -702,7 +778,7 @@ pub const Instruction = union(enum) {...@@ -702,7 +778,7 @@ pub const Instruction = union(enum) {
702 shift: bool,778 shift: bool,
703 ) Instruction {779 ) Instruction {
704 return Instruction{780 return Instruction{
705 .AddSubtractImmediate = .{781 .add_subtract_immediate = .{
706 .rd = rd.id(),782 .rd = rd.id(),
707 .rn = rn.id(),783 .rn = rn.id(),
708 .imm12 = imm12,784 .imm12 = imm12,
...@@ -718,6 +794,43 @@ pub const Instruction = union(enum) {...@@ -718,6 +794,43 @@ pub const Instruction = union(enum) {
718 };794 };
719 }795 }
720796
797 fn conditionalBranch(
798 o0: u1,
799 o1: u1,
800 cond: Condition,
801 offset: i21,
802 ) Instruction {
803 assert(offset & 0b11 == 0b00);
804 return Instruction{
805 .conditional_branch = .{
806 .cond = @enumToInt(cond),
807 .o0 = o0,
808 .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)),
809 .o1 = o1,
810 },
811 };
812 }
813
814 fn compareAndBranch(
815 op: u1,
816 rt: Register,
817 offset: i21,
818 ) Instruction {
819 assert(offset & 0b11 == 0b00);
820 return Instruction{
821 .compare_and_branch = .{
822 .rt = rt.id(),
823 .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)),
824 .op = op,
825 .sf = switch (rt.size()) {
826 32 => 0b0,
827 64 => 0b1,
828 else => unreachable, // unexpected register size
829 },
830 },
831 };
832 }
833
721 // Helper functions for assembly syntax functions834 // Helper functions for assembly syntax functions
722835
723 // Move wide (immediate)836 // Move wide (immediate)
...@@ -756,25 +869,33 @@ pub const Instruction = union(enum) {...@@ -756,25 +869,33 @@ pub const Instruction = union(enum) {
756869
757 pub fn ldr(rt: Register, args: LdrArgs) Instruction {870 pub fn ldr(rt: Register, args: LdrArgs) Instruction {
758 switch (args) {871 switch (args) {
759 .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .normal, true),872 .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .ldr),
760 .literal => |literal| return loadLiteral(rt, literal),873 .literal => |literal| return loadLiteral(rt, literal),
761 }874 }
762 }875 }
763876
877 pub fn ldrh(rt: Register, rn: Register, args: StrArgs) Instruction {
878 return loadStoreRegister(rt, rn, args.offset, .ldrh);
879 }
880
881 pub fn ldrb(rt: Register, rn: Register, args: StrArgs) Instruction {
882 return loadStoreRegister(rt, rn, args.offset, .ldrb);
883 }
884
764 pub const StrArgs = struct {885 pub const StrArgs = struct {
765 offset: LoadStoreOffset = LoadStoreOffset.none,886 offset: LoadStoreOffset = LoadStoreOffset.none,
766 };887 };
767888
768 pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {889 pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
769 return loadStoreRegister(rt, rn, args.offset, .normal, false);890 return loadStoreRegister(rt, rn, args.offset, .str);
770 }891 }
771892
772 pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction {893 pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction {
773 return loadStoreRegister(rt, rn, args.offset, .half, false);894 return loadStoreRegister(rt, rn, args.offset, .strh);
774 }895 }
775896
776 pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction {897 pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction {
777 return loadStoreRegister(rt, rn, args.offset, .byte, false);898 return loadStoreRegister(rt, rn, args.offset, .strb);
778 }899 }
779900
780 // Load or store pair of registers901 // Load or store pair of registers
...@@ -805,19 +926,19 @@ pub const Instruction = union(enum) {...@@ -805,19 +926,19 @@ pub const Instruction = union(enum) {
805 };926 };
806927
807 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {928 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
808 return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true);929 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true);
809 }930 }
810931
811 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {932 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
812 return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true);933 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true);
813 }934 }
814935
815 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {936 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
816 return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false);937 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false);
817 }938 }
818939
819 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {940 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
820 return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, false);941 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false);
821 }942 }
822943
823 // Exception generation944 // Exception generation
...@@ -869,7 +990,7 @@ pub const Instruction = union(enum) {...@@ -869,7 +990,7 @@ pub const Instruction = union(enum) {
869 // Nop990 // Nop
870991
871 pub fn nop() Instruction {992 pub fn nop() Instruction {
872 return Instruction{ .NoOperation = .{} };993 return Instruction{ .no_operation = .{} };
873 }994 }
874995
875 // Logical (shifted register)996 // Logical (shifted register)
...@@ -923,6 +1044,22 @@ pub const Instruction = union(enum) {...@@ -923,6 +1044,22 @@ pub const Instruction = union(enum) {
923 pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {1044 pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
924 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);1045 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
925 }1046 }
1047
1048 // Conditional branch
1049
1050 pub fn bCond(cond: Condition, offset: i21) Instruction {
1051 return conditionalBranch(0b0, 0b0, cond, offset);
1052 }
1053
1054 // Compare and branch
1055
1056 pub fn cbz(rt: Register, offset: i21) Instruction {
1057 return compareAndBranch(0b0, rt, offset);
1058 }
1059
1060 pub fn cbnz(rt: Register, offset: i21) Instruction {
1061 return compareAndBranch(0b1, rt, offset);
1062 }
926};1063};
9271064
928test {1065test {
...@@ -1004,6 +1141,14 @@ test "serialize instructions" {...@@ -1004,6 +1141,14 @@ test "serialize instructions" {
1004 .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }),1141 .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }),
1005 .expected = 0b01_011_0_00_0000000000000000001_00010,1142 .expected = 0b01_011_0_00_0000000000000000001_00010,
1006 },1143 },
1144 .{ // ldrh x7, [x4], #0xaa
1145 .inst = Instruction.ldrh(.x7, .x4, .{ .offset = Instruction.LoadStoreOffset.imm_post_index(0xaa) }),
1146 .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111,
1147 },
1148 .{ // ldrb x9, [x15, #0xff]!
1149 .inst = Instruction.ldrb(.x9, .x15, .{ .offset = Instruction.LoadStoreOffset.imm_pre_index(0xff) }),
1150 .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001,
1151 },
1007 .{ // str x2, [x1]1152 .{ // str x2, [x1]
1008 .inst = Instruction.str(.x2, .x1, .{}),1153 .inst = Instruction.str(.x2, .x1, .{}),
1009 .expected = 0b11_111_0_01_00_000000000000_00001_00010,1154 .expected = 0b11_111_0_01_00_000000000000_00001_00010,
...@@ -1068,6 +1213,14 @@ test "serialize instructions" {...@@ -1068,6 +1213,14 @@ test "serialize instructions" {
1068 .inst = Instruction.subs(.x0, .x5, 11, true),1213 .inst = Instruction.subs(.x0, .x5, 11, true),
1069 .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000,1214 .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000,
1070 },1215 },
1216 .{ // b.hi #-4
1217 .inst = Instruction.bCond(.hi, -4),
1218 .expected = 0b0101010_0_1111111111111111111_0_1000,
1219 },
1220 .{ // cbz x10, #40
1221 .inst = Instruction.cbz(.x10, 40),
1222 .expected = 0b1_011010_0_0000000000000001010_01010,
1223 },
1071 };1224 };
10721225
1073 for (testcases) |case| {1226 for (testcases) |case| {
src/codegen/c.zig+164-17
...@@ -44,22 +44,34 @@ fn formatTypeAsCIdentifier(...@@ -44,22 +44,34 @@ fn formatTypeAsCIdentifier(
44 var buffer = [1]u8{0} ** 128;44 var buffer = [1]u8{0} ** 128;
45 // We don't care if it gets cut off, it's still more unique than a number45 // We don't care if it gets cut off, it's still more unique than a number
46 var buf = std.fmt.bufPrint(&buffer, "{}", .{data}) catch &buffer;46 var buf = std.fmt.bufPrint(&buffer, "{}", .{data}) catch &buffer;
47 return formatIdent(buf, "", .{}, writer);
48}
49
50pub fn typeToCIdentifier(t: Type) std.fmt.Formatter(formatTypeAsCIdentifier) {
51 return .{ .data = t };
52}
4753
48 for (buf) |c, i| {54fn formatIdent(
55 ident: []const u8,
56 comptime fmt: []const u8,
57 options: std.fmt.FormatOptions,
58 writer: anytype,
59) !void {
60 for (ident) |c, i| {
49 switch (c) {61 switch (c) {
50 0 => return writer.writeAll(buf[0..i]),62 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),
51 'a'...'z', 'A'...'Z', '_', '$' => {},
52 '0'...'9' => if (i == 0) {63 '0'...'9' => if (i == 0) {
53 buf[i] = '_';64 try writer.print("${x:2}", .{c});
65 } else {
66 try writer.writeByte(c);
54 },67 },
55 else => buf[i] = '_',68 else => try writer.print("${x:2}", .{c}),
56 }69 }
57 }70 }
58 return writer.writeAll(buf);
59}71}
6072
61pub fn typeToCIdentifier(t: Type) std.fmt.Formatter(formatTypeAsCIdentifier) {73pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
62 return .{ .data = t };74 return .{ .data = ident };
63}75}
6476
65/// This data is available when outputting .c code for a Module.77/// This data is available when outputting .c code for a Module.
...@@ -160,7 +172,10 @@ pub const DeclGen = struct {...@@ -160,7 +172,10 @@ pub const DeclGen = struct {
160 val: Value,172 val: Value,
161 ) error{ OutOfMemory, AnalysisFail }!void {173 ) error{ OutOfMemory, AnalysisFail }!void {
162 if (val.isUndef()) {174 if (val.isUndef()) {
163 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{});175 // This should lower to 0xaa bytes in safe modes, and for unsafe modes should
176 // lower to leaving variables uninitialized (that might need to be implemented
177 // outside of this function).
178 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement renderValue undef", .{});
164 }179 }
165 switch (t.zigTypeTag()) {180 switch (t.zigTypeTag()) {
166 .Int => {181 .Int => {
...@@ -276,6 +291,31 @@ pub const DeclGen = struct {...@@ -276,6 +291,31 @@ pub const DeclGen = struct {
276 try writer.writeAll(", .error = 0 }");291 try writer.writeAll(", .error = 0 }");
277 }292 }
278 },293 },
294 .Enum => {
295 switch (val.tag()) {
296 .enum_field_index => {
297 const field_index = val.castTag(.enum_field_index).?.data;
298 switch (t.tag()) {
299 .enum_simple => return writer.print("{d}", .{field_index}),
300 .enum_full, .enum_nonexhaustive => {
301 const enum_full = t.cast(Type.Payload.EnumFull).?.data;
302 if (enum_full.values.count() != 0) {
303 const tag_val = enum_full.values.entries.items[field_index].key;
304 return dg.renderValue(writer, enum_full.tag_ty, tag_val);
305 } else {
306 return writer.print("{d}", .{field_index});
307 }
308 },
309 else => unreachable,
310 }
311 },
312 else => {
313 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
314 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
315 return dg.renderValue(writer, int_tag_ty, val);
316 },
317 }
318 },
279 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{319 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
280 @tagName(e),320 @tagName(e),
281 }),321 }),
...@@ -356,6 +396,9 @@ pub const DeclGen = struct {...@@ -356,6 +396,9 @@ pub const DeclGen = struct {
356 else => unreachable,396 else => unreachable,
357 }397 }
358 },398 },
399
400 .Float => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Float", .{}),
401
359 .Pointer => {402 .Pointer => {
360 if (t.isSlice()) {403 if (t.isSlice()) {
361 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});404 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});
...@@ -430,10 +473,59 @@ pub const DeclGen = struct {...@@ -430,10 +473,59 @@ pub const DeclGen = struct {
430 try w.writeAll(name);473 try w.writeAll(name);
431 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });474 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
432 },475 },
433 .Null, .Undefined => unreachable, // must be const or comptime476 .Struct => {
434 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{477 if (dg.typedefs.get(t)) |some| {
435 @tagName(e),478 return w.writeAll(some.name);
436 }),479 }
480 const struct_obj = t.castTag(.@"struct").?.data; // Handle 0 bit types elsewhere.
481 const fqn = try struct_obj.getFullyQualifiedName(dg.typedefs.allocator);
482 defer dg.typedefs.allocator.free(fqn);
483
484 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
485 defer buffer.deinit();
486
487 try buffer.appendSlice("typedef struct {\n");
488 for (struct_obj.fields.entries.items) |entry| {
489 try buffer.append(' ');
490 try dg.renderType(buffer.writer(), entry.value.ty);
491 try buffer.writer().print(" {s};\n", .{fmtIdent(entry.key)});
492 }
493 try buffer.appendSlice("} ");
494
495 const name_start = buffer.items.len;
496 try buffer.writer().print("zig_S_{s};\n", .{fmtIdent(fqn)});
497
498 const rendered = buffer.toOwnedSlice();
499 errdefer dg.typedefs.allocator.free(rendered);
500 const name = rendered[name_start .. rendered.len - 2];
501
502 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);
503 try w.writeAll(name);
504 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
505 },
506 .Enum => {
507 // For enums, we simply use the integer tag type.
508 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
509 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
510
511 try dg.renderType(w, int_tag_ty);
512 },
513 .Union => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Union", .{}),
514 .Fn => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Fn", .{}),
515 .Opaque => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Opaque", .{}),
516 .Frame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Frame", .{}),
517 .AnyFrame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type AnyFrame", .{}),
518 .Vector => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Vector", .{}),
519
520 .Null,
521 .Undefined,
522 .EnumLiteral,
523 .ComptimeFloat,
524 .ComptimeInt,
525 .Type,
526 => unreachable, // must be const or comptime
527
528 .BoundFn => unreachable, // this type will be deleted from the language
437 }529 }
438 }530 }
439531
...@@ -525,8 +617,26 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -525,8 +617,26 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
525617
526 for (body.instructions) |inst| {618 for (body.instructions) |inst| {
527 const result_value = switch (inst.tag) {619 const result_value = switch (inst.tag) {
528 .constant => unreachable, // excluded from function bodies620 // TODO use a different strategy for add that communicates to the optimizer
621 // that wrapping is UB.
529 .add => try genBinOp(o, inst.castTag(.add).?, " + "),622 .add => try genBinOp(o, inst.castTag(.add).?, " + "),
623 // TODO make this do wrapping arithmetic for signed ints
624 .addwrap => try genBinOp(o, inst.castTag(.add).?, " + "),
625 // TODO use a different strategy for sub that communicates to the optimizer
626 // that wrapping is UB.
627 .sub => try genBinOp(o, inst.castTag(.sub).?, " - "),
628 // TODO make this do wrapping arithmetic for signed ints
629 .subwrap => try genBinOp(o, inst.castTag(.sub).?, " - "),
630 // TODO use a different strategy for mul that communicates to the optimizer
631 // that wrapping is UB.
632 .mul => try genBinOp(o, inst.castTag(.sub).?, " * "),
633 // TODO make this do wrapping multiplication for signed ints
634 .mulwrap => try genBinOp(o, inst.castTag(.sub).?, " * "),
635 // TODO use a different strategy for div that communicates to the optimizer
636 // that wrapping is UB.
637 .div => try genBinOp(o, inst.castTag(.div).?, " / "),
638
639 .constant => unreachable, // excluded from function bodies
530 .alloc => try genAlloc(o, inst.castTag(.alloc).?),640 .alloc => try genAlloc(o, inst.castTag(.alloc).?),
531 .arg => genArg(o),641 .arg => genArg(o),
532 .assembly => try genAsm(o, inst.castTag(.assembly).?),642 .assembly => try genAsm(o, inst.castTag(.assembly).?),
...@@ -546,7 +656,6 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -546,7 +656,6 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
546 .ret => try genRet(o, inst.castTag(.ret).?),656 .ret => try genRet(o, inst.castTag(.ret).?),
547 .retvoid => try genRetVoid(o),657 .retvoid => try genRetVoid(o),
548 .store => try genStore(o, inst.castTag(.store).?),658 .store => try genStore(o, inst.castTag(.store).?),
549 .sub => try genBinOp(o, inst.castTag(.sub).?, " - "),
550 .unreach => try genUnreach(o, inst.castTag(.unreach).?),659 .unreach => try genUnreach(o, inst.castTag(.unreach).?),
551 .loop => try genLoop(o, inst.castTag(.loop).?),660 .loop => try genLoop(o, inst.castTag(.loop).?),
552 .condbr => try genCondBr(o, inst.castTag(.condbr).?),661 .condbr => try genCondBr(o, inst.castTag(.condbr).?),
...@@ -567,17 +676,24 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -567,17 +676,24 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
567 .wrap_optional => try genWrapOptional(o, inst.castTag(.wrap_optional).?),676 .wrap_optional => try genWrapOptional(o, inst.castTag(.wrap_optional).?),
568 .optional_payload => try genOptionalPayload(o, inst.castTag(.optional_payload).?),677 .optional_payload => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
569 .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload_ptr).?),678 .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload_ptr).?),
679 .ref => try genRef(o, inst.castTag(.ref).?),
680 .struct_field_ptr => try genStructFieldPtr(o, inst.castTag(.struct_field_ptr).?),
681
570 .is_err => try genIsErr(o, inst.castTag(.is_err).?),682 .is_err => try genIsErr(o, inst.castTag(.is_err).?),
571 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),683 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),
572 .error_to_int => try genErrorToInt(o, inst.castTag(.error_to_int).?),684 .error_to_int => try genErrorToInt(o, inst.castTag(.error_to_int).?),
573 .int_to_error => try genIntToError(o, inst.castTag(.int_to_error).?),685 .int_to_error => try genIntToError(o, inst.castTag(.int_to_error).?),
686
574 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),687 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
575 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),688 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
576 .unwrap_errunion_payload_ptr => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload_ptr).?),689 .unwrap_errunion_payload_ptr => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload_ptr).?),
577 .unwrap_errunion_err_ptr => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err_ptr).?),690 .unwrap_errunion_err_ptr => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err_ptr).?),
578 .wrap_errunion_payload => try genWrapErrUnionPay(o, inst.castTag(.wrap_errunion_payload).?),691 .wrap_errunion_payload => try genWrapErrUnionPay(o, inst.castTag(.wrap_errunion_payload).?),
579 .wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?),692 .wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?),
580 else => |e| return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for {}", .{e}),693 .br_block_flat => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for br_block_flat", .{}),
694 .ptrtoint => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for ptrtoint", .{}),
695 .varptr => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for varptr", .{}),
696 .floatcast => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for floatcast", .{}),
581 };697 };
582 switch (result_value) {698 switch (result_value) {
583 .none => {},699 .none => {},
...@@ -996,6 +1112,37 @@ fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -996,6 +1112,37 @@ fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue {
996 return local;1112 return local;
997}1113}
9981114
1115fn genRef(o: *Object, inst: *Inst.UnOp) !CValue {
1116 const writer = o.writer();
1117 const operand = try o.resolveInst(inst.operand);
1118
1119 const local = try o.allocLocal(inst.base.ty, .Const);
1120 try writer.writeAll(" = ");
1121 try o.writeCValue(writer, operand);
1122 try writer.writeAll(";\n");
1123 return local;
1124}
1125
1126fn genStructFieldPtr(o: *Object, inst: *Inst.StructFieldPtr) !CValue {
1127 const writer = o.writer();
1128 const struct_ptr = try o.resolveInst(inst.struct_ptr);
1129 const struct_obj = inst.struct_ptr.ty.elemType().castTag(.@"struct").?.data;
1130 const field_name = struct_obj.fields.entries.items[inst.field_index].key;
1131
1132 const local = try o.allocLocal(inst.base.ty, .Const);
1133 switch (struct_ptr) {
1134 .local_ref => |i| {
1135 try writer.print(" = &t{d}.{};\n", .{ i, fmtIdent(field_name) });
1136 },
1137 else => {
1138 try writer.writeAll(" = &");
1139 try o.writeCValue(writer, struct_ptr);
1140 try writer.print("->{};\n", .{fmtIdent(field_name)});
1141 },
1142 }
1143 return local;
1144}
1145
999// *(E!T) -> E NOT *E1146// *(E!T) -> E NOT *E
1000fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {1147fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {
1001 const writer = o.writer();1148 const writer = o.writer();
...@@ -1088,7 +1235,7 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {...@@ -1088,7 +1235,7 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {
1088 pub const Error = UnderlyingWriter.Error;1235 pub const Error = UnderlyingWriter.Error;
1089 pub const Writer = std.io.Writer(*Self, Error, write);1236 pub const Writer = std.io.Writer(*Self, Error, write);
10901237
1091 pub const indent_delta = 4;1238 pub const indent_delta = 1;
10921239
1093 underlying_writer: UnderlyingWriter,1240 underlying_writer: UnderlyingWriter,
1094 indent_count: usize = 0,1241 indent_count: usize = 0,
src/codegen/llvm.zig-1
...@@ -76,7 +76,6 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {...@@ -76,7 +76,6 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
76 .spirv32 => return error.LLVMBackendDoesNotSupportSPIRV,76 .spirv32 => return error.LLVMBackendDoesNotSupportSPIRV,
77 .spirv64 => return error.LLVMBackendDoesNotSupportSPIRV,77 .spirv64 => return error.LLVMBackendDoesNotSupportSPIRV,
78 };78 };
79 // TODO Add a sub-arch for some architectures depending on CPU features.
8079
81 const llvm_os = switch (target.os.tag) {80 const llvm_os = switch (target.os.tag) {
82 .freestanding => "unknown",81 .freestanding => "unknown",
src/codegen/wasm.zig+623-139
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
2const Allocator = std.mem.Allocator;2const Allocator = std.mem.Allocator;
3const ArrayList = std.ArrayList;3const ArrayList = std.ArrayList;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const testing = std.testing;
5const leb = std.leb;6const leb = std.leb;
6const mem = std.mem;7const mem = std.mem;
7const wasm = std.wasm;8const wasm = std.wasm;
...@@ -15,9 +16,12 @@ const Value = @import("../value.zig").Value;...@@ -15,9 +16,12 @@ const Value = @import("../value.zig").Value;
15const Compilation = @import("../Compilation.zig");16const Compilation = @import("../Compilation.zig");
16const AnyMCValue = @import("../codegen.zig").AnyMCValue;17const AnyMCValue = @import("../codegen.zig").AnyMCValue;
17const LazySrcLoc = Module.LazySrcLoc;18const LazySrcLoc = Module.LazySrcLoc;
19const link = @import("../link.zig");
20const TypedValue = @import("../TypedValue.zig");
1821
19/// Wasm Value, created when generating an instruction22/// Wasm Value, created when generating an instruction
20const WValue = union(enum) {23const WValue = union(enum) {
24 /// May be referenced but is unused
21 none: void,25 none: void,
22 /// Index of the local variable26 /// Index of the local variable
23 local: u32,27 local: u32,
...@@ -29,6 +33,450 @@ const WValue = union(enum) {...@@ -29,6 +33,450 @@ const WValue = union(enum) {
29 block_idx: u32,33 block_idx: u32,
30};34};
3135
36/// Wasm ops, but without input/output/signedness information
37/// Used for `buildOpcode`
38const Op = enum {
39 @"unreachable",
40 nop,
41 block,
42 loop,
43 @"if",
44 @"else",
45 end,
46 br,
47 br_if,
48 br_table,
49 @"return",
50 call,
51 call_indirect,
52 drop,
53 select,
54 local_get,
55 local_set,
56 local_tee,
57 global_get,
58 global_set,
59 load,
60 store,
61 memory_size,
62 memory_grow,
63 @"const",
64 eqz,
65 eq,
66 ne,
67 lt,
68 gt,
69 le,
70 ge,
71 clz,
72 ctz,
73 popcnt,
74 add,
75 sub,
76 mul,
77 div,
78 rem,
79 @"and",
80 @"or",
81 xor,
82 shl,
83 shr,
84 rotl,
85 rotr,
86 abs,
87 neg,
88 ceil,
89 floor,
90 trunc,
91 nearest,
92 sqrt,
93 min,
94 max,
95 copysign,
96 wrap,
97 convert,
98 demote,
99 promote,
100 reinterpret,
101 extend,
102};
103
104/// Contains the settings needed to create an `Opcode` using `buildOpcode`.
105///
106/// The fields correspond to the opcode name. Here is an example
107/// i32_trunc_f32_s
108/// ^ ^ ^ ^
109/// | | | |
110/// valtype1 | | |
111/// = .i32 | | |
112/// | | |
113/// op | |
114/// = .trunc | |
115/// | |
116/// valtype2 |
117/// = .f32 |
118/// |
119/// width |
120/// = null |
121/// |
122/// signed
123/// = true
124///
125/// There can be missing fields, here are some more examples:
126/// i64_load8_u
127/// --> .{ .valtype1 = .i64, .op = .load, .width = 8, signed = false }
128/// i32_mul
129/// --> .{ .valtype1 = .i32, .op = .trunc }
130/// nop
131/// --> .{ .op = .nop }
132const OpcodeBuildArguments = struct {
133 /// First valtype in the opcode (usually represents the type of the output)
134 valtype1: ?wasm.Valtype = null,
135 /// The operation (e.g. call, unreachable, div, min, sqrt, etc.)
136 op: Op,
137 /// Width of the operation (e.g. 8 for i32_load8_s, 16 for i64_extend16_i32_s)
138 width: ?u8 = null,
139 /// Second valtype in the opcode name (usually represents the type of the input)
140 valtype2: ?wasm.Valtype = null,
141 /// Signedness of the op
142 signedness: ?std.builtin.Signedness = null,
143};
144
145/// Helper function that builds an Opcode given the arguments needed
146fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode {
147 switch (args.op) {
148 .@"unreachable" => return .@"unreachable",
149 .nop => return .nop,
150 .block => return .block,
151 .loop => return .loop,
152 .@"if" => return .@"if",
153 .@"else" => return .@"else",
154 .end => return .end,
155 .br => return .br,
156 .br_if => return .br_if,
157 .br_table => return .br_table,
158 .@"return" => return .@"return",
159 .call => return .call,
160 .call_indirect => return .call_indirect,
161 .drop => return .drop,
162 .select => return .select,
163 .local_get => return .local_get,
164 .local_set => return .local_set,
165 .local_tee => return .local_tee,
166 .global_get => return .global_get,
167 .global_set => return .global_set,
168
169 .load => if (args.width) |width| switch (width) {
170 8 => switch (args.valtype1.?) {
171 .i32 => if (args.signedness.? == .signed) return .i32_load8_s else return .i32_load8_u,
172 .i64 => if (args.signedness.? == .signed) return .i64_load8_s else return .i64_load8_u,
173 .f32, .f64 => unreachable,
174 },
175 16 => switch (args.valtype1.?) {
176 .i32 => if (args.signedness.? == .signed) return .i32_load16_s else return .i32_load16_u,
177 .i64 => if (args.signedness.? == .signed) return .i64_load16_s else return .i64_load16_u,
178 .f32, .f64 => unreachable,
179 },
180 32 => switch (args.valtype1.?) {
181 .i64 => if (args.signedness.? == .signed) return .i64_load32_s else return .i64_load32_u,
182 .i32, .f32, .f64 => unreachable,
183 },
184 else => unreachable,
185 } else switch (args.valtype1.?) {
186 .i32 => return .i32_load,
187 .i64 => return .i64_load,
188 .f32 => return .f32_load,
189 .f64 => return .f64_load,
190 },
191 .store => if (args.width) |width| {
192 switch (width) {
193 8 => switch (args.valtype1.?) {
194 .i32 => return .i32_store8,
195 .i64 => return .i64_store8,
196 .f32, .f64 => unreachable,
197 },
198 16 => switch (args.valtype1.?) {
199 .i32 => return .i32_store16,
200 .i64 => return .i64_store16,
201 .f32, .f64 => unreachable,
202 },
203 32 => switch (args.valtype1.?) {
204 .i64 => return .i64_store32,
205 .i32, .f32, .f64 => unreachable,
206 },
207 else => unreachable,
208 }
209 } else {
210 switch (args.valtype1.?) {
211 .i32 => return .i32_store,
212 .i64 => return .i64_store,
213 .f32 => return .f32_store,
214 .f64 => return .f64_store,
215 }
216 },
217
218 .memory_size => return .memory_size,
219 .memory_grow => return .memory_grow,
220
221 .@"const" => switch (args.valtype1.?) {
222 .i32 => return .i32_const,
223 .i64 => return .i64_const,
224 .f32 => return .f32_const,
225 .f64 => return .f64_const,
226 },
227
228 .eqz => switch (args.valtype1.?) {
229 .i32 => return .i32_eqz,
230 .i64 => return .i64_eqz,
231 .f32, .f64 => unreachable,
232 },
233 .eq => switch (args.valtype1.?) {
234 .i32 => return .i32_eq,
235 .i64 => return .i64_eq,
236 .f32 => return .f32_eq,
237 .f64 => return .f64_eq,
238 },
239 .ne => switch (args.valtype1.?) {
240 .i32 => return .i32_ne,
241 .i64 => return .i64_ne,
242 .f32 => return .f32_ne,
243 .f64 => return .f64_ne,
244 },
245
246 .lt => switch (args.valtype1.?) {
247 .i32 => if (args.signedness.? == .signed) return .i32_lt_s else return .i32_lt_u,
248 .i64 => if (args.signedness.? == .signed) return .i64_lt_s else return .i64_lt_u,
249 .f32 => return .f32_lt,
250 .f64 => return .f64_lt,
251 },
252 .gt => switch (args.valtype1.?) {
253 .i32 => if (args.signedness.? == .signed) return .i32_gt_s else return .i32_gt_u,
254 .i64 => if (args.signedness.? == .signed) return .i64_gt_s else return .i64_gt_u,
255 .f32 => return .f32_gt,
256 .f64 => return .f64_gt,
257 },
258 .le => switch (args.valtype1.?) {
259 .i32 => if (args.signedness.? == .signed) return .i32_le_s else return .i32_le_u,
260 .i64 => if (args.signedness.? == .signed) return .i64_le_s else return .i64_le_u,
261 .f32 => return .f32_le,
262 .f64 => return .f64_le,
263 },
264 .ge => switch (args.valtype1.?) {
265 .i32 => if (args.signedness.? == .signed) return .i32_ge_s else return .i32_ge_u,
266 .i64 => if (args.signedness.? == .signed) return .i64_ge_s else return .i64_ge_u,
267 .f32 => return .f32_ge,
268 .f64 => return .f64_ge,
269 },
270
271 .clz => switch (args.valtype1.?) {
272 .i32 => return .i32_clz,
273 .i64 => return .i64_clz,
274 .f32, .f64 => unreachable,
275 },
276 .ctz => switch (args.valtype1.?) {
277 .i32 => return .i32_ctz,
278 .i64 => return .i64_ctz,
279 .f32, .f64 => unreachable,
280 },
281 .popcnt => switch (args.valtype1.?) {
282 .i32 => return .i32_popcnt,
283 .i64 => return .i64_popcnt,
284 .f32, .f64 => unreachable,
285 },
286
287 .add => switch (args.valtype1.?) {
288 .i32 => return .i32_add,
289 .i64 => return .i64_add,
290 .f32 => return .f32_add,
291 .f64 => return .f64_add,
292 },
293 .sub => switch (args.valtype1.?) {
294 .i32 => return .i32_sub,
295 .i64 => return .i64_sub,
296 .f32 => return .f32_sub,
297 .f64 => return .f64_sub,
298 },
299 .mul => switch (args.valtype1.?) {
300 .i32 => return .i32_mul,
301 .i64 => return .i64_mul,
302 .f32 => return .f32_mul,
303 .f64 => return .f64_mul,
304 },
305
306 .div => switch (args.valtype1.?) {
307 .i32 => if (args.signedness.? == .signed) return .i32_div_s else return .i32_div_u,
308 .i64 => if (args.signedness.? == .signed) return .i64_div_s else return .i64_div_u,
309 .f32 => return .f32_div,
310 .f64 => return .f64_div,
311 },
312 .rem => switch (args.valtype1.?) {
313 .i32 => if (args.signedness.? == .signed) return .i32_rem_s else return .i32_rem_u,
314 .i64 => if (args.signedness.? == .signed) return .i64_rem_s else return .i64_rem_u,
315 .f32, .f64 => unreachable,
316 },
317
318 .@"and" => switch (args.valtype1.?) {
319 .i32 => return .i32_and,
320 .i64 => return .i64_and,
321 .f32, .f64 => unreachable,
322 },
323 .@"or" => switch (args.valtype1.?) {
324 .i32 => return .i32_or,
325 .i64 => return .i64_or,
326 .f32, .f64 => unreachable,
327 },
328 .xor => switch (args.valtype1.?) {
329 .i32 => return .i32_xor,
330 .i64 => return .i64_xor,
331 .f32, .f64 => unreachable,
332 },
333
334 .shl => switch (args.valtype1.?) {
335 .i32 => return .i32_shl,
336 .i64 => return .i64_shl,
337 .f32, .f64 => unreachable,
338 },
339 .shr => switch (args.valtype1.?) {
340 .i32 => if (args.signedness.? == .signed) return .i32_shr_s else return .i32_shr_u,
341 .i64 => if (args.signedness.? == .signed) return .i64_shr_s else return .i64_shr_u,
342 .f32, .f64 => unreachable,
343 },
344 .rotl => switch (args.valtype1.?) {
345 .i32 => return .i32_rotl,
346 .i64 => return .i64_rotl,
347 .f32, .f64 => unreachable,
348 },
349 .rotr => switch (args.valtype1.?) {
350 .i32 => return .i32_rotr,
351 .i64 => return .i64_rotr,
352 .f32, .f64 => unreachable,
353 },
354
355 .abs => switch (args.valtype1.?) {
356 .i32, .i64 => unreachable,
357 .f32 => return .f32_abs,
358 .f64 => return .f64_abs,
359 },
360 .neg => switch (args.valtype1.?) {
361 .i32, .i64 => unreachable,
362 .f32 => return .f32_neg,
363 .f64 => return .f64_neg,
364 },
365 .ceil => switch (args.valtype1.?) {
366 .i32, .i64 => unreachable,
367 .f32 => return .f32_ceil,
368 .f64 => return .f64_ceil,
369 },
370 .floor => switch (args.valtype1.?) {
371 .i32, .i64 => unreachable,
372 .f32 => return .f32_floor,
373 .f64 => return .f64_floor,
374 },
375 .trunc => switch (args.valtype1.?) {
376 .i32 => switch (args.valtype2.?) {
377 .i32 => unreachable,
378 .i64 => unreachable,
379 .f32 => if (args.signedness.? == .signed) return .i32_trunc_f32_s else return .i32_trunc_f32_u,
380 .f64 => if (args.signedness.? == .signed) return .i32_trunc_f64_s else return .i32_trunc_f64_u,
381 },
382 .i64 => unreachable,
383 .f32 => return .f32_trunc,
384 .f64 => return .f64_trunc,
385 },
386 .nearest => switch (args.valtype1.?) {
387 .i32, .i64 => unreachable,
388 .f32 => return .f32_nearest,
389 .f64 => return .f64_nearest,
390 },
391 .sqrt => switch (args.valtype1.?) {
392 .i32, .i64 => unreachable,
393 .f32 => return .f32_sqrt,
394 .f64 => return .f64_sqrt,
395 },
396 .min => switch (args.valtype1.?) {
397 .i32, .i64 => unreachable,
398 .f32 => return .f32_min,
399 .f64 => return .f64_min,
400 },
401 .max => switch (args.valtype1.?) {
402 .i32, .i64 => unreachable,
403 .f32 => return .f32_max,
404 .f64 => return .f64_max,
405 },
406 .copysign => switch (args.valtype1.?) {
407 .i32, .i64 => unreachable,
408 .f32 => return .f32_copysign,
409 .f64 => return .f64_copysign,
410 },
411
412 .wrap => switch (args.valtype1.?) {
413 .i32 => switch (args.valtype2.?) {
414 .i32 => unreachable,
415 .i64 => return .i32_wrap_i64,
416 .f32, .f64 => unreachable,
417 },
418 .i64, .f32, .f64 => unreachable,
419 },
420 .convert => switch (args.valtype1.?) {
421 .i32, .i64 => unreachable,
422 .f32 => switch (args.valtype2.?) {
423 .i32 => if (args.signedness.? == .signed) return .f32_convert_i32_s else return .f32_convert_i32_u,
424 .i64 => if (args.signedness.? == .signed) return .f32_convert_i64_s else return .f32_convert_i64_u,
425 .f32, .f64 => unreachable,
426 },
427 .f64 => switch (args.valtype2.?) {
428 .i32 => if (args.signedness.? == .signed) return .f64_convert_i32_s else return .f64_convert_i32_u,
429 .i64 => if (args.signedness.? == .signed) return .f64_convert_i64_s else return .f64_convert_i64_u,
430 .f32, .f64 => unreachable,
431 },
432 },
433 .demote => if (args.valtype1.? == .f32 and args.valtype2.? == .f64) return .f32_demote_f64 else unreachable,
434 .promote => if (args.valtype1.? == .f64 and args.valtype2.? == .f32) return .f64_promote_f32 else unreachable,
435 .reinterpret => switch (args.valtype1.?) {
436 .i32 => if (args.valtype2.? == .f32) return .i32_reinterpret_f32 else unreachable,
437 .i64 => if (args.valtype2.? == .f64) return .i64_reinterpret_f64 else unreachable,
438 .f32 => if (args.valtype2.? == .i32) return .f32_reinterpret_i32 else unreachable,
439 .f64 => if (args.valtype2.? == .i64) return .f64_reinterpret_i64 else unreachable,
440 },
441 .extend => switch (args.valtype1.?) {
442 .i32 => switch (args.width.?) {
443 8 => if (args.signedness.? == .signed) return .i32_extend8_s else unreachable,
444 16 => if (args.signedness.? == .signed) return .i32_extend16_s else unreachable,
445 else => unreachable,
446 },
447 .i64 => switch (args.width.?) {
448 8 => if (args.signedness.? == .signed) return .i64_extend8_s else unreachable,
449 16 => if (args.signedness.? == .signed) return .i64_extend16_s else unreachable,
450 32 => if (args.signedness.? == .signed) return .i64_extend32_s else unreachable,
451 else => unreachable,
452 },
453 .f32, .f64 => unreachable,
454 },
455 }
456}
457
458test "Wasm - buildOpcode" {
459 // Make sure buildOpcode is referenced, and test some examples
460 const i32_const = buildOpcode(.{ .op = .@"const", .valtype1 = .i32 });
461 const end = buildOpcode(.{ .op = .end });
462 const local_get = buildOpcode(.{ .op = .local_get });
463 const i64_extend32_s = buildOpcode(.{ .op = .extend, .valtype1 = .i64, .width = 32, .signedness = .signed });
464 const f64_reinterpret_i64 = buildOpcode(.{ .op = .reinterpret, .valtype1 = .f64, .valtype2 = .i64 });
465
466 testing.expectEqual(@as(wasm.Opcode, .i32_const), i32_const);
467 testing.expectEqual(@as(wasm.Opcode, .end), end);
468 testing.expectEqual(@as(wasm.Opcode, .local_get), local_get);
469 testing.expectEqual(@as(wasm.Opcode, .i64_extend32_s), i64_extend32_s);
470 testing.expectEqual(@as(wasm.Opcode, .f64_reinterpret_i64), f64_reinterpret_i64);
471}
472
473pub const Result = union(enum) {
474 /// The codegen bytes have been appended to `Context.code`
475 appended: void,
476 /// The data is managed externally and are part of the `Result`
477 externally_managed: []const u8,
478};
479
32/// Hashmap to store generated `WValue` for each `Inst`480/// Hashmap to store generated `WValue` for each `Inst`
33pub const ValueTable = std.AutoHashMapUnmanaged(*Inst, WValue);481pub const ValueTable = std.AutoHashMapUnmanaged(*Inst, WValue);
34482
...@@ -58,10 +506,14 @@ pub const Context = struct {...@@ -58,10 +506,14 @@ pub const Context = struct {
58 /// List of all locals' types generated throughout this declaration506 /// List of all locals' types generated throughout this declaration
59 /// used to emit locals count at start of 'code' section.507 /// used to emit locals count at start of 'code' section.
60 locals: std.ArrayListUnmanaged(u8),508 locals: std.ArrayListUnmanaged(u8),
509 /// The Target we're emitting (used to call intInfo)
510 target: std.Target,
61511
62 const InnerError = error{512 const InnerError = error{
63 OutOfMemory,513 OutOfMemory,
64 CodegenFail,514 CodegenFail,
515 /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed
516 AnalysisFail,
65 };517 };
66518
67 pub fn deinit(self: *Context) void {519 pub fn deinit(self: *Context) void {
...@@ -89,17 +541,31 @@ pub const Context = struct {...@@ -89,17 +541,31 @@ pub const Context = struct {
89 return self.values.get(inst).?; // Instruction does not dominate all uses!541 return self.values.get(inst).?; // Instruction does not dominate all uses!
90 }542 }
91543
92 /// Using a given `Type`, returns the corresponding wasm value type544 /// Using a given `Type`, returns the corresponding wasm Valtype
93 fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {545 fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype {
94 return switch (ty.tag()) {546 return switch (ty.zigTypeTag()) {
95 .f32 => wasm.valtype(.f32),547 .Float => blk: {
96 .f64 => wasm.valtype(.f64),548 const bits = ty.floatBits(self.target);
97 .u32, .i32, .bool => wasm.valtype(.i32),549 if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32;
98 .u64, .i64 => wasm.valtype(.i64),550 if (bits == 64) break :blk wasm.Valtype.f64;
99 else => self.fail(src, "TODO - Wasm genValtype for type '{s}'", .{ty.tag()}),551 return self.fail(src, "Float bit size not supported by wasm: '{d}'", .{bits});
552 },
553 .Int => blk: {
554 const info = ty.intInfo(self.target);
555 if (info.bits <= 32) break :blk wasm.Valtype.i32;
556 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;
557 return self.fail(src, "Integer bit size not supported by wasm: '{d}'", .{info.bits});
558 },
559 .Bool, .Pointer => wasm.Valtype.i32,
560 else => self.fail(src, "TODO - Wasm valtype for type '{s}'", .{ty.tag()}),
100 };561 };
101 }562 }
102563
564 /// Using a given `Type`, returns the byte representation of its wasm value type
565 fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
566 return wasm.valtype(try self.typeToValtype(src, ty));
567 }
568
103 /// Using a given `Type`, returns the corresponding wasm value type569 /// Using a given `Type`, returns the corresponding wasm value type
104 /// Differently from `genValtype` this also allows `void` to create a block570 /// Differently from `genValtype` this also allows `void` to create a block
105 /// with no return type571 /// with no return type
...@@ -157,59 +623,97 @@ pub const Context = struct {...@@ -157,59 +623,97 @@ pub const Context = struct {
157 }623 }
158624
159 /// Generates the wasm bytecode for the function declaration belonging to `Context`625 /// Generates the wasm bytecode for the function declaration belonging to `Context`
160 pub fn gen(self: *Context) InnerError!void {626 pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
161 assert(self.code.items.len == 0);627 switch (typed_value.ty.zigTypeTag()) {
162 try self.genFunctype();628 .Fn => {
163629 try self.genFunctype();
164 // Write instructions630
165 // TODO: check for and handle death of instructions631 // Write instructions
166 const tv = self.decl.typed_value.most_recent.typed_value;632 // TODO: check for and handle death of instructions
167 const mod_fn = blk: {633 const mod_fn = blk: {
168 if (tv.val.castTag(.function)) |func| break :blk func.data;634 if (typed_value.val.castTag(.function)) |func| break :blk func.data;
169 if (tv.val.castTag(.extern_fn)) |ext_fn| return; // don't need codegen for extern functions635 if (typed_value.val.castTag(.extern_fn)) |ext_fn| return Result.appended; // don't need code body for extern functions
170 return self.fail(.{ .node_offset = 0 }, "TODO: Wasm codegen for decl type '{s}'", .{tv.ty.tag()});636 unreachable;
171 };637 };
172638
173 // Reserve space to write the size after generating the code as well as space for locals count639 // Reserve space to write the size after generating the code as well as space for locals count
174 try self.code.resize(10);640 try self.code.resize(10);
175641
176 try self.genBody(mod_fn.body);642 try self.genBody(mod_fn.body);
177643
178 // finally, write our local types at the 'offset' position644 // finally, write our local types at the 'offset' position
179 {645 {
180 leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));646 leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
181647
182 // offset into 'code' section where we will put our locals types648 // offset into 'code' section where we will put our locals types
183 var local_offset: usize = 10;649 var local_offset: usize = 10;
184650
185 // emit the actual locals amount651 // emit the actual locals amount
186 for (self.locals.items) |local| {652 for (self.locals.items) |local| {
187 var buf: [6]u8 = undefined;653 var buf: [6]u8 = undefined;
188 leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));654 leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
189 buf[5] = local;655 buf[5] = local;
190 try self.code.insertSlice(local_offset, &buf);656 try self.code.insertSlice(local_offset, &buf);
191 local_offset += 6;657 local_offset += 6;
192 }658 }
659 }
660
661 const writer = self.code.writer();
662 try writer.writeByte(wasm.opcode(.end));
663
664 // Fill in the size of the generated code to the reserved space at the
665 // beginning of the buffer.
666 const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5;
667 leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
668
669 // codegen data has been appended to `code`
670 return Result.appended;
671 },
672 .Array => {
673 if (typed_value.val.castTag(.bytes)) |payload| {
674 if (typed_value.ty.sentinel()) |sentinel| {
675 try self.code.appendSlice(payload.data);
676
677 switch (try self.gen(.{
678 .ty = typed_value.ty.elemType(),
679 .val = sentinel,
680 })) {
681 .appended => return Result.appended,
682 .externally_managed => |data| {
683 try self.code.appendSlice(data);
684 return Result.appended;
685 },
686 }
687 }
688 return Result{ .externally_managed = payload.data };
689 } else return self.fail(.{ .node_offset = 0 }, "TODO implement gen for more kinds of arrays", .{});
690 },
691 .Int => {
692 const info = typed_value.ty.intInfo(self.target);
693 if (info.bits == 8 and info.signedness == .unsigned) {
694 const int_byte = typed_value.val.toUnsignedInt();
695 try self.code.append(@intCast(u8, int_byte));
696 return Result.appended;
697 }
698 return self.fail(.{ .node_offset = 0 }, "TODO: Implement codegen for int type: '{}'", .{typed_value.ty});
699 },
700 else => |tag| return self.fail(.{ .node_offset = 0 }, "TODO: Implement zig type codegen for type: '{s}'", .{tag}),
193 }701 }
194
195 const writer = self.code.writer();
196 try writer.writeByte(wasm.opcode(.end));
197
198 // Fill in the size of the generated code to the reserved space at the
199 // beginning of the buffer.
200 const size = self.code.items.len - 5 + self.decl.fn_link.wasm.?.idx_refs.items.len * 5;
201 leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
202 }702 }
203703
204 fn genInst(self: *Context, inst: *Inst) InnerError!WValue {704 fn genInst(self: *Context, inst: *Inst) InnerError!WValue {
205 return switch (inst.tag) {705 return switch (inst.tag) {
206 .add => self.genAdd(inst.castTag(.add).?),706 .add => self.genBinOp(inst.castTag(.add).?, .add),
207 .alloc => self.genAlloc(inst.castTag(.alloc).?),707 .alloc => self.genAlloc(inst.castTag(.alloc).?),
208 .arg => self.genArg(inst.castTag(.arg).?),708 .arg => self.genArg(inst.castTag(.arg).?),
209 .block => self.genBlock(inst.castTag(.block).?),709 .block => self.genBlock(inst.castTag(.block).?),
210 .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),710 .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
211 .br => self.genBr(inst.castTag(.br).?),711 .br => self.genBr(inst.castTag(.br).?),
212 .call => self.genCall(inst.castTag(.call).?),712 .call => self.genCall(inst.castTag(.call).?),
713 .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
714 .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
715 .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
716 .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
213 .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),717 .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
214 .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),718 .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
215 .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),719 .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
...@@ -221,10 +725,14 @@ pub const Context = struct {...@@ -221,10 +725,14 @@ pub const Context = struct {
221 .dbg_stmt => WValue.none,725 .dbg_stmt => WValue.none,
222 .load => self.genLoad(inst.castTag(.load).?),726 .load => self.genLoad(inst.castTag(.load).?),
223 .loop => self.genLoop(inst.castTag(.loop).?),727 .loop => self.genLoop(inst.castTag(.loop).?),
728 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
729 .div => self.genBinOp(inst.castTag(.div).?, .div),
730 .xor => self.genBinOp(inst.castTag(.xor).?, .xor),
224 .not => self.genNot(inst.castTag(.not).?),731 .not => self.genNot(inst.castTag(.not).?),
225 .ret => self.genRet(inst.castTag(.ret).?),732 .ret => self.genRet(inst.castTag(.ret).?),
226 .retvoid => WValue.none,733 .retvoid => WValue.none,
227 .store => self.genStore(inst.castTag(.store).?),734 .store => self.genStore(inst.castTag(.store).?),
735 .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
228 .unreach => self.genUnreachable(inst.castTag(.unreach).?),736 .unreach => self.genUnreachable(inst.castTag(.unreach).?),
229 else => self.fail(inst.src, "TODO: Implement wasm inst: {s}", .{inst.tag}),737 else => self.fail(inst.src, "TODO: Implement wasm inst: {s}", .{inst.tag}),
230 };738 };
...@@ -266,7 +774,7 @@ pub const Context = struct {...@@ -266,7 +774,7 @@ pub const Context = struct {
266774
267 // The function index immediate argument will be filled in using this data775 // The function index immediate argument will be filled in using this data
268 // in link.Wasm.flush().776 // in link.Wasm.flush().
269 try self.decl.fn_link.wasm.?.idx_refs.append(self.gpa, .{777 try self.decl.fn_link.wasm.idx_refs.append(self.gpa, .{
270 .offset = @intCast(u32, self.code.items.len),778 .offset = @intCast(u32, self.code.items.len),
271 .decl = target,779 .decl = target,
272 });780 });
...@@ -305,56 +813,76 @@ pub const Context = struct {...@@ -305,56 +813,76 @@ pub const Context = struct {
305 return WValue{ .local = self.local_index };813 return WValue{ .local = self.local_index };
306 }814 }
307815
308 fn genAdd(self: *Context, inst: *Inst.BinOp) InnerError!WValue {816 fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue {
309 const lhs = self.resolveInst(inst.lhs);817 const lhs = self.resolveInst(inst.lhs);
310 const rhs = self.resolveInst(inst.rhs);818 const rhs = self.resolveInst(inst.rhs);
311819
312 try self.emitWValue(lhs);820 try self.emitWValue(lhs);
313 try self.emitWValue(rhs);821 try self.emitWValue(rhs);
314822
315 const opcode: wasm.Opcode = switch (inst.base.ty.tag()) {823 const opcode: wasm.Opcode = buildOpcode(.{
316 .u32, .i32 => .i32_add,824 .op = op,
317 .u64, .i64 => .i64_add,825 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
318 .f32 => .f32_add,826 .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
319 .f64 => .f64_add,827 });
320 else => return self.fail(inst.base.src, "TODO - Implement wasm genAdd for type '{s}'", .{inst.base.ty.tag()}),
321 };
322
323 try self.code.append(wasm.opcode(opcode));828 try self.code.append(wasm.opcode(opcode));
324 return .none;829 return .none;
325 }830 }
326831
327 fn emitConstant(self: *Context, inst: *Inst.Constant) InnerError!void {832 fn emitConstant(self: *Context, inst: *Inst.Constant) InnerError!void {
328 const writer = self.code.writer();833 const writer = self.code.writer();
329 switch (inst.base.ty.tag()) {834 switch (inst.base.ty.zigTypeTag()) {
330 .u32 => {835 .Int => {
331 try writer.writeByte(wasm.opcode(.i32_const));836 // write opcode
332 try leb.writeILEB128(writer, inst.val.toUnsignedInt());837 const opcode: wasm.Opcode = buildOpcode(.{
838 .op = .@"const",
839 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
840 });
841 try writer.writeByte(wasm.opcode(opcode));
842 // write constant
843 switch (inst.base.ty.intInfo(self.target).signedness) {
844 .signed => try leb.writeILEB128(writer, inst.val.toSignedInt()),
845 .unsigned => try leb.writeILEB128(writer, inst.val.toUnsignedInt()),
846 }
333 },847 },
334 .i32, .bool => {848 .Bool => {
849 // write opcode
335 try writer.writeByte(wasm.opcode(.i32_const));850 try writer.writeByte(wasm.opcode(.i32_const));
851 // write constant
336 try leb.writeILEB128(writer, inst.val.toSignedInt());852 try leb.writeILEB128(writer, inst.val.toSignedInt());
337 },853 },
338 .u64 => {854 .Float => {
339 try writer.writeByte(wasm.opcode(.i64_const));855 // write opcode
340 try leb.writeILEB128(writer, inst.val.toUnsignedInt());856 const opcode: wasm.Opcode = buildOpcode(.{
341 },857 .op = .@"const",
342 .i64 => {858 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
343 try writer.writeByte(wasm.opcode(.i64_const));859 });
344 try leb.writeILEB128(writer, inst.val.toSignedInt());860 try writer.writeByte(wasm.opcode(opcode));
861 // write constant
862 switch (inst.base.ty.floatBits(self.target)) {
863 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, inst.val.toFloat(f32))),
864 64 => try writer.writeIntLittle(u64, @bitCast(u64, inst.val.toFloat(f64))),
865 else => |bits| return self.fail(inst.base.src, "Wasm TODO: emitConstant for float with {d} bits", .{bits}),
866 }
345 },867 },
346 .f32 => {868 .Pointer => {
347 try writer.writeByte(wasm.opcode(.f32_const));869 if (inst.val.castTag(.decl_ref)) |payload| {
348 // TODO: enforce LE byte order870 const decl = payload.data;
349 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f32)));871
872 // offset into the offset table within the 'data' section
873 const ptr_width = self.target.cpu.arch.ptrBitWidth() / 8;
874 try writer.writeByte(wasm.opcode(.i32_const));
875 try leb.writeULEB128(writer, decl.link.wasm.offset_index * ptr_width);
876
877 // memory instruction followed by their memarg immediate
878 // memarg ::== x:u32, y:u32 => {align x, offset y}
879 try writer.writeByte(wasm.opcode(.i32_load));
880 try leb.writeULEB128(writer, @as(u32, 0));
881 try leb.writeULEB128(writer, @as(u32, 0));
882 } else return self.fail(inst.base.src, "Wasm TODO: emitConstant for other const pointer tag {s}", .{inst.val.tag()});
350 },883 },
351 .f64 => {884 .Void => {},
352 try writer.writeByte(wasm.opcode(.f64_const));885 else => |ty| return self.fail(inst.base.src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{ty}),
353 // TODO: enforce LE byte order
354 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f64)));
355 },
356 .void => {},
357 else => |ty| return self.fail(inst.base.src, "Wasm TODO: emitConstant for type {s}", .{ty}),
358 }886 }
359 }887 }
360888
...@@ -455,62 +983,18 @@ pub const Context = struct {...@@ -455,62 +983,18 @@ pub const Context = struct {
455 try self.emitWValue(lhs);983 try self.emitWValue(lhs);
456 try self.emitWValue(rhs);984 try self.emitWValue(rhs);
457985
458 const opcode_maybe: ?wasm.Opcode = switch (op) {986 const opcode: wasm.Opcode = buildOpcode(.{
459 .lt => @as(?wasm.Opcode, switch (ty) {987 .valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty),
460 .i32 => .i32_lt_s,988 .op = switch (op) {
461 .u32 => .i32_lt_u,989 .lt => .lt,
462 .i64 => .i64_lt_s,990 .lte => .le,
463 .u64 => .i64_lt_u,991 .eq => .eq,
464 .f32 => .f32_lt,992 .neq => .ne,
465 .f64 => .f64_lt,993 .gte => .ge,
466 else => null,994 .gt => .gt,
467 }),995 },
468 .lte => @as(?wasm.Opcode, switch (ty) {996 .signedness = inst.lhs.ty.intInfo(self.target).signedness,
469 .i32 => .i32_le_s,997 });
470 .u32 => .i32_le_u,
471 .i64 => .i64_le_s,
472 .u64 => .i64_le_u,
473 .f32 => .f32_le,
474 .f64 => .f64_le,
475 else => null,
476 }),
477 .eq => @as(?wasm.Opcode, switch (ty) {
478 .i32, .u32 => .i32_eq,
479 .i64, .u64 => .i64_eq,
480 .f32 => .f32_eq,
481 .f64 => .f64_eq,
482 else => null,
483 }),
484 .gte => @as(?wasm.Opcode, switch (ty) {
485 .i32 => .i32_ge_s,
486 .u32 => .i32_ge_u,
487 .i64 => .i64_ge_s,
488 .u64 => .i64_ge_u,
489 .f32 => .f32_ge,
490 .f64 => .f64_ge,
491 else => null,
492 }),
493 .gt => @as(?wasm.Opcode, switch (ty) {
494 .i32 => .i32_gt_s,
495 .u32 => .i32_gt_u,
496 .i64 => .i64_gt_s,
497 .u64 => .i64_gt_u,
498 .f32 => .f32_gt,
499 .f64 => .f64_gt,
500 else => null,
501 }),
502 .neq => @as(?wasm.Opcode, switch (ty) {
503 .i32, .u32 => .i32_ne,
504 .i64, .u64 => .i64_ne,
505 .f32 => .f32_ne,
506 .f64 => .f64_ne,
507 else => null,
508 }),
509 };
510
511 const opcode = opcode_maybe orelse
512 return self.fail(inst.base.src, "TODO - Wasm genCmp for type '{s}' and operator '{s}'", .{ ty, @tagName(op) });
513
514 try self.code.append(wasm.opcode(opcode));998 try self.code.append(wasm.opcode(opcode));
515 return WValue{ .code_offset = offset };999 return WValue{ .code_offset = offset };
516 }1000 }
src/ir.zig+4
...@@ -115,6 +115,7 @@ pub const Inst = struct {...@@ -115,6 +115,7 @@ pub const Inst = struct {
115 unreach,115 unreach,
116 mul,116 mul,
117 mulwrap,117 mulwrap,
118 div,
118 not,119 not,
119 floatcast,120 floatcast,
120 intcast,121 intcast,
...@@ -181,6 +182,7 @@ pub const Inst = struct {...@@ -181,6 +182,7 @@ pub const Inst = struct {
181 .subwrap,182 .subwrap,
182 .mul,183 .mul,
183 .mulwrap,184 .mulwrap,
185 .div,
184 .cmp_lt,186 .cmp_lt,
185 .cmp_lte,187 .cmp_lte,
186 .cmp_eq,188 .cmp_eq,
...@@ -752,6 +754,7 @@ const DumpTzir = struct {...@@ -752,6 +754,7 @@ const DumpTzir = struct {
752 .subwrap,754 .subwrap,
753 .mul,755 .mul,
754 .mulwrap,756 .mulwrap,
757 .div,
755 .cmp_lt,758 .cmp_lt,
756 .cmp_lte,759 .cmp_lte,
757 .cmp_eq,760 .cmp_eq,
...@@ -891,6 +894,7 @@ const DumpTzir = struct {...@@ -891,6 +894,7 @@ const DumpTzir = struct {
891 .subwrap,894 .subwrap,
892 .mul,895 .mul,
893 .mulwrap,896 .mulwrap,
897 .div,
894 .cmp_lt,898 .cmp_lt,
895 .cmp_lte,899 .cmp_lte,
896 .cmp_eq,900 .cmp_eq,
src/link.zig+4-3
...@@ -138,7 +138,7 @@ pub const File = struct {...@@ -138,7 +138,7 @@ pub const File = struct {
138 coff: Coff.TextBlock,138 coff: Coff.TextBlock,
139 macho: MachO.TextBlock,139 macho: MachO.TextBlock,
140 c: C.DeclBlock,140 c: C.DeclBlock,
141 wasm: void,141 wasm: Wasm.DeclBlock,
142 spirv: void,142 spirv: void,
143 };143 };
144144
...@@ -147,7 +147,7 @@ pub const File = struct {...@@ -147,7 +147,7 @@ pub const File = struct {
147 coff: Coff.SrcFn,147 coff: Coff.SrcFn,
148 macho: MachO.SrcFn,148 macho: MachO.SrcFn,
149 c: C.FnBlock,149 c: C.FnBlock,
150 wasm: ?Wasm.FnData,150 wasm: Wasm.FnData,
151 spirv: SpirV.FnData,151 spirv: SpirV.FnData,
152 };152 };
153153
...@@ -328,7 +328,8 @@ pub const File = struct {...@@ -328,7 +328,8 @@ pub const File = struct {
328 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),328 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
329 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),329 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),
330 .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),330 .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),
331 .wasm, .spirv => {},331 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),
332 .spirv => {},
332 }333 }
333 }334 }
334335
src/link/Elf.zig+2-4
...@@ -2228,10 +2228,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2228,10 +2228,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2228 const node_datas = tree.nodes.items(.data);2228 const node_datas = tree.nodes.items(.data);
2229 const token_starts = tree.tokens.items(.start);2229 const token_starts = tree.tokens.items(.start);
22302230
2231 const file_ast_decls = tree.rootDecls();
2232 // TODO Look into improving the performance here by adding a token-index-to-line2231 // TODO Look into improving the performance here by adding a token-index-to-line
2233 // lookup table. Currently this involves scanning over the source code for newlines.2232 // lookup table. Currently this involves scanning over the source code for newlines.
2234 const fn_decl = file_ast_decls[decl.src_index];2233 const fn_decl = decl.src_node;
2235 assert(node_tags[fn_decl] == .fn_decl);2234 assert(node_tags[fn_decl] == .fn_decl);
2236 const block = node_datas[fn_decl].rhs;2235 const block = node_datas[fn_decl].rhs;
2237 const lbrace = tree.firstToken(block);2236 const lbrace = tree.firstToken(block);
...@@ -2755,10 +2754,9 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec...@@ -2755,10 +2754,9 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
2755 const node_datas = tree.nodes.items(.data);2754 const node_datas = tree.nodes.items(.data);
2756 const token_starts = tree.tokens.items(.start);2755 const token_starts = tree.tokens.items(.start);
27572756
2758 const file_ast_decls = tree.rootDecls();
2759 // TODO Look into improving the performance here by adding a token-index-to-line2757 // TODO Look into improving the performance here by adding a token-index-to-line
2760 // lookup table. Currently this involves scanning over the source code for newlines.2758 // lookup table. Currently this involves scanning over the source code for newlines.
2761 const fn_decl = file_ast_decls[decl.src_index];2759 const fn_decl = decl.src_node;
2762 assert(node_tags[fn_decl] == .fn_decl);2760 assert(node_tags[fn_decl] == .fn_decl);
2763 const block = node_datas[fn_decl].rhs;2761 const block = node_datas[fn_decl].rhs;
2764 const lbrace = tree.firstToken(block);2762 const lbrace = tree.firstToken(block);
src/link/MachO.zig+2-2
...@@ -1256,7 +1256,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1256,7 +1256,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1256 const inst = code_buffer.items[fixup.offset..][0..4];1256 const inst = code_buffer.items[fixup.offset..][0..4];
1257 var parsed = mem.bytesAsValue(meta.TagPayload(1257 var parsed = mem.bytesAsValue(meta.TagPayload(
1258 aarch64.Instruction,1258 aarch64.Instruction,
1259 aarch64.Instruction.PCRelativeAddress,1259 aarch64.Instruction.pc_relative_address,
1260 ), inst);1260 ), inst);
1261 const this_page = @intCast(i32, this_addr >> 12);1261 const this_page = @intCast(i32, this_addr >> 12);
1262 const target_page = @intCast(i32, target_addr >> 12);1262 const target_page = @intCast(i32, target_addr >> 12);
...@@ -1268,7 +1268,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1268,7 +1268,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1268 const inst = code_buffer.items[fixup.offset + 4 ..][0..4];1268 const inst = code_buffer.items[fixup.offset + 4 ..][0..4];
1269 var parsed = mem.bytesAsValue(meta.TagPayload(1269 var parsed = mem.bytesAsValue(meta.TagPayload(
1270 aarch64.Instruction,1270 aarch64.Instruction,
1271 aarch64.Instruction.LoadStoreRegister,1271 aarch64.Instruction.load_store_register,
1272 ), inst);1272 ), inst);
1273 const narrowed = @truncate(u12, target_addr);1273 const narrowed = @truncate(u12, target_addr);
1274 const offset = try math.divExact(u12, narrowed, 8);1274 const offset = try math.divExact(u12, narrowed, 8);
src/link/MachO/DebugSymbols.zig+2-4
...@@ -909,10 +909,9 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M...@@ -909,10 +909,9 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
909 const node_datas = tree.nodes.items(.data);909 const node_datas = tree.nodes.items(.data);
910 const token_starts = tree.tokens.items(.start);910 const token_starts = tree.tokens.items(.start);
911911
912 const file_ast_decls = tree.rootDecls();
913 // TODO Look into improving the performance here by adding a token-index-to-line912 // TODO Look into improving the performance here by adding a token-index-to-line
914 // lookup table. Currently this involves scanning over the source code for newlines.913 // lookup table. Currently this involves scanning over the source code for newlines.
915 const fn_decl = file_ast_decls[decl.src_index];914 const fn_decl = decl.src_node;
916 assert(node_tags[fn_decl] == .fn_decl);915 assert(node_tags[fn_decl] == .fn_decl);
917 const block = node_datas[fn_decl].rhs;916 const block = node_datas[fn_decl].rhs;
918 const lbrace = tree.firstToken(block);917 const lbrace = tree.firstToken(block);
...@@ -959,10 +958,9 @@ pub fn initDeclDebugBuffers(...@@ -959,10 +958,9 @@ pub fn initDeclDebugBuffers(
959 const node_datas = tree.nodes.items(.data);958 const node_datas = tree.nodes.items(.data);
960 const token_starts = tree.tokens.items(.start);959 const token_starts = tree.tokens.items(.start);
961960
962 const file_ast_decls = tree.rootDecls();
963 // TODO Look into improving the performance here by adding a token-index-to-line961 // TODO Look into improving the performance here by adding a token-index-to-line
964 // lookup table. Currently this involves scanning over the source code for newlines.962 // lookup table. Currently this involves scanning over the source code for newlines.
965 const fn_decl = file_ast_decls[decl.src_index];963 const fn_decl = decl.src_node;
966 assert(node_tags[fn_decl] == .fn_decl);964 assert(node_tags[fn_decl] == .fn_decl);
967 const block = node_datas[fn_decl].rhs;965 const block = node_datas[fn_decl].rhs;
968 const lbrace = tree.firstToken(block);966 const lbrace = tree.firstToken(block);
src/link/MachO/Zld.zig+6-6
...@@ -1668,7 +1668,7 @@ fn doRelocs(self: *Zld) !void {...@@ -1668,7 +1668,7 @@ fn doRelocs(self: *Zld) !void {
1668 var parsed = mem.bytesAsValue(1668 var parsed = mem.bytesAsValue(
1669 meta.TagPayload(1669 meta.TagPayload(
1670 aarch64.Instruction,1670 aarch64.Instruction,
1671 aarch64.Instruction.UnconditionalBranchImmediate,1671 aarch64.Instruction.unconditional_branch_immediate,
1672 ),1672 ),
1673 inst,1673 inst,
1674 );1674 );
...@@ -1688,7 +1688,7 @@ fn doRelocs(self: *Zld) !void {...@@ -1688,7 +1688,7 @@ fn doRelocs(self: *Zld) !void {
1688 var parsed = mem.bytesAsValue(1688 var parsed = mem.bytesAsValue(
1689 meta.TagPayload(1689 meta.TagPayload(
1690 aarch64.Instruction,1690 aarch64.Instruction,
1691 aarch64.Instruction.PCRelativeAddress,1691 aarch64.Instruction.pc_relative_address,
1692 ),1692 ),
1693 inst,1693 inst,
1694 );1694 );
...@@ -1706,7 +1706,7 @@ fn doRelocs(self: *Zld) !void {...@@ -1706,7 +1706,7 @@ fn doRelocs(self: *Zld) !void {
1706 var parsed = mem.bytesAsValue(1706 var parsed = mem.bytesAsValue(
1707 meta.TagPayload(1707 meta.TagPayload(
1708 aarch64.Instruction,1708 aarch64.Instruction,
1709 aarch64.Instruction.AddSubtractImmediate,1709 aarch64.Instruction.add_subtract_immediate,
1710 ),1710 ),
1711 inst,1711 inst,
1712 );1712 );
...@@ -1719,7 +1719,7 @@ fn doRelocs(self: *Zld) !void {...@@ -1719,7 +1719,7 @@ fn doRelocs(self: *Zld) !void {
1719 var parsed = mem.bytesAsValue(1719 var parsed = mem.bytesAsValue(
1720 meta.TagPayload(1720 meta.TagPayload(
1721 aarch64.Instruction,1721 aarch64.Instruction,
1722 aarch64.Instruction.LoadStoreRegister,1722 aarch64.Instruction.load_store_register,
1723 ),1723 ),
1724 inst,1724 inst,
1725 );1725 );
...@@ -1774,7 +1774,7 @@ fn doRelocs(self: *Zld) !void {...@@ -1774,7 +1774,7 @@ fn doRelocs(self: *Zld) !void {
1774 const curr = mem.bytesAsValue(1774 const curr = mem.bytesAsValue(
1775 meta.TagPayload(1775 meta.TagPayload(
1776 aarch64.Instruction,1776 aarch64.Instruction,
1777 aarch64.Instruction.AddSubtractImmediate,1777 aarch64.Instruction.add_subtract_immediate,
1778 ),1778 ),
1779 inst,1779 inst,
1780 );1780 );
...@@ -1783,7 +1783,7 @@ fn doRelocs(self: *Zld) !void {...@@ -1783,7 +1783,7 @@ fn doRelocs(self: *Zld) !void {
1783 const curr = mem.bytesAsValue(1783 const curr = mem.bytesAsValue(
1784 meta.TagPayload(1784 meta.TagPayload(
1785 aarch64.Instruction,1785 aarch64.Instruction,
1786 aarch64.Instruction.LoadStoreRegister,1786 aarch64.Instruction.load_store_register,
1787 ),1787 ),
1788 inst,1788 inst,
1789 );1789 );
src/link/Wasm.zig+279-62
...@@ -16,21 +16,11 @@ const link = @import("../link.zig");...@@ -16,21 +16,11 @@ const link = @import("../link.zig");
16const trace = @import("../tracy.zig").trace;16const trace = @import("../tracy.zig").trace;
17const build_options = @import("build_options");17const build_options = @import("build_options");
18const Cache = @import("../Cache.zig");18const Cache = @import("../Cache.zig");
19const TypedValue = @import("../TypedValue.zig");
1920
20pub const base_tag = link.File.Tag.wasm;21pub const base_tag = link.File.Tag.wasm;
2122
22pub const FnData = struct {
23 /// Generated code for the type of the function
24 functype: std.ArrayListUnmanaged(u8) = .{},
25 /// Generated code for the body of the function
26 code: std.ArrayListUnmanaged(u8) = .{},
27 /// Locations in the generated code where function indexes must be filled in.
28 /// This must be kept ordered by offset.
29 idx_refs: std.ArrayListUnmanaged(struct { offset: u32, decl: *Module.Decl }) = .{},
30};
31
32base: link.File,23base: link.File,
33
34/// List of all function Decls to be written to the output file. The index of24/// List of all function Decls to be written to the output file. The index of
35/// each Decl in this list at the time of writing the binary is used as the25/// each Decl in this list at the time of writing the binary is used as the
36/// function index. In the event where ext_funcs' size is not 0, the index of26/// function index. In the event where ext_funcs' size is not 0, the index of
...@@ -45,6 +35,77 @@ ext_funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},...@@ -45,6 +35,77 @@ ext_funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},
45/// to support existing code.35/// to support existing code.
46/// TODO: Allow setting this through a flag?36/// TODO: Allow setting this through a flag?
47host_name: []const u8 = "env",37host_name: []const u8 = "env",
38/// The last `DeclBlock` that was initialized will be saved here.
39last_block: ?*DeclBlock = null,
40/// Table with offsets, each element represents an offset with the value being
41/// the offset into the 'data' section where the data lives
42offset_table: std.ArrayListUnmanaged(u32) = .{},
43/// List of offset indexes which are free to be used for new decl's.
44/// Each element's value points to an index into the offset_table.
45offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
46/// List of all `Decl` that are currently alive.
47/// This is ment for bookkeeping so we can safely cleanup all codegen memory
48/// when calling `deinit`
49symbols: std.ArrayListUnmanaged(*Module.Decl) = .{},
50
51pub const FnData = struct {
52 /// Generated code for the type of the function
53 functype: std.ArrayListUnmanaged(u8),
54 /// Generated code for the body of the function
55 code: std.ArrayListUnmanaged(u8),
56 /// Locations in the generated code where function indexes must be filled in.
57 /// This must be kept ordered by offset.
58 idx_refs: std.ArrayListUnmanaged(struct { offset: u32, decl: *Module.Decl }),
59
60 pub const empty: FnData = .{
61 .functype = .{},
62 .code = .{},
63 .idx_refs = .{},
64 };
65};
66
67pub const DeclBlock = struct {
68 /// Determines whether the `DeclBlock` has been initialized for codegen.
69 init: bool,
70 /// Index into the `symbols` list.
71 symbol_index: u32,
72 /// Index into the offset table
73 offset_index: u32,
74 /// The size of the block and how large part of the data section it occupies.
75 /// Will be 0 when the Decl will not live inside the data section and `data` will be undefined.
76 size: u32,
77 /// Points to the previous and next blocks.
78 /// Can be used to find the total size, and used to calculate the `offset` based on the previous block.
79 prev: ?*DeclBlock,
80 next: ?*DeclBlock,
81 /// Pointer to data that will be written to the 'data' section.
82 /// This data either lives in `FnData.code` or is externally managed.
83 /// For data that does not live inside the 'data' section, this field will be undefined. (size == 0).
84 data: [*]const u8,
85
86 pub const empty: DeclBlock = .{
87 .init = false,
88 .symbol_index = 0,
89 .offset_index = 0,
90 .size = 0,
91 .prev = null,
92 .next = null,
93 .data = undefined,
94 };
95
96 /// Unplugs the `DeclBlock` from the chain
97 fn unplug(self: *DeclBlock) void {
98 if (self.prev) |prev| {
99 prev.next = self.next;
100 }
101
102 if (self.next) |next| {
103 next.prev = self.prev;
104 }
105 self.next = null;
106 self.prev = null;
107 }
108};
48109
49pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {110pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
50 assert(options.object_format == .wasm);111 assert(options.object_format == .wasm);
...@@ -52,7 +113,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -52,7 +113,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
52 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForWasm; // TODO113 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForWasm; // TODO
53 if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO114 if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO
54115
55 // TODO: read the file and keep vaild parts instead of truncating116 // TODO: read the file and keep valid parts instead of truncating
56 const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });117 const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
57 errdefer file.close();118 errdefer file.close();
58119
...@@ -80,58 +141,76 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {...@@ -80,58 +141,76 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {
80}141}
81142
82pub fn deinit(self: *Wasm) void {143pub fn deinit(self: *Wasm) void {
83 for (self.funcs.items) |decl| {144 for (self.symbols.items) |decl| {
84 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);145 decl.fn_link.wasm.functype.deinit(self.base.allocator);
85 decl.fn_link.wasm.?.code.deinit(self.base.allocator);146 decl.fn_link.wasm.code.deinit(self.base.allocator);
86 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);147 decl.fn_link.wasm.idx_refs.deinit(self.base.allocator);
87 }
88 for (self.ext_funcs.items) |decl| {
89 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
90 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
91 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
92 }148 }
149
93 self.funcs.deinit(self.base.allocator);150 self.funcs.deinit(self.base.allocator);
94 self.ext_funcs.deinit(self.base.allocator);151 self.ext_funcs.deinit(self.base.allocator);
152 self.offset_table.deinit(self.base.allocator);
153 self.offset_table_free_list.deinit(self.base.allocator);
154 self.symbols.deinit(self.base.allocator);
95}155}
96156
97// Generate code for the Decl, storing it in memory to be later written to157pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
98// the file on flush().158 if (decl.link.wasm.init) return;
99pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {159
100 const typed_value = decl.typed_value.most_recent.typed_value;160 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
101 if (typed_value.ty.zigTypeTag() != .Fn)161 try self.symbols.ensureCapacity(self.base.allocator, self.symbols.items.len + 1);
102 return error.TODOImplementNonFnDeclsForWasm;
103162
104 if (decl.fn_link.wasm) |*fn_data| {163 const block = &decl.link.wasm;
105 fn_data.functype.items.len = 0;164 block.init = true;
106 fn_data.code.items.len = 0;165
107 fn_data.idx_refs.items.len = 0;166 block.symbol_index = @intCast(u32, self.symbols.items.len);
167 self.symbols.appendAssumeCapacity(decl);
168
169 if (self.offset_table_free_list.popOrNull()) |index| {
170 block.offset_index = index;
108 } else {171 } else {
109 decl.fn_link.wasm = .{};172 block.offset_index = @intCast(u32, self.offset_table.items.len);
110 // dependent on function type, appends it to the correct list173 _ = self.offset_table.addOneAssumeCapacity();
111 switch (decl.typed_value.most_recent.typed_value.val.tag()) {174 }
175
176 self.offset_table.items[block.offset_index] = 0;
177
178 const typed_value = decl.typed_value.most_recent.typed_value;
179 if (typed_value.ty.zigTypeTag() == .Fn) {
180 switch (typed_value.val.tag()) {
181 // dependent on function type, appends it to the correct list
112 .function => try self.funcs.append(self.base.allocator, decl),182 .function => try self.funcs.append(self.base.allocator, decl),
113 .extern_fn => try self.ext_funcs.append(self.base.allocator, decl),183 .extern_fn => try self.ext_funcs.append(self.base.allocator, decl),
114 else => return error.TODOImplementNonFnDeclsForWasm,184 else => unreachable,
115 }185 }
116 }186 }
117 const fn_data = &decl.fn_link.wasm.?;187}
118188
119 var managed_functype = fn_data.functype.toManaged(self.base.allocator);189// Generate code for the Decl, storing it in memory to be later written to
120 var managed_code = fn_data.code.toManaged(self.base.allocator);190// the file on flush().
191pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
192 std.debug.assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
193
194 const typed_value = decl.typed_value.most_recent.typed_value;
195 const fn_data = &decl.fn_link.wasm;
196 fn_data.functype.items.len = 0;
197 fn_data.code.items.len = 0;
198 fn_data.idx_refs.items.len = 0;
121199
122 var context = codegen.Context{200 var context = codegen.Context{
123 .gpa = self.base.allocator,201 .gpa = self.base.allocator,
124 .values = .{},202 .values = .{},
125 .code = managed_code,203 .code = fn_data.code.toManaged(self.base.allocator),
126 .func_type_data = managed_functype,204 .func_type_data = fn_data.functype.toManaged(self.base.allocator),
127 .decl = decl,205 .decl = decl,
128 .err_msg = undefined,206 .err_msg = undefined,
129 .locals = .{},207 .locals = .{},
208 .target = self.base.options.target,
130 };209 };
131 defer context.deinit();210 defer context.deinit();
132211
133 // generate the 'code' section for the function declaration212 // generate the 'code' section for the function declaration
134 context.gen() catch |err| switch (err) {213 const result = context.gen(typed_value) catch |err| switch (err) {
135 error.CodegenFail => {214 error.CodegenFail => {
136 decl.analysis = .codegen_failure;215 decl.analysis = .codegen_failure;
137 try module.failed_decls.put(module.gpa, decl, context.err_msg);216 try module.failed_decls.put(module.gpa, decl, context.err_msg);
...@@ -140,15 +219,38 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -140,15 +219,38 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
140 else => |e| return err,219 else => |e| return err,
141 };220 };
142221
143 // as locals are patched afterwards, the offsets of funcidx's are off,222 const code: []const u8 = switch (result) {
144 // here we update them to correct them223 .appended => @as([]const u8, context.code.items),
145 for (decl.fn_link.wasm.?.idx_refs.items) |*func| {224 .externally_managed => |payload| payload,
146 // For each local, add 6 bytes (count + type)225 };
147 func.offset += @intCast(u32, context.locals.items.len * 6);
148 }
149226
150 fn_data.functype = context.func_type_data.toUnmanaged();
151 fn_data.code = context.code.toUnmanaged();227 fn_data.code = context.code.toUnmanaged();
228 fn_data.functype = context.func_type_data.toUnmanaged();
229
230 const block = &decl.link.wasm;
231 if (typed_value.ty.zigTypeTag() == .Fn) {
232 // as locals are patched afterwards, the offsets of funcidx's are off,
233 // here we update them to correct them
234 for (fn_data.idx_refs.items) |*func| {
235 // For each local, add 6 bytes (count + type)
236 func.offset += @intCast(u32, context.locals.items.len * 6);
237 }
238 } else {
239 block.size = @intCast(u32, code.len);
240 block.data = code.ptr;
241 }
242
243 // If we're updating an existing decl, unplug it first
244 // to avoid infinite loops due to earlier links
245 block.unplug();
246
247 if (self.last_block) |last| {
248 if (last != block) {
249 last.next = block;
250 block.prev = last;
251 }
252 }
253 self.last_block = block;
152}254}
153255
154pub fn updateDeclExports(256pub fn updateDeclExports(
...@@ -159,18 +261,34 @@ pub fn updateDeclExports(...@@ -159,18 +261,34 @@ pub fn updateDeclExports(
159) !void {}261) !void {}
160262
161pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {263pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
162 // TODO: remove this assert when non-function Decls are implemented264 if (self.getFuncidx(decl)) |func_idx| {
163 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);265 switch (decl.typed_value.most_recent.typed_value.val.tag()) {
164 const func_idx = self.getFuncidx(decl).?;266 .function => _ = self.funcs.swapRemove(func_idx),
165 switch (decl.typed_value.most_recent.typed_value.val.tag()) {267 .extern_fn => _ = self.ext_funcs.swapRemove(func_idx),
166 .function => _ = self.funcs.swapRemove(func_idx),268 else => unreachable,
167 .extern_fn => _ = self.ext_funcs.swapRemove(func_idx),269 }
168 else => unreachable,270 }
271 const block = &decl.link.wasm;
272
273 if (self.last_block == block) {
274 self.last_block = block.prev;
169 }275 }
170 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);276
171 decl.fn_link.wasm.?.code.deinit(self.base.allocator);277 block.unplug();
172 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);278
173 decl.fn_link.wasm = null;279 self.offset_table_free_list.append(self.base.allocator, decl.link.wasm.offset_index) catch {};
280 _ = self.symbols.swapRemove(block.symbol_index);
281
282 // update symbol_index as we swap removed the last symbol into the removed's position
283 if (block.symbol_index < self.symbols.items.len)
284 self.symbols.items[block.symbol_index].link.wasm.symbol_index = block.symbol_index;
285
286 block.init = false;
287
288 decl.fn_link.wasm.functype.deinit(self.base.allocator);
289 decl.fn_link.wasm.code.deinit(self.base.allocator);
290 decl.fn_link.wasm.idx_refs.deinit(self.base.allocator);
291 decl.fn_link.wasm = undefined;
174}292}
175293
176pub fn flush(self: *Wasm, comp: *Compilation) !void {294pub fn flush(self: *Wasm, comp: *Compilation) !void {
...@@ -187,6 +305,25 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -187,6 +305,25 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
187305
188 const file = self.base.file.?;306 const file = self.base.file.?;
189 const header_size = 5 + 1;307 const header_size = 5 + 1;
308 // ptr_width in bytes
309 const ptr_width = self.base.options.target.cpu.arch.ptrBitWidth() / 8;
310 // The size of the offset table in bytes
311 // The table contains all decl's with its corresponding offset into
312 // the 'data' section
313 const offset_table_size = @intCast(u32, self.offset_table.items.len * ptr_width);
314
315 // The size of the data, this together with `offset_table_size` amounts to the
316 // total size of the 'data' section
317 var first_decl: ?*DeclBlock = null;
318 const data_size: u32 = if (self.last_block) |last| blk: {
319 var size = last.size;
320 var cur = last;
321 while (cur.prev) |prev| : (cur = prev) {
322 size += prev.size;
323 }
324 first_decl = cur;
325 break :blk size;
326 } else 0;
190327
191 // No need to rewrite the magic/version header328 // No need to rewrite the magic/version header
192 try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));329 try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));
...@@ -198,8 +335,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -198,8 +335,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
198335
199 // extern functions are defined in the wasm binary first through the `import`336 // extern functions are defined in the wasm binary first through the `import`
200 // section, so define their func types first337 // section, so define their func types first
201 for (self.ext_funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.?.functype.items);338 for (self.ext_funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.functype.items);
202 for (self.funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.?.functype.items);339 for (self.funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.functype.items);
203340
204 try writeVecSectionHeader(341 try writeVecSectionHeader(
205 file,342 file,
...@@ -256,6 +393,31 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -256,6 +393,31 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
256 );393 );
257 }394 }
258395
396 // Memory section
397 if (data_size != 0) {
398 const header_offset = try reserveVecSectionHeader(file);
399 const writer = file.writer();
400
401 try leb.writeULEB128(writer, @as(u32, 0));
402 // Calculate the amount of memory pages are required and write them.
403 // Wasm uses 64kB page sizes. Round up to ensure the data segments fit into the memory
404 try leb.writeULEB128(
405 writer,
406 try std.math.divCeil(
407 u32,
408 offset_table_size + data_size,
409 std.wasm.page_size,
410 ),
411 );
412 try writeVecSectionHeader(
413 file,
414 header_offset,
415 .memory,
416 @intCast(u32, (try file.getPos()) - header_offset - header_size),
417 @as(u32, 1), // wasm currently only supports 1 linear memory segment
418 );
419 }
420
259 // Export section421 // Export section
260 if (self.base.options.module) |module| {422 if (self.base.options.module) |module| {
261 const header_offset = try reserveVecSectionHeader(file);423 const header_offset = try reserveVecSectionHeader(file);
...@@ -280,6 +442,16 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -280,6 +442,16 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
280 count += 1;442 count += 1;
281 }443 }
282 }444 }
445
446 // export memory if size is not 0
447 if (data_size != 0) {
448 try leb.writeULEB128(writer, @intCast(u32, "memory".len));
449 try writer.writeAll("memory");
450 try writer.writeByte(wasm.externalKind(.memory));
451 try leb.writeULEB128(writer, @as(u32, 0)); // only 1 memory 'object' can exist
452 count += 1;
453 }
454
283 try writeVecSectionHeader(455 try writeVecSectionHeader(
284 file,456 file,
285 header_offset,457 header_offset,
...@@ -294,7 +466,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -294,7 +466,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
294 const header_offset = try reserveVecSectionHeader(file);466 const header_offset = try reserveVecSectionHeader(file);
295 const writer = file.writer();467 const writer = file.writer();
296 for (self.funcs.items) |decl| {468 for (self.funcs.items) |decl| {
297 const fn_data = &decl.fn_link.wasm.?;469 const fn_data = &decl.fn_link.wasm;
298470
299 // Write the already generated code to the file, inserting471 // Write the already generated code to the file, inserting
300 // function indexes where required.472 // function indexes where required.
...@@ -319,6 +491,51 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -319,6 +491,51 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
319 @intCast(u32, self.funcs.items.len),491 @intCast(u32, self.funcs.items.len),
320 );492 );
321 }493 }
494
495 // Data section
496 if (data_size != 0) {
497 const header_offset = try reserveVecSectionHeader(file);
498 const writer = file.writer();
499 var len: u32 = 0;
500 // index to memory section (currently, there can only be 1 memory section in wasm)
501 try leb.writeULEB128(writer, @as(u32, 0));
502
503 // offset into data section
504 try writer.writeByte(wasm.opcode(.i32_const));
505 try leb.writeILEB128(writer, @as(i32, 0));
506 try writer.writeByte(wasm.opcode(.end));
507
508 const total_size = offset_table_size + data_size;
509
510 // offset table + data size
511 try leb.writeULEB128(writer, total_size);
512
513 // fill in the offset table and the data segments
514 const file_offset = try file.getPos();
515 var cur = first_decl;
516 var data_offset = offset_table_size;
517 while (cur) |cur_block| : (cur = cur_block.next) {
518 if (cur_block.size == 0) continue;
519 std.debug.assert(cur_block.init);
520
521 const offset = (cur_block.offset_index) * ptr_width;
522 var buf: [4]u8 = undefined;
523 std.mem.writeIntLittle(u32, &buf, data_offset);
524
525 try file.pwriteAll(&buf, file_offset + offset);
526 try file.pwriteAll(cur_block.data[0..cur_block.size], file_offset + data_offset);
527 data_offset += cur_block.size;
528 }
529
530 try file.seekTo(file_offset + data_offset);
531 try writeVecSectionHeader(
532 file,
533 header_offset,
534 .data,
535 @intCast(u32, (file_offset + data_offset) - header_offset - header_size),
536 @intCast(u32, 1), // only 1 data section
537 );
538 }
322}539}
323540
324fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {541fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
src/main.zig+34-25
...@@ -505,7 +505,6 @@ fn buildOutputType(...@@ -505,7 +505,6 @@ fn buildOutputType(
505 var emit_bin: EmitBin = .yes_default_path;505 var emit_bin: EmitBin = .yes_default_path;
506 var emit_asm: Emit = .no;506 var emit_asm: Emit = .no;
507 var emit_llvm_ir: Emit = .no;507 var emit_llvm_ir: Emit = .no;
508 var emit_zir: Emit = .no;
509 var emit_docs: Emit = .no;508 var emit_docs: Emit = .no;
510 var emit_analysis: Emit = .no;509 var emit_analysis: Emit = .no;
511 var target_arch_os_abi: []const u8 = "native";510 var target_arch_os_abi: []const u8 = "native";
...@@ -599,15 +598,15 @@ fn buildOutputType(...@@ -599,15 +598,15 @@ fn buildOutputType(
599 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);598 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);
600 defer test_exec_args.deinit();599 defer test_exec_args.deinit();
601600
602 const pkg_tree_root = try gpa.create(Package);
603 // This package only exists to clean up the code parsing --pkg-begin and601 // This package only exists to clean up the code parsing --pkg-begin and
604 // --pkg-end flags. Use dummy values that are safe for the destroy call.602 // --pkg-end flags. Use dummy values that are safe for the destroy call.
605 pkg_tree_root.* = .{603 var pkg_tree_root: Package = .{
606 .root_src_directory = .{ .path = null, .handle = fs.cwd() },604 .root_src_directory = .{ .path = null, .handle = fs.cwd() },
607 .root_src_path = &[0]u8{},605 .root_src_path = &[0]u8{},
606 .namespace_hash = Package.root_namespace_hash,
608 };607 };
609 defer pkg_tree_root.destroy(gpa);608 defer freePkgTree(gpa, &pkg_tree_root, false);
610 var cur_pkg: *Package = pkg_tree_root;609 var cur_pkg: *Package = &pkg_tree_root;
611610
612 switch (arg_mode) {611 switch (arg_mode) {
613 .build, .translate_c, .zig_test, .run => {612 .build, .translate_c, .zig_test, .run => {
...@@ -658,8 +657,7 @@ fn buildOutputType(...@@ -658,8 +657,7 @@ fn buildOutputType(
658 ) catch |err| {657 ) catch |err| {
659 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });658 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });
660 };659 };
661 new_cur_pkg.parent = cur_pkg;660 try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg);
662 try cur_pkg.add(gpa, pkg_name, new_cur_pkg);
663 cur_pkg = new_cur_pkg;661 cur_pkg = new_cur_pkg;
664 } else if (mem.eql(u8, arg, "--pkg-end")) {662 } else if (mem.eql(u8, arg, "--pkg-end")) {
665 cur_pkg = cur_pkg.parent orelse663 cur_pkg = cur_pkg.parent orelse
...@@ -924,12 +922,6 @@ fn buildOutputType(...@@ -924,12 +922,6 @@ fn buildOutputType(
924 emit_bin = .{ .yes = arg["-femit-bin=".len..] };922 emit_bin = .{ .yes = arg["-femit-bin=".len..] };
925 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {923 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
926 emit_bin = .no;924 emit_bin = .no;
927 } else if (mem.eql(u8, arg, "-femit-zir")) {
928 emit_zir = .yes_default_path;
929 } else if (mem.startsWith(u8, arg, "-femit-zir=")) {
930 emit_zir = .{ .yes = arg["-femit-zir=".len..] };
931 } else if (mem.eql(u8, arg, "-fno-emit-zir")) {
932 emit_zir = .no;
933 } else if (mem.eql(u8, arg, "-femit-h")) {925 } else if (mem.eql(u8, arg, "-femit-h")) {
934 emit_h = .yes_default_path;926 emit_h = .yes_default_path;
935 } else if (mem.startsWith(u8, arg, "-femit-h=")) {927 } else if (mem.startsWith(u8, arg, "-femit-h=")) {
...@@ -1026,7 +1018,7 @@ fn buildOutputType(...@@ -1026,7 +1018,7 @@ fn buildOutputType(
1026 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),1018 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
1027 });1019 });
1028 },1020 },
1029 .zig, .zir => {1021 .zig => {
1030 if (root_src_file) |other| {1022 if (root_src_file) |other| {
1031 fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });1023 fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
1032 } else {1024 } else {
...@@ -1087,7 +1079,7 @@ fn buildOutputType(...@@ -1087,7 +1079,7 @@ fn buildOutputType(
1087 .unknown, .shared_library, .object, .static_library => {1079 .unknown, .shared_library, .object, .static_library => {
1088 try link_objects.append(it.only_arg);1080 try link_objects.append(it.only_arg);
1089 },1081 },
1090 .zig, .zir => {1082 .zig => {
1091 if (root_src_file) |other| {1083 if (root_src_file) |other| {
1092 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });1084 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
1093 } else {1085 } else {
...@@ -1725,13 +1717,6 @@ fn buildOutputType(...@@ -1725,13 +1717,6 @@ fn buildOutputType(
1725 var emit_docs_resolved = try emit_docs.resolve("docs");1717 var emit_docs_resolved = try emit_docs.resolve("docs");
1726 defer emit_docs_resolved.deinit();1718 defer emit_docs_resolved.deinit();
17271719
1728 switch (emit_zir) {
1729 .no => {},
1730 .yes_default_path, .yes => {
1731 fatal("The -femit-zir implementation has been intentionally deleted so that it can be rewritten as a proper backend.", .{});
1732 },
1733 }
1734
1735 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {1720 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
1736 if (main_pkg_path) |p| {1721 if (main_pkg_path) |p| {
1737 const rel_src_path = try fs.path.relative(gpa, p, src_path);1722 const rel_src_path = try fs.path.relative(gpa, p, src_path);
...@@ -1747,6 +1732,7 @@ fn buildOutputType(...@@ -1747,6 +1732,7 @@ fn buildOutputType(
1747 if (root_pkg) |pkg| {1732 if (root_pkg) |pkg| {
1748 pkg.table = pkg_tree_root.table;1733 pkg.table = pkg_tree_root.table;
1749 pkg_tree_root.table = .{};1734 pkg_tree_root.table = .{};
1735 pkg.namespace_hash = pkg_tree_root.namespace_hash;
1750 }1736 }
17511737
1752 const self_exe_path = try fs.selfExePathAlloc(arena);1738 const self_exe_path = try fs.selfExePathAlloc(arena);
...@@ -1815,6 +1801,11 @@ fn buildOutputType(...@@ -1815,6 +1801,11 @@ fn buildOutputType(
1815 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);1801 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);
1816 }1802 }
18171803
1804 const clang_passthrough_mode = switch (arg_mode) {
1805 .cc, .cpp, .translate_c => true,
1806 else => false,
1807 };
1808
1818 gimmeMoreOfThoseSweetSweetFileDescriptors();1809 gimmeMoreOfThoseSweetSweetFileDescriptors();
18191810
1820 const comp = Compilation.create(gpa, .{1811 const comp = Compilation.create(gpa, .{
...@@ -1886,7 +1877,7 @@ fn buildOutputType(...@@ -1886,7 +1877,7 @@ fn buildOutputType(
1886 .function_sections = function_sections,1877 .function_sections = function_sections,
1887 .self_exe_path = self_exe_path,1878 .self_exe_path = self_exe_path,
1888 .thread_pool = &thread_pool,1879 .thread_pool = &thread_pool,
1889 .clang_passthrough_mode = arg_mode != .build,1880 .clang_passthrough_mode = clang_passthrough_mode,
1890 .clang_preprocessor_mode = clang_preprocessor_mode,1881 .clang_preprocessor_mode = clang_preprocessor_mode,
1891 .version = optional_version,1882 .version = optional_version,
1892 .libc_installation = if (libc_installation) |*lci| lci else null,1883 .libc_installation = if (libc_installation) |*lci| lci else null,
...@@ -2101,8 +2092,12 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi...@@ -2101,8 +2092,12 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
2101 defer errors.deinit(comp.gpa);2092 defer errors.deinit(comp.gpa);
21022093
2103 if (errors.list.len != 0) {2094 if (errors.list.len != 0) {
2095 const ttyconf: std.debug.TTY.Config = switch (comp.color) {
2096 .auto, .on => std.debug.detectTTYConfig(),
2097 .off => .no_color,
2098 };
2104 for (errors.list) |full_err_msg| {2099 for (errors.list) |full_err_msg| {
2105 full_err_msg.renderToStdErr();2100 full_err_msg.renderToStdErr(ttyconf);
2106 }2101 }
2107 const log_text = comp.getCompileLogOutput();2102 const log_text = comp.getCompileLogOutput();
2108 if (log_text.len != 0) {2103 if (log_text.len != 0) {
...@@ -2146,6 +2141,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi...@@ -2146,6 +2141,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
2146 }2141 }
2147}2142}
21482143
2144fn freePkgTree(gpa: *Allocator, pkg: *Package, free_parent: bool) void {
2145 {
2146 var it = pkg.table.iterator();
2147 while (it.next()) |kv| {
2148 freePkgTree(gpa, kv.value, true);
2149 }
2150 }
2151 if (free_parent) {
2152 pkg.destroy(gpa);
2153 }
2154}
2155
2149fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {2156fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
2150 if (!build_options.have_llvm)2157 if (!build_options.have_llvm)
2151 fatal("cannot translate-c: compiler built without LLVM extensions", .{});2158 fatal("cannot translate-c: compiler built without LLVM extensions", .{});
...@@ -2500,6 +2507,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2500,6 +2507,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2500 .handle = try zig_lib_directory.handle.openDir(std_special, .{}),2507 .handle = try zig_lib_directory.handle.openDir(std_special, .{}),
2501 },2508 },
2502 .root_src_path = "build_runner.zig",2509 .root_src_path = "build_runner.zig",
2510 .namespace_hash = Package.root_namespace_hash,
2503 };2511 };
2504 defer root_pkg.root_src_directory.handle.close();2512 defer root_pkg.root_src_directory.handle.close();
25052513
...@@ -2545,8 +2553,9 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2545,8 +2553,9 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2545 var build_pkg: Package = .{2553 var build_pkg: Package = .{
2546 .root_src_directory = build_directory,2554 .root_src_directory = build_directory,
2547 .root_src_path = build_zig_basename,2555 .root_src_path = build_zig_basename,
2556 .namespace_hash = undefined,
2548 };2557 };
2549 try root_pkg.table.put(arena, "@build", &build_pkg);2558 try root_pkg.addAndAdopt(arena, "@build", &build_pkg);
25502559
2551 var global_cache_directory: Compilation.Directory = l: {2560 var global_cache_directory: Compilation.Directory = l: {
2552 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);2561 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
src/register_manager.zig+89-2
...@@ -35,6 +35,10 @@ pub fn RegisterManager(...@@ -35,6 +35,10 @@ pub fn RegisterManager(
35 self.registers.deinit(allocator);35 self.registers.deinit(allocator);
36 }36 }
3737
38 fn isTracked(reg: Register) bool {
39 return std.mem.indexOfScalar(Register, callee_preserved_regs, reg) != null;
40 }
41
38 fn markRegUsed(self: *Self, reg: Register) void {42 fn markRegUsed(self: *Self, reg: Register) void {
39 if (FreeRegInt == u0) return;43 if (FreeRegInt == u0) return;
40 const index = reg.allocIndex() orelse return;44 const index = reg.allocIndex() orelse return;
...@@ -51,6 +55,13 @@ pub fn RegisterManager(...@@ -51,6 +55,13 @@ pub fn RegisterManager(
51 self.free_registers |= @as(FreeRegInt, 1) << shift;55 self.free_registers |= @as(FreeRegInt, 1) << shift;
52 }56 }
5357
58 pub fn isRegFree(self: Self, reg: Register) bool {
59 if (FreeRegInt == u0) return true;
60 const index = reg.allocIndex() orelse return true;
61 const shift = @intCast(ShiftInt, index);
62 return self.free_registers & @as(FreeRegInt, 1) << shift != 0;
63 }
64
54 /// Returns whether this register was allocated in the course65 /// Returns whether this register was allocated in the course
55 /// of this function66 /// of this function
56 pub fn isRegAllocated(self: Self, reg: Register) bool {67 pub fn isRegAllocated(self: Self, reg: Register) bool {
...@@ -117,17 +128,61 @@ pub fn RegisterManager(...@@ -117,17 +128,61 @@ pub fn RegisterManager(
117 const regs_entry = self.registers.remove(reg).?;128 const regs_entry = self.registers.remove(reg).?;
118 const spilled_inst = regs_entry.value;129 const spilled_inst = regs_entry.value;
119 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);130 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
131 self.markRegFree(reg);
120132
121 break :b reg;133 break :b reg;
122 };134 };
123 }135 }
124136
125 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) !void {137 /// Allocates the specified register with the specified
126 try self.registers.putNoClobber(self.getFunction().gpa, reg, inst);138 /// instruction. Spills the register if it is currently
139 /// allocated.
140 /// Before calling, must ensureCapacity + 1 on self.registers.
141 pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void {
142 if (!isTracked(reg)) return;
143
144 if (!self.isRegFree(reg)) {
145 // Move the instruction that was previously there to a
146 // stack allocation.
147 const regs_entry = self.registers.getEntry(reg).?;
148 const spilled_inst = regs_entry.value;
149 regs_entry.value = inst;
150 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
151 } else {
152 self.getRegAssumeFree(reg, inst);
153 }
154 }
155
156 /// Spills the register if it is currently allocated.
157 /// Does not track the register.
158 pub fn getRegWithoutTracking(self: *Self, reg: Register) !void {
159 if (!isTracked(reg)) return;
160
161 if (!self.isRegFree(reg)) {
162 // Move the instruction that was previously there to a
163 // stack allocation.
164 const regs_entry = self.registers.remove(reg).?;
165 const spilled_inst = regs_entry.value;
166 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
167 self.markRegFree(reg);
168 }
169 }
170
171 /// Allocates the specified register with the specified
172 /// instruction. Assumes that the register is free and no
173 /// spilling is necessary.
174 /// Before calling, must ensureCapacity + 1 on self.registers.
175 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) void {
176 if (!isTracked(reg)) return;
177
178 self.registers.putAssumeCapacityNoClobber(reg, inst);
127 self.markRegUsed(reg);179 self.markRegUsed(reg);
128 }180 }
129181
182 /// Marks the specified register as free
130 pub fn freeReg(self: *Self, reg: Register) void {183 pub fn freeReg(self: *Self, reg: Register) void {
184 if (!isTracked(reg)) return;
185
131 _ = self.registers.remove(reg);186 _ = self.registers.remove(reg);
132 self.markRegFree(reg);187 self.markRegFree(reg);
133 }188 }
...@@ -226,3 +281,35 @@ test "allocReg: spilling" {...@@ -226,3 +281,35 @@ test "allocReg: spilling" {
226 std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction));281 std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction));
227 std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);282 std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
228}283}
284
285test "getReg" {
286 const allocator = std.testing.allocator;
287
288 var function = MockFunction{
289 .allocator = allocator,
290 };
291 defer function.deinit();
292
293 var mock_instruction = ir.Inst{
294 .tag = .breakpoint,
295 .ty = Type.initTag(.void),
296 .src = .unneeded,
297 };
298
299 std.testing.expect(!function.register_manager.isRegAllocated(.r2));
300 std.testing.expect(!function.register_manager.isRegAllocated(.r3));
301
302 try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2);
303 try function.register_manager.getReg(.r3, &mock_instruction);
304
305 std.testing.expect(!function.register_manager.isRegAllocated(.r2));
306 std.testing.expect(function.register_manager.isRegAllocated(.r3));
307
308 // Spill r3
309 try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2);
310 try function.register_manager.getReg(.r3, &mock_instruction);
311
312 std.testing.expect(!function.register_manager.isRegAllocated(.r2));
313 std.testing.expect(function.register_manager.isRegAllocated(.r3));
314 std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r3}, function.spilled.items);
315}
src/stage1/codegen.cpp+1
...@@ -9110,6 +9110,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -9110,6 +9110,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
9110 buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));9110 buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));
9111 buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));9111 buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));
9112 buf_appendf(contents, "pub const code_model = CodeModel.default;\n");9112 buf_appendf(contents, "pub const code_model = CodeModel.default;\n");
9113 buf_appendf(contents, "pub const zig_is_stage2 = false;\n");
91139114
9114 {9115 {
9115 TargetSubsystem detected_subsystem = detect_subsystem(g);9116 TargetSubsystem detected_subsystem = detect_subsystem(g);
src/test.zig+21-42
...@@ -122,11 +122,6 @@ pub const TestContext = struct {...@@ -122,11 +122,6 @@ pub const TestContext = struct {
122 path: []const u8,122 path: []const u8,
123 };123 };
124124
125 pub const Extension = enum {
126 Zig,
127 ZIR,
128 };
129
130 /// A `Case` consists of a list of `Update`. The same `Compilation` is used for each125 /// A `Case` consists of a list of `Update`. The same `Compilation` is used for each
131 /// update, so each update's source is treated as a single file being126 /// update, so each update's source is treated as a single file being
132 /// updated by the test harness and incrementally compiled.127 /// updated by the test harness and incrementally compiled.
...@@ -141,7 +136,6 @@ pub const TestContext = struct {...@@ -141,7 +136,6 @@ pub const TestContext = struct {
141 /// to Executable.136 /// to Executable.
142 output_mode: std.builtin.OutputMode,137 output_mode: std.builtin.OutputMode,
143 updates: std.ArrayList(Update),138 updates: std.ArrayList(Update),
144 extension: Extension,
145 object_format: ?std.builtin.ObjectFormat = null,139 object_format: ?std.builtin.ObjectFormat = null,
146 emit_h: bool = false,140 emit_h: bool = false,
147 llvm_backend: bool = false,141 llvm_backend: bool = false,
...@@ -238,14 +232,12 @@ pub const TestContext = struct {...@@ -238,14 +232,12 @@ pub const TestContext = struct {
238 ctx: *TestContext,232 ctx: *TestContext,
239 name: []const u8,233 name: []const u8,
240 target: CrossTarget,234 target: CrossTarget,
241 extension: Extension,
242 ) *Case {235 ) *Case {
243 ctx.cases.append(Case{236 ctx.cases.append(Case{
244 .name = name,237 .name = name,
245 .target = target,238 .target = target,
246 .updates = std.ArrayList(Update).init(ctx.cases.allocator),239 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
247 .output_mode = .Exe,240 .output_mode = .Exe,
248 .extension = extension,
249 .files = std.ArrayList(File).init(ctx.cases.allocator),241 .files = std.ArrayList(File).init(ctx.cases.allocator),
250 }) catch @panic("out of memory");242 }) catch @panic("out of memory");
251 return &ctx.cases.items[ctx.cases.items.len - 1];243 return &ctx.cases.items[ctx.cases.items.len - 1];
...@@ -253,7 +245,7 @@ pub const TestContext = struct {...@@ -253,7 +245,7 @@ pub const TestContext = struct {
253245
254 /// Adds a test case for Zig input, producing an executable246 /// Adds a test case for Zig input, producing an executable
255 pub fn exe(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {247 pub fn exe(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
256 return ctx.addExe(name, target, .Zig);248 return ctx.addExe(name, target);
257 }249 }
258250
259 /// Adds a test case for ZIR input, producing an executable251 /// Adds a test case for ZIR input, producing an executable
...@@ -269,7 +261,6 @@ pub const TestContext = struct {...@@ -269,7 +261,6 @@ pub const TestContext = struct {
269 .target = target,261 .target = target,
270 .updates = std.ArrayList(Update).init(ctx.cases.allocator),262 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
271 .output_mode = .Exe,263 .output_mode = .Exe,
272 .extension = .Zig,
273 .object_format = .c,264 .object_format = .c,
274 .files = std.ArrayList(File).init(ctx.cases.allocator),265 .files = std.ArrayList(File).init(ctx.cases.allocator),
275 }) catch @panic("out of memory");266 }) catch @panic("out of memory");
...@@ -284,7 +275,6 @@ pub const TestContext = struct {...@@ -284,7 +275,6 @@ pub const TestContext = struct {
284 .target = target,275 .target = target,
285 .updates = std.ArrayList(Update).init(ctx.cases.allocator),276 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
286 .output_mode = .Exe,277 .output_mode = .Exe,
287 .extension = .Zig,
288 .files = std.ArrayList(File).init(ctx.cases.allocator),278 .files = std.ArrayList(File).init(ctx.cases.allocator),
289 .llvm_backend = true,279 .llvm_backend = true,
290 }) catch @panic("out of memory");280 }) catch @panic("out of memory");
...@@ -295,14 +285,12 @@ pub const TestContext = struct {...@@ -295,14 +285,12 @@ pub const TestContext = struct {
295 ctx: *TestContext,285 ctx: *TestContext,
296 name: []const u8,286 name: []const u8,
297 target: CrossTarget,287 target: CrossTarget,
298 extension: Extension,
299 ) *Case {288 ) *Case {
300 ctx.cases.append(Case{289 ctx.cases.append(Case{
301 .name = name,290 .name = name,
302 .target = target,291 .target = target,
303 .updates = std.ArrayList(Update).init(ctx.cases.allocator),292 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
304 .output_mode = .Obj,293 .output_mode = .Obj,
305 .extension = extension,
306 .files = std.ArrayList(File).init(ctx.cases.allocator),294 .files = std.ArrayList(File).init(ctx.cases.allocator),
307 }) catch @panic("out of memory");295 }) catch @panic("out of memory");
308 return &ctx.cases.items[ctx.cases.items.len - 1];296 return &ctx.cases.items[ctx.cases.items.len - 1];
...@@ -310,7 +298,7 @@ pub const TestContext = struct {...@@ -310,7 +298,7 @@ pub const TestContext = struct {
310298
311 /// Adds a test case for Zig input, producing an object file.299 /// Adds a test case for Zig input, producing an object file.
312 pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {300 pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
313 return ctx.addObj(name, target, .Zig);301 return ctx.addObj(name, target);
314 }302 }
315303
316 /// Adds a test case for ZIR input, producing an object file.304 /// Adds a test case for ZIR input, producing an object file.
...@@ -319,13 +307,12 @@ pub const TestContext = struct {...@@ -319,13 +307,12 @@ pub const TestContext = struct {
319 }307 }
320308
321 /// Adds a test case for Zig or ZIR input, producing C code.309 /// Adds a test case for Zig or ZIR input, producing C code.
322 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget, ext: Extension) *Case {310 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
323 ctx.cases.append(Case{311 ctx.cases.append(Case{
324 .name = name,312 .name = name,
325 .target = target,313 .target = target,
326 .updates = std.ArrayList(Update).init(ctx.cases.allocator),314 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
327 .output_mode = .Obj,315 .output_mode = .Obj,
328 .extension = ext,
329 .object_format = .c,316 .object_format = .c,
330 .files = std.ArrayList(File).init(ctx.cases.allocator),317 .files = std.ArrayList(File).init(ctx.cases.allocator),
331 }) catch @panic("out of memory");318 }) catch @panic("out of memory");
...@@ -333,21 +320,20 @@ pub const TestContext = struct {...@@ -333,21 +320,20 @@ pub const TestContext = struct {
333 }320 }
334321
335 pub fn c(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {322 pub fn c(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
336 ctx.addC(name, target, .Zig).addCompareObjectFile(src, zig_h ++ out);323 ctx.addC(name, target).addCompareObjectFile(src, zig_h ++ out);
337 }324 }
338325
339 pub fn h(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {326 pub fn h(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
340 ctx.addC(name, target, .Zig).addHeader(src, zig_h ++ out);327 ctx.addC(name, target).addHeader(src, zig_h ++ out);
341 }328 }
342329
343 pub fn addCompareOutput(330 pub fn addCompareOutput(
344 ctx: *TestContext,331 ctx: *TestContext,
345 name: []const u8,332 name: []const u8,
346 extension: Extension,
347 src: [:0]const u8,333 src: [:0]const u8,
348 expected_stdout: []const u8,334 expected_stdout: []const u8,
349 ) void {335 ) void {
350 ctx.addExe(name, .{}, extension).addCompareOutput(src, expected_stdout);336 ctx.addExe(name, .{}).addCompareOutput(src, expected_stdout);
351 }337 }
352338
353 /// Adds a test case that compiles the Zig source given in `src`, executes339 /// Adds a test case that compiles the Zig source given in `src`, executes
...@@ -358,7 +344,7 @@ pub const TestContext = struct {...@@ -358,7 +344,7 @@ pub const TestContext = struct {
358 src: [:0]const u8,344 src: [:0]const u8,
359 expected_stdout: []const u8,345 expected_stdout: []const u8,
360 ) void {346 ) void {
361 return ctx.addCompareOutput(name, .Zig, src, expected_stdout);347 return ctx.addCompareOutput(name, src, expected_stdout);
362 }348 }
363349
364 /// Adds a test case that compiles the ZIR source given in `src`, executes350 /// Adds a test case that compiles the ZIR source given in `src`, executes
...@@ -376,11 +362,10 @@ pub const TestContext = struct {...@@ -376,11 +362,10 @@ pub const TestContext = struct {
376 ctx: *TestContext,362 ctx: *TestContext,
377 name: []const u8,363 name: []const u8,
378 target: CrossTarget,364 target: CrossTarget,
379 extension: Extension,
380 src: [:0]const u8,365 src: [:0]const u8,
381 result: [:0]const u8,366 result: [:0]const u8,
382 ) void {367 ) void {
383 ctx.addObj(name, target, extension).addTransform(src, result);368 ctx.addObj(name, target).addTransform(src, result);
384 }369 }
385370
386 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests371 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests
...@@ -392,7 +377,7 @@ pub const TestContext = struct {...@@ -392,7 +377,7 @@ pub const TestContext = struct {
392 src: [:0]const u8,377 src: [:0]const u8,
393 result: [:0]const u8,378 result: [:0]const u8,
394 ) void {379 ) void {
395 ctx.addTransform(name, target, .Zig, src, result);380 ctx.addTransform(name, target, src, result);
396 }381 }
397382
398 /// Adds a test case that cleans up the ZIR source given in `src`, and383 /// Adds a test case that cleans up the ZIR source given in `src`, and
...@@ -411,11 +396,10 @@ pub const TestContext = struct {...@@ -411,11 +396,10 @@ pub const TestContext = struct {
411 ctx: *TestContext,396 ctx: *TestContext,
412 name: []const u8,397 name: []const u8,
413 target: CrossTarget,398 target: CrossTarget,
414 extension: Extension,
415 src: [:0]const u8,399 src: [:0]const u8,
416 expected_errors: []const []const u8,400 expected_errors: []const []const u8,
417 ) void {401 ) void {
418 ctx.addObj(name, target, extension).addError(src, expected_errors);402 ctx.addObj(name, target).addError(src, expected_errors);
419 }403 }
420404
421 /// Adds a test case that ensures that the Zig given in `src` fails to405 /// Adds a test case that ensures that the Zig given in `src` fails to
...@@ -428,7 +412,7 @@ pub const TestContext = struct {...@@ -428,7 +412,7 @@ pub const TestContext = struct {
428 src: [:0]const u8,412 src: [:0]const u8,
429 expected_errors: []const []const u8,413 expected_errors: []const []const u8,
430 ) void {414 ) void {
431 ctx.addError(name, target, .Zig, src, expected_errors);415 ctx.addError(name, target, src, expected_errors);
432 }416 }
433417
434 /// Adds a test case that ensures that the ZIR given in `src` fails to418 /// Adds a test case that ensures that the ZIR given in `src` fails to
...@@ -448,10 +432,9 @@ pub const TestContext = struct {...@@ -448,10 +432,9 @@ pub const TestContext = struct {
448 ctx: *TestContext,432 ctx: *TestContext,
449 name: []const u8,433 name: []const u8,
450 target: CrossTarget,434 target: CrossTarget,
451 extension: Extension,
452 src: [:0]const u8,435 src: [:0]const u8,
453 ) void {436 ) void {
454 ctx.addObj(name, target, extension).compiles(src);437 ctx.addObj(name, target).compiles(src);
455 }438 }
456439
457 /// Adds a test case that asserts that the Zig given in `src` compiles440 /// Adds a test case that asserts that the Zig given in `src` compiles
...@@ -462,7 +445,7 @@ pub const TestContext = struct {...@@ -462,7 +445,7 @@ pub const TestContext = struct {
462 target: CrossTarget,445 target: CrossTarget,
463 src: [:0]const u8,446 src: [:0]const u8,
464 ) void {447 ) void {
465 ctx.addCompiles(name, target, .Zig, src);448 ctx.addCompiles(name, target, src);
466 }449 }
467450
468 /// Adds a test case that asserts that the ZIR given in `src` compiles451 /// Adds a test case that asserts that the ZIR given in `src` compiles
...@@ -489,7 +472,7 @@ pub const TestContext = struct {...@@ -489,7 +472,7 @@ pub const TestContext = struct {
489 expected_errors: []const []const u8,472 expected_errors: []const []const u8,
490 fixed_src: [:0]const u8,473 fixed_src: [:0]const u8,
491 ) void {474 ) void {
492 var case = ctx.addObj(name, target, .Zig);475 var case = ctx.addObj(name, target);
493 case.addError(src, expected_errors);476 case.addError(src, expected_errors);
494 case.compiles(fixed_src);477 case.compiles(fixed_src);
495 }478 }
...@@ -614,15 +597,14 @@ pub const TestContext = struct {...@@ -614,15 +597,14 @@ pub const TestContext = struct {
614 .path = try std.fs.path.join(arena, &[_][]const u8{ tmp_dir_path, "zig-cache" }),597 .path = try std.fs.path.join(arena, &[_][]const u8{ tmp_dir_path, "zig-cache" }),
615 };598 };
616599
617 const tmp_src_path = switch (case.extension) {600 const tmp_src_path = "test_case.zig";
618 .Zig => "test_case.zig",
619 .ZIR => "test_case.zir",
620 };
621601
622 var root_pkg: Package = .{602 var root_pkg: Package = .{
623 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },603 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
624 .root_src_path = tmp_src_path,604 .root_src_path = tmp_src_path,
605 .namespace_hash = Package.root_namespace_hash,
625 };606 };
607 defer root_pkg.table.deinit(allocator);
626608
627 const bin_name = try std.zig.binNameAlloc(arena, .{609 const bin_name = try std.zig.binNameAlloc(arena, .{
628 .root_name = "test_case",610 .root_name = "test_case",
...@@ -639,13 +621,10 @@ pub const TestContext = struct {...@@ -639,13 +621,10 @@ pub const TestContext = struct {
639 .directory = emit_directory,621 .directory = emit_directory,
640 .basename = bin_name,622 .basename = bin_name,
641 };623 };
642 const emit_h: ?Compilation.EmitLoc = if (case.emit_h)624 const emit_h: ?Compilation.EmitLoc = if (case.emit_h) .{
643 .{625 .directory = emit_directory,
644 .directory = emit_directory,626 .basename = "test_case.h",
645 .basename = "test_case.h",627 } else null;
646 }
647 else
648 null;
649 const comp = try Compilation.create(allocator, .{628 const comp = try Compilation.create(allocator, .{
650 .local_cache_directory = zig_cache_directory,629 .local_cache_directory = zig_cache_directory,
651 .global_cache_directory = global_cache_directory,630 .global_cache_directory = global_cache_directory,
src/translate_c.zig+233-13
...@@ -1123,6 +1123,16 @@ fn transStmt(...@@ -1123,6 +1123,16 @@ fn transStmt(
1123 const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt);1123 const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt);
1124 return transExpr(c, scope, gen_sel.getResultExpr(), result_used);1124 return transExpr(c, scope, gen_sel.getResultExpr(), result_used);
1125 },1125 },
1126 .ConvertVectorExprClass => {
1127 const conv_vec = @ptrCast(*const clang.ConvertVectorExpr, stmt);
1128 const conv_vec_node = try transConvertVectorExpr(c, scope, stmt.getBeginLoc(), conv_vec);
1129 return maybeSuppressResult(c, scope, result_used, conv_vec_node);
1130 },
1131 .ShuffleVectorExprClass => {
1132 const shuffle_vec_expr = @ptrCast(*const clang.ShuffleVectorExpr, stmt);
1133 const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr);
1134 return maybeSuppressResult(c, scope, result_used, shuffle_vec_node);
1135 },
1126 // When adding new cases here, see comment for maybeBlockify()1136 // When adding new cases here, see comment for maybeBlockify()
1127 else => {1137 else => {
1128 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});1138 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
...@@ -1130,6 +1140,128 @@ fn transStmt(...@@ -1130,6 +1140,128 @@ fn transStmt(
1130 }1140 }
1131}1141}
11321142
1143/// See https://clang.llvm.org/docs/LanguageExtensions.html#langext-builtin-convertvector
1144fn transConvertVectorExpr(
1145 c: *Context,
1146 scope: *Scope,
1147 source_loc: clang.SourceLocation,
1148 expr: *const clang.ConvertVectorExpr,
1149) TransError!Node {
1150 const base_stmt = @ptrCast(*const clang.Stmt, expr);
1151
1152 var block_scope = try Scope.Block.init(c, scope, true);
1153 defer block_scope.deinit();
1154
1155 const src_expr = expr.getSrcExpr();
1156 const src_type = qualTypeCanon(src_expr.getType());
1157 const src_vector_ty = @ptrCast(*const clang.VectorType, src_type);
1158 const src_element_qt = src_vector_ty.getElementType();
1159 const src_element_type_node = try transQualType(c, &block_scope.base, src_element_qt, base_stmt.getBeginLoc());
1160
1161 const src_expr_node = try transExpr(c, &block_scope.base, src_expr, .used);
1162
1163 const dst_qt = expr.getTypeSourceInfo_getType();
1164 const dst_type_node = try transQualType(c, &block_scope.base, dst_qt, base_stmt.getBeginLoc());
1165 const dst_vector_ty = @ptrCast(*const clang.VectorType, qualTypeCanon(dst_qt));
1166 const num_elements = dst_vector_ty.getNumElements();
1167 const dst_element_qt = dst_vector_ty.getElementType();
1168
1169 // workaround for https://github.com/ziglang/zig/issues/8322
1170 // we store the casted results into temp variables and use those
1171 // to initialize the vector. Eventually we can just directly
1172 // construct the init_list from casted source members
1173 var i: usize = 0;
1174 while (i < num_elements) : (i += 1) {
1175 const mangled_name = try block_scope.makeMangledName(c, "tmp");
1176 const value = try Tag.array_access.create(c.arena, .{
1177 .lhs = src_expr_node,
1178 .rhs = try transCreateNodeNumber(c, i, .int),
1179 });
1180 const tmp_decl_node = try Tag.var_simple.create(c.arena, .{
1181 .name = mangled_name,
1182 .init = try transCCast(c, &block_scope.base, base_stmt.getBeginLoc(), dst_element_qt, src_element_qt, value),
1183 });
1184 try block_scope.statements.append(tmp_decl_node);
1185 }
1186
1187 const init_list = try c.arena.alloc(Node, num_elements);
1188 for (init_list) |*init, init_index| {
1189 const tmp_decl = block_scope.statements.items[init_index];
1190 const name = tmp_decl.castTag(.var_simple).?.data.name;
1191 init.* = try Tag.identifier.create(c.arena, name);
1192 }
1193
1194 const vec_init = try Tag.array_init.create(c.arena, .{
1195 .cond = dst_type_node,
1196 .cases = init_list,
1197 });
1198
1199 const break_node = try Tag.break_val.create(c.arena, .{
1200 .label = block_scope.label,
1201 .val = vec_init,
1202 });
1203 try block_scope.statements.append(break_node);
1204 return block_scope.complete(c);
1205}
1206
1207fn makeShuffleMask(c: *Context, scope: *Scope, expr: *const clang.ShuffleVectorExpr, vector_len: Node) TransError!Node {
1208 const num_subexprs = expr.getNumSubExprs();
1209 assert(num_subexprs >= 3); // two source vectors + at least 1 index expression
1210 const mask_len = num_subexprs - 2;
1211
1212 const mask_type = try Tag.std_meta_vector.create(c.arena, .{
1213 .lhs = try transCreateNodeNumber(c, mask_len, .int),
1214 .rhs = try Tag.type.create(c.arena, "i32"),
1215 });
1216
1217 const init_list = try c.arena.alloc(Node, mask_len);
1218
1219 for (init_list) |*init, i| {
1220 const index_expr = try transExprCoercing(c, scope, expr.getExpr(@intCast(c_uint, i + 2)), .used);
1221 const converted_index = try Tag.std_meta_shuffle_vector_index.create(c.arena, .{ .lhs = index_expr, .rhs = vector_len });
1222 init.* = converted_index;
1223 }
1224
1225 const mask_init = try Tag.array_init.create(c.arena, .{
1226 .cond = mask_type,
1227 .cases = init_list,
1228 });
1229 return Tag.@"comptime".create(c.arena, mask_init);
1230}
1231
1232/// @typeInfo(@TypeOf(vec_node)).Vector.<field>
1233fn vectorTypeInfo(arena: *mem.Allocator, vec_node: Node, field: []const u8) TransError!Node {
1234 const typeof_call = try Tag.typeof.create(arena, vec_node);
1235 const typeinfo_call = try Tag.typeinfo.create(arena, typeof_call);
1236 const vector_type_info = try Tag.field_access.create(arena, .{ .lhs = typeinfo_call, .field_name = "Vector" });
1237 return Tag.field_access.create(arena, .{ .lhs = vector_type_info, .field_name = field });
1238}
1239
1240fn transShuffleVectorExpr(
1241 c: *Context,
1242 scope: *Scope,
1243 expr: *const clang.ShuffleVectorExpr,
1244) TransError!Node {
1245 const base_expr = @ptrCast(*const clang.Expr, expr);
1246 const num_subexprs = expr.getNumSubExprs();
1247 if (num_subexprs < 3) return fail(c, error.UnsupportedTranslation, base_expr.getBeginLoc(), "ShuffleVector needs at least 1 index", .{});
1248
1249 const a = try transExpr(c, scope, expr.getExpr(0), .used);
1250 const b = try transExpr(c, scope, expr.getExpr(1), .used);
1251
1252 // clang requires first two arguments to __builtin_shufflevector to be same type
1253 const vector_child_type = try vectorTypeInfo(c.arena, a, "child");
1254 const vector_len = try vectorTypeInfo(c.arena, a, "len");
1255 const shuffle_mask = try makeShuffleMask(c, scope, expr, vector_len);
1256
1257 return Tag.shuffle.create(c.arena, .{
1258 .element_type = vector_child_type,
1259 .a = a,
1260 .b = b,
1261 .mask_vector = shuffle_mask,
1262 });
1263}
1264
1133/// Translate a "simple" offsetof expression containing exactly one component,1265/// Translate a "simple" offsetof expression containing exactly one component,
1134/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)1266/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
1135fn transSimpleOffsetOfExpr(1267fn transSimpleOffsetOfExpr(
...@@ -1935,6 +2067,10 @@ fn cIsEnum(qt: clang.QualType) bool {...@@ -1935,6 +2067,10 @@ fn cIsEnum(qt: clang.QualType) bool {
1935 return qt.getCanonicalType().getTypeClass() == .Enum;2067 return qt.getCanonicalType().getTypeClass() == .Enum;
1936}2068}
19372069
2070fn cIsVector(qt: clang.QualType) bool {
2071 return qt.getCanonicalType().getTypeClass() == .Vector;
2072}
2073
1938/// Get the underlying int type of an enum. The C compiler chooses a signed int2074/// Get the underlying int type of an enum. The C compiler chooses a signed int
1939/// type that is large enough to hold all of the enum's values. It is not required2075/// type that is large enough to hold all of the enum's values. It is not required
1940/// to be the smallest possible type that can hold all the values.2076/// to be the smallest possible type that can hold all the values.
...@@ -1991,6 +2127,11 @@ fn transCCast(...@@ -1991,6 +2127,11 @@ fn transCCast(
1991 // @bitCast(dest_type, intermediate_value)2127 // @bitCast(dest_type, intermediate_value)
1992 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr });2128 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr });
1993 }2129 }
2130 if (cIsVector(src_type) or cIsVector(dst_type)) {
2131 // C cast where at least 1 operand is a vector requires them to be same size
2132 // @bitCast(dest_type, val)
2133 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
2134 }
1994 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {2135 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
1995 // @intCast(dest_type, @ptrToInt(val))2136 // @intCast(dest_type, @ptrToInt(val))
1996 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);2137 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
...@@ -2209,6 +2350,63 @@ fn transInitListExprArray(...@@ -2209,6 +2350,63 @@ fn transInitListExprArray(
2209 }2350 }
2210}2351}
22112352
2353fn transInitListExprVector(
2354 c: *Context,
2355 scope: *Scope,
2356 loc: clang.SourceLocation,
2357 expr: *const clang.InitListExpr,
2358 ty: *const clang.Type,
2359) TransError!Node {
2360
2361 const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
2362 const vector_type = try transQualType(c, scope, qt, loc);
2363 const init_count = expr.getNumInits();
2364
2365 if (init_count == 0) {
2366 return Tag.container_init.create(c.arena, .{
2367 .lhs = vector_type,
2368 .inits = try c.arena.alloc(ast.Payload.ContainerInit.Initializer, 0),
2369 });
2370 }
2371
2372 var block_scope = try Scope.Block.init(c, scope, true);
2373 defer block_scope.deinit();
2374
2375 // workaround for https://github.com/ziglang/zig/issues/8322
2376 // we store the initializers in temp variables and use those
2377 // to initialize the vector. Eventually we can just directly
2378 // construct the init_list from casted source members
2379 var i: usize = 0;
2380 while (i < init_count) : (i += 1) {
2381 const mangled_name = try block_scope.makeMangledName(c, "tmp");
2382 const init_expr = expr.getInit(@intCast(c_uint, i));
2383 const tmp_decl_node = try Tag.var_simple.create(c.arena, .{
2384 .name = mangled_name,
2385 .init = try transExpr(c, &block_scope.base, init_expr, .used),
2386 });
2387 try block_scope.statements.append(tmp_decl_node);
2388 }
2389
2390 const init_list = try c.arena.alloc(Node, init_count);
2391 for (init_list) |*init, init_index| {
2392 const tmp_decl = block_scope.statements.items[init_index];
2393 const name = tmp_decl.castTag(.var_simple).?.data.name;
2394 init.* = try Tag.identifier.create(c.arena, name);
2395 }
2396
2397 const array_init = try Tag.array_init.create(c.arena, .{
2398 .cond = vector_type,
2399 .cases = init_list,
2400 });
2401 const break_node = try Tag.break_val.create(c.arena, .{
2402 .label = block_scope.label,
2403 .val = array_init,
2404 });
2405 try block_scope.statements.append(break_node);
2406
2407 return block_scope.complete(c);
2408}
2409
2212fn transInitListExpr(2410fn transInitListExpr(
2213 c: *Context,2411 c: *Context,
2214 scope: *Scope,2412 scope: *Scope,
...@@ -2235,6 +2433,14 @@ fn transInitListExpr(...@@ -2235,6 +2433,14 @@ fn transInitListExpr(
2235 expr,2433 expr,
2236 qual_type,2434 qual_type,
2237 ));2435 ));
2436 } else if (qual_type.isVectorType()) {
2437 return maybeSuppressResult(c, scope, used, try transInitListExprVector(
2438 c,
2439 scope,
2440 source_loc,
2441 expr,
2442 qual_type,
2443 ));
2238 } else {2444 } else {
2239 const type_name = c.str(qual_type.getTypeClassName());2445 const type_name = c.str(qual_type.getTypeClassName());
2240 return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});2446 return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});
...@@ -4085,6 +4291,15 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan...@@ -4085,6 +4291,15 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan
4085 };4291 };
4086 return Tag.typeof.create(c.arena, underlying_expr);4292 return Tag.typeof.create(c.arena, underlying_expr);
4087 },4293 },
4294 .Vector => {
4295 const vector_ty = @ptrCast(*const clang.VectorType, ty);
4296 const num_elements = vector_ty.getNumElements();
4297 const element_qt = vector_ty.getElementType();
4298 return Tag.std_meta_vector.create(c.arena, .{
4299 .lhs = try transCreateNodeNumber(c, num_elements, .int),
4300 .rhs = try transQualType(c, scope, element_qt, source_loc),
4301 });
4302 },
4088 else => {4303 else => {
4089 const type_name = c.str(ty.getTypeClassName());4304 const type_name = c.str(ty.getTypeClassName());
4090 return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});4305 return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
...@@ -5211,21 +5426,26 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5211,21 +5426,26 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5211 }5426 }
5212 },5427 },
5213 .LParen => {5428 .LParen => {
5214 var args = std.ArrayList(Node).init(c.gpa);5429 if (m.peek().? == .RParen) {
5215 defer args.deinit();5430 m.i += 1;
5216 while (true) {5431 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });
5217 const arg = try parseCCondExpr(c, m, scope);5432 } else {
5218 try args.append(arg);5433 var args = std.ArrayList(Node).init(c.gpa);
5219 switch (m.next().?) {5434 defer args.deinit();
5220 .Comma => {},5435 while (true) {
5221 .RParen => break,5436 const arg = try parseCCondExpr(c, m, scope);
5222 else => {5437 try args.append(arg);
5223 try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});5438 switch (m.next().?) {
5224 return error.ParseError;5439 .Comma => {},
5225 },5440 .RParen => break,
5441 else => {
5442 try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});
5443 return error.ParseError;
5444 },
5445 }
5226 }5446 }
5447 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
5227 }5448 }
5228 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
5229 },5449 },
5230 .LBrace => {5450 .LBrace => {
5231 var init_vals = std.ArrayList(Node).init(c.gpa);5451 var init_vals = std.ArrayList(Node).init(c.gpa);
src/translate_c/ast.zig+95-8
...@@ -66,6 +66,7 @@ pub const Node = extern union {...@@ -66,6 +66,7 @@ pub const Node = extern union {
66 @"enum",66 @"enum",
67 @"struct",67 @"struct",
68 @"union",68 @"union",
69 @"comptime",
69 array_init,70 array_init,
70 tuple,71 tuple,
71 container_init,72 container_init,
...@@ -154,6 +155,8 @@ pub const Node = extern union {...@@ -154,6 +155,8 @@ pub const Node = extern union {
154 div_exact,155 div_exact,
155 /// @byteOffsetOf(lhs, rhs)156 /// @byteOffsetOf(lhs, rhs)
156 byte_offset_of,157 byte_offset_of,
158 /// @shuffle(type, a, b, mask)
159 shuffle,
157160
158 negate,161 negate,
159 negate_wrap,162 negate_wrap,
...@@ -172,6 +175,7 @@ pub const Node = extern union {...@@ -172,6 +175,7 @@ pub const Node = extern union {
172 sizeof,175 sizeof,
173 alignof,176 alignof,
174 typeof,177 typeof,
178 typeinfo,
175 type,179 type,
176180
177 optional_type,181 optional_type,
...@@ -182,6 +186,10 @@ pub const Node = extern union {...@@ -182,6 +186,10 @@ pub const Node = extern union {
182186
183 /// @import("std").meta.sizeof(operand)187 /// @import("std").meta.sizeof(operand)
184 std_meta_sizeof,188 std_meta_sizeof,
189 /// @import("std").meta.shuffleVectorIndex(lhs, rhs)
190 std_meta_shuffle_vector_index,
191 /// @import("std").meta.Vector(lhs, rhs)
192 std_meta_vector,
185 /// @import("std").mem.zeroes(operand)193 /// @import("std").mem.zeroes(operand)
186 std_mem_zeroes,194 std_mem_zeroes,
187 /// @import("std").mem.zeroInit(lhs, rhs)195 /// @import("std").mem.zeroInit(lhs, rhs)
...@@ -233,6 +241,7 @@ pub const Node = extern union {...@@ -233,6 +241,7 @@ pub const Node = extern union {
233241
234 .std_mem_zeroes,242 .std_mem_zeroes,
235 .@"return",243 .@"return",
244 .@"comptime",
236 .discard,245 .discard,
237 .std_math_Log2Int,246 .std_math_Log2Int,
238 .negate,247 .negate,
...@@ -255,6 +264,7 @@ pub const Node = extern union {...@@ -255,6 +264,7 @@ pub const Node = extern union {
255 .sizeof,264 .sizeof,
256 .alignof,265 .alignof,
257 .typeof,266 .typeof,
267 .typeinfo,
258 => Payload.UnOp,268 => Payload.UnOp,
259269
260 .add,270 .add,
...@@ -308,6 +318,8 @@ pub const Node = extern union {...@@ -308,6 +318,8 @@ pub const Node = extern union {
308 .align_cast,318 .align_cast,
309 .array_access,319 .array_access,
310 .std_mem_zeroinit,320 .std_mem_zeroinit,
321 .std_meta_shuffle_vector_index,
322 .std_meta_vector,
311 .ptr_cast,323 .ptr_cast,
312 .div_exact,324 .div_exact,
313 .byte_offset_of,325 .byte_offset_of,
...@@ -346,6 +358,7 @@ pub const Node = extern union {...@@ -346,6 +358,7 @@ pub const Node = extern union {
346 .pub_inline_fn => Payload.PubInlineFn,358 .pub_inline_fn => Payload.PubInlineFn,
347 .field_access => Payload.FieldAccess,359 .field_access => Payload.FieldAccess,
348 .string_slice => Payload.StringSlice,360 .string_slice => Payload.StringSlice,
361 .shuffle => Payload.Shuffle,
349 };362 };
350 }363 }
351364
...@@ -678,6 +691,16 @@ pub const Payload = struct {...@@ -678,6 +691,16 @@ pub const Payload = struct {
678 end: usize,691 end: usize,
679 },692 },
680 };693 };
694
695 pub const Shuffle = struct {
696 base: Payload,
697 data: struct {
698 element_type: Node,
699 a: Node,
700 b: Node,
701 mask_vector: Node,
702 },
703 };
681};704};
682705
683/// Converts the nodes into a Zig ast.706/// Converts the nodes into a Zig ast.
...@@ -868,6 +891,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -868,6 +891,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
868 const import_node = try renderStdImport(c, "mem", "zeroInit");891 const import_node = try renderStdImport(c, "mem", "zeroInit");
869 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });892 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
870 },893 },
894 .std_meta_shuffle_vector_index => {
895 const payload = node.castTag(.std_meta_shuffle_vector_index).?.data;
896 const import_node = try renderStdImport(c, "meta", "shuffleVectorIndex");
897 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
898 },
899 .std_meta_vector => {
900 const payload = node.castTag(.std_meta_vector).?.data;
901 const import_node = try renderStdImport(c, "meta", "Vector");
902 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
903 },
871 .call => {904 .call => {
872 const payload = node.castTag(.call).?.data;905 const payload = node.castTag(.call).?.data;
873 const lhs = try renderNode(c, payload.lhs);906 const lhs = try renderNode(c, payload.lhs);
...@@ -964,6 +997,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -964,6 +997,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
964 },997 },
965 });998 });
966 },999 },
1000 .@"comptime" => {
1001 const payload = node.castTag(.@"comptime").?.data;
1002 return c.addNode(.{
1003 .tag = .@"comptime",
1004 .main_token = try c.addToken(.keyword_comptime, "comptime"),
1005 .data = .{
1006 .lhs = try renderNode(c, payload),
1007 .rhs = undefined,
1008 },
1009 });
1010 },
967 .type => {1011 .type => {
968 const payload = node.castTag(.type).?.data;1012 const payload = node.castTag(.type).?.data;
969 return c.addNode(.{1013 return c.addNode(.{
...@@ -1217,6 +1261,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1217,6 +1261,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1217 const payload = node.castTag(.sizeof).?.data;1261 const payload = node.castTag(.sizeof).?.data;
1218 return renderBuiltinCall(c, "@sizeOf", &.{payload});1262 return renderBuiltinCall(c, "@sizeOf", &.{payload});
1219 },1263 },
1264 .shuffle => {
1265 const payload = node.castTag(.shuffle).?.data;
1266 return renderBuiltinCall(c, "@shuffle", &.{
1267 payload.element_type,
1268 payload.a,
1269 payload.b,
1270 payload.mask_vector,
1271 });
1272 },
1220 .alignof => {1273 .alignof => {
1221 const payload = node.castTag(.alignof).?.data;1274 const payload = node.castTag(.alignof).?.data;
1222 return renderBuiltinCall(c, "@alignOf", &.{payload});1275 return renderBuiltinCall(c, "@alignOf", &.{payload});
...@@ -1225,6 +1278,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1225,6 +1278,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1225 const payload = node.castTag(.typeof).?.data;1278 const payload = node.castTag(.typeof).?.data;
1226 return renderBuiltinCall(c, "@TypeOf", &.{payload});1279 return renderBuiltinCall(c, "@TypeOf", &.{payload});
1227 },1280 },
1281 .typeinfo => {
1282 const payload = node.castTag(.typeinfo).?.data;
1283 return renderBuiltinCall(c, "@typeInfo", &.{payload});
1284 },
1228 .negate => return renderPrefixOp(c, node, .negation, .minus, "-"),1285 .negate => return renderPrefixOp(c, node, .negation, .minus, "-"),
1229 .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"),1286 .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"),
1230 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),1287 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),
...@@ -2085,9 +2142,12 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2085,9 +2142,12 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2085 .sizeof,2142 .sizeof,
2086 .alignof,2143 .alignof,
2087 .typeof,2144 .typeof,
2145 .typeinfo,
2088 .std_meta_sizeof,2146 .std_meta_sizeof,
2089 .std_meta_cast,2147 .std_meta_cast,
2090 .std_meta_promoteIntLiteral,2148 .std_meta_promoteIntLiteral,
2149 .std_meta_vector,
2150 .std_meta_shuffle_vector_index,
2091 .std_mem_zeroinit,2151 .std_mem_zeroinit,
2092 .integer_literal,2152 .integer_literal,
2093 .float_literal,2153 .float_literal,
...@@ -2118,6 +2178,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2118,6 +2178,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2118 .bool_to_int,2178 .bool_to_int,
2119 .div_exact,2179 .div_exact,
2120 .byte_offset_of,2180 .byte_offset_of,
2181 .shuffle,
2121 => {2182 => {
2122 // no grouping needed2183 // no grouping needed
2123 return renderNode(c, node);2184 return renderNode(c, node);
...@@ -2185,6 +2246,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2185,6 +2246,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2185 .discard,2246 .discard,
2186 .@"continue",2247 .@"continue",
2187 .@"return",2248 .@"return",
2249 .@"comptime",
2188 .usingnamespace_builtins,2250 .usingnamespace_builtins,
2189 .while_true,2251 .while_true,
2190 .if_not_break,2252 .if_not_break,
...@@ -2327,6 +2389,8 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node...@@ -2327,6 +2389,8 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node
2327 _ = try c.addToken(.l_paren, "(");2389 _ = try c.addToken(.l_paren, "(");
2328 var arg_1: NodeIndex = 0;2390 var arg_1: NodeIndex = 0;
2329 var arg_2: NodeIndex = 0;2391 var arg_2: NodeIndex = 0;
2392 var arg_3: NodeIndex = 0;
2393 var arg_4: NodeIndex = 0;
2330 switch (args.len) {2394 switch (args.len) {
2331 0 => {},2395 0 => {},
2332 1 => {2396 1 => {
...@@ -2337,18 +2401,41 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node...@@ -2337,18 +2401,41 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node
2337 _ = try c.addToken(.comma, ",");2401 _ = try c.addToken(.comma, ",");
2338 arg_2 = try renderNode(c, args[1]);2402 arg_2 = try renderNode(c, args[1]);
2339 },2403 },
2404 4 => {
2405 arg_1 = try renderNode(c, args[0]);
2406 _ = try c.addToken(.comma, ",");
2407 arg_2 = try renderNode(c, args[1]);
2408 _ = try c.addToken(.comma, ",");
2409 arg_3 = try renderNode(c, args[2]);
2410 _ = try c.addToken(.comma, ",");
2411 arg_4 = try renderNode(c, args[3]);
2412 },
2340 else => unreachable, // expand this function as needed.2413 else => unreachable, // expand this function as needed.
2341 }2414 }
23422415
2343 _ = try c.addToken(.r_paren, ")");2416 _ = try c.addToken(.r_paren, ")");
2344 return c.addNode(.{2417 if (args.len <= 2) {
2345 .tag = .builtin_call_two,2418 return c.addNode(.{
2346 .main_token = builtin_tok,2419 .tag = .builtin_call_two,
2347 .data = .{2420 .main_token = builtin_tok,
2348 .lhs = arg_1,2421 .data = .{
2349 .rhs = arg_2,2422 .lhs = arg_1,
2350 },2423 .rhs = arg_2,
2351 });2424 },
2425 });
2426 } else {
2427 std.debug.assert(args.len == 4);
2428
2429 const params = try c.listToSpan(&.{ arg_1, arg_2, arg_3, arg_4 });
2430 return c.addNode(.{
2431 .tag = .builtin_call,
2432 .main_token = builtin_tok,
2433 .data = .{
2434 .lhs = params.start,
2435 .rhs = params.end,
2436 },
2437 });
2438 }
2352}2439}
23532440
2354fn renderVar(c: *Context, node: Node) !NodeIndex {2441fn renderVar(c: *Context, node: Node) !NodeIndex {
src/type.zig+621-1734
...@@ -93,14 +93,56 @@ pub const Type = extern union {...@@ -93,14 +93,56 @@ pub const Type = extern union {
9393
94 .anyerror_void_error_union, .error_union => return .ErrorUnion,94 .anyerror_void_error_union, .error_union => return .ErrorUnion,
9595
96 .empty_struct => return .Struct,96 .empty_struct,
97 .empty_struct_literal => return .Struct,97 .empty_struct_literal,
98 .@"struct" => return .Struct,98 .@"struct",
99 => return .Struct,
100
101 .enum_full,
102 .enum_nonexhaustive,
103 .enum_simple,
104 => return .Enum,
99105
100 .var_args_param => unreachable, // can be any type106 .var_args_param => unreachable, // can be any type
101 }107 }
102 }108 }
103109
110 pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool {
111 return switch (ty.zigTypeTag()) {
112 .Int,
113 .Float,
114 .ComptimeFloat,
115 .ComptimeInt,
116 .Vector, // TODO some vectors require is_equality_cmp==true
117 => true,
118
119 .Bool,
120 .Type,
121 .Void,
122 .ErrorSet,
123 .Fn,
124 .BoundFn,
125 .Opaque,
126 .AnyFrame,
127 .Enum,
128 .EnumLiteral,
129 => is_equality_cmp,
130
131 .NoReturn,
132 .Array,
133 .Struct,
134 .Undefined,
135 .Null,
136 .ErrorUnion,
137 .Union,
138 .Frame,
139 => false,
140
141 .Pointer => is_equality_cmp or ty.isCPtr(),
142 .Optional => is_equality_cmp and ty.isPtrLikeOptional(),
143 };
144 }
145
104 pub fn initTag(comptime small_tag: Tag) Type {146 pub fn initTag(comptime small_tag: Tag) Type {
105 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);147 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
106 return .{ .tag_if_small_enough = @enumToInt(small_tag) };148 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
...@@ -614,6 +656,8 @@ pub const Type = extern union {...@@ -614,6 +656,8 @@ pub const Type = extern union {
614 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),656 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
615 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),657 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
616 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),658 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
659 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
660 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
617 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),661 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
618 }662 }
619 }663 }
...@@ -626,13 +670,13 @@ pub const Type = extern union {...@@ -626,13 +670,13 @@ pub const Type = extern union {
626 }670 }
627671
628 pub fn format(672 pub fn format(
629 self: Type,673 start_type: Type,
630 comptime fmt: []const u8,674 comptime fmt: []const u8,
631 options: std.fmt.FormatOptions,675 options: std.fmt.FormatOptions,
632 out_stream: anytype,676 writer: anytype,
633 ) @TypeOf(out_stream).Error!void {677 ) @TypeOf(writer).Error!void {
634 comptime assert(fmt.len == 0);678 comptime assert(fmt.len == 0);
635 var ty = self;679 var ty = start_type;
636 while (true) {680 while (true) {
637 const t = ty.tag();681 const t = ty.tag();
638 switch (t) {682 switch (t) {
...@@ -670,132 +714,149 @@ pub const Type = extern union {...@@ -670,132 +714,149 @@ pub const Type = extern union {
670 .comptime_float,714 .comptime_float,
671 .noreturn,715 .noreturn,
672 .var_args_param,716 .var_args_param,
673 => return out_stream.writeAll(@tagName(t)),717 => return writer.writeAll(@tagName(t)),
674718
675 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),719 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
676 .@"null" => return out_stream.writeAll("@Type(.Null)"),720 .@"null" => return writer.writeAll("@Type(.Null)"),
677 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),721 .@"undefined" => return writer.writeAll("@Type(.Undefined)"),
678722
679 .empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"),723 .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"),
680 .@"struct" => return out_stream.writeAll("(struct)"),724
681 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),725 .@"struct" => {
682 .const_slice_u8 => return out_stream.writeAll("[]const u8"),726 const struct_obj = ty.castTag(.@"struct").?.data;
683 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),727 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
684 .fn_void_no_args => return out_stream.writeAll("fn() void"),728 },
685 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),729 .enum_full, .enum_nonexhaustive => {
686 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),730 const enum_full = ty.cast(Payload.EnumFull).?.data;
687 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),731 return enum_full.owner_decl.renderFullyQualifiedName(writer);
732 },
733 .enum_simple => {
734 const enum_simple = ty.castTag(.enum_simple).?.data;
735 return enum_simple.owner_decl.renderFullyQualifiedName(writer);
736 },
737 .@"opaque" => {
738 // TODO use declaration name
739 return writer.writeAll("opaque {}");
740 },
741
742 .anyerror_void_error_union => return writer.writeAll("anyerror!void"),
743 .const_slice_u8 => return writer.writeAll("[]const u8"),
744 .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"),
745 .fn_void_no_args => return writer.writeAll("fn() void"),
746 .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),
747 .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"),
748 .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),
688 .function => {749 .function => {
689 const payload = ty.castTag(.function).?.data;750 const payload = ty.castTag(.function).?.data;
690 try out_stream.writeAll("fn(");751 try writer.writeAll("fn(");
691 for (payload.param_types) |param_type, i| {752 for (payload.param_types) |param_type, i| {
692 if (i != 0) try out_stream.writeAll(", ");753 if (i != 0) try writer.writeAll(", ");
693 try param_type.format("", .{}, out_stream);754 try param_type.format("", .{}, writer);
694 }755 }
695 if (payload.is_var_args) {756 if (payload.is_var_args) {
696 if (payload.param_types.len != 0) {757 if (payload.param_types.len != 0) {
697 try out_stream.writeAll(", ");758 try writer.writeAll(", ");
698 }759 }
699 try out_stream.writeAll("...");760 try writer.writeAll("...");
700 }761 }
701 try out_stream.writeAll(") callconv(.");762 try writer.writeAll(") callconv(.");
702 try out_stream.writeAll(@tagName(payload.cc));763 try writer.writeAll(@tagName(payload.cc));
703 try out_stream.writeAll(")");764 try writer.writeAll(")");
704 ty = payload.return_type;765 ty = payload.return_type;
705 continue;766 continue;
706 },767 },
707768
708 .array_u8 => {769 .array_u8 => {
709 const len = ty.castTag(.array_u8).?.data;770 const len = ty.castTag(.array_u8).?.data;
710 return out_stream.print("[{d}]u8", .{len});771 return writer.print("[{d}]u8", .{len});
711 },772 },
712 .array_u8_sentinel_0 => {773 .array_u8_sentinel_0 => {
713 const len = ty.castTag(.array_u8_sentinel_0).?.data;774 const len = ty.castTag(.array_u8_sentinel_0).?.data;
714 return out_stream.print("[{d}:0]u8", .{len});775 return writer.print("[{d}:0]u8", .{len});
715 },776 },
716 .array => {777 .array => {
717 const payload = ty.castTag(.array).?.data;778 const payload = ty.castTag(.array).?.data;
718 try out_stream.print("[{d}]", .{payload.len});779 try writer.print("[{d}]", .{payload.len});
719 ty = payload.elem_type;780 ty = payload.elem_type;
720 continue;781 continue;
721 },782 },
722 .array_sentinel => {783 .array_sentinel => {
723 const payload = ty.castTag(.array_sentinel).?.data;784 const payload = ty.castTag(.array_sentinel).?.data;
724 try out_stream.print("[{d}:{}]", .{ payload.len, payload.sentinel });785 try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel });
725 ty = payload.elem_type;786 ty = payload.elem_type;
726 continue;787 continue;
727 },788 },
728 .single_const_pointer => {789 .single_const_pointer => {
729 const pointee_type = ty.castTag(.single_const_pointer).?.data;790 const pointee_type = ty.castTag(.single_const_pointer).?.data;
730 try out_stream.writeAll("*const ");791 try writer.writeAll("*const ");
731 ty = pointee_type;792 ty = pointee_type;
732 continue;793 continue;
733 },794 },
734 .single_mut_pointer => {795 .single_mut_pointer => {
735 const pointee_type = ty.castTag(.single_mut_pointer).?.data;796 const pointee_type = ty.castTag(.single_mut_pointer).?.data;
736 try out_stream.writeAll("*");797 try writer.writeAll("*");
737 ty = pointee_type;798 ty = pointee_type;
738 continue;799 continue;
739 },800 },
740 .many_const_pointer => {801 .many_const_pointer => {
741 const pointee_type = ty.castTag(.many_const_pointer).?.data;802 const pointee_type = ty.castTag(.many_const_pointer).?.data;
742 try out_stream.writeAll("[*]const ");803 try writer.writeAll("[*]const ");
743 ty = pointee_type;804 ty = pointee_type;
744 continue;805 continue;
745 },806 },
746 .many_mut_pointer => {807 .many_mut_pointer => {
747 const pointee_type = ty.castTag(.many_mut_pointer).?.data;808 const pointee_type = ty.castTag(.many_mut_pointer).?.data;
748 try out_stream.writeAll("[*]");809 try writer.writeAll("[*]");
749 ty = pointee_type;810 ty = pointee_type;
750 continue;811 continue;
751 },812 },
752 .c_const_pointer => {813 .c_const_pointer => {
753 const pointee_type = ty.castTag(.c_const_pointer).?.data;814 const pointee_type = ty.castTag(.c_const_pointer).?.data;
754 try out_stream.writeAll("[*c]const ");815 try writer.writeAll("[*c]const ");
755 ty = pointee_type;816 ty = pointee_type;
756 continue;817 continue;
757 },818 },
758 .c_mut_pointer => {819 .c_mut_pointer => {
759 const pointee_type = ty.castTag(.c_mut_pointer).?.data;820 const pointee_type = ty.castTag(.c_mut_pointer).?.data;
760 try out_stream.writeAll("[*c]");821 try writer.writeAll("[*c]");
761 ty = pointee_type;822 ty = pointee_type;
762 continue;823 continue;
763 },824 },
764 .const_slice => {825 .const_slice => {
765 const pointee_type = ty.castTag(.const_slice).?.data;826 const pointee_type = ty.castTag(.const_slice).?.data;
766 try out_stream.writeAll("[]const ");827 try writer.writeAll("[]const ");
767 ty = pointee_type;828 ty = pointee_type;
768 continue;829 continue;
769 },830 },
770 .mut_slice => {831 .mut_slice => {
771 const pointee_type = ty.castTag(.mut_slice).?.data;832 const pointee_type = ty.castTag(.mut_slice).?.data;
772 try out_stream.writeAll("[]");833 try writer.writeAll("[]");
773 ty = pointee_type;834 ty = pointee_type;
774 continue;835 continue;
775 },836 },
776 .int_signed => {837 .int_signed => {
777 const bits = ty.castTag(.int_signed).?.data;838 const bits = ty.castTag(.int_signed).?.data;
778 return out_stream.print("i{d}", .{bits});839 return writer.print("i{d}", .{bits});
779 },840 },
780 .int_unsigned => {841 .int_unsigned => {
781 const bits = ty.castTag(.int_unsigned).?.data;842 const bits = ty.castTag(.int_unsigned).?.data;
782 return out_stream.print("u{d}", .{bits});843 return writer.print("u{d}", .{bits});
783 },844 },
784 .optional => {845 .optional => {
785 const child_type = ty.castTag(.optional).?.data;846 const child_type = ty.castTag(.optional).?.data;
786 try out_stream.writeByte('?');847 try writer.writeByte('?');
787 ty = child_type;848 ty = child_type;
788 continue;849 continue;
789 },850 },
790 .optional_single_const_pointer => {851 .optional_single_const_pointer => {
791 const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;852 const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;
792 try out_stream.writeAll("?*const ");853 try writer.writeAll("?*const ");
793 ty = pointee_type;854 ty = pointee_type;
794 continue;855 continue;
795 },856 },
796 .optional_single_mut_pointer => {857 .optional_single_mut_pointer => {
797 const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;858 const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;
798 try out_stream.writeAll("?*");859 try writer.writeAll("?*");
799 ty = pointee_type;860 ty = pointee_type;
800 continue;861 continue;
801 },862 },
...@@ -804,48 +865,46 @@ pub const Type = extern union {...@@ -804,48 +865,46 @@ pub const Type = extern union {
804 const payload = ty.castTag(.pointer).?.data;865 const payload = ty.castTag(.pointer).?.data;
805 if (payload.sentinel) |some| switch (payload.size) {866 if (payload.sentinel) |some| switch (payload.size) {
806 .One, .C => unreachable,867 .One, .C => unreachable,
807 .Many => try out_stream.print("[*:{}]", .{some}),868 .Many => try writer.print("[*:{}]", .{some}),
808 .Slice => try out_stream.print("[:{}]", .{some}),869 .Slice => try writer.print("[:{}]", .{some}),
809 } else switch (payload.size) {870 } else switch (payload.size) {
810 .One => try out_stream.writeAll("*"),871 .One => try writer.writeAll("*"),
811 .Many => try out_stream.writeAll("[*]"),872 .Many => try writer.writeAll("[*]"),
812 .C => try out_stream.writeAll("[*c]"),873 .C => try writer.writeAll("[*c]"),
813 .Slice => try out_stream.writeAll("[]"),874 .Slice => try writer.writeAll("[]"),
814 }875 }
815 if (payload.@"align" != 0) {876 if (payload.@"align" != 0) {
816 try out_stream.print("align({d}", .{payload.@"align"});877 try writer.print("align({d}", .{payload.@"align"});
817878
818 if (payload.bit_offset != 0) {879 if (payload.bit_offset != 0) {
819 try out_stream.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size });880 try writer.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size });
820 }881 }
821 try out_stream.writeAll(") ");882 try writer.writeAll(") ");
822 }883 }
823 if (!payload.mutable) try out_stream.writeAll("const ");884 if (!payload.mutable) try writer.writeAll("const ");
824 if (payload.@"volatile") try out_stream.writeAll("volatile ");885 if (payload.@"volatile") try writer.writeAll("volatile ");
825 if (payload.@"allowzero") try out_stream.writeAll("allowzero ");886 if (payload.@"allowzero") try writer.writeAll("allowzero ");
826887
827 ty = payload.pointee_type;888 ty = payload.pointee_type;
828 continue;889 continue;
829 },890 },
830 .error_union => {891 .error_union => {
831 const payload = ty.castTag(.error_union).?.data;892 const payload = ty.castTag(.error_union).?.data;
832 try payload.error_set.format("", .{}, out_stream);893 try payload.error_set.format("", .{}, writer);
833 try out_stream.writeAll("!");894 try writer.writeAll("!");
834 ty = payload.payload;895 ty = payload.payload;
835 continue;896 continue;
836 },897 },
837 .error_set => {898 .error_set => {
838 const error_set = ty.castTag(.error_set).?.data;899 const error_set = ty.castTag(.error_set).?.data;
839 return out_stream.writeAll(std.mem.spanZ(error_set.owner_decl.name));900 return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));
840 },901 },
841 .error_set_single => {902 .error_set_single => {
842 const name = ty.castTag(.error_set_single).?.data;903 const name = ty.castTag(.error_set_single).?.data;
843 return out_stream.print("error{{{s}}}", .{name});904 return writer.print("error{{{s}}}", .{name});
844 },905 },
845 .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"),906 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
846 .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"),907 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
847 // TODO use declaration name
848 .@"opaque" => return out_stream.writeAll("opaque {}"),
849 }908 }
850 unreachable;909 unreachable;
851 }910 }
...@@ -954,6 +1013,19 @@ pub const Type = extern union {...@@ -954,6 +1013,19 @@ pub const Type = extern union {
954 return false;1013 return false;
955 }1014 }
956 },1015 },
1016 .enum_full => {
1017 const enum_full = self.castTag(.enum_full).?.data;
1018 return enum_full.fields.count() >= 2;
1019 },
1020 .enum_simple => {
1021 const enum_simple = self.castTag(.enum_simple).?.data;
1022 return enum_simple.fields.count() >= 2;
1023 },
1024 .enum_nonexhaustive => {
1025 var buffer: Payload.Bits = undefined;
1026 const int_tag_ty = self.intTagType(&buffer);
1027 return int_tag_ty.hasCodeGenBits();
1028 },
9571029
958 // TODO lazy types1030 // TODO lazy types
959 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,1031 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
...@@ -1112,13 +1184,37 @@ pub const Type = extern union {...@@ -1112,13 +1184,37 @@ pub const Type = extern union {
1112 } else if (!payload.payload.hasCodeGenBits()) {1184 } else if (!payload.payload.hasCodeGenBits()) {
1113 return payload.error_set.abiAlignment(target);1185 return payload.error_set.abiAlignment(target);
1114 }1186 }
1115 @panic("TODO abiAlignment error union");1187 return std.math.max(
1188 payload.payload.abiAlignment(target),
1189 payload.error_set.abiAlignment(target),
1190 );
1116 },1191 },
11171192
1118 .@"struct" => {1193 .@"struct" => {
1119 @panic("TODO abiAlignment struct");1194 // TODO take into account field alignment
1195 // also make this possible to fail, and lazy
1196 // I think we need to move all the functions from type.zig which can
1197 // fail into Sema.
1198 // Probably will need to introduce multi-stage struct resolution just
1199 // like we have in stage1.
1200 const struct_obj = self.castTag(.@"struct").?.data;
1201 var biggest: u32 = 0;
1202 for (struct_obj.fields.entries.items) |entry| {
1203 const field_ty = entry.value.ty;
1204 if (!field_ty.hasCodeGenBits()) continue;
1205 const field_align = field_ty.abiAlignment(target);
1206 if (field_align > biggest) {
1207 return field_align;
1208 }
1209 }
1210 assert(biggest != 0);
1211 return biggest;
1212 },
1213 .enum_full, .enum_nonexhaustive, .enum_simple => {
1214 var buffer: Payload.Bits = undefined;
1215 const int_tag_ty = self.intTagType(&buffer);
1216 return int_tag_ty.abiAlignment(target);
1120 },1217 },
1121
1122 .c_void,1218 .c_void,
1123 .void,1219 .void,
1124 .type,1220 .type,
...@@ -1166,6 +1262,11 @@ pub const Type = extern union {...@@ -1166,6 +1262,11 @@ pub const Type = extern union {
1166 .@"struct" => {1262 .@"struct" => {
1167 @panic("TODO abiSize struct");1263 @panic("TODO abiSize struct");
1168 },1264 },
1265 .enum_simple, .enum_full, .enum_nonexhaustive => {
1266 var buffer: Payload.Bits = undefined;
1267 const int_tag_ty = self.intTagType(&buffer);
1268 return int_tag_ty.abiSize(target);
1269 },
11691270
1170 .u8,1271 .u8,
1171 .i8,1272 .i8,
...@@ -1276,76 +1377,25 @@ pub const Type = extern union {...@@ -1276,76 +1377,25 @@ pub const Type = extern union {
1276 };1377 };
1277 }1378 }
12781379
1380 /// Asserts the type is an enum.
1381 pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
1382 switch (self.tag()) {
1383 .enum_full, .enum_nonexhaustive => return self.cast(Payload.EnumFull).?.data.tag_ty,
1384 .enum_simple => {
1385 const enum_simple = self.castTag(.enum_simple).?.data;
1386 const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());
1387 buffer.* = .{
1388 .base = .{ .tag = .int_unsigned },
1389 .data = bits,
1390 };
1391 return Type.initPayload(&buffer.base);
1392 },
1393 else => unreachable,
1394 }
1395 }
1396
1279 pub fn isSinglePointer(self: Type) bool {1397 pub fn isSinglePointer(self: Type) bool {
1280 return switch (self.tag()) {1398 return switch (self.tag()) {
1281 .u8,
1282 .i8,
1283 .u16,
1284 .i16,
1285 .u32,
1286 .i32,
1287 .u64,
1288 .i64,
1289 .u128,
1290 .i128,
1291 .usize,
1292 .isize,
1293 .c_short,
1294 .c_ushort,
1295 .c_int,
1296 .c_uint,
1297 .c_long,
1298 .c_ulong,
1299 .c_longlong,
1300 .c_ulonglong,
1301 .c_longdouble,
1302 .f16,
1303 .f32,
1304 .f64,
1305 .f128,
1306 .c_void,
1307 .bool,
1308 .void,
1309 .type,
1310 .anyerror,
1311 .comptime_int,
1312 .comptime_float,
1313 .noreturn,
1314 .@"null",
1315 .@"undefined",
1316 .array,
1317 .array_sentinel,
1318 .array_u8,
1319 .array_u8_sentinel_0,
1320 .const_slice_u8,
1321 .fn_noreturn_no_args,
1322 .fn_void_no_args,
1323 .fn_naked_noreturn_no_args,
1324 .fn_ccc_void_no_args,
1325 .function,
1326 .int_unsigned,
1327 .int_signed,
1328 .optional,
1329 .optional_single_mut_pointer,
1330 .optional_single_const_pointer,
1331 .enum_literal,
1332 .many_const_pointer,
1333 .many_mut_pointer,
1334 .c_const_pointer,
1335 .c_mut_pointer,
1336 .const_slice,
1337 .mut_slice,
1338 .error_union,
1339 .anyerror_void_error_union,
1340 .error_set,
1341 .error_set_single,
1342 .@"struct",
1343 .empty_struct,
1344 .empty_struct_literal,
1345 .@"opaque",
1346 .var_args_param,
1347 => false,
1348
1349 .single_const_pointer,1399 .single_const_pointer,
1350 .single_mut_pointer,1400 .single_mut_pointer,
1351 .single_const_pointer_to_comptime_int,1401 .single_const_pointer_to_comptime_int,
...@@ -1354,73 +1404,14 @@ pub const Type = extern union {...@@ -1354,73 +1404,14 @@ pub const Type = extern union {
1354 => true,1404 => true,
13551405
1356 .pointer => self.castTag(.pointer).?.data.size == .One,1406 .pointer => self.castTag(.pointer).?.data.size == .One,
1407
1408 else => false,
1357 };1409 };
1358 }1410 }
13591411
1360 /// Asserts the `Type` is a pointer.1412 /// Asserts the `Type` is a pointer.
1361 pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size {1413 pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size {
1362 return switch (self.tag()) {1414 return switch (self.tag()) {
1363 .u8,
1364 .i8,
1365 .u16,
1366 .i16,
1367 .u32,
1368 .i32,
1369 .u64,
1370 .i64,
1371 .u128,
1372 .i128,
1373 .usize,
1374 .isize,
1375 .c_short,
1376 .c_ushort,
1377 .c_int,
1378 .c_uint,
1379 .c_long,
1380 .c_ulong,
1381 .c_longlong,
1382 .c_ulonglong,
1383 .c_longdouble,
1384 .f16,
1385 .f32,
1386 .f64,
1387 .f128,
1388 .c_void,
1389 .bool,
1390 .void,
1391 .type,
1392 .anyerror,
1393 .comptime_int,
1394 .comptime_float,
1395 .noreturn,
1396 .@"null",
1397 .@"undefined",
1398 .array,
1399 .array_sentinel,
1400 .array_u8,
1401 .array_u8_sentinel_0,
1402 .fn_noreturn_no_args,
1403 .fn_void_no_args,
1404 .fn_naked_noreturn_no_args,
1405 .fn_ccc_void_no_args,
1406 .function,
1407 .int_unsigned,
1408 .int_signed,
1409 .optional,
1410 .optional_single_mut_pointer,
1411 .optional_single_const_pointer,
1412 .enum_literal,
1413 .error_union,
1414 .anyerror_void_error_union,
1415 .error_set,
1416 .error_set_single,
1417 .empty_struct,
1418 .empty_struct_literal,
1419 .@"opaque",
1420 .@"struct",
1421 .var_args_param,
1422 => unreachable,
1423
1424 .const_slice,1415 .const_slice,
1425 .mut_slice,1416 .mut_slice,
1426 .const_slice_u8,1417 .const_slice_u8,
...@@ -1442,159 +1433,26 @@ pub const Type = extern union {...@@ -1442,159 +1433,26 @@ pub const Type = extern union {
1442 => .One,1433 => .One,
14431434
1444 .pointer => self.castTag(.pointer).?.data.size,1435 .pointer => self.castTag(.pointer).?.data.size,
1436
1437 else => unreachable,
1445 };1438 };
1446 }1439 }
14471440
1448 pub fn isSlice(self: Type) bool {1441 pub fn isSlice(self: Type) bool {
1449 return switch (self.tag()) {1442 return switch (self.tag()) {
1450 .u8,1443 .const_slice,
1451 .i8,1444 .mut_slice,
1452 .u16,1445 .const_slice_u8,
1453 .i16,1446 => true,
1454 .u32,1447
1455 .i32,1448 .pointer => self.castTag(.pointer).?.data.size == .Slice,
1456 .u64,1449
1457 .i64,1450 else => false,
1458 .u128,1451 };
1459 .i128,1452 }
1460 .usize,1453
1461 .isize,1454 pub fn isConstPtr(self: Type) bool {
1462 .c_short,1455 return switch (self.tag()) {
1463 .c_ushort,
1464 .c_int,
1465 .c_uint,
1466 .c_long,
1467 .c_ulong,
1468 .c_longlong,
1469 .c_ulonglong,
1470 .c_longdouble,
1471 .f16,
1472 .f32,
1473 .f64,
1474 .f128,
1475 .c_void,
1476 .bool,
1477 .void,
1478 .type,
1479 .anyerror,
1480 .comptime_int,
1481 .comptime_float,
1482 .noreturn,
1483 .@"null",
1484 .@"undefined",
1485 .array,
1486 .array_sentinel,
1487 .array_u8,
1488 .array_u8_sentinel_0,
1489 .single_const_pointer,
1490 .single_mut_pointer,
1491 .many_const_pointer,
1492 .many_mut_pointer,
1493 .c_const_pointer,
1494 .c_mut_pointer,
1495 .single_const_pointer_to_comptime_int,
1496 .fn_noreturn_no_args,
1497 .fn_void_no_args,
1498 .fn_naked_noreturn_no_args,
1499 .fn_ccc_void_no_args,
1500 .function,
1501 .int_unsigned,
1502 .int_signed,
1503 .optional,
1504 .optional_single_mut_pointer,
1505 .optional_single_const_pointer,
1506 .enum_literal,
1507 .error_union,
1508 .anyerror_void_error_union,
1509 .error_set,
1510 .error_set_single,
1511 .empty_struct,
1512 .empty_struct_literal,
1513 .inferred_alloc_const,
1514 .inferred_alloc_mut,
1515 .@"struct",
1516 .@"opaque",
1517 .var_args_param,
1518 => false,
1519
1520 .const_slice,
1521 .mut_slice,
1522 .const_slice_u8,
1523 => true,
1524
1525 .pointer => self.castTag(.pointer).?.data.size == .Slice,
1526 };
1527 }
1528
1529 pub fn isConstPtr(self: Type) bool {
1530 return switch (self.tag()) {
1531 .u8,
1532 .i8,
1533 .u16,
1534 .i16,
1535 .u32,
1536 .i32,
1537 .u64,
1538 .i64,
1539 .u128,
1540 .i128,
1541 .usize,
1542 .isize,
1543 .c_short,
1544 .c_ushort,
1545 .c_int,
1546 .c_uint,
1547 .c_long,
1548 .c_ulong,
1549 .c_longlong,
1550 .c_ulonglong,
1551 .c_longdouble,
1552 .f16,
1553 .f32,
1554 .f64,
1555 .f128,
1556 .c_void,
1557 .bool,
1558 .void,
1559 .type,
1560 .anyerror,
1561 .comptime_int,
1562 .comptime_float,
1563 .noreturn,
1564 .@"null",
1565 .@"undefined",
1566 .array,
1567 .array_sentinel,
1568 .array_u8,
1569 .array_u8_sentinel_0,
1570 .fn_noreturn_no_args,
1571 .fn_void_no_args,
1572 .fn_naked_noreturn_no_args,
1573 .fn_ccc_void_no_args,
1574 .function,
1575 .int_unsigned,
1576 .int_signed,
1577 .single_mut_pointer,
1578 .many_mut_pointer,
1579 .c_mut_pointer,
1580 .optional,
1581 .optional_single_mut_pointer,
1582 .optional_single_const_pointer,
1583 .enum_literal,
1584 .mut_slice,
1585 .error_union,
1586 .anyerror_void_error_union,
1587 .error_set,
1588 .error_set_single,
1589 .empty_struct,
1590 .empty_struct_literal,
1591 .inferred_alloc_const,
1592 .inferred_alloc_mut,
1593 .@"struct",
1594 .@"opaque",
1595 .var_args_param,
1596 => false,
1597
1598 .single_const_pointer,1456 .single_const_pointer,
1599 .many_const_pointer,1457 .many_const_pointer,
1600 .c_const_pointer,1458 .c_const_pointer,
...@@ -1604,182 +1462,52 @@ pub const Type = extern union {...@@ -1604,182 +1462,52 @@ pub const Type = extern union {
1604 => true,1462 => true,
16051463
1606 .pointer => !self.castTag(.pointer).?.data.mutable,1464 .pointer => !self.castTag(.pointer).?.data.mutable,
1465
1466 else => false,
1607 };1467 };
1608 }1468 }
16091469
1610 pub fn isVolatilePtr(self: Type) bool {1470 pub fn isVolatilePtr(self: Type) bool {
1611 return switch (self.tag()) {1471 return switch (self.tag()) {
1612 .u8,
1613 .i8,
1614 .u16,
1615 .i16,
1616 .u32,
1617 .i32,
1618 .u64,
1619 .i64,
1620 .u128,
1621 .i128,
1622 .usize,
1623 .isize,
1624 .c_short,
1625 .c_ushort,
1626 .c_int,
1627 .c_uint,
1628 .c_long,
1629 .c_ulong,
1630 .c_longlong,
1631 .c_ulonglong,
1632 .c_longdouble,
1633 .f16,
1634 .f32,
1635 .f64,
1636 .f128,
1637 .c_void,
1638 .bool,
1639 .void,
1640 .type,
1641 .anyerror,
1642 .comptime_int,
1643 .comptime_float,
1644 .noreturn,
1645 .@"null",
1646 .@"undefined",
1647 .array,
1648 .array_sentinel,
1649 .array_u8,
1650 .array_u8_sentinel_0,
1651 .fn_noreturn_no_args,
1652 .fn_void_no_args,
1653 .fn_naked_noreturn_no_args,
1654 .fn_ccc_void_no_args,
1655 .function,
1656 .int_unsigned,
1657 .int_signed,
1658 .single_mut_pointer,
1659 .single_const_pointer,
1660 .many_const_pointer,
1661 .many_mut_pointer,
1662 .c_const_pointer,
1663 .c_mut_pointer,
1664 .const_slice,
1665 .mut_slice,
1666 .single_const_pointer_to_comptime_int,
1667 .const_slice_u8,
1668 .optional,
1669 .optional_single_mut_pointer,
1670 .optional_single_const_pointer,
1671 .enum_literal,
1672 .error_union,
1673 .anyerror_void_error_union,
1674 .error_set,
1675 .error_set_single,
1676 .empty_struct,
1677 .empty_struct_literal,
1678 .inferred_alloc_const,
1679 .inferred_alloc_mut,
1680 .@"struct",
1681 .@"opaque",
1682 .var_args_param,
1683 => false,
1684
1685 .pointer => {1472 .pointer => {
1686 const payload = self.castTag(.pointer).?.data;1473 const payload = self.castTag(.pointer).?.data;
1687 return payload.@"volatile";1474 return payload.@"volatile";
1688 },1475 },
1476 else => false,
1689 };1477 };
1690 }1478 }
16911479
1692 pub fn isAllowzeroPtr(self: Type) bool {1480 pub fn isAllowzeroPtr(self: Type) bool {
1693 return switch (self.tag()) {1481 return switch (self.tag()) {
1694 .u8,
1695 .i8,
1696 .u16,
1697 .i16,
1698 .u32,
1699 .i32,
1700 .u64,
1701 .i64,
1702 .u128,
1703 .i128,
1704 .usize,
1705 .isize,
1706 .c_short,
1707 .c_ushort,
1708 .c_int,
1709 .c_uint,
1710 .c_long,
1711 .c_ulong,
1712 .c_longlong,
1713 .c_ulonglong,
1714 .c_longdouble,
1715 .f16,
1716 .f32,
1717 .f64,
1718 .f128,
1719 .c_void,
1720 .bool,
1721 .void,
1722 .type,
1723 .anyerror,
1724 .comptime_int,
1725 .comptime_float,
1726 .noreturn,
1727 .@"null",
1728 .@"undefined",
1729 .array,
1730 .array_sentinel,
1731 .array_u8,
1732 .array_u8_sentinel_0,
1733 .fn_noreturn_no_args,
1734 .fn_void_no_args,
1735 .fn_naked_noreturn_no_args,
1736 .fn_ccc_void_no_args,
1737 .function,
1738 .int_unsigned,
1739 .int_signed,
1740 .single_mut_pointer,
1741 .single_const_pointer,
1742 .many_const_pointer,
1743 .many_mut_pointer,
1744 .c_const_pointer,
1745 .c_mut_pointer,
1746 .const_slice,
1747 .mut_slice,
1748 .single_const_pointer_to_comptime_int,
1749 .const_slice_u8,
1750 .optional,
1751 .optional_single_mut_pointer,
1752 .optional_single_const_pointer,
1753 .enum_literal,
1754 .error_union,
1755 .anyerror_void_error_union,
1756 .error_set,
1757 .error_set_single,
1758 .empty_struct,
1759 .empty_struct_literal,
1760 .inferred_alloc_const,
1761 .inferred_alloc_mut,
1762 .@"struct",
1763 .@"opaque",
1764 .var_args_param,
1765 => false,
1766
1767 .pointer => {1482 .pointer => {
1768 const payload = self.castTag(.pointer).?.data;1483 const payload = self.castTag(.pointer).?.data;
1769 return payload.@"allowzero";1484 return payload.@"allowzero";
1770 },1485 },
1486 else => false,
1771 };1487 };
1772 }1488 }
17731489
1774 /// Asserts that the type is an optional1490 pub fn isCPtr(self: Type) bool {
1775 pub fn isPtrLikeOptional(self: Type) bool {1491 return switch (self.tag()) {
1776 switch (self.tag()) {1492 .c_const_pointer,
1777 .optional_single_const_pointer, .optional_single_mut_pointer => return true,1493 .c_mut_pointer,
1778 .optional => {1494 => return true,
1779 var buf: Payload.ElemType = undefined;1495
1780 const child_type = self.optionalChild(&buf);1496 .pointer => self.castTag(.pointer).?.data.size == .C,
1781 // optionals of zero sized pointers behave like bools1497
1782 if (!child_type.hasCodeGenBits()) return false;1498 else => return false,
1499 };
1500 }
1501
1502 /// Asserts that the type is an optional
1503 pub fn isPtrLikeOptional(self: Type) bool {
1504 switch (self.tag()) {
1505 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
1506 .optional => {
1507 var buf: Payload.ElemType = undefined;
1508 const child_type = self.optionalChild(&buf);
1509 // optionals of zero sized pointers behave like bools
1510 if (!child_type.hasCodeGenBits()) return false;
17831511
1784 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();1512 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();
1785 },1513 },
...@@ -1833,64 +1561,6 @@ pub const Type = extern union {...@@ -1833,64 +1561,6 @@ pub const Type = extern union {
1833 /// Asserts the type is a pointer or array type.1561 /// Asserts the type is a pointer or array type.
1834 pub fn elemType(self: Type) Type {1562 pub fn elemType(self: Type) Type {
1835 return switch (self.tag()) {1563 return switch (self.tag()) {
1836 .u8 => unreachable,
1837 .i8 => unreachable,
1838 .u16 => unreachable,
1839 .i16 => unreachable,
1840 .u32 => unreachable,
1841 .i32 => unreachable,
1842 .u64 => unreachable,
1843 .i64 => unreachable,
1844 .u128 => unreachable,
1845 .i128 => unreachable,
1846 .usize => unreachable,
1847 .isize => unreachable,
1848 .c_short => unreachable,
1849 .c_ushort => unreachable,
1850 .c_int => unreachable,
1851 .c_uint => unreachable,
1852 .c_long => unreachable,
1853 .c_ulong => unreachable,
1854 .c_longlong => unreachable,
1855 .c_ulonglong => unreachable,
1856 .c_longdouble => unreachable,
1857 .f16 => unreachable,
1858 .f32 => unreachable,
1859 .f64 => unreachable,
1860 .f128 => unreachable,
1861 .c_void => unreachable,
1862 .bool => unreachable,
1863 .void => unreachable,
1864 .type => unreachable,
1865 .anyerror => unreachable,
1866 .comptime_int => unreachable,
1867 .comptime_float => unreachable,
1868 .noreturn => unreachable,
1869 .@"null" => unreachable,
1870 .@"undefined" => unreachable,
1871 .fn_noreturn_no_args => unreachable,
1872 .fn_void_no_args => unreachable,
1873 .fn_naked_noreturn_no_args => unreachable,
1874 .fn_ccc_void_no_args => unreachable,
1875 .function => unreachable,
1876 .int_unsigned => unreachable,
1877 .int_signed => unreachable,
1878 .optional => unreachable,
1879 .optional_single_const_pointer => unreachable,
1880 .optional_single_mut_pointer => unreachable,
1881 .enum_literal => unreachable,
1882 .error_union => unreachable,
1883 .anyerror_void_error_union => unreachable,
1884 .error_set => unreachable,
1885 .error_set_single => unreachable,
1886 .@"struct" => unreachable,
1887 .empty_struct => unreachable,
1888 .empty_struct_literal => unreachable,
1889 .inferred_alloc_const => unreachable,
1890 .inferred_alloc_mut => unreachable,
1891 .@"opaque" => unreachable,
1892 .var_args_param => unreachable,
1893
1894 .array => self.castTag(.array).?.data.elem_type,1564 .array => self.castTag(.array).?.data.elem_type,
1895 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,1565 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
1896 .single_const_pointer,1566 .single_const_pointer,
...@@ -1902,9 +1572,12 @@ pub const Type = extern union {...@@ -1902,9 +1572,12 @@ pub const Type = extern union {
1902 .const_slice,1572 .const_slice,
1903 .mut_slice,1573 .mut_slice,
1904 => self.castPointer().?.data,1574 => self.castPointer().?.data,
1575
1905 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),1576 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
1906 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),1577 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
1907 .pointer => self.castTag(.pointer).?.data.pointee_type,1578 .pointer => self.castTag(.pointer).?.data.pointee_type,
1579
1580 else => unreachable,
1908 };1581 };
1909 }1582 }
19101583
...@@ -1972,823 +1645,120 @@ pub const Type = extern union {...@@ -1972,823 +1645,120 @@ pub const Type = extern union {
1972 /// Asserts the type is an array or vector.1645 /// Asserts the type is an array or vector.
1973 pub fn arrayLen(self: Type) u64 {1646 pub fn arrayLen(self: Type) u64 {
1974 return switch (self.tag()) {1647 return switch (self.tag()) {
1975 .u8,
1976 .i8,
1977 .u16,
1978 .i16,
1979 .u32,
1980 .i32,
1981 .u64,
1982 .i64,
1983 .u128,
1984 .i128,
1985 .usize,
1986 .isize,
1987 .c_short,
1988 .c_ushort,
1989 .c_int,
1990 .c_uint,
1991 .c_long,
1992 .c_ulong,
1993 .c_longlong,
1994 .c_ulonglong,
1995 .c_longdouble,
1996 .f16,
1997 .f32,
1998 .f64,
1999 .f128,
2000 .c_void,
2001 .bool,
2002 .void,
2003 .type,
2004 .anyerror,
2005 .comptime_int,
2006 .comptime_float,
2007 .noreturn,
2008 .@"null",
2009 .@"undefined",
2010 .fn_noreturn_no_args,
2011 .fn_void_no_args,
2012 .fn_naked_noreturn_no_args,
2013 .fn_ccc_void_no_args,
2014 .function,
2015 .pointer,
2016 .single_const_pointer,
2017 .single_mut_pointer,
2018 .many_const_pointer,
2019 .many_mut_pointer,
2020 .c_const_pointer,
2021 .c_mut_pointer,
2022 .const_slice,
2023 .mut_slice,
2024 .single_const_pointer_to_comptime_int,
2025 .const_slice_u8,
2026 .int_unsigned,
2027 .int_signed,
2028 .optional,
2029 .optional_single_mut_pointer,
2030 .optional_single_const_pointer,
2031 .enum_literal,
2032 .error_union,
2033 .anyerror_void_error_union,
2034 .error_set,
2035 .error_set_single,
2036 .@"struct",
2037 .empty_struct,
2038 .empty_struct_literal,
2039 .inferred_alloc_const,
2040 .inferred_alloc_mut,
2041 .@"opaque",
2042 .var_args_param,
2043 => unreachable,
2044
2045 .array => self.castTag(.array).?.data.len,1648 .array => self.castTag(.array).?.data.len,
2046 .array_sentinel => self.castTag(.array_sentinel).?.data.len,1649 .array_sentinel => self.castTag(.array_sentinel).?.data.len,
2047 .array_u8 => self.castTag(.array_u8).?.data,1650 .array_u8 => self.castTag(.array_u8).?.data,
2048 .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data,1651 .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data,
2049 };
2050 }
2051
2052 /// Asserts the type is an array, pointer or vector.
2053 pub fn sentinel(self: Type) ?Value {
2054 return switch (self.tag()) {
2055 .u8,
2056 .i8,
2057 .u16,
2058 .i16,
2059 .u32,
2060 .i32,
2061 .u64,
2062 .i64,
2063 .u128,
2064 .i128,
2065 .usize,
2066 .isize,
2067 .c_short,
2068 .c_ushort,
2069 .c_int,
2070 .c_uint,
2071 .c_long,
2072 .c_ulong,
2073 .c_longlong,
2074 .c_ulonglong,
2075 .c_longdouble,
2076 .f16,
2077 .f32,
2078 .f64,
2079 .f128,
2080 .c_void,
2081 .bool,
2082 .void,
2083 .type,
2084 .anyerror,
2085 .comptime_int,
2086 .comptime_float,
2087 .noreturn,
2088 .@"null",
2089 .@"undefined",
2090 .fn_noreturn_no_args,
2091 .fn_void_no_args,
2092 .fn_naked_noreturn_no_args,
2093 .fn_ccc_void_no_args,
2094 .function,
2095 .const_slice,
2096 .mut_slice,
2097 .const_slice_u8,
2098 .int_unsigned,
2099 .int_signed,
2100 .optional,
2101 .optional_single_mut_pointer,
2102 .optional_single_const_pointer,
2103 .enum_literal,
2104 .error_union,
2105 .anyerror_void_error_union,
2106 .error_set,
2107 .error_set_single,
2108 .@"struct",
2109 .empty_struct,
2110 .empty_struct_literal,
2111 .inferred_alloc_const,
2112 .inferred_alloc_mut,
2113 .@"opaque",
2114 .var_args_param,
2115 => unreachable,
21161652
2117 .single_const_pointer,1653 else => unreachable,
2118 .single_mut_pointer,
2119 .many_const_pointer,
2120 .many_mut_pointer,
2121 .c_const_pointer,
2122 .c_mut_pointer,
2123 .single_const_pointer_to_comptime_int,
2124 .array,
2125 .array_u8,
2126 => return null,
2127
2128 .pointer => return self.castTag(.pointer).?.data.sentinel,
2129 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
2130 .array_u8_sentinel_0 => return Value.initTag(.zero),
2131 };1654 };
2132 }1655 }
21331656
2134 /// Returns true if and only if the type is a fixed-width integer.1657 /// Asserts the type is an array, pointer or vector.
2135 pub fn isInt(self: Type) bool {1658 pub fn sentinel(self: Type) ?Value {
2136 return self.isSignedInt() or self.isUnsignedInt();1659 return switch (self.tag()) {
2137 }
2138
2139 /// Returns true if and only if the type is a fixed-width, signed integer.
2140 pub fn isSignedInt(self: Type) bool {
2141 return switch (self.tag()) {
2142 .f16,
2143 .f32,
2144 .f64,
2145 .f128,
2146 .c_longdouble,
2147 .c_void,
2148 .bool,
2149 .void,
2150 .type,
2151 .anyerror,
2152 .comptime_int,
2153 .comptime_float,
2154 .noreturn,
2155 .@"null",
2156 .@"undefined",
2157 .fn_noreturn_no_args,
2158 .fn_void_no_args,
2159 .fn_naked_noreturn_no_args,
2160 .fn_ccc_void_no_args,
2161 .function,
2162 .array,
2163 .array_sentinel,
2164 .array_u8,
2165 .array_u8_sentinel_0,
2166 .pointer,
2167 .single_const_pointer,
2168 .single_mut_pointer,
2169 .many_const_pointer,
2170 .many_mut_pointer,
2171 .c_const_pointer,
2172 .c_mut_pointer,
2173 .const_slice,
2174 .mut_slice,
2175 .single_const_pointer_to_comptime_int,
2176 .const_slice_u8,
2177 .int_unsigned,
2178 .u8,
2179 .usize,
2180 .c_ushort,
2181 .c_uint,
2182 .c_ulong,
2183 .c_ulonglong,
2184 .u16,
2185 .u32,
2186 .u64,
2187 .optional,
2188 .optional_single_mut_pointer,
2189 .optional_single_const_pointer,
2190 .enum_literal,
2191 .error_union,
2192 .anyerror_void_error_union,
2193 .error_set,
2194 .error_set_single,
2195 .@"struct",
2196 .empty_struct,
2197 .empty_struct_literal,
2198 .inferred_alloc_const,
2199 .inferred_alloc_mut,
2200 .@"opaque",
2201 .var_args_param,
2202 => false,
2203
2204 .int_signed,
2205 .i8,
2206 .isize,
2207 .c_short,
2208 .c_int,
2209 .c_long,
2210 .c_longlong,
2211 .i16,
2212 .i32,
2213 .i64,
2214 .u128,
2215 .i128,
2216 => true,
2217 };
2218 }
2219
2220 /// Returns true if and only if the type is a fixed-width, unsigned integer.
2221 pub fn isUnsignedInt(self: Type) bool {
2222 return switch (self.tag()) {
2223 .f16,
2224 .f32,
2225 .f64,
2226 .f128,
2227 .c_longdouble,
2228 .c_void,
2229 .bool,
2230 .void,
2231 .type,
2232 .anyerror,
2233 .comptime_int,
2234 .comptime_float,
2235 .noreturn,
2236 .@"null",
2237 .@"undefined",
2238 .fn_noreturn_no_args,
2239 .fn_void_no_args,
2240 .fn_naked_noreturn_no_args,
2241 .fn_ccc_void_no_args,
2242 .function,
2243 .array,
2244 .array_sentinel,
2245 .array_u8,
2246 .array_u8_sentinel_0,
2247 .pointer,
2248 .single_const_pointer,
2249 .single_mut_pointer,
2250 .many_const_pointer,
2251 .many_mut_pointer,
2252 .c_const_pointer,
2253 .c_mut_pointer,
2254 .const_slice,
2255 .mut_slice,
2256 .single_const_pointer_to_comptime_int,
2257 .const_slice_u8,
2258 .int_signed,
2259 .i8,
2260 .isize,
2261 .c_short,
2262 .c_int,
2263 .c_long,
2264 .c_longlong,
2265 .i16,
2266 .i32,
2267 .i64,
2268 .u128,
2269 .i128,
2270 .optional,
2271 .optional_single_mut_pointer,
2272 .optional_single_const_pointer,
2273 .enum_literal,
2274 .error_union,
2275 .anyerror_void_error_union,
2276 .error_set,
2277 .error_set_single,
2278 .@"struct",
2279 .empty_struct,
2280 .empty_struct_literal,
2281 .inferred_alloc_const,
2282 .inferred_alloc_mut,
2283 .@"opaque",
2284 .var_args_param,
2285 => false,
2286
2287 .int_unsigned,
2288 .u8,
2289 .usize,
2290 .c_ushort,
2291 .c_uint,
2292 .c_ulong,
2293 .c_ulonglong,
2294 .u16,
2295 .u32,
2296 .u64,
2297 => true,
2298 };
2299 }
2300
2301 /// Asserts the type is an integer.
2302 pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
2303 return switch (self.tag()) {
2304 .f16,
2305 .f32,
2306 .f64,
2307 .f128,
2308 .c_longdouble,
2309 .c_void,
2310 .bool,
2311 .void,
2312 .type,
2313 .anyerror,
2314 .comptime_int,
2315 .comptime_float,
2316 .noreturn,
2317 .@"null",
2318 .@"undefined",
2319 .fn_noreturn_no_args,
2320 .fn_void_no_args,
2321 .fn_naked_noreturn_no_args,
2322 .fn_ccc_void_no_args,
2323 .function,
2324 .array,
2325 .array_sentinel,
2326 .array_u8,
2327 .array_u8_sentinel_0,
2328 .pointer,
2329 .single_const_pointer,
2330 .single_mut_pointer,
2331 .many_const_pointer,
2332 .many_mut_pointer,
2333 .c_const_pointer,
2334 .c_mut_pointer,
2335 .const_slice,
2336 .mut_slice,
2337 .single_const_pointer_to_comptime_int,
2338 .const_slice_u8,
2339 .optional,
2340 .optional_single_mut_pointer,
2341 .optional_single_const_pointer,
2342 .enum_literal,
2343 .error_union,
2344 .anyerror_void_error_union,
2345 .error_set,
2346 .error_set_single,
2347 .@"struct",
2348 .empty_struct,
2349 .empty_struct_literal,
2350 .inferred_alloc_const,
2351 .inferred_alloc_mut,
2352 .@"opaque",
2353 .var_args_param,
2354 => unreachable,
2355
2356 .int_unsigned => .{
2357 .signedness = .unsigned,
2358 .bits = self.castTag(.int_unsigned).?.data,
2359 },
2360 .int_signed => .{
2361 .signedness = .signed,
2362 .bits = self.castTag(.int_signed).?.data,
2363 },
2364 .u8 => .{ .signedness = .unsigned, .bits = 8 },
2365 .i8 => .{ .signedness = .signed, .bits = 8 },
2366 .u16 => .{ .signedness = .unsigned, .bits = 16 },
2367 .i16 => .{ .signedness = .signed, .bits = 16 },
2368 .u32 => .{ .signedness = .unsigned, .bits = 32 },
2369 .i32 => .{ .signedness = .signed, .bits = 32 },
2370 .u64 => .{ .signedness = .unsigned, .bits = 64 },
2371 .i64 => .{ .signedness = .signed, .bits = 64 },
2372 .u128 => .{ .signedness = .unsigned, .bits = 128 },
2373 .i128 => .{ .signedness = .signed, .bits = 128 },
2374 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
2375 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
2376 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
2377 .c_ushort => .{ .signedness = .unsigned, .bits = CType.ushort.sizeInBits(target) },
2378 .c_int => .{ .signedness = .signed, .bits = CType.int.sizeInBits(target) },
2379 .c_uint => .{ .signedness = .unsigned, .bits = CType.uint.sizeInBits(target) },
2380 .c_long => .{ .signedness = .signed, .bits = CType.long.sizeInBits(target) },
2381 .c_ulong => .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) },
2382 .c_longlong => .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) },
2383 .c_ulonglong => .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) },
2384 };
2385 }
2386
2387 pub fn isNamedInt(self: Type) bool {
2388 return switch (self.tag()) {
2389 .f16,
2390 .f32,
2391 .f64,
2392 .f128,
2393 .c_longdouble,
2394 .c_void,
2395 .bool,
2396 .void,
2397 .type,
2398 .anyerror,
2399 .comptime_int,
2400 .comptime_float,
2401 .noreturn,
2402 .@"null",
2403 .@"undefined",
2404 .fn_noreturn_no_args,
2405 .fn_void_no_args,
2406 .fn_naked_noreturn_no_args,
2407 .fn_ccc_void_no_args,
2408 .function,
2409 .array,
2410 .array_sentinel,
2411 .array_u8,
2412 .array_u8_sentinel_0,
2413 .pointer,
2414 .single_const_pointer,
2415 .single_mut_pointer,
2416 .many_const_pointer,
2417 .many_mut_pointer,
2418 .c_const_pointer,
2419 .c_mut_pointer,
2420 .const_slice,
2421 .mut_slice,
2422 .single_const_pointer_to_comptime_int,
2423 .const_slice_u8,
2424 .int_unsigned,
2425 .int_signed,
2426 .u8,
2427 .i8,
2428 .u16,
2429 .i16,
2430 .u32,
2431 .i32,
2432 .u64,
2433 .i64,
2434 .u128,
2435 .i128,
2436 .optional,
2437 .optional_single_mut_pointer,
2438 .optional_single_const_pointer,
2439 .enum_literal,
2440 .error_union,
2441 .anyerror_void_error_union,
2442 .error_set,
2443 .error_set_single,
2444 .@"struct",
2445 .empty_struct,
2446 .empty_struct_literal,
2447 .inferred_alloc_const,
2448 .inferred_alloc_mut,
2449 .@"opaque",
2450 .var_args_param,
2451 => false,
2452
2453 .usize,
2454 .isize,
2455 .c_short,
2456 .c_ushort,
2457 .c_int,
2458 .c_uint,
2459 .c_long,
2460 .c_ulong,
2461 .c_longlong,
2462 .c_ulonglong,
2463 => true,
2464 };
2465 }
2466
2467 pub fn isFloat(self: Type) bool {
2468 return switch (self.tag()) {
2469 .f16,
2470 .f32,
2471 .f64,
2472 .f128,
2473 .c_longdouble,
2474 => true,
2475
2476 else => false,
2477 };
2478 }
2479
2480 /// Asserts the type is a fixed-size float.
2481 pub fn floatBits(self: Type, target: Target) u16 {
2482 return switch (self.tag()) {
2483 .f16 => 16,
2484 .f32 => 32,
2485 .f64 => 64,
2486 .f128 => 128,
2487 .c_longdouble => CType.longdouble.sizeInBits(target),
2488
2489 else => unreachable,
2490 };
2491 }
2492
2493 /// Asserts the type is a function.
2494 pub fn fnParamLen(self: Type) usize {
2495 return switch (self.tag()) {
2496 .fn_noreturn_no_args => 0,
2497 .fn_void_no_args => 0,
2498 .fn_naked_noreturn_no_args => 0,
2499 .fn_ccc_void_no_args => 0,
2500 .function => self.castTag(.function).?.data.param_types.len,
2501
2502 .f16,
2503 .f32,
2504 .f64,
2505 .f128,
2506 .c_longdouble,
2507 .c_void,
2508 .bool,
2509 .void,
2510 .type,
2511 .anyerror,
2512 .comptime_int,
2513 .comptime_float,
2514 .noreturn,
2515 .@"null",
2516 .@"undefined",
2517 .array,
2518 .array_sentinel,
2519 .array_u8,
2520 .array_u8_sentinel_0,
2521 .pointer,
2522 .single_const_pointer,
2523 .single_mut_pointer,
2524 .many_const_pointer,
2525 .many_mut_pointer,
2526 .c_const_pointer,
2527 .c_mut_pointer,
2528 .const_slice,
2529 .mut_slice,
2530 .single_const_pointer_to_comptime_int,
2531 .const_slice_u8,
2532 .u8,
2533 .i8,
2534 .u16,
2535 .i16,
2536 .u32,
2537 .i32,
2538 .u64,
2539 .i64,
2540 .u128,
2541 .i128,
2542 .usize,
2543 .isize,
2544 .c_short,
2545 .c_ushort,
2546 .c_int,
2547 .c_uint,
2548 .c_long,
2549 .c_ulong,
2550 .c_longlong,
2551 .c_ulonglong,
2552 .int_unsigned,
2553 .int_signed,
2554 .optional,
2555 .optional_single_mut_pointer,
2556 .optional_single_const_pointer,
2557 .enum_literal,
2558 .error_union,
2559 .anyerror_void_error_union,
2560 .error_set,
2561 .error_set_single,
2562 .@"struct",
2563 .empty_struct,
2564 .empty_struct_literal,
2565 .inferred_alloc_const,
2566 .inferred_alloc_mut,
2567 .@"opaque",
2568 .var_args_param,
2569 => unreachable,
2570 };
2571 }
2572
2573 /// Asserts the type is a function. The length of the slice must be at least the length
2574 /// given by `fnParamLen`.
2575 pub fn fnParamTypes(self: Type, types: []Type) void {
2576 switch (self.tag()) {
2577 .fn_noreturn_no_args => return,
2578 .fn_void_no_args => return,
2579 .fn_naked_noreturn_no_args => return,
2580 .fn_ccc_void_no_args => return,
2581 .function => {
2582 const payload = self.castTag(.function).?.data;
2583 std.mem.copy(Type, types, payload.param_types);
2584 },
2585
2586 .f16,
2587 .f32,
2588 .f64,
2589 .f128,
2590 .c_longdouble,
2591 .c_void,
2592 .bool,
2593 .void,
2594 .type,
2595 .anyerror,
2596 .comptime_int,
2597 .comptime_float,
2598 .noreturn,
2599 .@"null",
2600 .@"undefined",
2601 .array,
2602 .array_sentinel,
2603 .array_u8,
2604 .array_u8_sentinel_0,
2605 .pointer,
2606 .single_const_pointer,
2607 .single_mut_pointer,
2608 .many_const_pointer,
2609 .many_mut_pointer,
2610 .c_const_pointer,
2611 .c_mut_pointer,
2612 .const_slice,
2613 .mut_slice,
2614 .single_const_pointer_to_comptime_int,
2615 .const_slice_u8,
2616 .u8,
2617 .i8,
2618 .u16,
2619 .i16,
2620 .u32,
2621 .i32,
2622 .u64,
2623 .i64,
2624 .u128,
2625 .i128,
2626 .usize,
2627 .isize,
2628 .c_short,
2629 .c_ushort,
2630 .c_int,
2631 .c_uint,
2632 .c_long,
2633 .c_ulong,
2634 .c_longlong,
2635 .c_ulonglong,
2636 .int_unsigned,
2637 .int_signed,
2638 .optional,
2639 .optional_single_mut_pointer,
2640 .optional_single_const_pointer,
2641 .enum_literal,
2642 .error_union,
2643 .anyerror_void_error_union,
2644 .error_set,
2645 .error_set_single,
2646 .@"struct",
2647 .empty_struct,
2648 .empty_struct_literal,
2649 .inferred_alloc_const,
2650 .inferred_alloc_mut,
2651 .@"opaque",
2652 .var_args_param,
2653 => unreachable,
2654 }
2655 }
2656
2657 /// Asserts the type is a function.
2658 pub fn fnParamType(self: Type, index: usize) Type {
2659 switch (self.tag()) {
2660 .function => {
2661 const payload = self.castTag(.function).?.data;
2662 return payload.param_types[index];
2663 },
2664
2665 .fn_noreturn_no_args,
2666 .fn_void_no_args,
2667 .fn_naked_noreturn_no_args,
2668 .fn_ccc_void_no_args,
2669 .f16,
2670 .f32,
2671 .f64,
2672 .f128,
2673 .c_longdouble,
2674 .c_void,
2675 .bool,
2676 .void,
2677 .type,
2678 .anyerror,
2679 .comptime_int,
2680 .comptime_float,
2681 .noreturn,
2682 .@"null",
2683 .@"undefined",
2684 .array,
2685 .array_sentinel,
2686 .array_u8,
2687 .array_u8_sentinel_0,
2688 .pointer,
2689 .single_const_pointer,1660 .single_const_pointer,
2690 .single_mut_pointer,1661 .single_mut_pointer,
2691 .many_const_pointer,1662 .many_const_pointer,
2692 .many_mut_pointer,1663 .many_mut_pointer,
2693 .c_const_pointer,1664 .c_const_pointer,
2694 .c_mut_pointer,1665 .c_mut_pointer,
2695 .const_slice,
2696 .mut_slice,
2697 .single_const_pointer_to_comptime_int,1666 .single_const_pointer_to_comptime_int,
2698 .const_slice_u8,1667 .array,
2699 .u8,1668 .array_u8,
1669 => return null,
1670
1671 .pointer => return self.castTag(.pointer).?.data.sentinel,
1672 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
1673 .array_u8_sentinel_0 => return Value.initTag(.zero),
1674
1675 else => unreachable,
1676 };
1677 }
1678
1679 /// Returns true if and only if the type is a fixed-width integer.
1680 pub fn isInt(self: Type) bool {
1681 return self.isSignedInt() or self.isUnsignedInt();
1682 }
1683
1684 /// Returns true if and only if the type is a fixed-width, signed integer.
1685 pub fn isSignedInt(self: Type) bool {
1686 return switch (self.tag()) {
1687 .int_signed,
2700 .i8,1688 .i8,
2701 .u16,1689 .isize,
1690 .c_short,
1691 .c_int,
1692 .c_long,
1693 .c_longlong,
2702 .i16,1694 .i16,
2703 .u32,
2704 .i32,1695 .i32,
2705 .u64,
2706 .i64,1696 .i64,
2707 .u128,
2708 .i128,1697 .i128,
1698 => true,
1699
1700 else => false,
1701 };
1702 }
1703
1704 /// Returns true if and only if the type is a fixed-width, unsigned integer.
1705 pub fn isUnsignedInt(self: Type) bool {
1706 return switch (self.tag()) {
1707 .int_unsigned,
1708 .u8,
2709 .usize,1709 .usize,
2710 .isize,
2711 .c_short,
2712 .c_ushort,1710 .c_ushort,
2713 .c_int,
2714 .c_uint,1711 .c_uint,
2715 .c_long,
2716 .c_ulong,1712 .c_ulong,
2717 .c_longlong,
2718 .c_ulonglong,1713 .c_ulonglong,
2719 .int_unsigned,1714 .u16,
2720 .int_signed,1715 .u32,
2721 .optional,1716 .u64,
2722 .optional_single_mut_pointer,1717 .u128,
2723 .optional_single_const_pointer,1718 => true,
2724 .enum_literal,1719
2725 .error_union,1720 else => false,
2726 .anyerror_void_error_union,1721 };
2727 .error_set,
2728 .error_set_single,
2729 .@"struct",
2730 .empty_struct,
2731 .empty_struct_literal,
2732 .inferred_alloc_const,
2733 .inferred_alloc_mut,
2734 .@"opaque",
2735 .var_args_param,
2736 => unreachable,
2737 }
2738 }1722 }
27391723
2740 /// Asserts the type is a function.1724 /// Asserts the type is an integer.
2741 pub fn fnReturnType(self: Type) Type {1725 pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
2742 return switch (self.tag()) {1726 return switch (self.tag()) {
2743 .fn_noreturn_no_args => Type.initTag(.noreturn),1727 .int_unsigned => .{
2744 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),1728 .signedness = .unsigned,
27451729 .bits = self.castTag(.int_unsigned).?.data,
2746 .fn_void_no_args,1730 },
2747 .fn_ccc_void_no_args,1731 .int_signed => .{
2748 => Type.initTag(.void),1732 .signedness = .signed,
1733 .bits = self.castTag(.int_signed).?.data,
1734 },
1735 .u8 => .{ .signedness = .unsigned, .bits = 8 },
1736 .i8 => .{ .signedness = .signed, .bits = 8 },
1737 .u16 => .{ .signedness = .unsigned, .bits = 16 },
1738 .i16 => .{ .signedness = .signed, .bits = 16 },
1739 .u32 => .{ .signedness = .unsigned, .bits = 32 },
1740 .i32 => .{ .signedness = .signed, .bits = 32 },
1741 .u64 => .{ .signedness = .unsigned, .bits = 64 },
1742 .i64 => .{ .signedness = .signed, .bits = 64 },
1743 .u128 => .{ .signedness = .unsigned, .bits = 128 },
1744 .i128 => .{ .signedness = .signed, .bits = 128 },
1745 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
1746 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
1747 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
1748 .c_ushort => .{ .signedness = .unsigned, .bits = CType.ushort.sizeInBits(target) },
1749 .c_int => .{ .signedness = .signed, .bits = CType.int.sizeInBits(target) },
1750 .c_uint => .{ .signedness = .unsigned, .bits = CType.uint.sizeInBits(target) },
1751 .c_long => .{ .signedness = .signed, .bits = CType.long.sizeInBits(target) },
1752 .c_ulong => .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) },
1753 .c_longlong => .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) },
1754 .c_ulonglong => .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) },
27491755
2750 .function => self.castTag(.function).?.data.return_type,1756 else => unreachable,
1757 };
1758 }
27511759
2752 .f16,1760 pub fn isNamedInt(self: Type) bool {
2753 .f32,1761 return switch (self.tag()) {
2754 .f64,
2755 .f128,
2756 .c_longdouble,
2757 .c_void,
2758 .bool,
2759 .void,
2760 .type,
2761 .anyerror,
2762 .comptime_int,
2763 .comptime_float,
2764 .noreturn,
2765 .@"null",
2766 .@"undefined",
2767 .array,
2768 .array_sentinel,
2769 .array_u8,
2770 .array_u8_sentinel_0,
2771 .pointer,
2772 .single_const_pointer,
2773 .single_mut_pointer,
2774 .many_const_pointer,
2775 .many_mut_pointer,
2776 .c_const_pointer,
2777 .c_mut_pointer,
2778 .const_slice,
2779 .mut_slice,
2780 .single_const_pointer_to_comptime_int,
2781 .const_slice_u8,
2782 .u8,
2783 .i8,
2784 .u16,
2785 .i16,
2786 .u32,
2787 .i32,
2788 .u64,
2789 .i64,
2790 .u128,
2791 .i128,
2792 .usize,1762 .usize,
2793 .isize,1763 .isize,
2794 .c_short,1764 .c_short,
...@@ -2799,24 +1769,93 @@ pub const Type = extern union {...@@ -2799,24 +1769,93 @@ pub const Type = extern union {
2799 .c_ulong,1769 .c_ulong,
2800 .c_longlong,1770 .c_longlong,
2801 .c_ulonglong,1771 .c_ulonglong,
2802 .int_unsigned,1772 => true,
2803 .int_signed,1773
2804 .optional,1774 else => false,
2805 .optional_single_mut_pointer,1775 };
2806 .optional_single_const_pointer,1776 }
2807 .enum_literal,1777
2808 .error_union,1778 pub fn isFloat(self: Type) bool {
2809 .anyerror_void_error_union,1779 return switch (self.tag()) {
2810 .error_set,1780 .f16,
2811 .error_set_single,1781 .f32,
2812 .@"struct",1782 .f64,
2813 .empty_struct,1783 .f128,
2814 .empty_struct_literal,1784 .c_longdouble,
2815 .inferred_alloc_const,1785 => true,
2816 .inferred_alloc_mut,1786
2817 .@"opaque",1787 else => false,
2818 .var_args_param,1788 };
2819 => unreachable,1789 }
1790
1791 /// Asserts the type is a fixed-size float.
1792 pub fn floatBits(self: Type, target: Target) u16 {
1793 return switch (self.tag()) {
1794 .f16 => 16,
1795 .f32 => 32,
1796 .f64 => 64,
1797 .f128 => 128,
1798 .c_longdouble => CType.longdouble.sizeInBits(target),
1799
1800 else => unreachable,
1801 };
1802 }
1803
1804 /// Asserts the type is a function.
1805 pub fn fnParamLen(self: Type) usize {
1806 return switch (self.tag()) {
1807 .fn_noreturn_no_args => 0,
1808 .fn_void_no_args => 0,
1809 .fn_naked_noreturn_no_args => 0,
1810 .fn_ccc_void_no_args => 0,
1811 .function => self.castTag(.function).?.data.param_types.len,
1812
1813 else => unreachable,
1814 };
1815 }
1816
1817 /// Asserts the type is a function. The length of the slice must be at least the length
1818 /// given by `fnParamLen`.
1819 pub fn fnParamTypes(self: Type, types: []Type) void {
1820 switch (self.tag()) {
1821 .fn_noreturn_no_args => return,
1822 .fn_void_no_args => return,
1823 .fn_naked_noreturn_no_args => return,
1824 .fn_ccc_void_no_args => return,
1825 .function => {
1826 const payload = self.castTag(.function).?.data;
1827 std.mem.copy(Type, types, payload.param_types);
1828 },
1829
1830 else => unreachable,
1831 }
1832 }
1833
1834 /// Asserts the type is a function.
1835 pub fn fnParamType(self: Type, index: usize) Type {
1836 switch (self.tag()) {
1837 .function => {
1838 const payload = self.castTag(.function).?.data;
1839 return payload.param_types[index];
1840 },
1841
1842 else => unreachable,
1843 }
1844 }
1845
1846 /// Asserts the type is a function.
1847 pub fn fnReturnType(self: Type) Type {
1848 return switch (self.tag()) {
1849 .fn_noreturn_no_args => Type.initTag(.noreturn),
1850 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
1851
1852 .fn_void_no_args,
1853 .fn_ccc_void_no_args,
1854 => Type.initTag(.void),
1855
1856 .function => self.castTag(.function).?.data.return_type,
1857
1858 else => unreachable,
2820 };1859 };
2821 }1860 }
28221861
...@@ -2829,74 +1868,7 @@ pub const Type = extern union {...@@ -2829,74 +1868,7 @@ pub const Type = extern union {
2829 .fn_ccc_void_no_args => .C,1868 .fn_ccc_void_no_args => .C,
2830 .function => self.castTag(.function).?.data.cc,1869 .function => self.castTag(.function).?.data.cc,
28311870
2832 .f16,1871 else => unreachable,
2833 .f32,
2834 .f64,
2835 .f128,
2836 .c_longdouble,
2837 .c_void,
2838 .bool,
2839 .void,
2840 .type,
2841 .anyerror,
2842 .comptime_int,
2843 .comptime_float,
2844 .noreturn,
2845 .@"null",
2846 .@"undefined",
2847 .array,
2848 .array_sentinel,
2849 .array_u8,
2850 .array_u8_sentinel_0,
2851 .pointer,
2852 .single_const_pointer,
2853 .single_mut_pointer,
2854 .many_const_pointer,
2855 .many_mut_pointer,
2856 .c_const_pointer,
2857 .c_mut_pointer,
2858 .const_slice,
2859 .mut_slice,
2860 .single_const_pointer_to_comptime_int,
2861 .const_slice_u8,
2862 .u8,
2863 .i8,
2864 .u16,
2865 .i16,
2866 .u32,
2867 .i32,
2868 .u64,
2869 .i64,
2870 .u128,
2871 .i128,
2872 .usize,
2873 .isize,
2874 .c_short,
2875 .c_ushort,
2876 .c_int,
2877 .c_uint,
2878 .c_long,
2879 .c_ulong,
2880 .c_longlong,
2881 .c_ulonglong,
2882 .int_unsigned,
2883 .int_signed,
2884 .optional,
2885 .optional_single_mut_pointer,
2886 .optional_single_const_pointer,
2887 .enum_literal,
2888 .error_union,
2889 .anyerror_void_error_union,
2890 .error_set,
2891 .error_set_single,
2892 .@"struct",
2893 .empty_struct,
2894 .empty_struct_literal,
2895 .inferred_alloc_const,
2896 .inferred_alloc_mut,
2897 .@"opaque",
2898 .var_args_param,
2899 => unreachable,
2900 };1872 };
2901 }1873 }
29021874
...@@ -2909,74 +1881,7 @@ pub const Type = extern union {...@@ -2909,74 +1881,7 @@ pub const Type = extern union {
2909 .fn_ccc_void_no_args => false,1881 .fn_ccc_void_no_args => false,
2910 .function => self.castTag(.function).?.data.is_var_args,1882 .function => self.castTag(.function).?.data.is_var_args,
29111883
2912 .f16,1884 else => unreachable,
2913 .f32,
2914 .f64,
2915 .f128,
2916 .c_longdouble,
2917 .c_void,
2918 .bool,
2919 .void,
2920 .type,
2921 .anyerror,
2922 .comptime_int,
2923 .comptime_float,
2924 .noreturn,
2925 .@"null",
2926 .@"undefined",
2927 .array,
2928 .array_sentinel,
2929 .array_u8,
2930 .array_u8_sentinel_0,
2931 .pointer,
2932 .single_const_pointer,
2933 .single_mut_pointer,
2934 .many_const_pointer,
2935 .many_mut_pointer,
2936 .c_const_pointer,
2937 .c_mut_pointer,
2938 .const_slice,
2939 .mut_slice,
2940 .single_const_pointer_to_comptime_int,
2941 .const_slice_u8,
2942 .u8,
2943 .i8,
2944 .u16,
2945 .i16,
2946 .u32,
2947 .i32,
2948 .u64,
2949 .i64,
2950 .u128,
2951 .i128,
2952 .usize,
2953 .isize,
2954 .c_short,
2955 .c_ushort,
2956 .c_int,
2957 .c_uint,
2958 .c_long,
2959 .c_ulong,
2960 .c_longlong,
2961 .c_ulonglong,
2962 .int_unsigned,
2963 .int_signed,
2964 .optional,
2965 .optional_single_mut_pointer,
2966 .optional_single_const_pointer,
2967 .enum_literal,
2968 .error_union,
2969 .anyerror_void_error_union,
2970 .error_set,
2971 .error_set_single,
2972 .@"struct",
2973 .empty_struct,
2974 .empty_struct_literal,
2975 .inferred_alloc_const,
2976 .inferred_alloc_mut,
2977 .@"opaque",
2978 .var_args_param,
2979 => unreachable,
2980 };1885 };
2981 }1886 }
29821887
...@@ -2984,84 +1889,41 @@ pub const Type = extern union {...@@ -2984,84 +1889,41 @@ pub const Type = extern union {
2984 return switch (self.tag()) {1889 return switch (self.tag()) {
2985 .f16,1890 .f16,
2986 .f32,1891 .f32,
2987 .f64,1892 .f64,
2988 .f128,1893 .f128,
2989 .c_longdouble,1894 .c_longdouble,
2990 .comptime_int,1895 .comptime_int,
2991 .comptime_float,1896 .comptime_float,
2992 .u8,1897 .u8,
2993 .i8,1898 .i8,
2994 .u16,1899 .u16,
2995 .i16,1900 .i16,
2996 .u32,1901 .u32,
2997 .i32,1902 .i32,
2998 .u64,1903 .u64,
2999 .i64,1904 .i64,
3000 .u128,1905 .u128,
3001 .i128,1906 .i128,
3002 .usize,1907 .usize,
3003 .isize,1908 .isize,
3004 .c_short,1909 .c_short,
3005 .c_ushort,1910 .c_ushort,
3006 .c_int,1911 .c_int,
3007 .c_uint,1912 .c_uint,
3008 .c_long,1913 .c_long,
3009 .c_ulong,1914 .c_ulong,
3010 .c_longlong,1915 .c_longlong,
3011 .c_ulonglong,1916 .c_ulonglong,
3012 .int_unsigned,1917 .int_unsigned,
3013 .int_signed,1918 .int_signed,
3014 => true,1919 => true,
30151920
3016 .c_void,1921 else => false,
3017 .bool,
3018 .void,
3019 .type,
3020 .anyerror,
3021 .noreturn,
3022 .@"null",
3023 .@"undefined",
3024 .fn_noreturn_no_args,
3025 .fn_void_no_args,
3026 .fn_naked_noreturn_no_args,
3027 .fn_ccc_void_no_args,
3028 .function,
3029 .array,
3030 .array_sentinel,
3031 .array_u8,
3032 .array_u8_sentinel_0,
3033 .pointer,
3034 .single_const_pointer,
3035 .single_mut_pointer,
3036 .many_const_pointer,
3037 .many_mut_pointer,
3038 .c_const_pointer,
3039 .c_mut_pointer,
3040 .const_slice,
3041 .mut_slice,
3042 .single_const_pointer_to_comptime_int,
3043 .const_slice_u8,
3044 .optional,
3045 .optional_single_mut_pointer,
3046 .optional_single_const_pointer,
3047 .enum_literal,
3048 .error_union,
3049 .anyerror_void_error_union,
3050 .error_set,
3051 .error_set_single,
3052 .@"struct",
3053 .empty_struct,
3054 .empty_struct_literal,
3055 .inferred_alloc_const,
3056 .inferred_alloc_mut,
3057 .@"opaque",
3058 .var_args_param,
3059 => false,
3060 };1922 };
3061 }1923 }
30621924
3063 pub fn onePossibleValue(self: Type) ?Value {1925 pub fn onePossibleValue(starting_type: Type) ?Value {
3064 var ty = self;1926 var ty = starting_type;
3065 while (true) switch (ty.tag()) {1927 while (true) switch (ty.tag()) {
3066 .f16,1928 .f16,
3067 .f32,1929 .f32,
...@@ -3118,9 +1980,32 @@ pub const Type = extern union {...@@ -3118,9 +1980,32 @@ pub const Type = extern union {
3118 => return null,1980 => return null,
31191981
3120 .@"struct" => {1982 .@"struct" => {
3121 log.warn("TODO implement Type.onePossibleValue for structs", .{});1983 const s = ty.castTag(.@"struct").?.data;
3122 return null;1984 for (s.fields.entries.items) |entry| {
1985 const field_ty = entry.value.ty;
1986 if (field_ty.onePossibleValue() == null) {
1987 return null;
1988 }
1989 }
1990 return Value.initTag(.empty_struct_value);
1991 },
1992 .enum_full => {
1993 const enum_full = ty.castTag(.enum_full).?.data;
1994 if (enum_full.fields.count() == 1) {
1995 return enum_full.values.entries.items[0].key;
1996 } else {
1997 return null;
1998 }
1999 },
2000 .enum_simple => {
2001 const enum_simple = ty.castTag(.enum_simple).?.data;
2002 if (enum_simple.fields.count() == 1) {
2003 return Value.initTag(.zero);
2004 } else {
2005 return null;
2006 }
3123 },2007 },
2008 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
31242009
3125 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),2010 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
3126 .void => return Value.initTag(.void_value),2011 .void => return Value.initTag(.void_value),
...@@ -3160,87 +2045,6 @@ pub const Type = extern union {...@@ -3160,87 +2045,6 @@ pub const Type = extern union {
3160 };2045 };
3161 }2046 }
31622047
3163 pub fn isCPtr(self: Type) bool {
3164 return switch (self.tag()) {
3165 .f16,
3166 .f32,
3167 .f64,
3168 .f128,
3169 .c_longdouble,
3170 .comptime_int,
3171 .comptime_float,
3172 .u8,
3173 .i8,
3174 .u16,
3175 .i16,
3176 .u32,
3177 .i32,
3178 .u64,
3179 .i64,
3180 .u128,
3181 .i128,
3182 .usize,
3183 .isize,
3184 .c_short,
3185 .c_ushort,
3186 .c_int,
3187 .c_uint,
3188 .c_long,
3189 .c_ulong,
3190 .c_longlong,
3191 .c_ulonglong,
3192 .bool,
3193 .type,
3194 .anyerror,
3195 .fn_noreturn_no_args,
3196 .fn_void_no_args,
3197 .fn_naked_noreturn_no_args,
3198 .fn_ccc_void_no_args,
3199 .function,
3200 .single_const_pointer_to_comptime_int,
3201 .const_slice_u8,
3202 .c_void,
3203 .void,
3204 .noreturn,
3205 .@"null",
3206 .@"undefined",
3207 .int_unsigned,
3208 .int_signed,
3209 .array,
3210 .array_sentinel,
3211 .array_u8,
3212 .array_u8_sentinel_0,
3213 .single_const_pointer,
3214 .single_mut_pointer,
3215 .many_const_pointer,
3216 .many_mut_pointer,
3217 .const_slice,
3218 .mut_slice,
3219 .optional,
3220 .optional_single_mut_pointer,
3221 .optional_single_const_pointer,
3222 .enum_literal,
3223 .error_union,
3224 .anyerror_void_error_union,
3225 .error_set,
3226 .error_set_single,
3227 .@"struct",
3228 .empty_struct,
3229 .empty_struct_literal,
3230 .inferred_alloc_const,
3231 .inferred_alloc_mut,
3232 .@"opaque",
3233 .var_args_param,
3234 => return false,
3235
3236 .c_const_pointer,
3237 .c_mut_pointer,
3238 => return true,
3239
3240 .pointer => self.castTag(.pointer).?.data.size == .C,
3241 };
3242 }
3243
3244 pub fn isIndexable(self: Type) bool {2048 pub fn isIndexable(self: Type) bool {
3245 const zig_tag = self.zigTypeTag();2049 const zig_tag = self.zigTypeTag();
3246 // TODO tuples are indexable2050 // TODO tuples are indexable
...@@ -3248,83 +2052,15 @@ pub const Type = extern union {...@@ -3248,83 +2052,15 @@ pub const Type = extern union {
3248 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);2052 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
3249 }2053 }
32502054
3251 /// Asserts that the type is a container. (note: ErrorSet is not a container).2055 /// Returns null if the type has no container.
3252 pub fn getContainerScope(self: Type) *Module.Scope.Container {2056 pub fn getContainerScope(self: Type) ?*Module.Scope.Container {
3253 return switch (self.tag()) {2057 return switch (self.tag()) {
3254 .f16,
3255 .f32,
3256 .f64,
3257 .f128,
3258 .c_longdouble,
3259 .comptime_int,
3260 .comptime_float,
3261 .u8,
3262 .i8,
3263 .u16,
3264 .i16,
3265 .u32,
3266 .i32,
3267 .u64,
3268 .i64,
3269 .u128,
3270 .i128,
3271 .usize,
3272 .isize,
3273 .c_short,
3274 .c_ushort,
3275 .c_int,
3276 .c_uint,
3277 .c_long,
3278 .c_ulong,
3279 .c_longlong,
3280 .c_ulonglong,
3281 .bool,
3282 .type,
3283 .anyerror,
3284 .fn_noreturn_no_args,
3285 .fn_void_no_args,
3286 .fn_naked_noreturn_no_args,
3287 .fn_ccc_void_no_args,
3288 .function,
3289 .single_const_pointer_to_comptime_int,
3290 .const_slice_u8,
3291 .c_void,
3292 .void,
3293 .noreturn,
3294 .@"null",
3295 .@"undefined",
3296 .int_unsigned,
3297 .int_signed,
3298 .array,
3299 .array_sentinel,
3300 .array_u8,
3301 .array_u8_sentinel_0,
3302 .single_const_pointer,
3303 .single_mut_pointer,
3304 .many_const_pointer,
3305 .many_mut_pointer,
3306 .const_slice,
3307 .mut_slice,
3308 .optional,
3309 .optional_single_mut_pointer,
3310 .optional_single_const_pointer,
3311 .enum_literal,
3312 .error_union,
3313 .anyerror_void_error_union,
3314 .error_set,
3315 .error_set_single,
3316 .c_const_pointer,
3317 .c_mut_pointer,
3318 .pointer,
3319 .inferred_alloc_const,
3320 .inferred_alloc_mut,
3321 .var_args_param,
3322 .empty_struct_literal,
3323 => unreachable,
3324
3325 .@"struct" => &self.castTag(.@"struct").?.data.container,2058 .@"struct" => &self.castTag(.@"struct").?.data.container,
2059 .enum_full => &self.castTag(.enum_full).?.data.container,
3326 .empty_struct => self.castTag(.empty_struct).?.data,2060 .empty_struct => self.castTag(.empty_struct).?.data,
3327 .@"opaque" => &self.castTag(.@"opaque").?.data,2061 .@"opaque" => &self.castTag(.@"opaque").?.data,
2062
2063 else => null,
3328 };2064 };
3329 }2065 }
33302066
...@@ -3383,8 +2119,144 @@ pub const Type = extern union {...@@ -3383,8 +2119,144 @@ pub const Type = extern union {
3383 }2119 }
3384 }2120 }
33852121
3386 pub fn isExhaustiveEnum(ty: Type) bool {2122 pub fn isNonexhaustiveEnum(ty: Type) bool {
3387 return false; // TODO2123 return switch (ty.tag()) {
2124 .enum_nonexhaustive => true,
2125 else => false,
2126 };
2127 }
2128
2129 pub fn enumFieldCount(ty: Type) usize {
2130 switch (ty.tag()) {
2131 .enum_full, .enum_nonexhaustive => {
2132 const enum_full = ty.cast(Payload.EnumFull).?.data;
2133 return enum_full.fields.count();
2134 },
2135 .enum_simple => {
2136 const enum_simple = ty.castTag(.enum_simple).?.data;
2137 return enum_simple.fields.count();
2138 },
2139 else => unreachable,
2140 }
2141 }
2142
2143 pub fn enumFieldName(ty: Type, field_index: usize) []const u8 {
2144 switch (ty.tag()) {
2145 .enum_full, .enum_nonexhaustive => {
2146 const enum_full = ty.cast(Payload.EnumFull).?.data;
2147 return enum_full.fields.entries.items[field_index].key;
2148 },
2149 .enum_simple => {
2150 const enum_simple = ty.castTag(.enum_simple).?.data;
2151 return enum_simple.fields.entries.items[field_index].key;
2152 },
2153 else => unreachable,
2154 }
2155 }
2156
2157 pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize {
2158 switch (ty.tag()) {
2159 .enum_full, .enum_nonexhaustive => {
2160 const enum_full = ty.cast(Payload.EnumFull).?.data;
2161 return enum_full.fields.getIndex(field_name);
2162 },
2163 .enum_simple => {
2164 const enum_simple = ty.castTag(.enum_simple).?.data;
2165 return enum_simple.fields.getIndex(field_name);
2166 },
2167 else => unreachable,
2168 }
2169 }
2170
2171 /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
2172 /// an integer which represents the enum value. Returns the field index in
2173 /// declaration order, or `null` if `enum_tag` does not match any field.
2174 pub fn enumTagFieldIndex(ty: Type, enum_tag: Value) ?usize {
2175 if (enum_tag.castTag(.enum_field_index)) |payload| {
2176 return @as(usize, payload.data);
2177 }
2178 const S = struct {
2179 fn fieldWithRange(int_val: Value, end: usize) ?usize {
2180 if (int_val.compareWithZero(.lt)) return null;
2181 var end_payload: Value.Payload.U64 = .{
2182 .base = .{ .tag = .int_u64 },
2183 .data = end,
2184 };
2185 const end_val = Value.initPayload(&end_payload.base);
2186 if (int_val.compare(.gte, end_val)) return null;
2187 return int_val.toUnsignedInt();
2188 }
2189 };
2190 switch (ty.tag()) {
2191 .enum_full, .enum_nonexhaustive => {
2192 const enum_full = ty.cast(Payload.EnumFull).?.data;
2193 if (enum_full.values.count() == 0) {
2194 return S.fieldWithRange(enum_tag, enum_full.fields.count());
2195 } else {
2196 return enum_full.values.getIndex(enum_tag);
2197 }
2198 },
2199 .enum_simple => {
2200 const enum_simple = ty.castTag(.enum_simple).?.data;
2201 return S.fieldWithRange(enum_tag, enum_simple.fields.count());
2202 },
2203 else => unreachable,
2204 }
2205 }
2206
2207 pub fn declSrcLoc(ty: Type) Module.SrcLoc {
2208 switch (ty.tag()) {
2209 .enum_full, .enum_nonexhaustive => {
2210 const enum_full = ty.cast(Payload.EnumFull).?.data;
2211 return enum_full.srcLoc();
2212 },
2213 .enum_simple => {
2214 const enum_simple = ty.castTag(.enum_simple).?.data;
2215 return enum_simple.srcLoc();
2216 },
2217 .@"struct" => {
2218 const struct_obj = ty.castTag(.@"struct").?.data;
2219 return struct_obj.srcLoc();
2220 },
2221 .error_set => {
2222 const error_set = ty.castTag(.error_set).?.data;
2223 return error_set.srcLoc();
2224 },
2225 else => unreachable,
2226 }
2227 }
2228
2229 /// Asserts the type is an enum.
2230 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
2231 const S = struct {
2232 fn intInRange(int_val: Value, end: usize) bool {
2233 if (int_val.compareWithZero(.lt)) return false;
2234 var end_payload: Value.Payload.U64 = .{
2235 .base = .{ .tag = .int_u64 },
2236 .data = end,
2237 };
2238 const end_val = Value.initPayload(&end_payload.base);
2239 if (int_val.compare(.gte, end_val)) return false;
2240 return true;
2241 }
2242 };
2243 switch (ty.tag()) {
2244 .enum_nonexhaustive => return int.intFitsInType(ty, target),
2245 .enum_full => {
2246 const enum_full = ty.castTag(.enum_full).?.data;
2247 if (enum_full.values.count() == 0) {
2248 return S.intInRange(int, enum_full.fields.count());
2249 } else {
2250 return enum_full.values.contains(int);
2251 }
2252 },
2253 .enum_simple => {
2254 const enum_simple = ty.castTag(.enum_simple).?.data;
2255 return S.intInRange(int, enum_simple.fields.count());
2256 },
2257
2258 else => unreachable,
2259 }
3388 }2260 }
33892261
3390 /// This enum does not directly correspond to `std.builtin.TypeId` because2262 /// This enum does not directly correspond to `std.builtin.TypeId` because
...@@ -3476,6 +2348,9 @@ pub const Type = extern union {...@@ -3476,6 +2348,9 @@ pub const Type = extern union {
3476 empty_struct,2348 empty_struct,
3477 @"opaque",2349 @"opaque",
3478 @"struct",2350 @"struct",
2351 enum_simple,
2352 enum_full,
2353 enum_nonexhaustive,
34792354
3480 pub const last_no_payload_tag = Tag.inferred_alloc_const;2355 pub const last_no_payload_tag = Tag.inferred_alloc_const;
3481 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;2356 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -3562,6 +2437,8 @@ pub const Type = extern union {...@@ -3562,6 +2437,8 @@ pub const Type = extern union {
3562 .error_set_single => Payload.Name,2437 .error_set_single => Payload.Name,
3563 .@"opaque" => Payload.Opaque,2438 .@"opaque" => Payload.Opaque,
3564 .@"struct" => Payload.Struct,2439 .@"struct" => Payload.Struct,
2440 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
2441 .enum_simple => Payload.EnumSimple,
3565 .empty_struct => Payload.ContainerScope,2442 .empty_struct => Payload.ContainerScope,
3566 };2443 };
3567 }2444 }
...@@ -3699,6 +2576,16 @@ pub const Type = extern union {...@@ -3699,6 +2576,16 @@ pub const Type = extern union {
3699 base: Payload = .{ .tag = .@"struct" },2576 base: Payload = .{ .tag = .@"struct" },
3700 data: *Module.Struct,2577 data: *Module.Struct,
3701 };2578 };
2579
2580 pub const EnumFull = struct {
2581 base: Payload,
2582 data: *Module.EnumFull,
2583 };
2584
2585 pub const EnumSimple = struct {
2586 base: Payload = .{ .tag = .enum_simple },
2587 data: *Module.EnumSimple,
2588 };
3702 };2589 };
3703};2590};
37042591
src/value.zig+57-780
...@@ -103,6 +103,8 @@ pub const Value = extern union {...@@ -103,6 +103,8 @@ pub const Value = extern union {
103 float_64,103 float_64,
104 float_128,104 float_128,
105 enum_literal,105 enum_literal,
106 /// A specific enum tag, indicated by the field index (declaration order).
107 enum_field_index,
106 @"error",108 @"error",
107 error_union,109 error_union,
108 /// This is a special value that tracks a set of types that have been stored110 /// This is a special value that tracks a set of types that have been stored
...@@ -186,6 +188,8 @@ pub const Value = extern union {...@@ -186,6 +188,8 @@ pub const Value = extern union {
186 .enum_literal,188 .enum_literal,
187 => Payload.Bytes,189 => Payload.Bytes,
188190
191 .enum_field_index => Payload.U32,
192
189 .ty => Payload.Ty,193 .ty => Payload.Ty,
190 .int_type => Payload.IntType,194 .int_type => Payload.IntType,
191 .int_u64 => Payload.U64,195 .int_u64 => Payload.U64,
...@@ -394,6 +398,7 @@ pub const Value = extern union {...@@ -394,6 +398,7 @@ pub const Value = extern union {
394 };398 };
395 return Value{ .ptr_otherwise = &new_payload.base };399 return Value{ .ptr_otherwise = &new_payload.base };
396 },400 },
401 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
397 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),402 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
398 .error_union => {403 .error_union => {
399 const payload = self.castTag(.error_union).?;404 const payload = self.castTag(.error_union).?;
...@@ -416,6 +421,8 @@ pub const Value = extern union {...@@ -416,6 +421,8 @@ pub const Value = extern union {
416 return Value{ .ptr_otherwise = &new_payload.base };421 return Value{ .ptr_otherwise = &new_payload.base };
417 }422 }
418423
424 /// TODO this should become a debug dump() function. In order to print values in a meaningful way
425 /// we also need access to the type.
419 pub fn format(426 pub fn format(
420 self: Value,427 self: Value,
421 comptime fmt: []const u8,428 comptime fmt: []const u8,
...@@ -506,6 +513,7 @@ pub const Value = extern union {...@@ -506,6 +513,7 @@ pub const Value = extern union {
506 },513 },
507 .empty_array => return out_stream.writeAll(".{}"),514 .empty_array => return out_stream.writeAll(".{}"),
508 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),515 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),
516 .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),
509 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),517 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),
510 .repeated => {518 .repeated => {
511 try out_stream.writeAll("(repeated) ");519 try out_stream.writeAll("(repeated) ");
...@@ -626,6 +634,7 @@ pub const Value = extern union {...@@ -626,6 +634,7 @@ pub const Value = extern union {
626 .float_64,634 .float_64,
627 .float_128,635 .float_128,
628 .enum_literal,636 .enum_literal,
637 .enum_field_index,
629 .@"error",638 .@"error",
630 .error_union,639 .error_union,
631 .empty_struct_value,640 .empty_struct_value,
...@@ -638,76 +647,6 @@ pub const Value = extern union {...@@ -638,76 +647,6 @@ pub const Value = extern union {
638 /// Asserts the value is an integer.647 /// Asserts the value is an integer.
639 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {648 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
640 switch (self.tag()) {649 switch (self.tag()) {
641 .ty,
642 .int_type,
643 .u8_type,
644 .i8_type,
645 .u16_type,
646 .i16_type,
647 .u32_type,
648 .i32_type,
649 .u64_type,
650 .i64_type,
651 .u128_type,
652 .i128_type,
653 .usize_type,
654 .isize_type,
655 .c_short_type,
656 .c_ushort_type,
657 .c_int_type,
658 .c_uint_type,
659 .c_long_type,
660 .c_ulong_type,
661 .c_longlong_type,
662 .c_ulonglong_type,
663 .c_longdouble_type,
664 .f16_type,
665 .f32_type,
666 .f64_type,
667 .f128_type,
668 .c_void_type,
669 .bool_type,
670 .void_type,
671 .type_type,
672 .anyerror_type,
673 .comptime_int_type,
674 .comptime_float_type,
675 .noreturn_type,
676 .null_type,
677 .undefined_type,
678 .fn_noreturn_no_args_type,
679 .fn_void_no_args_type,
680 .fn_naked_noreturn_no_args_type,
681 .fn_ccc_void_no_args_type,
682 .single_const_pointer_to_comptime_int_type,
683 .const_slice_u8_type,
684 .enum_literal_type,
685 .null_value,
686 .function,
687 .extern_fn,
688 .variable,
689 .ref_val,
690 .decl_ref,
691 .elem_ptr,
692 .bytes,
693 .repeated,
694 .float_16,
695 .float_32,
696 .float_64,
697 .float_128,
698 .void_value,
699 .unreachable_value,
700 .empty_array,
701 .enum_literal,
702 .error_union,
703 .@"error",
704 .empty_struct_value,
705 .inferred_alloc,
706 .abi_align_default,
707 => unreachable,
708
709 .undef => unreachable,
710
711 .zero,650 .zero,
712 .bool_false,651 .bool_false,
713 => return BigIntMutable.init(&space.limbs, 0).toConst(),652 => return BigIntMutable.init(&space.limbs, 0).toConst(),
...@@ -720,82 +659,15 @@ pub const Value = extern union {...@@ -720,82 +659,15 @@ pub const Value = extern union {
720 .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),659 .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
721 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),660 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
722 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),661 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
662
663 .undef => unreachable,
664 else => unreachable,
723 }665 }
724 }666 }
725667
726 /// Asserts the value is an integer and it fits in a u64668 /// Asserts the value is an integer and it fits in a u64
727 pub fn toUnsignedInt(self: Value) u64 {669 pub fn toUnsignedInt(self: Value) u64 {
728 switch (self.tag()) {670 switch (self.tag()) {
729 .ty,
730 .int_type,
731 .u8_type,
732 .i8_type,
733 .u16_type,
734 .i16_type,
735 .u32_type,
736 .i32_type,
737 .u64_type,
738 .i64_type,
739 .u128_type,
740 .i128_type,
741 .usize_type,
742 .isize_type,
743 .c_short_type,
744 .c_ushort_type,
745 .c_int_type,
746 .c_uint_type,
747 .c_long_type,
748 .c_ulong_type,
749 .c_longlong_type,
750 .c_ulonglong_type,
751 .c_longdouble_type,
752 .f16_type,
753 .f32_type,
754 .f64_type,
755 .f128_type,
756 .c_void_type,
757 .bool_type,
758 .void_type,
759 .type_type,
760 .anyerror_type,
761 .comptime_int_type,
762 .comptime_float_type,
763 .noreturn_type,
764 .null_type,
765 .undefined_type,
766 .fn_noreturn_no_args_type,
767 .fn_void_no_args_type,
768 .fn_naked_noreturn_no_args_type,
769 .fn_ccc_void_no_args_type,
770 .single_const_pointer_to_comptime_int_type,
771 .const_slice_u8_type,
772 .enum_literal_type,
773 .null_value,
774 .function,
775 .extern_fn,
776 .variable,
777 .ref_val,
778 .decl_ref,
779 .elem_ptr,
780 .bytes,
781 .repeated,
782 .float_16,
783 .float_32,
784 .float_64,
785 .float_128,
786 .void_value,
787 .unreachable_value,
788 .empty_array,
789 .enum_literal,
790 .@"error",
791 .error_union,
792 .empty_struct_value,
793 .inferred_alloc,
794 .abi_align_default,
795 => unreachable,
796
797 .undef => unreachable,
798
799 .zero,671 .zero,
800 .bool_false,672 .bool_false,
801 => return 0,673 => return 0,
...@@ -808,82 +680,15 @@ pub const Value = extern union {...@@ -808,82 +680,15 @@ pub const Value = extern union {
808 .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),680 .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
809 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,681 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
810 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,682 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
683
684 .undef => unreachable,
685 else => unreachable,
811 }686 }
812 }687 }
813688
814 /// Asserts the value is an integer and it fits in a i64689 /// Asserts the value is an integer and it fits in a i64
815 pub fn toSignedInt(self: Value) i64 {690 pub fn toSignedInt(self: Value) i64 {
816 switch (self.tag()) {691 switch (self.tag()) {
817 .ty,
818 .int_type,
819 .u8_type,
820 .i8_type,
821 .u16_type,
822 .i16_type,
823 .u32_type,
824 .i32_type,
825 .u64_type,
826 .i64_type,
827 .u128_type,
828 .i128_type,
829 .usize_type,
830 .isize_type,
831 .c_short_type,
832 .c_ushort_type,
833 .c_int_type,
834 .c_uint_type,
835 .c_long_type,
836 .c_ulong_type,
837 .c_longlong_type,
838 .c_ulonglong_type,
839 .c_longdouble_type,
840 .f16_type,
841 .f32_type,
842 .f64_type,
843 .f128_type,
844 .c_void_type,
845 .bool_type,
846 .void_type,
847 .type_type,
848 .anyerror_type,
849 .comptime_int_type,
850 .comptime_float_type,
851 .noreturn_type,
852 .null_type,
853 .undefined_type,
854 .fn_noreturn_no_args_type,
855 .fn_void_no_args_type,
856 .fn_naked_noreturn_no_args_type,
857 .fn_ccc_void_no_args_type,
858 .single_const_pointer_to_comptime_int_type,
859 .const_slice_u8_type,
860 .enum_literal_type,
861 .null_value,
862 .function,
863 .extern_fn,
864 .variable,
865 .ref_val,
866 .decl_ref,
867 .elem_ptr,
868 .bytes,
869 .repeated,
870 .float_16,
871 .float_32,
872 .float_64,
873 .float_128,
874 .void_value,
875 .unreachable_value,
876 .empty_array,
877 .enum_literal,
878 .@"error",
879 .error_union,
880 .empty_struct_value,
881 .inferred_alloc,
882 .abi_align_default,
883 => unreachable,
884
885 .undef => unreachable,
886
887 .zero,692 .zero,
888 .bool_false,693 .bool_false,
889 => return 0,694 => return 0,
...@@ -896,6 +701,9 @@ pub const Value = extern union {...@@ -896,6 +701,9 @@ pub const Value = extern union {
896 .int_i64 => return self.castTag(.int_i64).?.data,701 .int_i64 => return self.castTag(.int_i64).?.data,
897 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,702 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
898 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,703 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
704
705 .undef => unreachable,
706 else => unreachable,
899 }707 }
900 }708 }
901709
...@@ -929,75 +737,6 @@ pub const Value = extern union {...@@ -929,75 +737,6 @@ pub const Value = extern union {
929 /// Returns the number of bits the value requires to represent stored in twos complement form.737 /// Returns the number of bits the value requires to represent stored in twos complement form.
930 pub fn intBitCountTwosComp(self: Value) usize {738 pub fn intBitCountTwosComp(self: Value) usize {
931 switch (self.tag()) {739 switch (self.tag()) {
932 .ty,
933 .int_type,
934 .u8_type,
935 .i8_type,
936 .u16_type,
937 .i16_type,
938 .u32_type,
939 .i32_type,
940 .u64_type,
941 .i64_type,
942 .u128_type,
943 .i128_type,
944 .usize_type,
945 .isize_type,
946 .c_short_type,
947 .c_ushort_type,
948 .c_int_type,
949 .c_uint_type,
950 .c_long_type,
951 .c_ulong_type,
952 .c_longlong_type,
953 .c_ulonglong_type,
954 .c_longdouble_type,
955 .f16_type,
956 .f32_type,
957 .f64_type,
958 .f128_type,
959 .c_void_type,
960 .bool_type,
961 .void_type,
962 .type_type,
963 .anyerror_type,
964 .comptime_int_type,
965 .comptime_float_type,
966 .noreturn_type,
967 .null_type,
968 .undefined_type,
969 .fn_noreturn_no_args_type,
970 .fn_void_no_args_type,
971 .fn_naked_noreturn_no_args_type,
972 .fn_ccc_void_no_args_type,
973 .single_const_pointer_to_comptime_int_type,
974 .const_slice_u8_type,
975 .enum_literal_type,
976 .null_value,
977 .function,
978 .extern_fn,
979 .variable,
980 .ref_val,
981 .decl_ref,
982 .elem_ptr,
983 .bytes,
984 .undef,
985 .repeated,
986 .float_16,
987 .float_32,
988 .float_64,
989 .float_128,
990 .void_value,
991 .unreachable_value,
992 .empty_array,
993 .enum_literal,
994 .@"error",
995 .error_union,
996 .empty_struct_value,
997 .inferred_alloc,
998 .abi_align_default,
999 => unreachable,
1000
1001 .zero,740 .zero,
1002 .bool_false,741 .bool_false,
1003 => return 0,742 => return 0,
...@@ -1016,80 +755,14 @@ pub const Value = extern union {...@@ -1016,80 +755,14 @@ pub const Value = extern union {
1016 },755 },
1017 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),756 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1018 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),757 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
758
759 else => unreachable,
1019 }760 }
1020 }761 }
1021762
1022 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.763 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
1023 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {764 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
1024 switch (self.tag()) {765 switch (self.tag()) {
1025 .ty,
1026 .int_type,
1027 .u8_type,
1028 .i8_type,
1029 .u16_type,
1030 .i16_type,
1031 .u32_type,
1032 .i32_type,
1033 .u64_type,
1034 .i64_type,
1035 .u128_type,
1036 .i128_type,
1037 .usize_type,
1038 .isize_type,
1039 .c_short_type,
1040 .c_ushort_type,
1041 .c_int_type,
1042 .c_uint_type,
1043 .c_long_type,
1044 .c_ulong_type,
1045 .c_longlong_type,
1046 .c_ulonglong_type,
1047 .c_longdouble_type,
1048 .f16_type,
1049 .f32_type,
1050 .f64_type,
1051 .f128_type,
1052 .c_void_type,
1053 .bool_type,
1054 .void_type,
1055 .type_type,
1056 .anyerror_type,
1057 .comptime_int_type,
1058 .comptime_float_type,
1059 .noreturn_type,
1060 .null_type,
1061 .undefined_type,
1062 .fn_noreturn_no_args_type,
1063 .fn_void_no_args_type,
1064 .fn_naked_noreturn_no_args_type,
1065 .fn_ccc_void_no_args_type,
1066 .single_const_pointer_to_comptime_int_type,
1067 .const_slice_u8_type,
1068 .enum_literal_type,
1069 .null_value,
1070 .function,
1071 .extern_fn,
1072 .variable,
1073 .ref_val,
1074 .decl_ref,
1075 .elem_ptr,
1076 .bytes,
1077 .repeated,
1078 .float_16,
1079 .float_32,
1080 .float_64,
1081 .float_128,
1082 .void_value,
1083 .unreachable_value,
1084 .empty_array,
1085 .enum_literal,
1086 .@"error",
1087 .error_union,
1088 .empty_struct_value,
1089 .inferred_alloc,
1090 .abi_align_default,
1091 => unreachable,
1092
1093 .zero,766 .zero,
1094 .undef,767 .undef,
1095 .bool_false,768 .bool_false,
...@@ -1144,6 +817,8 @@ pub const Value = extern union {...@@ -1144,6 +817,8 @@ pub const Value = extern union {
1144 .ComptimeInt => return true,817 .ComptimeInt => return true,
1145 else => unreachable,818 else => unreachable,
1146 },819 },
820
821 else => unreachable,
1147 }822 }
1148 }823 }
1149824
...@@ -1180,77 +855,6 @@ pub const Value = extern union {...@@ -1180,77 +855,6 @@ pub const Value = extern union {
1180 /// Asserts the value is a float855 /// Asserts the value is a float
1181 pub fn floatHasFraction(self: Value) bool {856 pub fn floatHasFraction(self: Value) bool {
1182 return switch (self.tag()) {857 return switch (self.tag()) {
1183 .ty,
1184 .int_type,
1185 .u8_type,
1186 .i8_type,
1187 .u16_type,
1188 .i16_type,
1189 .u32_type,
1190 .i32_type,
1191 .u64_type,
1192 .i64_type,
1193 .u128_type,
1194 .i128_type,
1195 .usize_type,
1196 .isize_type,
1197 .c_short_type,
1198 .c_ushort_type,
1199 .c_int_type,
1200 .c_uint_type,
1201 .c_long_type,
1202 .c_ulong_type,
1203 .c_longlong_type,
1204 .c_ulonglong_type,
1205 .c_longdouble_type,
1206 .f16_type,
1207 .f32_type,
1208 .f64_type,
1209 .f128_type,
1210 .c_void_type,
1211 .bool_type,
1212 .void_type,
1213 .type_type,
1214 .anyerror_type,
1215 .comptime_int_type,
1216 .comptime_float_type,
1217 .noreturn_type,
1218 .null_type,
1219 .undefined_type,
1220 .fn_noreturn_no_args_type,
1221 .fn_void_no_args_type,
1222 .fn_naked_noreturn_no_args_type,
1223 .fn_ccc_void_no_args_type,
1224 .single_const_pointer_to_comptime_int_type,
1225 .const_slice_u8_type,
1226 .enum_literal_type,
1227 .bool_true,
1228 .bool_false,
1229 .null_value,
1230 .function,
1231 .extern_fn,
1232 .variable,
1233 .ref_val,
1234 .decl_ref,
1235 .elem_ptr,
1236 .bytes,
1237 .repeated,
1238 .undef,
1239 .int_u64,
1240 .int_i64,
1241 .int_big_positive,
1242 .int_big_negative,
1243 .empty_array,
1244 .void_value,
1245 .unreachable_value,
1246 .enum_literal,
1247 .@"error",
1248 .error_union,
1249 .empty_struct_value,
1250 .inferred_alloc,
1251 .abi_align_default,
1252 => unreachable,
1253
1254 .zero,858 .zero,
1255 .one,859 .one,
1256 => false,860 => false,
...@@ -1260,76 +864,13 @@ pub const Value = extern union {...@@ -1260,76 +864,13 @@ pub const Value = extern union {
1260 .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,864 .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
1261 // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,865 // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
1262 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),866 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
867
868 else => unreachable,
1263 };869 };
1264 }870 }
1265871
1266 pub fn orderAgainstZero(lhs: Value) std.math.Order {872 pub fn orderAgainstZero(lhs: Value) std.math.Order {
1267 return switch (lhs.tag()) {873 return switch (lhs.tag()) {
1268 .ty,
1269 .int_type,
1270 .u8_type,
1271 .i8_type,
1272 .u16_type,
1273 .i16_type,
1274 .u32_type,
1275 .i32_type,
1276 .u64_type,
1277 .i64_type,
1278 .u128_type,
1279 .i128_type,
1280 .usize_type,
1281 .isize_type,
1282 .c_short_type,
1283 .c_ushort_type,
1284 .c_int_type,
1285 .c_uint_type,
1286 .c_long_type,
1287 .c_ulong_type,
1288 .c_longlong_type,
1289 .c_ulonglong_type,
1290 .c_longdouble_type,
1291 .f16_type,
1292 .f32_type,
1293 .f64_type,
1294 .f128_type,
1295 .c_void_type,
1296 .bool_type,
1297 .void_type,
1298 .type_type,
1299 .anyerror_type,
1300 .comptime_int_type,
1301 .comptime_float_type,
1302 .noreturn_type,
1303 .null_type,
1304 .undefined_type,
1305 .fn_noreturn_no_args_type,
1306 .fn_void_no_args_type,
1307 .fn_naked_noreturn_no_args_type,
1308 .fn_ccc_void_no_args_type,
1309 .single_const_pointer_to_comptime_int_type,
1310 .const_slice_u8_type,
1311 .enum_literal_type,
1312 .null_value,
1313 .function,
1314 .extern_fn,
1315 .variable,
1316 .ref_val,
1317 .decl_ref,
1318 .elem_ptr,
1319 .bytes,
1320 .repeated,
1321 .undef,
1322 .void_value,
1323 .unreachable_value,
1324 .empty_array,
1325 .enum_literal,
1326 .@"error",
1327 .error_union,
1328 .empty_struct_value,
1329 .inferred_alloc,
1330 .abi_align_default,
1331 => unreachable,
1332
1333 .zero,874 .zero,
1334 .bool_false,875 .bool_false,
1335 => .eq,876 => .eq,
...@@ -1347,6 +888,8 @@ pub const Value = extern union {...@@ -1347,6 +888,8 @@ pub const Value = extern union {
1347 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),888 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
1348 .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),889 .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
1349 .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),890 .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
891
892 else => unreachable,
1350 };893 };
1351 }894 }
1352895
...@@ -1396,10 +939,12 @@ pub const Value = extern union {...@@ -1396,10 +939,12 @@ pub const Value = extern union {
1396 }939 }
1397940
1398 pub fn eql(a: Value, b: Value) bool {941 pub fn eql(a: Value, b: Value) bool {
1399 if (a.tag() == b.tag()) {942 const a_tag = a.tag();
1400 if (a.tag() == .void_value or a.tag() == .null_value) {943 const b_tag = b.tag();
944 if (a_tag == b_tag) {
945 if (a_tag == .void_value or a_tag == .null_value) {
1401 return true;946 return true;
1402 } else if (a.tag() == .enum_literal) {947 } else if (a_tag == .enum_literal) {
1403 const a_name = a.castTag(.enum_literal).?.data;948 const a_name = a.castTag(.enum_literal).?.data;
1404 const b_name = b.castTag(.enum_literal).?.data;949 const b_name = b.castTag(.enum_literal).?.data;
1405 return std.mem.eql(u8, a_name, b_name);950 return std.mem.eql(u8, a_name, b_name);
...@@ -1416,6 +961,10 @@ pub const Value = extern union {...@@ -1416,6 +961,10 @@ pub const Value = extern union {
1416 return compare(a, .eq, b);961 return compare(a, .eq, b);
1417 }962 }
1418963
964 pub fn hash_u32(self: Value) u32 {
965 return @truncate(u32, self.hash());
966 }
967
1419 pub fn hash(self: Value) u64 {968 pub fn hash(self: Value) u64 {
1420 var hasher = std.hash.Wyhash.init(0);969 var hasher = std.hash.Wyhash.init(0);
1421970
...@@ -1493,11 +1042,18 @@ pub const Value = extern union {...@@ -1493,11 +1042,18 @@ pub const Value = extern union {
1493 .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),1042 .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),
1494 .one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),1043 .one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),
14951044
1496 .float_16, .float_32, .float_64, .float_128 => {},1045 .float_16, .float_32, .float_64, .float_128 => {
1046 @panic("TODO implement Value.hash for floats");
1047 },
1048
1497 .enum_literal => {1049 .enum_literal => {
1498 const payload = self.castTag(.enum_literal).?;1050 const payload = self.castTag(.enum_literal).?;
1499 hasher.update(payload.data);1051 hasher.update(payload.data);
1500 },1052 },
1053 .enum_field_index => {
1054 const payload = self.castTag(.enum_field_index).?;
1055 std.hash.autoHash(&hasher, payload.data);
1056 },
1501 .bytes => {1057 .bytes => {
1502 const payload = self.castTag(.bytes).?;1058 const payload = self.castTag(.bytes).?;
1503 hasher.update(payload.data);1059 hasher.update(payload.data);
...@@ -1573,80 +1129,6 @@ pub const Value = extern union {...@@ -1573,80 +1129,6 @@ pub const Value = extern union {
1573 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.1129 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
1574 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {1130 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
1575 return switch (self.tag()) {1131 return switch (self.tag()) {
1576 .ty,
1577 .int_type,
1578 .u8_type,
1579 .i8_type,
1580 .u16_type,
1581 .i16_type,
1582 .u32_type,
1583 .i32_type,
1584 .u64_type,
1585 .i64_type,
1586 .u128_type,
1587 .i128_type,
1588 .usize_type,
1589 .isize_type,
1590 .c_short_type,
1591 .c_ushort_type,
1592 .c_int_type,
1593 .c_uint_type,
1594 .c_long_type,
1595 .c_ulong_type,
1596 .c_longlong_type,
1597 .c_ulonglong_type,
1598 .c_longdouble_type,
1599 .f16_type,
1600 .f32_type,
1601 .f64_type,
1602 .f128_type,
1603 .c_void_type,
1604 .bool_type,
1605 .void_type,
1606 .type_type,
1607 .anyerror_type,
1608 .comptime_int_type,
1609 .comptime_float_type,
1610 .noreturn_type,
1611 .null_type,
1612 .undefined_type,
1613 .fn_noreturn_no_args_type,
1614 .fn_void_no_args_type,
1615 .fn_naked_noreturn_no_args_type,
1616 .fn_ccc_void_no_args_type,
1617 .single_const_pointer_to_comptime_int_type,
1618 .const_slice_u8_type,
1619 .enum_literal_type,
1620 .zero,
1621 .one,
1622 .bool_true,
1623 .bool_false,
1624 .null_value,
1625 .function,
1626 .extern_fn,
1627 .variable,
1628 .int_u64,
1629 .int_i64,
1630 .int_big_positive,
1631 .int_big_negative,
1632 .bytes,
1633 .undef,
1634 .repeated,
1635 .float_16,
1636 .float_32,
1637 .float_64,
1638 .float_128,
1639 .void_value,
1640 .unreachable_value,
1641 .empty_array,
1642 .enum_literal,
1643 .@"error",
1644 .error_union,
1645 .empty_struct_value,
1646 .inferred_alloc,
1647 .abi_align_default,
1648 => unreachable,
1649
1650 .ref_val => self.castTag(.ref_val).?.data,1132 .ref_val => self.castTag(.ref_val).?.data,
1651 .decl_ref => self.castTag(.decl_ref).?.data.value(),1133 .decl_ref => self.castTag(.decl_ref).?.data.value(),
1652 .elem_ptr => {1134 .elem_ptr => {
...@@ -1654,6 +1136,8 @@ pub const Value = extern union {...@@ -1654,6 +1136,8 @@ pub const Value = extern union {
1654 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);1136 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
1655 return array_val.elemValue(allocator, elem_ptr.index);1137 return array_val.elemValue(allocator, elem_ptr.index);
1656 },1138 },
1139
1140 else => unreachable,
1657 };1141 };
1658 }1142 }
16591143
...@@ -1661,86 +1145,14 @@ pub const Value = extern union {...@@ -1661,86 +1145,14 @@ pub const Value = extern union {
1661 /// or an unknown-length pointer, and returns the element value at the index.1145 /// or an unknown-length pointer, and returns the element value at the index.
1662 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {1146 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
1663 switch (self.tag()) {1147 switch (self.tag()) {
1664 .ty,
1665 .int_type,
1666 .u8_type,
1667 .i8_type,
1668 .u16_type,
1669 .i16_type,
1670 .u32_type,
1671 .i32_type,
1672 .u64_type,
1673 .i64_type,
1674 .u128_type,
1675 .i128_type,
1676 .usize_type,
1677 .isize_type,
1678 .c_short_type,
1679 .c_ushort_type,
1680 .c_int_type,
1681 .c_uint_type,
1682 .c_long_type,
1683 .c_ulong_type,
1684 .c_longlong_type,
1685 .c_ulonglong_type,
1686 .c_longdouble_type,
1687 .f16_type,
1688 .f32_type,
1689 .f64_type,
1690 .f128_type,
1691 .c_void_type,
1692 .bool_type,
1693 .void_type,
1694 .type_type,
1695 .anyerror_type,
1696 .comptime_int_type,
1697 .comptime_float_type,
1698 .noreturn_type,
1699 .null_type,
1700 .undefined_type,
1701 .fn_noreturn_no_args_type,
1702 .fn_void_no_args_type,
1703 .fn_naked_noreturn_no_args_type,
1704 .fn_ccc_void_no_args_type,
1705 .single_const_pointer_to_comptime_int_type,
1706 .const_slice_u8_type,
1707 .enum_literal_type,
1708 .zero,
1709 .one,
1710 .bool_true,
1711 .bool_false,
1712 .null_value,
1713 .function,
1714 .extern_fn,
1715 .variable,
1716 .int_u64,
1717 .int_i64,
1718 .int_big_positive,
1719 .int_big_negative,
1720 .undef,
1721 .elem_ptr,
1722 .ref_val,
1723 .decl_ref,
1724 .float_16,
1725 .float_32,
1726 .float_64,
1727 .float_128,
1728 .void_value,
1729 .unreachable_value,
1730 .enum_literal,
1731 .@"error",
1732 .error_union,
1733 .empty_struct_value,
1734 .inferred_alloc,
1735 .abi_align_default,
1736 => unreachable,
1737
1738 .empty_array => unreachable, // out of bounds array index1148 .empty_array => unreachable, // out of bounds array index
17391149
1740 .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),1150 .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
17411151
1742 // No matter the index; all the elements are the same!1152 // No matter the index; all the elements are the same!
1743 .repeated => return self.castTag(.repeated).?.data,1153 .repeated => return self.castTag(.repeated).?.data,
1154
1155 else => unreachable,
1744 }1156 }
1745 }1157 }
17461158
...@@ -1766,161 +1178,18 @@ pub const Value = extern union {...@@ -1766,161 +1178,18 @@ pub const Value = extern union {
1766 /// Valid for all types. Asserts the value is not undefined and not unreachable.1178 /// Valid for all types. Asserts the value is not undefined and not unreachable.
1767 pub fn isNull(self: Value) bool {1179 pub fn isNull(self: Value) bool {
1768 return switch (self.tag()) {1180 return switch (self.tag()) {
1769 .ty,
1770 .int_type,
1771 .u8_type,
1772 .i8_type,
1773 .u16_type,
1774 .i16_type,
1775 .u32_type,
1776 .i32_type,
1777 .u64_type,
1778 .i64_type,
1779 .u128_type,
1780 .i128_type,
1781 .usize_type,
1782 .isize_type,
1783 .c_short_type,
1784 .c_ushort_type,
1785 .c_int_type,
1786 .c_uint_type,
1787 .c_long_type,
1788 .c_ulong_type,
1789 .c_longlong_type,
1790 .c_ulonglong_type,
1791 .c_longdouble_type,
1792 .f16_type,
1793 .f32_type,
1794 .f64_type,
1795 .f128_type,
1796 .c_void_type,
1797 .bool_type,
1798 .void_type,
1799 .type_type,
1800 .anyerror_type,
1801 .comptime_int_type,
1802 .comptime_float_type,
1803 .noreturn_type,
1804 .null_type,
1805 .undefined_type,
1806 .fn_noreturn_no_args_type,
1807 .fn_void_no_args_type,
1808 .fn_naked_noreturn_no_args_type,
1809 .fn_ccc_void_no_args_type,
1810 .single_const_pointer_to_comptime_int_type,
1811 .const_slice_u8_type,
1812 .enum_literal_type,
1813 .zero,
1814 .one,
1815 .empty_array,
1816 .bool_true,
1817 .bool_false,
1818 .function,
1819 .extern_fn,
1820 .variable,
1821 .int_u64,
1822 .int_i64,
1823 .int_big_positive,
1824 .int_big_negative,
1825 .ref_val,
1826 .decl_ref,
1827 .elem_ptr,
1828 .bytes,
1829 .repeated,
1830 .float_16,
1831 .float_32,
1832 .float_64,
1833 .float_128,
1834 .void_value,
1835 .enum_literal,
1836 .@"error",
1837 .error_union,
1838 .empty_struct_value,
1839 .abi_align_default,
1840 => false,
1841
1842 .undef => unreachable,1181 .undef => unreachable,
1843 .unreachable_value => unreachable,1182 .unreachable_value => unreachable,
1844 .inferred_alloc => unreachable,1183 .inferred_alloc => unreachable,
1845 .null_value => true,1184 .null_value => true,
1185
1186 else => false,
1846 };1187 };
1847 }1188 }
18481189
1849 /// Valid for all types. Asserts the value is not undefined and not unreachable.1190 /// Valid for all types. Asserts the value is not undefined and not unreachable.
1850 pub fn getError(self: Value) ?[]const u8 {1191 pub fn getError(self: Value) ?[]const u8 {
1851 return switch (self.tag()) {1192 return switch (self.tag()) {
1852 .ty,
1853 .int_type,
1854 .u8_type,
1855 .i8_type,
1856 .u16_type,
1857 .i16_type,
1858 .u32_type,
1859 .i32_type,
1860 .u64_type,
1861 .i64_type,
1862 .u128_type,
1863 .i128_type,
1864 .usize_type,
1865 .isize_type,
1866 .c_short_type,
1867 .c_ushort_type,
1868 .c_int_type,
1869 .c_uint_type,
1870 .c_long_type,
1871 .c_ulong_type,
1872 .c_longlong_type,
1873 .c_ulonglong_type,
1874 .c_longdouble_type,
1875 .f16_type,
1876 .f32_type,
1877 .f64_type,
1878 .f128_type,
1879 .c_void_type,
1880 .bool_type,
1881 .void_type,
1882 .type_type,
1883 .anyerror_type,
1884 .comptime_int_type,
1885 .comptime_float_type,
1886 .noreturn_type,
1887 .null_type,
1888 .undefined_type,
1889 .fn_noreturn_no_args_type,
1890 .fn_void_no_args_type,
1891 .fn_naked_noreturn_no_args_type,
1892 .fn_ccc_void_no_args_type,
1893 .single_const_pointer_to_comptime_int_type,
1894 .const_slice_u8_type,
1895 .enum_literal_type,
1896 .zero,
1897 .one,
1898 .null_value,
1899 .empty_array,
1900 .bool_true,
1901 .bool_false,
1902 .function,
1903 .extern_fn,
1904 .variable,
1905 .int_u64,
1906 .int_i64,
1907 .int_big_positive,
1908 .int_big_negative,
1909 .ref_val,
1910 .decl_ref,
1911 .elem_ptr,
1912 .bytes,
1913 .repeated,
1914 .float_16,
1915 .float_32,
1916 .float_64,
1917 .float_128,
1918 .void_value,
1919 .enum_literal,
1920 .empty_struct_value,
1921 .abi_align_default,
1922 => null,
1923
1924 .error_union => {1193 .error_union => {
1925 const data = self.castTag(.error_union).?.data;1194 const data = self.castTag(.error_union).?.data;
1926 return if (data.tag() == .@"error")1195 return if (data.tag() == .@"error")
...@@ -1932,6 +1201,8 @@ pub const Value = extern union {...@@ -1932,6 +1201,8 @@ pub const Value = extern union {
1932 .undef => unreachable,1201 .undef => unreachable,
1933 .unreachable_value => unreachable,1202 .unreachable_value => unreachable,
1934 .inferred_alloc => unreachable,1203 .inferred_alloc => unreachable,
1204
1205 else => null,
1935 };1206 };
1936 }1207 }
1937 /// Valid for all types. Asserts the value is not undefined.1208 /// Valid for all types. Asserts the value is not undefined.
...@@ -2021,6 +1292,7 @@ pub const Value = extern union {...@@ -2021,6 +1292,7 @@ pub const Value = extern union {
2021 .float_128,1292 .float_128,
2022 .void_value,1293 .void_value,
2023 .enum_literal,1294 .enum_literal,
1295 .enum_field_index,
2024 .@"error",1296 .@"error",
2025 .error_union,1297 .error_union,
2026 .empty_struct_value,1298 .empty_struct_value,
...@@ -2038,6 +1310,11 @@ pub const Value = extern union {...@@ -2038,6 +1310,11 @@ pub const Value = extern union {
2038 pub const Payload = struct {1310 pub const Payload = struct {
2039 tag: Tag,1311 tag: Tag,
20401312
1313 pub const U32 = struct {
1314 base: Payload,
1315 data: u32,
1316 };
1317
2041 pub const U64 = struct {1318 pub const U64 = struct {
2042 base: Payload,1319 base: Payload,
2043 data: u64,1320 data: u64,
src/zig_clang.cpp+34
...@@ -2060,6 +2060,11 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {...@@ -2060,6 +2060,11 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {
2060 return casted->isRecordType();2060 return casted->isRecordType();
2061}2061}
20622062
2063bool ZigClangType_isVectorType(const ZigClangType *self) {
2064 auto casted = reinterpret_cast<const clang::Type *>(self);
2065 return casted->isVectorType();
2066}
2067
2063bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,2068bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,
2064 const struct ZigClangASTContext *ctx)2069 const struct ZigClangASTContext *ctx)
2065{2070{
...@@ -2752,6 +2757,16 @@ struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBina...@@ -2752,6 +2757,16 @@ struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBina
2752 return bitcast(casted->getType());2757 return bitcast(casted->getType());
2753}2758}
27542759
2760const struct ZigClangExpr *ZigClangConvertVectorExpr_getSrcExpr(const struct ZigClangConvertVectorExpr *self) {
2761 auto casted = reinterpret_cast<const clang::ConvertVectorExpr *>(self);
2762 return reinterpret_cast<const struct ZigClangExpr *>(casted->getSrcExpr());
2763}
2764
2765struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *self) {
2766 auto casted = reinterpret_cast<const clang::ConvertVectorExpr *>(self);
2767 return bitcast(casted->getTypeSourceInfo()->getType());
2768}
2769
2755struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *self) {2770struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *self) {
2756 auto casted = reinterpret_cast<const clang::DecayedType *>(self);2771 auto casted = reinterpret_cast<const clang::DecayedType *>(self);
2757 return bitcast(casted->getDecayedType());2772 return bitcast(casted->getDecayedType());
...@@ -2857,6 +2872,16 @@ struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl...@@ -2857,6 +2872,16 @@ struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl
2857 return bitcast(casted->getType());2872 return bitcast(casted->getType());
2858}2873}
28592874
2875struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *self) {
2876 auto casted = reinterpret_cast<const clang::VectorType *>(self);
2877 return bitcast(casted->getElementType());
2878}
2879
2880unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *self) {
2881 auto casted = reinterpret_cast<const clang::VectorType *>(self);
2882 return casted->getNumElements();
2883}
2884
2860const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) {2885const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) {
2861 auto casted = reinterpret_cast<const clang::WhileStmt *>(self);2886 auto casted = reinterpret_cast<const clang::WhileStmt *>(self);
2862 return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());2887 return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());
...@@ -2936,6 +2961,15 @@ struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(...@@ -2936,6 +2961,15 @@ struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(
2936 return bitcast(casted->getBeginLoc());2961 return bitcast(casted->getBeginLoc());
2937}2962}
29382963
2964unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const ZigClangShuffleVectorExpr *self) {
2965 auto casted = reinterpret_cast<const clang::ShuffleVectorExpr *>(self);
2966 return casted->getNumSubExprs();
2967}
2968
2969const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *self, unsigned idx) {
2970 auto casted = reinterpret_cast<const clang::ShuffleVectorExpr *>(self);
2971 return reinterpret_cast<const struct ZigClangExpr *>(casted->getExpr(idx));
2972}
29392973
2940enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(2974enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(
2941 const struct ZigClangUnaryExprOrTypeTraitExpr *self)2975 const struct ZigClangUnaryExprOrTypeTraitExpr *self)
src/zig_clang.h+10
...@@ -1071,6 +1071,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);...@@ -1071,6 +1071,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
1071ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);1071ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
1072ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);1072ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
1073ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);1073ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
1074ZIG_EXTERN_C bool ZigClangType_isVectorType(const struct ZigClangType *self);
1074ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);1075ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);
1075ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);1076ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);
1076ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);1077ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
...@@ -1206,6 +1207,9 @@ ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const stru...@@ -1206,6 +1207,9 @@ ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const stru
1206ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *);1207ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *);
1207ZIG_EXTERN_C struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *);1208ZIG_EXTERN_C struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *);
12081209
1210ZIG_EXTERN_C const struct ZigClangExpr *ZigClangConvertVectorExpr_getSrcExpr(const struct ZigClangConvertVectorExpr *);
1211ZIG_EXTERN_C struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *);
1212
1209ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *);1213ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *);
12101214
1211ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *);1215ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *);
...@@ -1235,6 +1239,9 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(con...@@ -1235,6 +1239,9 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(con
12351239
1236ZIG_EXTERN_C struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *);1240ZIG_EXTERN_C struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *);
12371241
1242ZIG_EXTERN_C struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *);
1243ZIG_EXTERN_C unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *);
1244
1238ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *);1245ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *);
1239ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *);1246ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *);
12401247
...@@ -1259,6 +1266,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryExprOrTypeTraitExpr_getTypeOfA...@@ -1259,6 +1266,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryExprOrTypeTraitExpr_getTypeOfA
1259ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(const struct ZigClangUnaryExprOrTypeTraitExpr *);1266ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(const struct ZigClangUnaryExprOrTypeTraitExpr *);
1260ZIG_EXTERN_C enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(const struct ZigClangUnaryExprOrTypeTraitExpr *);1267ZIG_EXTERN_C enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(const struct ZigClangUnaryExprOrTypeTraitExpr *);
12611268
1269ZIG_EXTERN_C unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const struct ZigClangShuffleVectorExpr *);
1270ZIG_EXTERN_C const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *, unsigned);
1271
1262ZIG_EXTERN_C const struct ZigClangStmt *ZigClangDoStmt_getBody(const struct ZigClangDoStmt *);1272ZIG_EXTERN_C const struct ZigClangStmt *ZigClangDoStmt_getBody(const struct ZigClangDoStmt *);
1263ZIG_EXTERN_C const struct ZigClangExpr *ZigClangDoStmt_getCond(const struct ZigClangDoStmt *);1273ZIG_EXTERN_C const struct ZigClangExpr *ZigClangDoStmt_getCond(const struct ZigClangDoStmt *);
12641274
src/zir.zig+118-23
...@@ -37,8 +37,6 @@ pub const Code = struct {...@@ -37,8 +37,6 @@ pub const Code = struct {
37 string_bytes: []u8,37 string_bytes: []u8,
38 /// The meaning of this data is determined by `Inst.Tag` value.38 /// The meaning of this data is determined by `Inst.Tag` value.
39 extra: []u32,39 extra: []u32,
40 /// Used for decl_val and decl_ref instructions.
41 decls: []*Module.Decl,
4240
43 /// Returns the requested data, as well as the new index which is at the start of the41 /// Returns the requested data, as well as the new index which is at the start of the
44 /// trailers for the object.42 /// trailers for the object.
...@@ -78,7 +76,6 @@ pub const Code = struct {...@@ -78,7 +76,6 @@ pub const Code = struct {
78 code.instructions.deinit(gpa);76 code.instructions.deinit(gpa);
79 gpa.free(code.string_bytes);77 gpa.free(code.string_bytes);
80 gpa.free(code.extra);78 gpa.free(code.extra);
81 gpa.free(code.decls);
82 code.* = undefined;79 code.* = undefined;
83 }80 }
8481
...@@ -133,7 +130,7 @@ pub const Inst = struct {...@@ -133,7 +130,7 @@ pub const Inst = struct {
133 /// Same as `alloc` except mutable.130 /// Same as `alloc` except mutable.
134 alloc_mut,131 alloc_mut,
135 /// Same as `alloc` except the type is inferred.132 /// Same as `alloc` except the type is inferred.
136 /// The operand is unused.133 /// Uses the `node` union field.
137 alloc_inferred,134 alloc_inferred,
138 /// Same as `alloc_inferred` except mutable.135 /// Same as `alloc_inferred` except mutable.
139 alloc_inferred_mut,136 alloc_inferred_mut,
...@@ -267,9 +264,6 @@ pub const Inst = struct {...@@ -267,9 +264,6 @@ pub const Inst = struct {
267 /// only the taken branch is analyzed. The then block and else block must264 /// only the taken branch is analyzed. The then block and else block must
268 /// terminate with an "inline" variant of a noreturn instruction.265 /// terminate with an "inline" variant of a noreturn instruction.
269 condbr_inline,266 condbr_inline,
270 /// A comptime known value.
271 /// Uses the `const` union field.
272 @"const",
273 /// A struct type definition. Contains references to ZIR instructions for267 /// A struct type definition. Contains references to ZIR instructions for
274 /// the field types, defaults, and alignments.268 /// the field types, defaults, and alignments.
275 /// Uses the `pl_node` union field. Payload is `StructDecl`.269 /// Uses the `pl_node` union field. Payload is `StructDecl`.
...@@ -286,6 +280,8 @@ pub const Inst = struct {...@@ -286,6 +280,8 @@ pub const Inst = struct {
286 /// the field value expressions and optional type tag expression.280 /// the field value expressions and optional type tag expression.
287 /// Uses the `pl_node` union field. Payload is `EnumDecl`.281 /// Uses the `pl_node` union field. Payload is `EnumDecl`.
288 enum_decl,282 enum_decl,
283 /// Same as `enum_decl`, except the enum is non-exhaustive.
284 enum_decl_nonexhaustive,
289 /// An opaque type definition. Provides an AST node only.285 /// An opaque type definition. Provides an AST node only.
290 /// Uses the `node` union field.286 /// Uses the `node` union field.
291 opaque_decl,287 opaque_decl,
...@@ -332,12 +328,16 @@ pub const Inst = struct {...@@ -332,12 +328,16 @@ pub const Inst = struct {
332 error_union_type,328 error_union_type,
333 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.329 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
334 error_value,330 error_value,
331 /// Implements the `@export` builtin function.
332 /// Uses the `pl_node` union field. Payload is `Bin`.
333 @"export",
335 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer334 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
336 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.335 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
337 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.336 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
338 field_ptr,337 field_ptr,
339 /// Given a struct or object that contains virtual fields, returns the named field.338 /// Given a struct or object that contains virtual fields, returns the named field.
340 /// The field name is stored in string_bytes. Used by a.b syntax.339 /// The field name is stored in string_bytes. Used by a.b syntax.
340 /// This instruction also accepts a pointer.
341 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.341 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
342 field_val,342 field_val,
343 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer343 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
...@@ -363,11 +363,19 @@ pub const Inst = struct {...@@ -363,11 +363,19 @@ pub const Inst = struct {
363 fn_type_cc,363 fn_type_cc,
364 /// Same as `fn_type_cc` but the function is variadic.364 /// Same as `fn_type_cc` but the function is variadic.
365 fn_type_cc_var_args,365 fn_type_cc_var_args,
366 /// Implements the `@hasDecl` builtin.
367 /// Uses the `pl_node` union field. Payload is `Bin`.
368 has_decl,
366 /// `@import(operand)`.369 /// `@import(operand)`.
367 /// Uses the `un_node` field.370 /// Uses the `un_node` field.
368 import,371 import,
369 /// Integer literal that fits in a u64. Uses the int union value.372 /// Integer literal that fits in a u64. Uses the int union value.
370 int,373 int,
374 /// A float literal that fits in a f32. Uses the float union value.
375 float,
376 /// A float literal that fits in a f128. Uses the `pl_node` union value.
377 /// Payload is `Float128`.
378 float128,
371 /// Convert an integer value to another integer type, asserting that the destination type379 /// Convert an integer value to another integer type, asserting that the destination type
372 /// can hold the same mathematical value.380 /// can hold the same mathematical value.
373 /// Uses the `pl_node` field. AST is the `@intCast` syntax.381 /// Uses the `pl_node` field. AST is the `@intCast` syntax.
...@@ -659,11 +667,28 @@ pub const Inst = struct {...@@ -659,11 +667,28 @@ pub const Inst = struct {
659 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct667 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
660 /// initialization expression, and emits compile errors for duplicate fields668 /// initialization expression, and emits compile errors for duplicate fields
661 /// as well as missing fields, if applicable.669 /// as well as missing fields, if applicable.
670 /// This instruction asserts that there is at least one field_ptr instruction,
671 /// because it must use one of them to find out the struct type.
662 /// Uses the `pl_node` field. Payload is `Block`.672 /// Uses the `pl_node` field. Payload is `Block`.
663 validate_struct_init_ptr,673 validate_struct_init_ptr,
664 /// A struct literal with a specified type, with no fields.674 /// A struct literal with a specified type, with no fields.
665 /// Uses the `un_node` field.675 /// Uses the `un_node` field.
666 struct_init_empty,676 struct_init_empty,
677 /// Given a struct, union, enum, or opaque and a field name, returns the field type.
678 /// Uses the `pl_node` field. Payload is `FieldType`.
679 field_type,
680 /// Finalizes a typed struct initialization, performs validation, and returns the
681 /// struct value.
682 /// Uses the `pl_node` field. Payload is `StructInit`.
683 struct_init,
684 /// Converts an integer into an enum value.
685 /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
686 int_to_enum,
687 /// Converts an enum value into an integer. Resulting type will be the tag type
688 /// of the enum. Uses `un_node`.
689 enum_to_int,
690 /// Implements the `@typeInfo` builtin. Uses `un_node`.
691 type_info,
667692
668 /// Returns whether the instruction is one of the control flow "noreturn" types.693 /// Returns whether the instruction is one of the control flow "noreturn" types.
669 /// Function calls do not count.694 /// Function calls do not count.
...@@ -709,12 +734,12 @@ pub const Inst = struct {...@@ -709,12 +734,12 @@ pub const Inst = struct {
709 .cmp_gt,734 .cmp_gt,
710 .cmp_neq,735 .cmp_neq,
711 .coerce_result_ptr,736 .coerce_result_ptr,
712 .@"const",
713 .struct_decl,737 .struct_decl,
714 .struct_decl_packed,738 .struct_decl_packed,
715 .struct_decl_extern,739 .struct_decl_extern,
716 .union_decl,740 .union_decl,
717 .enum_decl,741 .enum_decl,
742 .enum_decl_nonexhaustive,
718 .opaque_decl,743 .opaque_decl,
719 .dbg_stmt_node,744 .dbg_stmt_node,
720 .decl_ref,745 .decl_ref,
...@@ -727,6 +752,7 @@ pub const Inst = struct {...@@ -727,6 +752,7 @@ pub const Inst = struct {
727 .elem_val_node,752 .elem_val_node,
728 .ensure_result_used,753 .ensure_result_used,
729 .ensure_result_non_error,754 .ensure_result_non_error,
755 .@"export",
730 .floatcast,756 .floatcast,
731 .field_ptr,757 .field_ptr,
732 .field_val,758 .field_val,
...@@ -736,7 +762,10 @@ pub const Inst = struct {...@@ -736,7 +762,10 @@ pub const Inst = struct {
736 .fn_type_var_args,762 .fn_type_var_args,
737 .fn_type_cc,763 .fn_type_cc,
738 .fn_type_cc_var_args,764 .fn_type_cc_var_args,
765 .has_decl,
739 .int,766 .int,
767 .float,
768 .float128,
740 .intcast,769 .intcast,
741 .int_type,770 .int_type,
742 .is_non_null,771 .is_non_null,
...@@ -819,6 +848,11 @@ pub const Inst = struct {...@@ -819,6 +848,11 @@ pub const Inst = struct {
819 .switch_block_ref_under_multi,848 .switch_block_ref_under_multi,
820 .validate_struct_init_ptr,849 .validate_struct_init_ptr,
821 .struct_init_empty,850 .struct_init_empty,
851 .struct_init,
852 .field_type,
853 .int_to_enum,
854 .enum_to_int,
855 .type_info,
822 => false,856 => false,
823857
824 .@"break",858 .@"break",
...@@ -1181,7 +1215,6 @@ pub const Inst = struct {...@@ -1181,7 +1215,6 @@ pub const Inst = struct {
1181 }1215 }
1182 },1216 },
1183 bin: Bin,1217 bin: Bin,
1184 @"const": *TypedValue,
1185 /// For strings which may contain null bytes.1218 /// For strings which may contain null bytes.
1186 str: struct {1219 str: struct {
1187 /// Offset into `string_bytes`.1220 /// Offset into `string_bytes`.
...@@ -1223,6 +1256,16 @@ pub const Inst = struct {...@@ -1223,6 +1256,16 @@ pub const Inst = struct {
1223 /// Offset from Decl AST node index.1256 /// Offset from Decl AST node index.
1224 node: i32,1257 node: i32,
1225 int: u64,1258 int: u64,
1259 float: struct {
1260 /// Offset from Decl AST node index.
1261 /// `Tag` determines which kind of AST node this points to.
1262 src_node: i32,
1263 number: f32,
1264
1265 pub fn src(self: @This()) LazySrcLoc {
1266 return .{ .node_offset = self.src_node };
1267 }
1268 },
1226 array_type_sentinel: struct {1269 array_type_sentinel: struct {
1227 len: Ref,1270 len: Ref,
1228 /// index into extra, points to an `ArrayTypeSentinel`1271 /// index into extra, points to an `ArrayTypeSentinel`
...@@ -1504,6 +1547,40 @@ pub const Inst = struct {...@@ -1504,6 +1547,40 @@ pub const Inst = struct {
1504 tag_type: Ref,1547 tag_type: Ref,
1505 fields_len: u32,1548 fields_len: u32,
1506 };1549 };
1550
1551 /// A f128 value, broken up into 4 u32 parts.
1552 pub const Float128 = struct {
1553 piece0: u32,
1554 piece1: u32,
1555 piece2: u32,
1556 piece3: u32,
1557
1558 pub fn get(self: Float128) f128 {
1559 const int_bits = @as(u128, self.piece0) |
1560 (@as(u128, self.piece1) << 32) |
1561 (@as(u128, self.piece2) << 64) |
1562 (@as(u128, self.piece3) << 96);
1563 return @bitCast(f128, int_bits);
1564 }
1565 };
1566
1567 /// Trailing is an item per field.
1568 pub const StructInit = struct {
1569 fields_len: u32,
1570
1571 pub const Item = struct {
1572 /// The `field_type` ZIR instruction for this field init.
1573 field_type: Index,
1574 /// The field init expression to be used as the field value.
1575 init: Ref,
1576 };
1577 };
1578
1579 pub const FieldType = struct {
1580 container_type: Ref,
1581 /// Offset into `string_bytes`, null terminated.
1582 name_start: u32,
1583 };
1507};1584};
15081585
1509pub const SpecialProng = enum { none, @"else", under };1586pub const SpecialProng = enum { none, @"else", under };
...@@ -1533,12 +1610,11 @@ const Writer = struct {...@@ -1533,12 +1610,11 @@ const Writer = struct {
1533 .intcast,1610 .intcast,
1534 .store,1611 .store,
1535 .store_to_block_ptr,1612 .store_to_block_ptr,
1613 .store_to_inferred_ptr,
1536 => try self.writeBin(stream, inst),1614 => try self.writeBin(stream, inst),
15371615
1538 .alloc,1616 .alloc,
1539 .alloc_mut,1617 .alloc_mut,
1540 .alloc_inferred,
1541 .alloc_inferred_mut,
1542 .indexable_ptr_len,1618 .indexable_ptr_len,
1543 .bit_not,1619 .bit_not,
1544 .bool_not,1620 .bool_not,
...@@ -1578,6 +1654,8 @@ const Writer = struct {...@@ -1578,6 +1654,8 @@ const Writer = struct {
1578 .typeof,1654 .typeof,
1579 .typeof_elem,1655 .typeof_elem,
1580 .struct_init_empty,1656 .struct_init_empty,
1657 .enum_to_int,
1658 .type_info,
1581 => try self.writeUnNode(stream, inst),1659 => try self.writeUnNode(stream, inst),
15821660
1583 .ref,1661 .ref,
...@@ -1591,11 +1669,12 @@ const Writer = struct {...@@ -1591,11 +1669,12 @@ const Writer = struct {
1591 => try self.writeBoolBr(stream, inst),1669 => try self.writeBoolBr(stream, inst),
15921670
1593 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),1671 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
1594 .@"const" => try self.writeConst(stream, inst),
1595 .param_type => try self.writeParamType(stream, inst),1672 .param_type => try self.writeParamType(stream, inst),
1596 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),1673 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
1597 .ptr_type => try self.writePtrType(stream, inst),1674 .ptr_type => try self.writePtrType(stream, inst),
1598 .int => try self.writeInt(stream, inst),1675 .int => try self.writeInt(stream, inst),
1676 .float => try self.writeFloat(stream, inst),
1677 .float128 => try self.writeFloat128(stream, inst),
1599 .str => try self.writeStr(stream, inst),1678 .str => try self.writeStr(stream, inst),
1600 .elided => try stream.writeAll(")"),1679 .elided => try stream.writeAll(")"),
1601 .int_type => try self.writeIntType(stream, inst),1680 .int_type => try self.writeIntType(stream, inst),
...@@ -1616,6 +1695,9 @@ const Writer = struct {...@@ -1616,6 +1695,9 @@ const Writer = struct {
1616 .slice_sentinel,1695 .slice_sentinel,
1617 .union_decl,1696 .union_decl,
1618 .enum_decl,1697 .enum_decl,
1698 .enum_decl_nonexhaustive,
1699 .struct_init,
1700 .field_type,
1619 => try self.writePlNode(stream, inst),1701 => try self.writePlNode(stream, inst),
16201702
1621 .add,1703 .add,
...@@ -1635,15 +1717,18 @@ const Writer = struct {...@@ -1635,15 +1717,18 @@ const Writer = struct {
1635 .cmp_gt,1717 .cmp_gt,
1636 .cmp_neq,1718 .cmp_neq,
1637 .div,1719 .div,
1720 .has_decl,
1638 .mod_rem,1721 .mod_rem,
1639 .shl,1722 .shl,
1640 .shr,1723 .shr,
1641 .xor,1724 .xor,
1642 .store_node,1725 .store_node,
1643 .error_union_type,1726 .error_union_type,
1727 .@"export",
1644 .merge_error_sets,1728 .merge_error_sets,
1645 .bit_and,1729 .bit_and,
1646 .bit_or,1730 .bit_or,
1731 .int_to_enum,
1647 => try self.writePlNodeBin(stream, inst),1732 => try self.writePlNodeBin(stream, inst),
16481733
1649 .call,1734 .call,
...@@ -1701,6 +1786,8 @@ const Writer = struct {...@@ -1701,6 +1786,8 @@ const Writer = struct {
1701 .ret_type,1786 .ret_type,
1702 .repeat,1787 .repeat,
1703 .repeat_inline,1788 .repeat_inline,
1789 .alloc_inferred,
1790 .alloc_inferred_mut,
1704 => try self.writeNode(stream, inst),1791 => try self.writeNode(stream, inst),
17051792
1706 .error_value,1793 .error_value,
...@@ -1726,7 +1813,6 @@ const Writer = struct {...@@ -1726,7 +1813,6 @@ const Writer = struct {
17261813
1727 .bitcast,1814 .bitcast,
1728 .bitcast_result_ptr,1815 .bitcast_result_ptr,
1729 .store_to_inferred_ptr,
1730 => try stream.writeAll("TODO)"),1816 => try stream.writeAll("TODO)"),
1731 }1817 }
1732 }1818 }
...@@ -1770,15 +1856,6 @@ const Writer = struct {...@@ -1770,15 +1856,6 @@ const Writer = struct {
1770 try stream.writeAll("TODO)");1856 try stream.writeAll("TODO)");
1771 }1857 }
17721858
1773 fn writeConst(
1774 self: *Writer,
1775 stream: anytype,
1776 inst: Inst.Index,
1777 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1778 const inst_data = self.code.instructions.items(.data)[inst].@"const";
1779 try stream.writeAll("TODO)");
1780 }
1781
1782 fn writeParamType(1859 fn writeParamType(
1783 self: *Writer,1860 self: *Writer,
1784 stream: anytype,1861 stream: anytype,
...@@ -1816,6 +1893,23 @@ const Writer = struct {...@@ -1816,6 +1893,23 @@ const Writer = struct {
1816 try stream.print("{d})", .{inst_data});1893 try stream.print("{d})", .{inst_data});
1817 }1894 }
18181895
1896 fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1897 const inst_data = self.code.instructions.items(.data)[inst].float;
1898 const src = inst_data.src();
1899 try stream.print("{d}) ", .{inst_data.number});
1900 try self.writeSrc(stream, src);
1901 }
1902
1903 fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1904 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1905 const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data;
1906 const src = inst_data.src();
1907 const number = extra.get();
1908 // TODO improve std.format to be able to print f128 values
1909 try stream.print("{d}) ", .{@floatCast(f64, number)});
1910 try self.writeSrc(stream, src);
1911 }
1912
1819 fn writeStr(1913 fn writeStr(
1820 self: *Writer,1914 self: *Writer,
1821 stream: anytype,1915 stream: anytype,
...@@ -2133,7 +2227,8 @@ const Writer = struct {...@@ -2133,7 +2227,8 @@ const Writer = struct {
21332227
2134 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {2228 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2135 const inst_data = self.code.instructions.items(.data)[inst].pl_node;2229 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2136 const decl = self.code.decls[inst_data.payload_index];2230 const owner_decl = self.scope.ownerDecl().?;
2231 const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key;
2137 try stream.print("{s}) ", .{decl.name});2232 try stream.print("{s}) ", .{decl.name});
2138 try self.writeSrc(stream, inst_data.src());2233 try self.writeSrc(stream, inst_data.src());
2139 }2234 }
test/run_translated_c.zig+102
...@@ -1308,4 +1308,106 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1308,4 +1308,106 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1308 \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted1308 \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted
1309 \\}1309 \\}
1310 , "");1310 , "");
1311
1312 cases.add("basic vector expressions",
1313 \\#include <stdlib.h>
1314 \\#include <stdint.h>
1315 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1316 \\int main(int argc, char**argv) {
1317 \\ __v8hi uninitialized;
1318 \\ __v8hi empty_init = {};
1319 \\ __v8hi partial_init = {0, 1, 2, 3};
1320 \\
1321 \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7};
1322 \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800};
1323 \\
1324 \\ __v8hi sum = a + b;
1325 \\ for (int i = 0; i < 8; i++) {
1326 \\ if (sum[i] != a[i] + b[i]) abort();
1327 \\ }
1328 \\ return 0;
1329 \\}
1330 , "");
1331
1332 cases.add("__builtin_shufflevector",
1333 \\#include <stdlib.h>
1334 \\#include <stdint.h>
1335 \\typedef int16_t __v4hi __attribute__((__vector_size__(8)));
1336 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1337 \\int main(int argc, char**argv) {
1338 \\ __v8hi v8_a = {0, 1, 2, 3, 4, 5, 6, 7};
1339 \\ __v8hi v8_b = {100, 200, 300, 400, 500, 600, 700, 800};
1340 \\ __v8hi shuffled = __builtin_shufflevector(v8_a, v8_b, 0, 1, 2, 3, 8, 9, 10, 11);
1341 \\ for (int i = 0; i < 8; i++) {
1342 \\ if (i < 4) {
1343 \\ if (shuffled[i] != v8_a[i]) abort();
1344 \\ } else {
1345 \\ if (shuffled[i] != v8_b[i - 4]) abort();
1346 \\ }
1347 \\ }
1348 \\ shuffled = __builtin_shufflevector(
1349 \\ (__v8hi) {-1, -1, -1, -1, -1, -1, -1, -1},
1350 \\ (__v8hi) {42, 42, 42, 42, 42, 42, 42, 42},
1351 \\ 0, 1, 2, 3, 8, 9, 10, 11
1352 \\ );
1353 \\ for (int i = 0; i < 8; i++) {
1354 \\ if (i < 4) {
1355 \\ if (shuffled[i] != -1) abort();
1356 \\ } else {
1357 \\ if (shuffled[i] != 42) abort();
1358 \\ }
1359 \\ }
1360 \\ __v4hi shuffled_to_fewer_elements = __builtin_shufflevector(v8_a, v8_b, 0, 1, 8, 9);
1361 \\ for (int i = 0; i < 4; i++) {
1362 \\ if (i < 2) {
1363 \\ if (shuffled_to_fewer_elements[i] != v8_a[i]) abort();
1364 \\ } else {
1365 \\ if (shuffled_to_fewer_elements[i] != v8_b[i - 2]) abort();
1366 \\ }
1367 \\ }
1368 \\ __v4hi v4_a = {0, 1, 2, 3};
1369 \\ __v4hi v4_b = {100, 200, 300, 400};
1370 \\ __v8hi shuffled_to_more_elements = __builtin_shufflevector(v4_a, v4_b, 0, 1, 2, 3, 4, 5, 6, 7);
1371 \\ for (int i = 0; i < 4; i++) {
1372 \\ if (shuffled_to_more_elements[i] != v4_a[i]) abort();
1373 \\ if (shuffled_to_more_elements[i + 4] != v4_b[i]) abort();
1374 \\ }
1375 \\ return 0;
1376 \\}
1377 , "");
1378
1379 cases.add("__builtin_convertvector",
1380 \\#include <stdlib.h>
1381 \\#include <stdint.h>
1382 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1383 \\typedef uint16_t __v8hu __attribute__((__vector_size__(16)));
1384 \\int main(int argc, char**argv) {
1385 \\ __v8hi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4};
1386 \\ __v8hu unsigned_vector = __builtin_convertvector(signed_vector, __v8hu);
1387 \\
1388 \\ for (int i = 0; i < 8; i++) {
1389 \\ if (unsigned_vector[i] != (uint16_t)signed_vector[i]) abort();
1390 \\ }
1391 \\ return 0;
1392 \\}
1393 , "");
1394
1395 cases.add("vector casting",
1396 \\#include <stdlib.h>
1397 \\#include <stdint.h>
1398 \\typedef int8_t __v8qi __attribute__((__vector_size__(8)));
1399 \\typedef uint8_t __v8qu __attribute__((__vector_size__(8)));
1400 \\int main(int argc, char**argv) {
1401 \\ __v8qi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4};
1402 \\
1403 \\ uint64_t big_int = (uint64_t) signed_vector;
1404 \\ if (big_int != 0x01020304FFFEFDFCULL && big_int != 0xFCFDFEFF04030201ULL) abort();
1405 \\ __v8qu unsigned_vector = (__v8qu) big_int;
1406 \\ for (int i = 0; i < 8; i++) {
1407 \\ if (unsigned_vector[i] != (uint8_t)signed_vector[i] && unsigned_vector[i] != (uint8_t)signed_vector[7 - i]) abort();
1408 \\ }
1409 \\ return 0;
1410 \\}
1411 , "");
1412
1311}1413}
test/stack_traces.zig+173-409
...@@ -3,16 +3,56 @@ const os = std.os;...@@ -3,16 +3,56 @@ const os = std.os;
3const tests = @import("tests.zig");3const tests = @import("tests.zig");
44
5pub fn addCases(cases: *tests.StackTracesContext) void {5pub fn addCases(cases: *tests.StackTracesContext) void {
6 const source_return =6 cases.addCase(.{
7 \\const std = @import("std");7 .name = "return",
8 \\8 .source =
9 \\pub fn main() !void {9 \\pub fn main() !void {
10 \\ return error.TheSkyIsFalling;10 \\ return error.TheSkyIsFalling;
11 \\}11 \\}
12 ;12 ,
13 const source_try_return =13 .Debug = .{
14 \\const std = @import("std");14 .expect =
15 \\15 \\error: TheSkyIsFalling
16 \\source.zig:2:5: [address] in main (test)
17 \\ return error.TheSkyIsFalling;
18 \\ ^
19 \\
20 ,
21 },
22 .ReleaseSafe = .{
23 .exclude = struct {
24 pub fn exclude() bool {
25 return if (std.builtin.object_format == .elf) true else false;
26 }
27 },
28 .exclude_os = .{
29 .windows, // segfault
30 },
31 .expect =
32 \\error: TheSkyIsFalling
33 \\source.zig:2:5: [address] in [function]
34 \\ return error.TheSkyIsFalling;
35 \\ ^
36 \\
37 ,
38 },
39 .ReleaseFast = .{
40 .expect =
41 \\error: TheSkyIsFalling
42 \\
43 ,
44 },
45 .ReleaseSmall = .{
46 .expect =
47 \\error: TheSkyIsFalling
48 \\
49 ,
50 },
51 });
52
53 cases.addCase(.{
54 .name = "try return",
55 .source =
16 \\fn foo() !void {56 \\fn foo() !void {
17 \\ return error.TheSkyIsFalling;57 \\ return error.TheSkyIsFalling;
18 \\}58 \\}
...@@ -20,10 +60,56 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -20,10 +60,56 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
20 \\pub fn main() !void {60 \\pub fn main() !void {
21 \\ try foo();61 \\ try foo();
22 \\}62 \\}
23 ;63 ,
24 const source_try_try_return_return =64 .Debug = .{
25 \\const std = @import("std");65 .expect =
26 \\66 \\error: TheSkyIsFalling
67 \\source.zig:2:5: [address] in foo (test)
68 \\ return error.TheSkyIsFalling;
69 \\ ^
70 \\source.zig:6:5: [address] in main (test)
71 \\ try foo();
72 \\ ^
73 \\
74 ,
75 },
76 .ReleaseSafe = .{
77 .exclude = struct {
78 pub fn exclude() bool {
79 return if (std.builtin.object_format == .elf) true else false;
80 }
81 },
82 .exclude_os = .{
83 .windows, // segfault
84 },
85 .expect =
86 \\error: TheSkyIsFalling
87 \\source.zig:2:5: [address] in [function]
88 \\ return error.TheSkyIsFalling;
89 \\ ^
90 \\source.zig:6:5: [address] in [function]
91 \\ try foo();
92 \\ ^
93 \\
94 ,
95 },
96 .ReleaseFast = .{
97 .expect =
98 \\error: TheSkyIsFalling
99 \\
100 ,
101 },
102 .ReleaseSmall = .{
103 .expect =
104 \\error: TheSkyIsFalling
105 \\
106 ,
107 },
108 });
109
110 cases.addCase(.{
111 .name = "try try return return",
112 .source =
27 \\fn foo() !void {113 \\fn foo() !void {
28 \\ try bar();114 \\ try bar();
29 \\}115 \\}
...@@ -39,9 +125,71 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -39,9 +125,71 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
39 \\pub fn main() !void {125 \\pub fn main() !void {
40 \\ try foo();126 \\ try foo();
41 \\}127 \\}
42 ;128 ,
129 .Debug = .{
130 .expect =
131 \\error: TheSkyIsFalling
132 \\source.zig:10:5: [address] in make_error (test)
133 \\ return error.TheSkyIsFalling;
134 \\ ^
135 \\source.zig:6:5: [address] in bar (test)
136 \\ return make_error();
137 \\ ^
138 \\source.zig:2:5: [address] in foo (test)
139 \\ try bar();
140 \\ ^
141 \\source.zig:14:5: [address] in main (test)
142 \\ try foo();
143 \\ ^
144 \\
145 ,
146 },
147 .ReleaseSafe = .{
148 .exclude = struct {
149 pub fn exclude() bool {
150 return if (std.builtin.object_format == .elf) true else false;
151 }
152 },
153 .exclude_os = .{
154 .windows, // segfault
155 },
156 .expect =
157 \\error: TheSkyIsFalling
158 \\source.zig:10:5: [address] in [function]
159 \\ return error.TheSkyIsFalling;
160 \\ ^
161 \\source.zig:6:5: [address] in [function]
162 \\ return make_error();
163 \\ ^
164 \\source.zig:2:5: [address] in [function]
165 \\ try bar();
166 \\ ^
167 \\source.zig:14:5: [address] in [function]
168 \\ try foo();
169 \\ ^
170 \\
171 ,
172 },
173 .ReleaseFast = .{
174 .expect =
175 \\error: TheSkyIsFalling
176 \\
177 ,
178 },
179 .ReleaseSmall = .{
180 .expect =
181 \\error: TheSkyIsFalling
182 \\
183 ,
184 },
185 });
43186
44 const source_dumpCurrentStackTrace =187 cases.addCase(.{
188 .exclude_os = .{
189 .windows,
190 },
191 .name = "dumpCurrentStackTrace",
192 .source =
45 \\const std = @import("std");193 \\const std = @import("std");
46 \\194 \\
47 \\fn bar() void {195 \\fn bar() void {
...@@ -54,401 +202,17 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -54,401 +202,17 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
54 \\ foo();202 \\ foo();
55 \\ return 1;203 \\ return 1;
56 \\}204 \\}
57 ;205 ,
58206 .Debug = .{
59 switch (std.Target.current.os.tag) {207 .expect =
60 .freebsd => {208 \\source.zig:7:8: [address] in foo (test)
61 cases.addCase(209 \\ bar();
62 "return",210 \\ ^
63 source_return,211 \\source.zig:10:8: [address] in main (test)
64 [_][]const u8{212 \\ foo();
65 // debug213 \\ ^
66 \\error: TheSkyIsFalling214 \\
67 \\source.zig:4:5: [address] in main (test)215 ,
68 \\ return error.TheSkyIsFalling;
69 \\ ^
70 \\
71 ,
72 // release-safe
73 // https://github.com/ziglang/zig/issues/8421
74 \\
75 ,
76 // release-fast
77 \\error: TheSkyIsFalling
78 \\
79 ,
80 // release-small
81 \\error: TheSkyIsFalling
82 \\
83 },
84 );
85 cases.addCase(
86 "try return",
87 source_try_return,
88 [_][]const u8{
89 // debug
90 \\error: TheSkyIsFalling
91 \\source.zig:4:5: [address] in foo (test)
92 \\ return error.TheSkyIsFalling;
93 \\ ^
94 \\source.zig:8:5: [address] in main (test)
95 \\ try foo();
96 \\ ^
97 \\
98 ,
99 // release-safe
100 // https://github.com/ziglang/zig/issues/8421
101 \\
102 ,
103 // release-fast
104 \\error: TheSkyIsFalling
105 \\
106 ,
107 // release-small
108 \\error: TheSkyIsFalling
109 \\
110 },
111 );
112 cases.addCase(
113 "try try return return",
114 source_try_try_return_return,
115 [_][]const u8{
116 // debug
117 \\error: TheSkyIsFalling
118 \\source.zig:12:5: [address] in make_error (test)
119 \\ return error.TheSkyIsFalling;
120 \\ ^
121 \\source.zig:8:5: [address] in bar (test)
122 \\ return make_error();
123 \\ ^
124 \\source.zig:4:5: [address] in foo (test)
125 \\ try bar();
126 \\ ^
127 \\source.zig:16:5: [address] in main (test)
128 \\ try foo();
129 \\ ^
130 \\
131 ,
132 // release-safe
133 // https://github.com/ziglang/zig/issues/8421
134 \\
135 ,
136 // release-fast
137 \\error: TheSkyIsFalling
138 \\
139 ,
140 // release-small
141 \\error: TheSkyIsFalling
142 \\
143 },
144 );
145 },
146 .linux => {
147 cases.addCase(
148 "return",
149 source_return,
150 [_][]const u8{
151 // debug
152 \\error: TheSkyIsFalling
153 \\source.zig:4:5: [address] in main (test)
154 \\ return error.TheSkyIsFalling;
155 \\ ^
156 \\
157 ,
158 // release-safe
159 // https://github.com/ziglang/zig/issues/8421
160 \\
161 ,
162 // release-fast
163 \\error: TheSkyIsFalling
164 \\
165 ,
166 // release-small
167 \\error: TheSkyIsFalling
168 \\
169 },
170 );
171 cases.addCase(
172 "try return",
173 source_try_return,
174 [_][]const u8{
175 // debug
176 \\error: TheSkyIsFalling
177 \\source.zig:4:5: [address] in foo (test)
178 \\ return error.TheSkyIsFalling;
179 \\ ^
180 \\source.zig:8:5: [address] in main (test)
181 \\ try foo();
182 \\ ^
183 \\
184 ,
185 // release-safe
186 // https://github.com/ziglang/zig/issues/8421
187 \\
188 ,
189 // release-fast
190 \\error: TheSkyIsFalling
191 \\
192 ,
193 // release-small
194 \\error: TheSkyIsFalling
195 \\
196 },
197 );
198 cases.addCase(
199 "try try return return",
200 source_try_try_return_return,
201 [_][]const u8{
202 // debug
203 \\error: TheSkyIsFalling
204 \\source.zig:12:5: [address] in make_error (test)
205 \\ return error.TheSkyIsFalling;
206 \\ ^
207 \\source.zig:8:5: [address] in bar (test)
208 \\ return make_error();
209 \\ ^
210 \\source.zig:4:5: [address] in foo (test)
211 \\ try bar();
212 \\ ^
213 \\source.zig:16:5: [address] in main (test)
214 \\ try foo();
215 \\ ^
216 \\
217 ,
218 // release-safe
219 // https://github.com/ziglang/zig/issues/8421
220 \\
221 ,
222 // release-fast
223 \\error: TheSkyIsFalling
224 \\
225 ,
226 // release-small
227 \\error: TheSkyIsFalling
228 \\
229 },
230 );
231 cases.addCase(
232 "dumpCurrentStackTrace",
233 source_dumpCurrentStackTrace,
234 [_][]const u8{
235 // debug
236 \\source.zig:7:8: [address] in foo (test)
237 \\ bar();
238 \\ ^
239 \\source.zig:10:8: [address] in main (test)
240 \\ foo();
241 \\ ^
242 \\start.zig:342:29: [address] in std.start.posixCallMainAndExit (test)
243 \\ return root.main();
244 \\ ^
245 \\start.zig:163:5: [address] in std.start._start (test)
246 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
247 \\ ^
248 \\
249 ,
250 // release-safe
251 // https://github.com/ziglang/zig/issues/8421
252 \\
253 ,
254 // release-fast
255 \\
256 ,
257 // release-small
258 \\
259 },
260 );
261 },
262 .macos => {
263 cases.addCase(
264 "return",
265 source_return,
266 [_][]const u8{
267 // debug
268 \\error: TheSkyIsFalling
269 \\source.zig:4:5: [address] in main (test)
270 \\ return error.TheSkyIsFalling;
271 \\ ^
272 \\
273 ,
274 // release-safe
275 \\error: TheSkyIsFalling
276 \\source.zig:4:5: [address] in std.start.main (test)
277 \\ return error.TheSkyIsFalling;
278 \\ ^
279 \\
280 ,
281 // release-fast
282 \\error: TheSkyIsFalling
283 \\
284 ,
285 // release-small
286 \\error: TheSkyIsFalling
287 \\
288 },
289 );
290 cases.addCase(
291 "try return",
292 source_try_return,
293 [_][]const u8{
294 // debug
295 \\error: TheSkyIsFalling
296 \\source.zig:4:5: [address] in foo (test)
297 \\ return error.TheSkyIsFalling;
298 \\ ^
299 \\source.zig:8:5: [address] in main (test)
300 \\ try foo();
301 \\ ^
302 \\
303 ,
304 // release-safe
305 \\error: TheSkyIsFalling
306 \\source.zig:4:5: [address] in std.start.main (test)
307 \\ return error.TheSkyIsFalling;
308 \\ ^
309 \\source.zig:8:5: [address] in std.start.main (test)
310 \\ try foo();
311 \\ ^
312 \\
313 ,
314 // release-fast
315 \\error: TheSkyIsFalling
316 \\
317 ,
318 // release-small
319 \\error: TheSkyIsFalling
320 \\
321 },
322 );
323 cases.addCase(
324 "try try return return",
325 source_try_try_return_return,
326 [_][]const u8{
327 // debug
328 \\error: TheSkyIsFalling
329 \\source.zig:12:5: [address] in make_error (test)
330 \\ return error.TheSkyIsFalling;
331 \\ ^
332 \\source.zig:8:5: [address] in bar (test)
333 \\ return make_error();
334 \\ ^
335 \\source.zig:4:5: [address] in foo (test)
336 \\ try bar();
337 \\ ^
338 \\source.zig:16:5: [address] in main (test)
339 \\ try foo();
340 \\ ^
341 \\
342 ,
343 // release-safe
344 \\error: TheSkyIsFalling
345 \\source.zig:12:5: [address] in std.start.main (test)
346 \\ return error.TheSkyIsFalling;
347 \\ ^
348 \\source.zig:8:5: [address] in std.start.main (test)
349 \\ return make_error();
350 \\ ^
351 \\source.zig:4:5: [address] in std.start.main (test)
352 \\ try bar();
353 \\ ^
354 \\source.zig:16:5: [address] in std.start.main (test)
355 \\ try foo();
356 \\ ^
357 \\
358 ,
359 // release-fast
360 \\error: TheSkyIsFalling
361 \\
362 ,
363 // release-small
364 \\error: TheSkyIsFalling
365 \\
366 },
367 );
368 },
369 .windows => {
370 cases.addCase(
371 "return",
372 source_return,
373 [_][]const u8{
374 // debug
375 \\error: TheSkyIsFalling
376 \\source.zig:4:5: [address] in main (test.obj)
377 \\ return error.TheSkyIsFalling;
378 \\ ^
379 \\
380 ,
381 // release-safe
382 // --disabled-- results in segmenetation fault
383 "",
384 // release-fast
385 \\error: TheSkyIsFalling
386 \\
387 ,
388 // release-small
389 \\error: TheSkyIsFalling
390 \\
391 },
392 );
393 cases.addCase(
394 "try return",
395 source_try_return,
396 [_][]const u8{
397 // debug
398 \\error: TheSkyIsFalling
399 \\source.zig:4:5: [address] in foo (test.obj)
400 \\ return error.TheSkyIsFalling;
401 \\ ^
402 \\source.zig:8:5: [address] in main (test.obj)
403 \\ try foo();
404 \\ ^
405 \\
406 ,
407 // release-safe
408 // --disabled-- results in segmenetation fault
409 "",
410 // release-fast
411 \\error: TheSkyIsFalling
412 \\
413 ,
414 // release-small
415 \\error: TheSkyIsFalling
416 \\
417 },
418 );
419 cases.addCase(
420 "try try return return",
421 source_try_try_return_return,
422 [_][]const u8{
423 // debug
424 \\error: TheSkyIsFalling
425 \\source.zig:12:5: [address] in make_error (test.obj)
426 \\ return error.TheSkyIsFalling;
427 \\ ^
428 \\source.zig:8:5: [address] in bar (test.obj)
429 \\ return make_error();
430 \\ ^
431 \\source.zig:4:5: [address] in foo (test.obj)
432 \\ try bar();
433 \\ ^
434 \\source.zig:16:5: [address] in main (test.obj)
435 \\ try foo();
436 \\ ^
437 \\
438 ,
439 // release-safe
440 // --disabled-- results in segmenetation fault
441 "",
442 // release-fast
443 \\error: TheSkyIsFalling
444 \\
445 ,
446 // release-small
447 \\error: TheSkyIsFalling
448 \\
449 },
450 );
451 },216 },
452 else => {},217 });
453 }
454}218}
test/stage2/cbe.zig+315-2
...@@ -280,6 +280,15 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -280,6 +280,15 @@ pub fn addCases(ctx: *TestContext) !void {
280 \\}280 \\}
281 , "");281 , "");
282282
283 // If expression with breakpoint that does not get hit
284 case.addCompareOutput(
285 \\export fn main() c_int {
286 \\ var x: i32 = 1;
287 \\ if (x != 1) @breakpoint();
288 \\ return 0;
289 \\}
290 , "");
291
283 // Switch expression292 // Switch expression
284 case.addCompareOutput(293 case.addCompareOutput(
285 \\export fn main() c_int {294 \\export fn main() c_int {
...@@ -481,6 +490,310 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -481,6 +490,310 @@ pub fn addCases(ctx: *TestContext) !void {
481 \\}490 \\}
482 , "");491 , "");
483 }492 }
493
494 {
495 var case = ctx.exeFromCompiledC("structs", .{});
496 case.addError(
497 \\const Point = struct { x: i32, y: i32 };
498 \\export fn main() c_int {
499 \\ var p: Point = .{
500 \\ .y = 24,
501 \\ .x = 12,
502 \\ .y = 24,
503 \\ };
504 \\ return p.y - p.x - p.x;
505 \\}
506 , &.{
507 ":6:10: error: duplicate field",
508 ":4:10: note: other field here",
509 });
510 case.addError(
511 \\const Point = struct { x: i32, y: i32 };
512 \\export fn main() c_int {
513 \\ var p: Point = .{
514 \\ .y = 24,
515 \\ };
516 \\ return p.y - p.x - p.x;
517 \\}
518 , &.{
519 ":3:21: error: mising struct field: x",
520 ":1:15: note: struct 'Point' declared here",
521 });
522 case.addError(
523 \\const Point = struct { x: i32, y: i32 };
524 \\export fn main() c_int {
525 \\ var p: Point = .{
526 \\ .x = 12,
527 \\ .y = 24,
528 \\ .z = 48,
529 \\ };
530 \\ return p.y - p.x - p.x;
531 \\}
532 , &.{
533 ":6:10: error: no field named 'z' in struct 'Point'",
534 ":1:15: note: struct declared here",
535 });
536 case.addCompareOutput(
537 \\const Point = struct { x: i32, y: i32 };
538 \\export fn main() c_int {
539 \\ var p: Point = .{
540 \\ .x = 12,
541 \\ .y = 24,
542 \\ };
543 \\ return p.y - p.x - p.x;
544 \\}
545 , "");
546 }
547
548 {
549 var case = ctx.exeFromCompiledC("enums", .{});
550
551 case.addError(
552 \\const E1 = packed enum { a, b, c };
553 \\const E2 = extern enum { a, b, c };
554 \\export fn foo() void {
555 \\ const x = E1.a;
556 \\}
557 \\export fn bar() void {
558 \\ const x = E2.a;
559 \\}
560 , &.{
561 ":1:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type",
562 ":2:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type",
563 });
564
565 // comptime and types are caught in AstGen.
566 case.addError(
567 \\const E1 = enum {
568 \\ a,
569 \\ comptime b,
570 \\ c,
571 \\};
572 \\const E2 = enum {
573 \\ a,
574 \\ b: i32,
575 \\ c,
576 \\};
577 \\export fn foo() void {
578 \\ const x = E1.a;
579 \\}
580 \\export fn bar() void {
581 \\ const x = E2.a;
582 \\}
583 , &.{
584 ":3:5: error: enum fields cannot be marked comptime",
585 ":8:8: error: enum fields do not have types",
586 });
587
588 // @enumToInt, @intToEnum, enum literal coercion, field access syntax, comparison, switch
589 case.addCompareOutput(
590 \\const Number = enum { One, Two, Three };
591 \\
592 \\export fn main() c_int {
593 \\ var number1 = Number.One;
594 \\ var number2: Number = .Two;
595 \\ const number3 = @intToEnum(Number, 2);
596 \\ if (number1 == number2) return 1;
597 \\ if (number2 == number3) return 1;
598 \\ if (@enumToInt(number1) != 0) return 1;
599 \\ if (@enumToInt(number2) != 1) return 1;
600 \\ if (@enumToInt(number3) != 2) return 1;
601 \\ var x: Number = .Two;
602 \\ if (number2 != x) return 1;
603 \\ switch (x) {
604 \\ .One => return 1,
605 \\ .Two => return 0,
606 \\ number3 => return 2,
607 \\ }
608 \\}
609 , "");
610
611 // Specifying alignment is a parse error.
612 // This also tests going from a successful build to a parse error.
613 case.addError(
614 \\const E1 = enum {
615 \\ a,
616 \\ b align(4),
617 \\ c,
618 \\};
619 \\export fn foo() void {
620 \\ const x = E1.a;
621 \\}
622 , &.{
623 ":3:7: error: expected ',', found 'align'",
624 });
625
626 // Redundant non-exhaustive enum mark.
627 // This also tests going from a parse error to an AstGen error.
628 case.addError(
629 \\const E1 = enum {
630 \\ a,
631 \\ _,
632 \\ b,
633 \\ c,
634 \\ _,
635 \\};
636 \\export fn foo() void {
637 \\ const x = E1.a;
638 \\}
639 , &.{
640 ":6:5: error: redundant non-exhaustive enum mark",
641 ":3:5: note: other mark here",
642 });
643
644 case.addError(
645 \\const E1 = enum {
646 \\ a,
647 \\ b,
648 \\ c,
649 \\ _ = 10,
650 \\};
651 \\export fn foo() void {
652 \\ const x = E1.a;
653 \\}
654 , &.{
655 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
656 });
657
658 case.addError(
659 \\const E1 = enum {};
660 \\export fn foo() void {
661 \\ const x = E1.a;
662 \\}
663 , &.{
664 ":1:12: error: enum declarations must have at least one tag",
665 });
666
667 case.addError(
668 \\const E1 = enum { a, b, _ };
669 \\export fn foo() void {
670 \\ const x = E1.a;
671 \\}
672 , &.{
673 ":1:12: error: non-exhaustive enum missing integer tag type",
674 ":1:25: note: marked non-exhaustive here",
675 });
676
677 case.addError(
678 \\const E1 = enum { a, b, c, b, d };
679 \\export fn foo() void {
680 \\ const x = E1.a;
681 \\}
682 , &.{
683 ":1:28: error: duplicate enum tag",
684 ":1:22: note: other tag here",
685 });
686
687 case.addError(
688 \\export fn foo() void {
689 \\ const a = true;
690 \\ const b = @enumToInt(a);
691 \\}
692 , &.{
693 ":3:26: error: expected enum or tagged union, found bool",
694 });
695
696 case.addError(
697 \\export fn foo() void {
698 \\ const a = 1;
699 \\ const b = @intToEnum(bool, a);
700 \\}
701 , &.{
702 ":3:26: error: expected enum, found bool",
703 });
704
705 case.addError(
706 \\const E = enum { a, b, c };
707 \\export fn foo() void {
708 \\ const b = @intToEnum(E, 3);
709 \\}
710 , &.{
711 ":3:15: error: enum 'E' has no tag with value 3",
712 ":1:11: note: enum declared here",
713 });
714
715 case.addError(
716 \\const E = enum { a, b, c };
717 \\export fn foo() void {
718 \\ var x: E = .a;
719 \\ switch (x) {
720 \\ .a => {},
721 \\ .c => {},
722 \\ }
723 \\}
724 , &.{
725 ":4:5: error: switch must handle all possibilities",
726 ":4:5: note: unhandled enumeration value: 'b'",
727 ":1:11: note: enum 'E' declared here",
728 });
729
730 case.addError(
731 \\const E = enum { a, b, c };
732 \\export fn foo() void {
733 \\ var x: E = .a;
734 \\ switch (x) {
735 \\ .a => {},
736 \\ .b => {},
737 \\ .b => {},
738 \\ .c => {},
739 \\ }
740 \\}
741 , &.{
742 ":7:10: error: duplicate switch value",
743 ":6:10: note: previous value here",
744 });
745
746 case.addError(
747 \\const E = enum { a, b, c };
748 \\export fn foo() void {
749 \\ var x: E = .a;
750 \\ switch (x) {
751 \\ .a => {},
752 \\ .b => {},
753 \\ .c => {},
754 \\ else => {},
755 \\ }
756 \\}
757 , &.{
758 ":8:14: error: unreachable else prong; all cases already handled",
759 });
760
761 case.addError(
762 \\const E = enum { a, b, c };
763 \\export fn foo() void {
764 \\ var x: E = .a;
765 \\ switch (x) {
766 \\ .a => {},
767 \\ .b => {},
768 \\ _ => {},
769 \\ }
770 \\}
771 , &.{
772 ":4:5: error: '_' prong only allowed when switching on non-exhaustive enums",
773 ":7:11: note: '_' prong here",
774 });
775
776 case.addError(
777 \\const E = enum { a, b, c };
778 \\export fn foo() void {
779 \\ var x = E.d;
780 \\}
781 , &.{
782 ":3:14: error: enum 'E' has no member named 'd'",
783 ":1:11: note: enum declared here",
784 });
785
786 case.addError(
787 \\const E = enum { a, b, c };
788 \\export fn foo() void {
789 \\ var x: E = .d;
790 \\}
791 , &.{
792 ":3:17: error: enum 'E' has no field named 'd'",
793 ":1:11: note: enum declared here",
794 });
795 }
796
484 ctx.c("empty start function", linux_x64,797 ctx.c("empty start function", linux_x64,
485 \\export fn _start() noreturn {798 \\export fn _start() noreturn {
486 \\ unreachable;799 \\ unreachable;
...@@ -489,8 +802,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -489,8 +802,8 @@ pub fn addCases(ctx: *TestContext) !void {
489 \\ZIG_EXTERN_C zig_noreturn void _start(void);802 \\ZIG_EXTERN_C zig_noreturn void _start(void);
490 \\803 \\
491 \\zig_noreturn void _start(void) {804 \\zig_noreturn void _start(void) {
492 \\ zig_breakpoint();805 \\ zig_breakpoint();
493 \\ zig_unreachable();806 \\ zig_unreachable();
494 \\}807 \\}
495 \\808 \\
496 );809 );
test/stage2/test.zig+78-2
...@@ -941,6 +941,32 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -941,6 +941,32 @@ pub fn addCases(ctx: *TestContext) !void {
941 "",941 "",
942 );942 );
943943
944 // Array access to a global array.
945 case.addCompareOutput(
946 \\const hello = "hello".*;
947 \\export fn _start() noreturn {
948 \\ assert(hello[1] == 'e');
949 \\
950 \\ exit();
951 \\}
952 \\
953 \\pub fn assert(ok: bool) void {
954 \\ if (!ok) unreachable; // assertion failure
955 \\}
956 \\
957 \\fn exit() noreturn {
958 \\ asm volatile ("syscall"
959 \\ :
960 \\ : [number] "{rax}" (231),
961 \\ [arg1] "{rdi}" (0)
962 \\ : "rcx", "r11", "memory"
963 \\ );
964 \\ unreachable;
965 \\}
966 ,
967 "",
968 );
969
944 // 64bit set stack970 // 64bit set stack
945 case.addCompareOutput(971 case.addCompareOutput(
946 \\export fn _start() noreturn {972 \\export fn _start() noreturn {
...@@ -1022,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1022,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {
1022 "Hello, World!\n",1048 "Hello, World!\n",
1023 );1049 );
1024 try case.files.append(.{1050 try case.files.append(.{
1025 .src = 1051 .src =
1026 \\pub fn print() void {1052 \\pub fn print() void {
1027 \\ asm volatile ("syscall"1053 \\ asm volatile ("syscall"
1028 \\ :1054 \\ :
...@@ -1038,11 +1064,61 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1038,11 +1064,61 @@ pub fn addCases(ctx: *TestContext) !void {
1038 .path = "print.zig",1064 .path = "print.zig",
1039 });1065 });
1040 }1066 }
1067 {
1068 var case = ctx.exe("import private", linux_x64);
1069 case.addError(
1070 \\export fn _start() noreturn {
1071 \\ @import("print.zig").print();
1072 \\ exit();
1073 \\}
1074 \\
1075 \\fn exit() noreturn {
1076 \\ asm volatile ("syscall"
1077 \\ :
1078 \\ : [number] "{rax}" (231),
1079 \\ [arg1] "{rdi}" (@as(usize, 0))
1080 \\ : "rcx", "r11", "memory"
1081 \\ );
1082 \\ unreachable;
1083 \\}
1084 ,
1085 &.{":2:25: error: 'print' is private"},
1086 );
1087 try case.files.append(.{
1088 .src =
1089 \\fn print() void {
1090 \\ asm volatile ("syscall"
1091 \\ :
1092 \\ : [number] "{rax}" (@as(usize, 1)),
1093 \\ [arg1] "{rdi}" (@as(usize, 1)),
1094 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
1095 \\ [arg3] "{rdx}" (@as(usize, 14))
1096 \\ : "rcx", "r11", "memory"
1097 \\ );
1098 \\ return;
1099 \\}
1100 ,
1101 .path = "print.zig",
1102 });
1103 }
10411104
1042 ctx.compileError("function redefinition", linux_x64,1105 ctx.compileError("function redefinition", linux_x64,
1106 \\// dummy comment
1043 \\fn entry() void {}1107 \\fn entry() void {}
1044 \\fn entry() void {}1108 \\fn entry() void {}
1045 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});1109 , &[_][]const u8{
1110 ":3:4: error: redefinition of 'entry'",
1111 ":2:1: note: previous definition here",
1112 });
1113
1114 ctx.compileError("global variable redefinition", linux_x64,
1115 \\// dummy comment
1116 \\var foo = false;
1117 \\var foo = true;
1118 , &[_][]const u8{
1119 ":3:5: error: redefinition of 'foo'",
1120 ":2:1: note: previous definition here",
1121 });
10461122
1047 ctx.compileError("compileError", linux_x64,1123 ctx.compileError("compileError", linux_x64,
1048 \\export fn _start() noreturn {1124 \\export fn _start() noreturn {
test/stage2/wasm.zig+132
...@@ -121,6 +121,138 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -121,6 +121,138 @@ pub fn addCases(ctx: *TestContext) !void {
121 \\ return x + y;121 \\ return x + y;
122 \\}122 \\}
123 , "35\n");123 , "35\n");
124
125 case.addCompareOutput(
126 \\export fn _start() u32 {
127 \\ var i: u32 = 20;
128 \\ i -= 5;
129 \\ return i;
130 \\}
131 , "15\n");
132
133 case.addCompareOutput(
134 \\export fn _start() u32 {
135 \\ var i: u32 = 5;
136 \\ i -= 3;
137 \\ var result: u32 = foo(i, 10);
138 \\ return result;
139 \\}
140 \\fn foo(x: u32, y: u32) u32 {
141 \\ return y - x;
142 \\}
143 , "8\n");
144
145 case.addCompareOutput(
146 \\export fn _start() u32 {
147 \\ var i: u32 = 5;
148 \\ i *= 7;
149 \\ var result: u32 = foo(i, 10);
150 \\ return result;
151 \\}
152 \\fn foo(x: u32, y: u32) u32 {
153 \\ return x * y;
154 \\}
155 , "350\n");
156
157 case.addCompareOutput(
158 \\export fn _start() u32 {
159 \\ var i: u32 = 352;
160 \\ i /= 7; // i = 50
161 \\ var result: u32 = foo(i, 7);
162 \\ return result;
163 \\}
164 \\fn foo(x: u32, y: u32) u32 {
165 \\ return x / y;
166 \\}
167 , "7\n");
168
169 case.addCompareOutput(
170 \\export fn _start() u32 {
171 \\ var i: u32 = 5;
172 \\ i &= 6;
173 \\ return i;
174 \\}
175 , "4\n");
176
177 case.addCompareOutput(
178 \\export fn _start() u32 {
179 \\ var i: u32 = 5;
180 \\ i |= 6;
181 \\ return i;
182 \\}
183 , "7\n");
184
185 case.addCompareOutput(
186 \\export fn _start() u32 {
187 \\ var i: u32 = 5;
188 \\ i ^= 6;
189 \\ return i;
190 \\}
191 , "3\n");
192
193 case.addCompareOutput(
194 \\export fn _start() bool {
195 \\ var b: bool = false;
196 \\ b = b or false;
197 \\ return b;
198 \\}
199 , "0\n");
200
201 case.addCompareOutput(
202 \\export fn _start() bool {
203 \\ var b: bool = true;
204 \\ b = b or false;
205 \\ return b;
206 \\}
207 , "1\n");
208
209 case.addCompareOutput(
210 \\export fn _start() bool {
211 \\ var b: bool = false;
212 \\ b = b or true;
213 \\ return b;
214 \\}
215 , "1\n");
216
217 case.addCompareOutput(
218 \\export fn _start() bool {
219 \\ var b: bool = true;
220 \\ b = b or true;
221 \\ return b;
222 \\}
223 , "1\n");
224
225 case.addCompareOutput(
226 \\export fn _start() bool {
227 \\ var b: bool = false;
228 \\ b = b and false;
229 \\ return b;
230 \\}
231 , "0\n");
232
233 case.addCompareOutput(
234 \\export fn _start() bool {
235 \\ var b: bool = true;
236 \\ b = b and false;
237 \\ return b;
238 \\}
239 , "0\n");
240
241 case.addCompareOutput(
242 \\export fn _start() bool {
243 \\ var b: bool = false;
244 \\ b = b and true;
245 \\ return b;
246 \\}
247 , "0\n");
248
249 case.addCompareOutput(
250 \\export fn _start() bool {
251 \\ var b: bool = true;
252 \\ b = b and true;
253 \\ return b;
254 \\}
255 , "1\n");
124 }256 }
125257
126 {258 {
test/tests.zig+98-33
...@@ -566,42 +566,87 @@ pub const StackTracesContext = struct {...@@ -566,42 +566,87 @@ pub const StackTracesContext = struct {
566566
567 const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8;567 const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8;
568568
569 pub fn addCase(569 pub fn addCase(self: *StackTracesContext, config: anytype) void {
570 if (@hasField(@TypeOf(config), "exclude")) {
571 if (config.exclude.exclude()) return;
572 }
573 if (@hasField(@TypeOf(config), "exclude_arch")) {
574 const exclude_arch: []const builtin.Cpu.Arch = &config.exclude_arch;
575 for (exclude_arch) |arch| if (arch == builtin.cpu.arch) return;
576 }
577 if (@hasField(@TypeOf(config), "exclude_os")) {
578 const exclude_os: []const builtin.Os.Tag = &config.exclude_os;
579 for (exclude_os) |os| if (os == builtin.os.tag) return;
580 }
581 for (self.modes) |mode| {
582 switch (mode) {
583 .Debug => {
584 if (@hasField(@TypeOf(config), "Debug")) {
585 self.addExpect(config.name, config.source, mode, config.Debug);
586 }
587 },
588 .ReleaseSafe => {
589 if (@hasField(@TypeOf(config), "ReleaseSafe")) {
590 self.addExpect(config.name, config.source, mode, config.ReleaseSafe);
591 }
592 },
593 .ReleaseFast => {
594 if (@hasField(@TypeOf(config), "ReleaseFast")) {
595 self.addExpect(config.name, config.source, mode, config.ReleaseFast);
596 }
597 },
598 .ReleaseSmall => {
599 if (@hasField(@TypeOf(config), "ReleaseSmall")) {
600 self.addExpect(config.name, config.source, mode, config.ReleaseSmall);
601 }
602 },
603 }
604 }
605 }
606
607 fn addExpect(
570 self: *StackTracesContext,608 self: *StackTracesContext,
571 name: []const u8,609 name: []const u8,
572 source: []const u8,610 source: []const u8,
573 expect: Expect,611 mode: Mode,
612 mode_config: anytype,
574 ) void {613 ) void {
575 const b = self.b;614 if (@hasField(@TypeOf(mode_config), "exclude")) {
576615 if (mode_config.exclude.exclude()) return;
577 for (self.modes) |mode| {616 }
578 const expect_for_mode = expect[@enumToInt(mode)];617 if (@hasField(@TypeOf(mode_config), "exclude_arch")) {
579 if (expect_for_mode.len == 0) continue;618 const exclude_arch: []const builtin.Cpu.Arch = &mode_config.exclude_arch;
580619 for (exclude_arch) |arch| if (arch == builtin.cpu.arch) return;
581 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s} ({s})", .{620 }
582 "stack-trace",621 if (@hasField(@TypeOf(mode_config), "exclude_os")) {
583 name,622 const exclude_os: []const builtin.Os.Tag = &mode_config.exclude_os;
584 @tagName(mode),623 for (exclude_os) |os| if (os == builtin.os.tag) return;
585 }) catch unreachable;624 }
586 if (self.test_filter) |filter| {
587 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
588 }
589
590 const src_basename = "source.zig";
591 const write_src = b.addWriteFile(src_basename, source);
592 const exe = b.addExecutableFromWriteFileStep("test", write_src, src_basename);
593 exe.setBuildMode(mode);
594
595 const run_and_compare = RunAndCompareStep.create(
596 self,
597 exe,
598 annotated_case_name,
599 mode,
600 expect_for_mode,
601 );
602625
603 self.step.dependOn(&run_and_compare.step);626 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s} ({s})", .{
627 "stack-trace",
628 name,
629 @tagName(mode),
630 }) catch unreachable;
631 if (self.test_filter) |filter| {
632 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
604 }633 }
634
635 const b = self.b;
636 const src_basename = "source.zig";
637 const write_src = b.addWriteFile(src_basename, source);
638 const exe = b.addExecutableFromWriteFileStep("test", write_src, src_basename);
639 exe.setBuildMode(mode);
640
641 const run_and_compare = RunAndCompareStep.create(
642 self,
643 exe,
644 annotated_case_name,
645 mode,
646 mode_config.expect,
647 );
648
649 self.step.dependOn(&run_and_compare.step);
605 }650 }
606651
607 const RunAndCompareStep = struct {652 const RunAndCompareStep = struct {
...@@ -703,6 +748,7 @@ pub const StackTracesContext = struct {...@@ -703,6 +748,7 @@ pub const StackTracesContext = struct {
703 // process result748 // process result
704 // - keep only basename of source file path749 // - keep only basename of source file path
705 // - replace address with symbolic string750 // - replace address with symbolic string
751 // - replace function name with symbolic string when mode != .Debug
706 // - skip empty lines752 // - skip empty lines
707 const got: []const u8 = got_result: {753 const got: []const u8 = got_result: {
708 var buf = ArrayList(u8).init(b.allocator);754 var buf = ArrayList(u8).init(b.allocator);
...@@ -711,26 +757,45 @@ pub const StackTracesContext = struct {...@@ -711,26 +757,45 @@ pub const StackTracesContext = struct {
711 var it = mem.split(stderr, "\n");757 var it = mem.split(stderr, "\n");
712 process_lines: while (it.next()) |line| {758 process_lines: while (it.next()) |line| {
713 if (line.len == 0) continue;759 if (line.len == 0) continue;
714 const delims = [_][]const u8{ ":", ":", ":", " in " };
715 var marks = [_]usize{0} ** 4;
716 // offset search past `[drive]:` on windows760 // offset search past `[drive]:` on windows
717 var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;761 var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;
762 // locate delims/anchor
763 const delims = [_][]const u8{ ":", ":", ":", " in ", "(", ")" };
764 var marks = [_]usize{0} ** delims.len;
718 for (delims) |delim, i| {765 for (delims) |delim, i| {
719 marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {766 marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {
767 // unexpected pattern: emit raw line and cont
720 try buf.appendSlice(line);768 try buf.appendSlice(line);
721 try buf.appendSlice("\n");769 try buf.appendSlice("\n");
722 continue :process_lines;770 continue :process_lines;
723 };771 };
724 pos = marks[i] + delim.len;772 pos = marks[i] + delim.len;
725 }773 }
774 // locate source basename
726 pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse {775 pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse {
776 // unexpected pattern: emit raw line and cont
727 try buf.appendSlice(line);777 try buf.appendSlice(line);
728 try buf.appendSlice("\n");778 try buf.appendSlice("\n");
729 continue :process_lines;779 continue :process_lines;
730 };780 };
781 // end processing if source basename changes
782 if (!mem.eql(u8, "source.zig", line[pos + 1 .. marks[0]])) break;
783 // emit substituted line
731 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);784 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);
732 try buf.appendSlice(" [address]");785 try buf.appendSlice(" [address]");
733 try buf.appendSlice(line[marks[3]..]);786 if (self.mode == .Debug) {
787 if (mem.lastIndexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| {
788 // On certain platforms (windows) or possibly depending on how we choose to link main
789 // the object file extension may be present so we simply strip any extension.
790 try buf.appendSlice(line[marks[3] .. marks[4] + idot]);
791 try buf.appendSlice(line[marks[5]..]);
792 } else {
793 try buf.appendSlice(line[marks[3]..]);
794 }
795 } else {
796 try buf.appendSlice(line[marks[3] .. marks[3] + delims[3].len]);
797 try buf.appendSlice("[function]");
798 }
734 try buf.appendSlice("\n");799 try buf.appendSlice("\n");
735 }800 }
736 break :got_result buf.toOwnedSlice();801 break :got_result buf.toOwnedSlice();
test/translate_c.zig+8
...@@ -2529,6 +2529,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2529,6 +2529,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2529 \\}2529 \\}
2530 });2530 });
25312531
2532 cases.add("macro call with no args",
2533 \\#define CALL(arg) bar()
2534 , &[_][]const u8{
2535 \\pub fn CALL(arg: anytype) callconv(.Inline) @TypeOf(bar()) {
2536 \\ return bar();
2537 \\}
2538 });
2539
2532 cases.add("logical and, logical or",2540 cases.add("logical and, logical or",
2533 \\int max(int a, int b) {2541 \\int max(int a, int b) {
2534 \\ if (a < b || a == b)2542 \\ if (a < b || a == b)