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
114114 SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
115115 BYTESIZE=$(wc -c < $TARBALL)
116116
117 JSONFILE="macos-$GITBRANCH.json"
117 JSONFILE="tarball.json"
118118 touch $JSONFILE
119119 echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
120120 echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
121121 echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
122122
123 s3cmd put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE"
124123 s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"
125124
126125 # `set -x` causes these variables to be mangled.
ci/azure/pipelines.yml+2-1
......@@ -24,7 +24,7 @@ jobs:
2424 secureFile: s3cfg
2525 - script: ci/azure/macos_arm64_script
2626 name: main
27 displayName: 'Build and cross-compile'
27 displayName: 'Build'
2828- job: BuildLinux
2929 pool:
3030 vmImage: 'ubuntu-18.04'
......@@ -66,6 +66,7 @@ jobs:
6666- job: OnMasterSuccess
6767 dependsOn:
6868 - BuildMacOS
69 - BuildMacOS_arm64
6970 - BuildLinux
7071 - BuildWindows
7172 condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
ci/srht/index.html+6
......@@ -199,6 +199,12 @@
199199 <td>{{X86_64_MACOS_BYTESIZE}}</td>
200200 <td class="code">{{X86_64_MACOS_SHASUM}}</td>
201201 </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>
202208 <tr>
203209 <td><a href="https://ziglang.org/builds/{{X86_64_FREEBSD_TARBALL}}">{{X86_64_FREEBSD_TARBALL}}</a></td>
204210 <td>Binary</td>
ci/srht/index.json+5
......@@ -19,6 +19,11 @@
1919 "shasum": "{{X86_64_MACOS_SHASUM}}",
2020 "size": "{{X86_64_MACOS_BYTESIZE}}"
2121 },
22 "aarch64-macos": {
23 "tarball": "https://ziglang.org/builds/{{AARCH64_MACOS_TARBALL}}",
24 "shasum": "{{AARCH64_MACOS_SHASUM}}",
25 "size": "{{AARCH64_MACOS_BYTESIZE}}"
26 },
2227 "x86_64-windows": {
2328 "tarball": "https://ziglang.org/builds/{{X86_64_WINDOWS_TARBALL}}",
2429 "shasum": "{{X86_64_WINDOWS_SHASUM}}",
ci/srht/update_download_page+7
......@@ -12,6 +12,7 @@ NATIVE_TARBALL="zig-linux-$(uname -m)-$VERSION.tar.xz"
1212AARCH64_LINUX_JSON_URL="https://ziglang.org/builds/aarch64-linux-$VERSION.json"
1313X86_64_LINUX_JSON_URL="https://ziglang.org/builds/x86_64-linux-$VERSION.json"
1414X86_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"
1516X86_64_MACOS_JSON_URL="https://ziglang.org/builds/x86_64-macos-$VERSION.json"
1617X86_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
2021curl --fail -I "$AARCH64_LINUX_JSON_URL" >/dev/null || exit 0
2122curl --fail -I "$X86_64_LINUX_JSON_URL" >/dev/null || exit 0
2223curl --fail -I "$X86_64_WINDOWS_JSON_URL" >/dev/null || exit 0
24curl --fail -I "$AARCH64_MACOS_JSON_URL" >/dev/null || exit 0
2325curl --fail -I "$X86_64_MACOS_JSON_URL" >/dev/null || exit 0
2426curl --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)"
5759export X86_64_WINDOWS_BYTESIZE="$(echo "$X86_64_WINDOWS_JSON" | jq .size -r)"
5860export 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
6067X86_64_MACOS_JSON=$(curl --fail "$X86_64_MACOS_JSON_URL" || exit 1)
6168export X86_64_MACOS_TARBALL="$(echo "$X86_64_MACOS_JSON" | jq .tarball -r)"
6269export 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
10231023 const builtin_code = try getBuiltinCode(allocator, &env_map, zig_exe);
10241024
10251025 for (toc.nodes) |node| {
1026 defer root_node.completeOne();
10261027 switch (node) {
10271028 .Content => |data| {
10281029 try out.writeAll(data);
......@@ -1062,8 +1063,6 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
10621063 try tokenizeAndPrint(tokenizer, out, content_tok);
10631064 },
10641065 .Code => |code| {
1065 root_node.completeOne();
1066
10671066 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
10681067 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
10691068 if (!code.is_inline) {
doc/langref.html.in+5-1
......@@ -85,7 +85,6 @@
8585 #main-wrapper {
8686 display: flex;
8787 flex-direction: column;
88 height: 100vh;
8988 }
9089
9190 #contents-wrapper {
......@@ -106,6 +105,11 @@
106105 #main-wrapper {
107106 flex-direction: row;
108107 }
108 #toc {
109 height: 100vh;
110 position: sticky;
111 top: 0;
112 }
109113 #contents-wrapper, #toc {
110114 overflow: auto;
111115 }
lib/std/build.zig+9
......@@ -1939,6 +1939,15 @@ pub const LibExeObjStep = struct {
19391939 out.print("pub const {}: []const u8 = \"{}\";\n", .{ std.zig.fmtId(name), std.zig.fmtEscapes(value) }) catch unreachable;
19401940 return;
19411941 },
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 },
19421951 ?[]const u8 => {
19431952 out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(name)}) catch unreachable;
19441953 if (value) |payload| {
lib/std/c/netbsd.zig+5-4
......@@ -18,14 +18,14 @@ pub extern "c" fn _lwp_self() lwpid_t;
1818
1919pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
2020pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
21pub extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int;
22pub extern "c" fn __stat50(path: [*:0]const u8, 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: *libc_stat) c_int;
2323pub extern "c" fn __clock_gettime50(clk_id: c_int, tp: *timespec) c_int;
2424pub extern "c" fn __clock_getres50(clk_id: c_int, tp: *timespec) c_int;
2525pub extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;
2626pub extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
2727pub 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;
2929pub extern "c" fn __sigprocmask14(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
3030pub extern "c" fn __socket30(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
3131pub 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;
3434pub extern "c" fn __libc_thr_yield() c_int;
3535
3636pub 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
3938pub const pthread_mutex_t = extern struct {
4039 ptm_magic: u32 = 0x33330003,
......@@ -93,3 +92,5 @@ pub const pthread_attr_t = extern struct {
9392 pta_flags: i32,
9493 pta_private: ?*c_void,
9594};
95
96pub const sem_t = ?*opaque {};
lib/std/debug.zig+1-1
......@@ -462,7 +462,7 @@ pub const TTY = struct {
462462 // TODO give this a payload of file handle
463463 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 {
466466 nosuspend switch (conf) {
467467 .no_color => return,
468468 .escape_codes => switch (color) {
lib/std/fs/file.zig+4-4
......@@ -223,15 +223,15 @@ pub const File = struct {
223223 return os.lseek_SET(self.handle, offset);
224224 }
225225
226 pub const GetPosError = os.SeekError || os.FStatError;
226 pub const GetSeekPosError = os.SeekError || os.FStatError;
227227
228228 /// TODO: integrate with async I/O
229 pub fn getPos(self: File) GetPosError!u64 {
229 pub fn getPos(self: File) GetSeekPosError!u64 {
230230 return os.lseek_CUR_get(self.handle);
231231 }
232232
233233 /// TODO: integrate with async I/O
234 pub fn getEndPos(self: File) GetPosError!u64 {
234 pub fn getEndPos(self: File) GetSeekPosError!u64 {
235235 if (builtin.os.tag == .windows) {
236236 return windows.GetFileSizeEx(self.handle);
237237 }
......@@ -819,7 +819,7 @@ pub const File = struct {
819819 pub const SeekableStream = io.SeekableStream(
820820 File,
821821 SeekError,
822 GetPosError,
822 GetSeekPosError,
823823 seekTo,
824824 seekBy,
825825 getPos,
lib/std/hash_map.zig-4
......@@ -398,10 +398,6 @@ pub fn HashMapUnmanaged(
398398 return size * 100 < max_load_percentage * cap;
399399 }
400400
401 pub fn init(allocator: *Allocator) Self {
402 return .{};
403 }
404
405401 pub fn deinit(self: *Self, allocator: *Allocator) void {
406402 self.deallocate(allocator);
407403 self.* = undefined;
lib/std/io/stream_source.zig+1-2
......@@ -5,7 +5,6 @@
55// and substantial portions of the software.
66const std = @import("../std.zig");
77const io = std.io;
8const testing = std.testing;
98
109/// Provides `io.Reader`, `io.Writer`, and `io.SeekableStream` for in-memory buffers as
1110/// well as files.
......@@ -19,7 +18,7 @@ pub const StreamSource = union(enum) {
1918 pub const ReadError = std.fs.File.ReadError;
2019 pub const WriteError = std.fs.File.WriteError;
2120 pub const SeekError = std.fs.File.SeekError;
22 pub const GetSeekPosError = std.fs.File.GetPosError;
21 pub const GetSeekPosError = std.fs.File.GetSeekPosError;
2322
2423 pub const Reader = io.Reader(*StreamSource, ReadError, read);
2524 pub const Writer = io.Writer(*StreamSource, WriteError, write);
lib/std/json.zig+2-2
......@@ -1234,7 +1234,7 @@ test "json.validate" {
12341234const Allocator = std.mem.Allocator;
12351235const ArenaAllocator = std.heap.ArenaAllocator;
12361236const ArrayList = std.ArrayList;
1237const StringHashMap = std.StringHashMap;
1237const StringArrayHashMap = std.StringArrayHashMap;
12381238
12391239pub const ValueTree = struct {
12401240 arena: ArenaAllocator,
......@@ -1245,7 +1245,7 @@ pub const ValueTree = struct {
12451245 }
12461246};
12471247
1248pub const ObjectMap = StringHashMap(Value);
1248pub const ObjectMap = StringArrayHashMap(Value);
12491249pub const Array = ArrayList(Value);
12501250
12511251/// Represents a JSON value
lib/std/json/test.zig+119-103
......@@ -12,7 +12,7 @@ const std = @import("../std.zig");
1212const json = std.json;
1313const testing = std.testing;
1414
15fn testNonStreaming(comptime s: []const u8) !void {
15fn testNonStreaming(s: []const u8) !void {
1616 var p = json.Parser.init(testing.allocator, false);
1717 defer p.deinit();
1818
......@@ -20,44 +20,60 @@ fn testNonStreaming(comptime s: []const u8) !void {
2020 defer tree.deinit();
2121}
2222
23fn ok(comptime s: []const u8) void {
23fn ok(s: []const u8) !void {
2424 testing.expect(json.validate(s));
2525
26 testNonStreaming(s) catch testing.expect(false);
26 try testNonStreaming(s);
2727}
2828
29fn err(comptime s: []const u8) void {
29fn err(s: []const u8) void {
3030 testing.expect(!json.validate(s));
3131
3232 testNonStreaming(s) catch return;
3333 testing.expect(false);
3434}
3535
36fn utf8Error(comptime s: []const u8) void {
36fn utf8Error(s: []const u8) void {
3737 testing.expect(!json.validate(s));
3838
3939 testing.expectError(error.InvalidUtf8Byte, testNonStreaming(s));
4040}
4141
42fn any(comptime s: []const u8) void {
42fn any(s: []const u8) void {
4343 _ = json.validate(s);
4444
4545 testNonStreaming(s) catch {};
4646}
4747
48fn anyStreamingErrNonStreaming(comptime s: []const u8) void {
48fn anyStreamingErrNonStreaming(s: []const u8) void {
4949 _ = json.validate(s);
5050
5151 testNonStreaming(s) catch return;
5252 testing.expect(false);
5353}
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
5571////////////////////////////////////////////////////////////////////////////////////////////////////
5672//
5773// Additional tests not part of test JSONTestSuite.
5874
5975test "y_trailing_comma_after_empty" {
60 ok(
76 try roundTrip(
6177 \\{"1":[],"2":{},"3":"4"}
6278 );
6379}
......@@ -65,252 +81,252 @@ test "y_trailing_comma_after_empty" {
6581////////////////////////////////////////////////////////////////////////////////////////////////////
6682
6783test "y_array_arraysWithSpaces" {
68 ok(
84 try ok(
6985 \\[[] ]
7086 );
7187}
7288
7389test "y_array_empty" {
74 ok(
90 try roundTrip(
7591 \\[]
7692 );
7793}
7894
7995test "y_array_empty-string" {
80 ok(
96 try roundTrip(
8197 \\[""]
8298 );
8399}
84100
85101test "y_array_ending_with_newline" {
86 ok(
102 try roundTrip(
87103 \\["a"]
88104 );
89105}
90106
91107test "y_array_false" {
92 ok(
108 try roundTrip(
93109 \\[false]
94110 );
95111}
96112
97113test "y_array_heterogeneous" {
98 ok(
114 try ok(
99115 \\[null, 1, "1", {}]
100116 );
101117}
102118
103119test "y_array_null" {
104 ok(
120 try roundTrip(
105121 \\[null]
106122 );
107123}
108124
109125test "y_array_with_1_and_newline" {
110 ok(
126 try ok(
111127 \\[1
112128 \\]
113129 );
114130}
115131
116132test "y_array_with_leading_space" {
117 ok(
133 try ok(
118134 \\ [1]
119135 );
120136}
121137
122138test "y_array_with_several_null" {
123 ok(
139 try roundTrip(
124140 \\[1,null,null,null,2]
125141 );
126142}
127143
128144test "y_array_with_trailing_space" {
129 ok("[2] ");
145 try ok("[2] ");
130146}
131147
132148test "y_number_0e+1" {
133 ok(
149 try ok(
134150 \\[0e+1]
135151 );
136152}
137153
138154test "y_number_0e1" {
139 ok(
155 try ok(
140156 \\[0e1]
141157 );
142158}
143159
144160test "y_number_after_space" {
145 ok(
161 try ok(
146162 \\[ 4]
147163 );
148164}
149165
150166test "y_number_double_close_to_zero" {
151 ok(
167 try ok(
152168 \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]
153169 );
154170}
155171
156172test "y_number_int_with_exp" {
157 ok(
173 try ok(
158174 \\[20e1]
159175 );
160176}
161177
162178test "y_number" {
163 ok(
179 try ok(
164180 \\[123e65]
165181 );
166182}
167183
168184test "y_number_minus_zero" {
169 ok(
185 try ok(
170186 \\[-0]
171187 );
172188}
173189
174190test "y_number_negative_int" {
175 ok(
191 try roundTrip(
176192 \\[-123]
177193 );
178194}
179195
180196test "y_number_negative_one" {
181 ok(
197 try roundTrip(
182198 \\[-1]
183199 );
184200}
185201
186202test "y_number_negative_zero" {
187 ok(
203 try ok(
188204 \\[-0]
189205 );
190206}
191207
192208test "y_number_real_capital_e" {
193 ok(
209 try ok(
194210 \\[1E22]
195211 );
196212}
197213
198214test "y_number_real_capital_e_neg_exp" {
199 ok(
215 try ok(
200216 \\[1E-2]
201217 );
202218}
203219
204220test "y_number_real_capital_e_pos_exp" {
205 ok(
221 try ok(
206222 \\[1E+2]
207223 );
208224}
209225
210226test "y_number_real_exponent" {
211 ok(
227 try ok(
212228 \\[123e45]
213229 );
214230}
215231
216232test "y_number_real_fraction_exponent" {
217 ok(
233 try ok(
218234 \\[123.456e78]
219235 );
220236}
221237
222238test "y_number_real_neg_exp" {
223 ok(
239 try ok(
224240 \\[1e-2]
225241 );
226242}
227243
228244test "y_number_real_pos_exponent" {
229 ok(
245 try ok(
230246 \\[1e+2]
231247 );
232248}
233249
234250test "y_number_simple_int" {
235 ok(
251 try roundTrip(
236252 \\[123]
237253 );
238254}
239255
240256test "y_number_simple_real" {
241 ok(
257 try ok(
242258 \\[123.456789]
243259 );
244260}
245261
246262test "y_object_basic" {
247 ok(
263 try roundTrip(
248264 \\{"asd":"sdf"}
249265 );
250266}
251267
252268test "y_object_duplicated_key_and_value" {
253 ok(
269 try ok(
254270 \\{"a":"b","a":"b"}
255271 );
256272}
257273
258274test "y_object_duplicated_key" {
259 ok(
275 try ok(
260276 \\{"a":"b","a":"c"}
261277 );
262278}
263279
264280test "y_object_empty" {
265 ok(
281 try roundTrip(
266282 \\{}
267283 );
268284}
269285
270286test "y_object_empty_key" {
271 ok(
287 try roundTrip(
272288 \\{"":0}
273289 );
274290}
275291
276292test "y_object_escaped_null_in_key" {
277 ok(
293 try ok(
278294 \\{"foo\u0000bar": 42}
279295 );
280296}
281297
282298test "y_object_extreme_numbers" {
283 ok(
299 try ok(
284300 \\{ "min": -1.0e+28, "max": 1.0e+28 }
285301 );
286302}
287303
288304test "y_object" {
289 ok(
305 try ok(
290306 \\{"asd":"sdf", "dfg":"fgh"}
291307 );
292308}
293309
294310test "y_object_long_strings" {
295 ok(
311 try ok(
296312 \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
297313 );
298314}
299315
300316test "y_object_simple" {
301 ok(
317 try roundTrip(
302318 \\{"a":[]}
303319 );
304320}
305321
306322test "y_object_string_unicode" {
307 ok(
323 try ok(
308324 \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }
309325 );
310326}
311327
312328test "y_object_with_newlines" {
313 ok(
329 try ok(
314330 \\{
315331 \\"a": "b"
316332 \\}
......@@ -318,311 +334,311 @@ test "y_object_with_newlines" {
318334}
319335
320336test "y_string_1_2_3_bytes_UTF-8_sequences" {
321 ok(
337 try ok(
322338 \\["\u0060\u012a\u12AB"]
323339 );
324340}
325341
326342test "y_string_accepted_surrogate_pair" {
327 ok(
343 try ok(
328344 \\["\uD801\udc37"]
329345 );
330346}
331347
332348test "y_string_accepted_surrogate_pairs" {
333 ok(
349 try ok(
334350 \\["\ud83d\ude39\ud83d\udc8d"]
335351 );
336352}
337353
338354test "y_string_allowed_escapes" {
339 ok(
355 try ok(
340356 \\["\"\\\/\b\f\n\r\t"]
341357 );
342358}
343359
344360test "y_string_backslash_and_u_escaped_zero" {
345 ok(
361 try ok(
346362 \\["\\u0000"]
347363 );
348364}
349365
350366test "y_string_backslash_doublequotes" {
351 ok(
367 try roundTrip(
352368 \\["\""]
353369 );
354370}
355371
356372test "y_string_comments" {
357 ok(
373 try ok(
358374 \\["a/*b*/c/*d//e"]
359375 );
360376}
361377
362378test "y_string_double_escape_a" {
363 ok(
379 try ok(
364380 \\["\\a"]
365381 );
366382}
367383
368384test "y_string_double_escape_n" {
369 ok(
385 try roundTrip(
370386 \\["\\n"]
371387 );
372388}
373389
374390test "y_string_escaped_control_character" {
375 ok(
391 try ok(
376392 \\["\u0012"]
377393 );
378394}
379395
380396test "y_string_escaped_noncharacter" {
381 ok(
397 try ok(
382398 \\["\uFFFF"]
383399 );
384400}
385401
386402test "y_string_in_array" {
387 ok(
403 try ok(
388404 \\["asd"]
389405 );
390406}
391407
392408test "y_string_in_array_with_leading_space" {
393 ok(
409 try ok(
394410 \\[ "asd"]
395411 );
396412}
397413
398414test "y_string_last_surrogates_1_and_2" {
399 ok(
415 try ok(
400416 \\["\uDBFF\uDFFF"]
401417 );
402418}
403419
404420test "y_string_nbsp_uescaped" {
405 ok(
421 try ok(
406422 \\["new\u00A0line"]
407423 );
408424}
409425
410426test "y_string_nonCharacterInUTF-8_U+10FFFF" {
411 ok(
427 try ok(
412428 \\["􏿿"]
413429 );
414430}
415431
416432test "y_string_nonCharacterInUTF-8_U+FFFF" {
417 ok(
433 try ok(
418434 \\["￿"]
419435 );
420436}
421437
422438test "y_string_null_escape" {
423 ok(
439 try ok(
424440 \\["\u0000"]
425441 );
426442}
427443
428444test "y_string_one-byte-utf-8" {
429 ok(
445 try ok(
430446 \\["\u002c"]
431447 );
432448}
433449
434450test "y_string_pi" {
435 ok(
451 try ok(
436452 \\["π"]
437453 );
438454}
439455
440456test "y_string_reservedCharacterInUTF-8_U+1BFFF" {
441 ok(
457 try ok(
442458 \\["𛿿"]
443459 );
444460}
445461
446462test "y_string_simple_ascii" {
447 ok(
463 try ok(
448464 \\["asd "]
449465 );
450466}
451467
452468test "y_string_space" {
453 ok(
469 try roundTrip(
454470 \\" "
455471 );
456472}
457473
458474test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" {
459 ok(
475 try ok(
460476 \\["\uD834\uDd1e"]
461477 );
462478}
463479
464480test "y_string_three-byte-utf-8" {
465 ok(
481 try ok(
466482 \\["\u0821"]
467483 );
468484}
469485
470486test "y_string_two-byte-utf-8" {
471 ok(
487 try ok(
472488 \\["\u0123"]
473489 );
474490}
475491
476492test "y_string_u+2028_line_sep" {
477 ok("[\"\xe2\x80\xa8\"]");
493 try ok("[\"\xe2\x80\xa8\"]");
478494}
479495
480496test "y_string_u+2029_par_sep" {
481 ok("[\"\xe2\x80\xa9\"]");
497 try ok("[\"\xe2\x80\xa9\"]");
482498}
483499
484500test "y_string_uescaped_newline" {
485 ok(
501 try ok(
486502 \\["new\u000Aline"]
487503 );
488504}
489505
490506test "y_string_uEscape" {
491 ok(
507 try ok(
492508 \\["\u0061\u30af\u30EA\u30b9"]
493509 );
494510}
495511
496512test "y_string_unescaped_char_delete" {
497 ok("[\"\x7f\"]");
513 try ok("[\"\x7f\"]");
498514}
499515
500516test "y_string_unicode_2" {
501 ok(
517 try ok(
502518 \\["⍂㈴⍂"]
503519 );
504520}
505521
506522test "y_string_unicodeEscapedBackslash" {
507 ok(
523 try ok(
508524 \\["\u005C"]
509525 );
510526}
511527
512528test "y_string_unicode_escaped_double_quote" {
513 ok(
529 try ok(
514530 \\["\u0022"]
515531 );
516532}
517533
518534test "y_string_unicode" {
519 ok(
535 try ok(
520536 \\["\uA66D"]
521537 );
522538}
523539
524540test "y_string_unicode_U+10FFFE_nonchar" {
525 ok(
541 try ok(
526542 \\["\uDBFF\uDFFE"]
527543 );
528544}
529545
530546test "y_string_unicode_U+1FFFE_nonchar" {
531 ok(
547 try ok(
532548 \\["\uD83F\uDFFE"]
533549 );
534550}
535551
536552test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" {
537 ok(
553 try ok(
538554 \\["\u200B"]
539555 );
540556}
541557
542558test "y_string_unicode_U+2064_invisible_plus" {
543 ok(
559 try ok(
544560 \\["\u2064"]
545561 );
546562}
547563
548564test "y_string_unicode_U+FDD0_nonchar" {
549 ok(
565 try ok(
550566 \\["\uFDD0"]
551567 );
552568}
553569
554570test "y_string_unicode_U+FFFE_nonchar" {
555 ok(
571 try ok(
556572 \\["\uFFFE"]
557573 );
558574}
559575
560576test "y_string_utf8" {
561 ok(
577 try ok(
562578 \\["€𝄞"]
563579 );
564580}
565581
566582test "y_string_with_del_character" {
567 ok("[\"a\x7fa\"]");
583 try ok("[\"a\x7fa\"]");
568584}
569585
570586test "y_structure_lonely_false" {
571 ok(
587 try roundTrip(
572588 \\false
573589 );
574590}
575591
576592test "y_structure_lonely_int" {
577 ok(
593 try roundTrip(
578594 \\42
579595 );
580596}
581597
582598test "y_structure_lonely_negative_real" {
583 ok(
599 try ok(
584600 \\-0.1
585601 );
586602}
587603
588604test "y_structure_lonely_null" {
589 ok(
605 try roundTrip(
590606 \\null
591607 );
592608}
593609
594610test "y_structure_lonely_string" {
595 ok(
611 try roundTrip(
596612 \\"asd"
597613 );
598614}
599615
600616test "y_structure_lonely_true" {
601 ok(
617 try roundTrip(
602618 \\true
603619 );
604620}
605621
606622test "y_structure_string_empty" {
607 ok(
623 try roundTrip(
608624 \\""
609625 );
610626}
611627
612628test "y_structure_trailing_newline" {
613 ok(
629 try roundTrip(
614630 \\["a"]
615631 );
616632}
617633
618634test "y_structure_true_in_array" {
619 ok(
635 try roundTrip(
620636 \\[true]
621637 );
622638}
623639
624640test "y_structure_whitespace_array" {
625 ok(" [] ");
641 try ok(" [] ");
626642}
627643
628644////////////////////////////////////////////////////////////////////////////////////////////////////
lib/std/math/ln.zig+3-2
......@@ -36,8 +36,9 @@ pub fn ln(x: anytype) @TypeOf(x) {
3636 .ComptimeInt => {
3737 return @as(comptime_int, math.floor(ln_64(@as(f64, x))));
3838 },
39 .Int => {
40 return @as(T, math.floor(ln_64(@as(f64, x))));
39 .Int => |IntType| switch (IntType.signedness) {
40 .signed => return @compileError("ln not implemented for signed integers"),
41 .unsigned => return @as(T, math.floor(ln_64(@as(f64, x)))),
4142 },
4243 else => @compileError("ln not implemented for " ++ @typeName(T)),
4344 }
lib/std/math/log.zig+6-4
......@@ -31,9 +31,11 @@ pub fn log(comptime T: type, base: T, x: T) T {
3131 .ComptimeInt => {
3232 return @as(comptime_int, math.floor(math.ln(@as(f64, x)) / math.ln(float_base)));
3333 },
34 .Int => {
35 // TODO implement integer log without using float math
36 return @floatToInt(T, math.floor(math.ln(@intToFloat(f64, x)) / math.ln(float_base)));
34
35 // TODO implement integer log without using float math
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))),
3739 },
3840
3941 .Float => {
......@@ -53,7 +55,7 @@ pub fn log(comptime T: type, base: T, x: T) T {
5355test "math.log integer" {
5456 expect(log(u8, 2, 0x1) == 0);
5557 expect(log(u8, 2, 0x2) == 1);
56 expect(log(i16, 2, 0x72) == 6);
58 expect(log(u16, 2, 0x72) == 6);
5759 expect(log(u32, 2, 0xFFFFFF) == 23);
5860 expect(log(u64, 2, 0x7FF0123456789ABC) == 62);
5961}
lib/std/math/log10.zig+3-2
......@@ -37,8 +37,9 @@ pub fn log10(x: anytype) @TypeOf(x) {
3737 .ComptimeInt => {
3838 return @as(comptime_int, math.floor(log10_64(@as(f64, x))));
3939 },
40 .Int => {
41 return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x))));
40 .Int => |IntType| switch (IntType.signedness) {
41 .signed => return @compileError("log10 not implemented for signed integers"),
42 .unsigned => return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x)))),
4243 },
4344 else => @compileError("log10 not implemented for " ++ @typeName(T)),
4445 }
lib/std/math/log2.zig+3-2
......@@ -43,8 +43,9 @@ pub fn log2(x: anytype) @TypeOf(x) {
4343 }) : (result += 1) {}
4444 return result;
4545 },
46 .Int => {
47 return math.log2_int(T, x);
46 .Int => |IntType| switch (IntType.signedness) {
47 .signed => return @compileError("log2 not implemented for signed integers"),
48 .unsigned => return math.log2_int(T, x),
4849 },
4950 else => @compileError("log2 not implemented for " ++ @typeName(T)),
5051 }
lib/std/math/sqrt.zig+4-1
......@@ -31,7 +31,10 @@ pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) {
3131 }
3232 return @as(T, sqrt_int(u128, x));
3333 },
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 },
3538 else => @compileError("sqrt not implemented for " ++ @typeName(T)),
3639 }
3740}
lib/std/meta.zig+38-1
......@@ -970,12 +970,15 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
970970
971971 if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile)
972972 return @intToPtr(DestType, @ptrToInt(target))
973 else if (@typeInfo(dest.child) == .Opaque)
974 // dest.alignment would error out
975 return @ptrCast(DestType, target)
973976 else
974977 return @ptrCast(DestType, @alignCast(dest.alignment, target));
975978}
976979
977980fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {
978 return switch(@typeInfo(PtrType)){
981 return switch (@typeInfo(PtrType)) {
979982 .Optional => |opt_info| @typeInfo(opt_info.child).Pointer,
980983 .Pointer => |ptr_info| ptr_info,
981984 else => unreachable,
......@@ -1010,6 +1013,8 @@ test "std.meta.cast" {
10101013
10111014 testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*const u8, 2)));
10121015 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)));
10131018}
10141019
10151020/// 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 {
12971302 return null;
12981303 return @as(T, @field(root, name));
12991304}
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{
32543254
32553255 /// Connection was reset by peer before connect could complete.
32563256 ConnectionResetByPeer,
3257
3258 /// Socket is non-blocking and already has a pending connection in progress.
3259 ConnectionPending,
32573260} || UnexpectedError;
32583261
32593262/// Initiate a connection on a socket.
......@@ -3294,7 +3297,7 @@ pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) Conne
32943297 EADDRNOTAVAIL => return error.AddressNotAvailable,
32953298 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
32963299 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,
32983301 EBADF => unreachable, // sockfd is not a valid open file descriptor.
32993302 ECONNREFUSED => return error.ConnectionRefused,
33003303 ECONNRESET => return error.ConnectionResetByPeer,
......@@ -3325,7 +3328,7 @@ pub fn getsockoptError(sockfd: fd_t) ConnectError!void {
33253328 EADDRNOTAVAIL => return error.AddressNotAvailable,
33263329 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
33273330 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,
33293332 EBADF => unreachable, // sockfd is not a valid open file descriptor.
33303333 ECONNREFUSED => return error.ConnectionRefused,
33313334 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) {
2121 .riscv64 => @import("linux/riscv64.zig"),
2222 .sparcv9 => @import("linux/sparc64.zig"),
2323 .mips, .mipsel => @import("linux/mips.zig"),
24 .powerpc => @import("linux/powerpc.zig"),
2425 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
2526 else => struct {},
2627};
......@@ -586,6 +587,92 @@ pub const IP_DEFAULT_MULTICAST_TTL = 1;
586587pub const IP_DEFAULT_MULTICAST_LOOP = 1;
587588pub 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
589676pub const MSG_OOB = 0x0001;
590677pub const MSG_PEEK = 0x0002;
591678pub 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 {
813813 __bits: [_SIG_WORDS]u32,
814814};
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
820816pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** _SIG_WORDS };
821817
822818// XXX x86_64 specific
......@@ -1219,3 +1215,25 @@ pub const rlimit = extern struct {
12191215pub const SHUT_RD = 0;
12201216pub const SHUT_WR = 1;
12211217pub 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) {
2626 .riscv64 => @import("linux/riscv64.zig"),
2727 .sparcv9 => @import("linux/sparc64.zig"),
2828 .mips, .mipsel => @import("linux/mips.zig"),
29 .powerpc => @import("linux/powerpc.zig"),
2930 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
3031 else => struct {},
3132};
lib/std/os/linux/io_uring.zig+1-1
......@@ -1354,7 +1354,7 @@ test "timeout (after a relative time)" {
13541354 .flags = 0,
13551355 }, 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.
13581358 if (!std.math.approxEqAbs(f64, ms, @intToFloat(f64, stopped - started), margin)) return error.SkipZigTest;
13591359}
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 {
491491 \\ syscall
492492 );
493493 },
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 },
494559 .powerpc64, .powerpc64le => {
495560 // __clone(func, stack, flags, arg, ptid, tls, ctid)
496561 // 3, 4, 5, 6, 7, 8, 9
lib/std/special/docs/index.html+16-5
......@@ -43,6 +43,8 @@
4343
4444 /* layout */
4545 .canvas {
46 display: flex;
47 flex-direction: column;
4648 width: 100vw;
4749 height: 100vh;
4850 overflow: hidden;
......@@ -53,12 +55,21 @@
5355 background-color: var(--bg-color);
5456 }
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
5670 .flex-main {
5771 display: flex;
58 width: 100%;
59 height: 100%;
60 justify-content: center;
61
72 overflow-y: hidden;
6273 z-index: 100;
6374 }
6475
......@@ -515,7 +526,7 @@
515526 </style>
516527 </head>
517528 <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>
519530 <div class="flex-main">
520531 <div class="flex-filler"></div>
521532 <div class="flex-left sidebar">
lib/std/special/docs/main.js+7-1
......@@ -1844,7 +1844,13 @@
18441844 var oldHash = location.hash;
18451845 var parts = oldHash.split("?");
18461846 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 }
18481854 }
18491855 function getSearchTerms() {
18501856 var list = curNavSearch.trim().split(/[ \r\n\t]+/);
lib/std/start.zig+102-27
......@@ -7,7 +7,7 @@
77
88const root = @import("root");
99const std = @import("std.zig");
10const builtin = std.builtin;
10const builtin = @import("builtin");
1111const assert = std.debug.assert;
1212const uefi = std.os.uefi;
1313const tlcsprng = @import("crypto/tlcsprng.zig");
......@@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined;
1717const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
1818
1919comptime {
20 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
21 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
22 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
20 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
21 // Until then, we have simplified logic here for self-hosted. TODO remove this once
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 }
2334 }
24 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
25 if (builtin.link_libc and @hasDecl(root, "main")) {
26 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
27 @export(main, .{ .name = "main", .linkage = .Weak });
35 } else {
36 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
37 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
38 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
2839 }
29 } else if (builtin.os.tag == .windows) {
30 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
31 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
32 {
33 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });
34 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
35 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
36 {
37 @compileError("WinMain not supported; declare wWinMain or main instead");
38 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
39 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
40 {
41 @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
40 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
41 if (builtin.link_libc and @hasDecl(root, "main")) {
42 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
43 @export(main, .{ .name = "main", .linkage = .Weak });
44 }
45 } else if (builtin.os.tag == .windows) {
46 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
47 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
48 {
49 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });
50 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
51 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "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 });
4265 }
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 });
4966 }
5067 }
5168}
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
53115fn _DllMainCRTStartup(
54116 hinstDLL: std.os.windows.HINSTANCE,
55117 fdwReason: std.os.windows.DWORD,
......@@ -135,6 +197,19 @@ fn _start() callconv(.Naked) noreturn {
135197 : [argc] "={sp}" (-> [*]usize)
136198 );
137199 },
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 },
138213 .powerpc64le => {
139214 // Setup the initial stack frame and clear the back chain pointer.
140215 // TODO: Support powerpc64 (big endian) on ELFv2.
lib/std/std.zig+1-1
......@@ -92,7 +92,7 @@ pub const zig = @import("zig.zig");
9292pub const start = @import("start.zig");
9393
9494// 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.
9696comptime {
9797 _ = start;
9898}
lib/std/target.zig+1-1
......@@ -1178,7 +1178,7 @@ pub const Target = struct {
11781178 return switch (arch) {
11791179 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
11801180 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
1181 .avr => &avr.cpu.avr1,
1181 .avr => &avr.cpu.avr2,
11821182 .bpfel, .bpfeb => &bpf.cpu.generic,
11831183 .hexagon => &hexagon.cpu.generic,
11841184 .mips, .mipsel => &mips.cpu.mips32,
lib/std/testing.zig+3-3
......@@ -431,7 +431,7 @@ fn printIndicatorLine(source: []const u8, indicator_index: usize) void {
431431
432432fn printWithVisibleNewlines(source: []const u8) void {
433433 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) {
435435 printLine(source[i .. i + nl]);
436436 }
437437 print("{s}␃\n", .{source[i..]}); // End of Text symbol (ETX)
......@@ -439,7 +439,7 @@ fn printWithVisibleNewlines(source: []const u8) void {
439439
440440fn printLine(line: []const u8) void {
441441 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,
443443 else => {},
444444 };
445445 print("{s}\n", .{line});
......@@ -451,7 +451,7 @@ test {
451451
452452/// Given a type, reference all the declarations inside, so that the semantic analyzer sees them.
453453pub fn refAllDecls(comptime T: type) void {
454 if (!@import("builtin").is_test) return;
454 if (!std.builtin.is_test) return;
455455 inline for (std.meta.declarations(T)) |decl| {
456456 _ = decl;
457457 }
lib/std/time.zig+6-2
......@@ -271,7 +271,9 @@ test "timestamp" {
271271 sleep(ns_per_ms);
272272 const time_1 = milliTimestamp();
273273 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;
275277}
276278
277279test "Timer" {
......@@ -280,7 +282,9 @@ test "Timer" {
280282 var timer = try Timer.start();
281283 sleep(10 * ns_per_ms);
282284 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
285289 const time_1 = timer.lap();
286290 testing.expect(time_1 >= time_0);
lib/std/wasm.zig+6-1
......@@ -5,6 +5,8 @@
55// and substantial portions of the software.
66const testing = @import("std.zig").testing;
77
8// TODO: Add support for multi-byte ops (e.g. table operations)
9
810/// Wasm instruction opcodes
911///
1012/// All instructions are defined as per spec:
......@@ -175,7 +177,7 @@ pub const Opcode = enum(u8) {
175177 i32_reinterpret_f32 = 0xBC,
176178 i64_reinterpret_f64 = 0xBD,
177179 f32_reinterpret_i32 = 0xBE,
178 i64_reinterpret_i64 = 0xBF,
180 f64_reinterpret_i64 = 0xBF,
179181 i32_extend8_s = 0xC0,
180182 i32_extend16_s = 0xC1,
181183 i64_extend8_s = 0xC2,
......@@ -278,3 +280,6 @@ pub const block_empty: u8 = 0x40;
278280// binary constants
279281pub const magic = [_]u8{ 0x00, 0x61, 0x73, 0x6D }; // \0asm
280282pub 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;
1818
1919pub 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.
2321pub fn hashSrc(src: []const u8) SrcHash {
2422 var out: SrcHash = undefined;
25 if (src.len <= @typeInfo(SrcHash).Array.len) {
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 }
23 std.crypto.hash.Blake3.hash(src, &out, .{});
3124 return out;
3225}
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 {
3545 var line: usize = 0;
3646 var column: usize = 0;
37 for (source[0..byte_offset]) |byte| {
38 switch (byte) {
47 var line_start: usize = 0;
48 var i: usize = 0;
49 while (i < byte_offset) : (i += 1) {
50 switch (source[i]) {
3951 '\n' => {
4052 line += 1;
4153 column = 0;
54 line_start = i + 1;
4255 },
4356 else => {
4457 column += 1;
4558 },
4659 }
4760 }
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 };
4969}
5070
5171pub 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" {
18011801 );
18021802}
18031803
1804test "zig fmt: array literal veritical column alignment" {
1804test "zig fmt: array literal vertical column alignment" {
18051805 try testTransform(
18061806 \\const a = []u8{
18071807 \\ 1000, 200,
18081808 \\ 30, 4,
1809 \\ 50000, 60
1809 \\ 50000, 60,
18101810 \\};
18111811 \\const a = []u8{0, 1, 2, 3, 40,
18121812 \\ 4,5,600,7,
18131813 \\ 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, };
18151819 \\
18161820 ,
18171821 \\const a = []u8{
......@@ -1825,6 +1829,21 @@ test "zig fmt: array literal veritical column alignment" {
18251829 \\ 9, 10, 11, 0, 13,
18261830 \\ 14, 15,
18271831 \\};
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 \\};
18281847 \\
18291848 );
18301849}
......@@ -2026,10 +2045,7 @@ test "zig fmt: add trailing comma to array literal" {
20262045 \\ return []u16{
20272046 \\ 'm', 's', 'y', 's', '-', // hi
20282047 \\ };
2029 \\ return []u16{
2030 \\ 'm', 's', 'y', 's',
2031 \\ '-',
2032 \\ };
2048 \\ return []u16{ 'm', 's', 'y', 's', '-' };
20332049 \\ return []u16{ 'm', 's', 'y', 's', '-' };
20342050 \\}
20352051 \\
......@@ -4661,6 +4677,90 @@ test "zig fmt: insert trailing comma if there are comments between switch values
46614677 );
46624678}
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
46644764test "zig fmt: error for invalid bit range" {
46654765 try testError(
46664766 \\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;
99const Tokenizer = std.zig.Tokenizer;
1010const Parser = std.zig.Parser;
1111const io = std.io;
12const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
1213
1314const source = @embedFile("../os.zig");
1415var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
......@@ -25,12 +26,15 @@ pub fn main() !void {
2526 const end = timer.read();
2627 memory_used /= iterations;
2728 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 mb_per_sec = bytes_per_sec / (1024 * 1024);
29 const bytes_per_sec_float = @intToFloat(f64, source.len * iterations) / elapsed_s;
30 const bytes_per_sec = @floatToInt(u64, @floor(bytes_per_sec_float));
3031
3132 var stdout_file = std.io.getStdOut();
3233 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 });
3438}
3539
3640fn testOnce() usize {
lib/std/zig/render.zig+35-15
......@@ -1632,9 +1632,10 @@ fn renderArrayInit(
16321632 }
16331633 }
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) {
16381639 // Render all on one line, no trailing comma.
16391640 if (array_init.ast.elements.len == 1) {
16401641 // If there is only one element, we don't use spaces
......@@ -1653,7 +1654,8 @@ fn renderArrayInit(
16531654 try renderToken(ais, tree, array_init.ast.lbrace, .newline);
16541655
16551656 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);
16571659 const row_exprs = array_init.ast.elements[expr_index..];
16581660 // A place to store the width of each expression and its column's maximum
16591661 const widths = try gpa.alloc(usize, row_exprs.len + row_size);
......@@ -1686,7 +1688,7 @@ fn renderArrayInit(
16861688 const maybe_comma = expr_last_token + 1;
16871689 if (token_tags[maybe_comma] == .comma) {
16881690 if (hasSameLineComment(tree, maybe_comma))
1689 break :sec_end i - this_line_size.? + 1;
1691 break :sec_end i - this_line_size + 1;
16901692 }
16911693 }
16921694 break :sec_end row_exprs.len;
......@@ -2238,17 +2240,36 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
22382240 }
22392241}
22402242
2241/// Returns true if there exists a comment between the start of token
2242/// `start_token` and the start of token `end_token`. This is used to determine
2243/// if e.g. a fn_proto should be wrapped and have a trailing comma inserted
2244/// even if there is none in the source.
2243/// Returns true if there exists a comment between any of the tokens from
2244/// `start_token` to `end_token`. This is used to determine if e.g. a
2245/// fn_proto should be wrapped and have a trailing comma inserted even if
2246/// there is none in the source.
22452247fn hasComment(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool {
22462248 const token_starts = tree.tokens.items(.start);
22472249
2248 const start = token_starts[start_token];
2249 const end = token_starts[end_token];
2250 var i = start_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;
22522273}
22532274
22542275/// Assumes that start is the first byte past the previous token and
......@@ -2500,9 +2521,8 @@ fn nodeCausesSliceOpSpace(tag: ast.Node.Tag) bool {
25002521 };
25012522}
25022523
2503// 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.
2505fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex) ?usize {
2524// Returns the number of nodes in `expr` that are on the same line as `rtoken`.
2525fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex) usize {
25062526 const token_tags = tree.tokens.items(.tag);
25072527
25082528 const first_token = tree.firstToken(exprs[0]);
......@@ -2510,7 +2530,7 @@ fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex
25102530 const maybe_comma = rtoken - 1;
25112531 if (token_tags[maybe_comma] == .comma)
25122532 return 1;
2513 return null; // no newlines
2533 return exprs.len; // no newlines
25142534 }
25152535
25162536 var count: usize = 1;
src/AstGen.zig+334-77
......@@ -28,8 +28,6 @@ const BuiltinFn = @import("BuiltinFn.zig");
2828instructions: std.MultiArrayList(zir.Inst) = .{},
2929string_bytes: ArrayListUnmanaged(u8) = .{},
3030extra: ArrayListUnmanaged(u32) = .{},
31decl_map: std.StringArrayHashMapUnmanaged(void) = .{},
32decls: ArrayListUnmanaged(*Decl) = .{},
3331/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
3432/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
3533ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,
......@@ -110,8 +108,6 @@ pub fn deinit(astgen: *AstGen) void {
110108 astgen.instructions.deinit(gpa);
111109 astgen.extra.deinit(gpa);
112110 astgen.string_bytes.deinit(gpa);
113 astgen.decl_map.deinit(gpa);
114 astgen.decls.deinit(gpa);
115111}
116112
117113pub const ResultLoc = union(enum) {
......@@ -124,6 +120,9 @@ pub const ResultLoc = union(enum) {
124120 /// The expression must generate a pointer rather than a value. For example, the left hand side
125121 /// of an assignment uses this kind of result location.
126122 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,
127126 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
128127 ty: zir.Inst.Ref,
129128 /// The expression must store its result into this typed pointer. The result instruction
......@@ -157,7 +156,7 @@ pub const ResultLoc = union(enum) {
157156 var elide_store_to_block_ptr_instructions = false;
158157 switch (rl) {
159158 // 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 .{
161160 .tag = .break_operand,
162161 .elide_store_to_block_ptr_instructions = false,
163162 },
......@@ -606,8 +605,13 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
606605
607606 .deref => {
608607 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
609 const result = try gz.addUnNode(.load, lhs, node);
610 return rvalue(gz, scope, rl, result, node);
608 switch (rl) {
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 }
611615 },
612616 .address_of => {
613617 const result = try expr(gz, scope, .ref, node_datas[node].lhs);
......@@ -816,10 +820,34 @@ pub fn structInitExpr(
816820 }
817821 switch (rl) {
818822 .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", .{}),
820824 .ref => unreachable, // struct literal not valid as l-value
821825 .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);
823851 },
824852 .ptr => |ptr_inst| {
825853 const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);
......@@ -1175,13 +1203,6 @@ fn blockExprStmts(
11751203 // in the above while loop.
11761204 const zir_tags = gz.astgen.instructions.items(.tag);
11771205 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 },
11851206 // For some instructions, swap in a slightly different ZIR tag
11861207 // so we can avoid a separate ensure_result_used instruction.
11871208 .call_none_chkused => unreachable,
......@@ -1248,7 +1269,10 @@ fn blockExprStmts(
12481269 .fn_type_var_args,
12491270 .fn_type_cc,
12501271 .fn_type_cc_var_args,
1272 .has_decl,
12511273 .int,
1274 .float,
1275 .float128,
12521276 .intcast,
12531277 .int_type,
12541278 .is_non_null,
......@@ -1321,12 +1345,18 @@ fn blockExprStmts(
13211345 .switch_capture_else,
13221346 .switch_capture_else_ref,
13231347 .struct_init_empty,
1348 .struct_init,
1349 .field_type,
13241350 .struct_decl,
13251351 .struct_decl_packed,
13261352 .struct_decl_extern,
13271353 .union_decl,
13281354 .enum_decl,
1355 .enum_decl_nonexhaustive,
13291356 .opaque_decl,
1357 .int_to_enum,
1358 .enum_to_int,
1359 .type_info,
13301360 => break :b false,
13311361
13321362 // ZIR instructions that are always either `noreturn` or `void`.
......@@ -1334,6 +1364,7 @@ fn blockExprStmts(
13341364 .dbg_stmt_node,
13351365 .ensure_result_used,
13361366 .ensure_result_non_error,
1367 .@"export",
13371368 .set_eval_branch_quota,
13381369 .compile_log,
13391370 .ensure_err_payload_void,
......@@ -1482,7 +1513,7 @@ fn varDecl(
14821513 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
14831514 init_scope.rl_ty_inst = type_inst;
14841515 } else {
1485 const alloc = try init_scope.addUnNode(.alloc_inferred, undefined, node);
1516 const alloc = try init_scope.addNode(.alloc_inferred, node);
14861517 resolve_inferred_alloc = alloc;
14871518 init_scope.rl_ptr = alloc;
14881519 }
......@@ -1557,7 +1588,7 @@ fn varDecl(
15571588 const alloc = try gz.addUnNode(.alloc_mut, type_inst, node);
15581589 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
15591590 } else a: {
1560 const alloc = try gz.addUnNode(.alloc_inferred_mut, undefined, node);
1591 const alloc = try gz.addNode(.alloc_inferred_mut, node);
15611592 resolve_inferred_alloc = alloc;
15621593 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
15631594 };
......@@ -1815,15 +1846,18 @@ fn containerDecl(
18151846 defer bit_bag.deinit(gpa);
18161847
18171848 var cur_bit_bag: u32 = 0;
1818 var member_index: usize = 0;
1819 while (true) {
1820 const member_node = container_decl.ast.members[member_index];
1849 var field_index: usize = 0;
1850 for (container_decl.ast.members) |member_node| {
18211851 const member = switch (node_tags[member_node]) {
18221852 .container_field_init => tree.containerFieldInit(member_node),
18231853 .container_field_align => tree.containerFieldAlign(member_node),
18241854 .container_field => tree.containerField(member_node),
1825 else => unreachable,
1855 else => continue,
18261856 };
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 }
18271861 if (member.comptime_token) |comptime_token| {
18281862 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
18291863 }
......@@ -1850,17 +1884,9 @@ fn containerDecl(
18501884 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
18511885 }
18521886
1853 member_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 }
1887 field_index += 1;
18621888 }
1863 const empty_slot_count = 16 - ((member_index - 1) % 16);
1889 const empty_slot_count = 16 - (field_index % 16);
18641890 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
18651891
18661892 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
......@@ -1877,7 +1903,172 @@ fn containerDecl(
18771903 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});
18781904 },
18791905 .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", .{});
18812072 },
18822073 .keyword_opaque => {
18832074 const result = try gz.addNode(.opaque_decl, node);
......@@ -1893,11 +2084,11 @@ fn errorSetDecl(
18932084 rl: ResultLoc,
18942085 node: ast.Node.Index,
18952086) InnerError!zir.Inst.Ref {
1896 const mod = gz.astgen.mod;
2087 const astgen = gz.astgen;
2088 const mod = astgen.mod;
18972089 const tree = gz.tree();
18982090 const main_tokens = tree.nodes.items(.main_token);
18992091 const token_tags = tree.tokens.items(.tag);
1900 const arena = gz.astgen.arena;
19012092
19022093 // Count how many fields there are.
19032094 const error_token = main_tokens[node];
......@@ -1914,6 +2105,11 @@ fn errorSetDecl(
19142105 } else unreachable; // TODO should not need else unreachable here
19152106 };
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
19172113 const fields = try arena.alloc([]const u8, count);
19182114 {
19192115 var tok_i = error_token + 2;
......@@ -1922,7 +2118,7 @@ fn errorSetDecl(
19222118 switch (token_tags[tok_i]) {
19232119 .doc_comment, .comma => {},
19242120 .identifier => {
1925 fields[field_i] = try mod.identifierTokenString(scope, tok_i);
2121 fields[field_i] = try mod.identifierTokenStringTreeArena(scope, tok_i, tree, arena);
19262122 field_i += 1;
19272123 },
19282124 .r_brace => break,
......@@ -1932,18 +2128,19 @@ fn errorSetDecl(
19322128 }
19332129 const error_set = try arena.create(Module.ErrorSet);
19342130 error_set.* = .{
1935 .owner_decl = gz.astgen.decl,
1936 .node_offset = gz.astgen.decl.nodeIndexToRelative(node),
2131 .owner_decl = astgen.decl,
2132 .node_offset = astgen.decl.nodeIndexToRelative(node),
19372133 .names_ptr = fields.ptr,
19382134 .names_len = @intCast(u32, fields.len),
19392135 };
19402136 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
1941 const typed_value = try arena.create(TypedValue);
1942 typed_value.* = .{
2137 const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
2138 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
19432139 .ty = Type.initTag(.type),
1944 .val = try Value.Tag.ty.create(arena, error_set_ty),
1945 };
1946 const result = try gz.addConst(typed_value);
2140 .val = error_set_val,
2141 });
2142 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2143 const result = try gz.addDecl(.decl_val, decl_index, node);
19472144 return rvalue(gz, scope, rl, result, node);
19482145}
19492146
......@@ -1980,7 +2177,7 @@ fn orelseCatchExpr(
19802177 // TODO handle catch
19812178 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
19822179 .ref => .ref,
1983 .discard, .none, .block_ptr, .inferred_ptr => .none,
2180 .discard, .none, .none_or_ref, .block_ptr, .inferred_ptr => .none,
19842181 .ty => |elem_ty| blk: {
19852182 const wrapped_ty = try block_scope.addUnNode(.optional_type, elem_ty, node);
19862183 break :blk .{ .ty = wrapped_ty };
......@@ -2156,7 +2353,7 @@ pub fn fieldAccess(
21562353 .field_name_start = str_index,
21572354 }),
21582355 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),
21602357 .field_name_start = str_index,
21612358 }), node),
21622359 }
......@@ -2179,7 +2376,7 @@ fn arrayAccess(
21792376 ),
21802377 else => return rvalue(gz, scope, rl, try gz.addBin(
21812378 .elem_val,
2182 try expr(gz, scope, .none, node_datas[node].lhs),
2379 try expr(gz, scope, .none_or_ref, node_datas[node].lhs),
21832380 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
21842381 ), node),
21852382 }
......@@ -3188,8 +3385,13 @@ fn switchExpr(
31883385 switch (strat.tag) {
31893386 .break_operand => {
31903387 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus
3191 // this is always true.
3192 assert(strat.elide_store_to_block_ptr_instructions);
3388 // `elide_store_to_block_ptr_instructions` will either be true,
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
31943396 // There will necessarily be a store_to_block_ptr for
31953397 // all prongs, except for prongs that ended with a noreturn instruction.
......@@ -3418,7 +3620,8 @@ fn identifier(
34183620 const tracy = trace(@src());
34193621 defer tracy.end();
34203622
3421 const mod = gz.astgen.mod;
3623 const astgen = gz.astgen;
3624 const mod = astgen.mod;
34223625 const tree = gz.tree();
34233626 const main_tokens = tree.nodes.items(.main_token);
34243627
......@@ -3451,7 +3654,7 @@ fn identifier(
34513654 const result = try gz.add(.{
34523655 .tag = .int_type,
34533656 .data = .{ .int_type = .{
3454 .src_node = gz.astgen.decl.nodeIndexToRelative(ident),
3657 .src_node = astgen.decl.nodeIndexToRelative(ident),
34553658 .signedness = signedness,
34563659 .bit_count = bit_count,
34573660 } },
......@@ -3474,9 +3677,13 @@ fn identifier(
34743677 .local_ptr => {
34753678 const local_ptr = s.cast(Scope.LocalPtr).?;
34763679 if (mem.eql(u8, local_ptr.name, ident_name)) {
3477 if (rl == .ref) return local_ptr.ptr;
3478 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
3479 return rvalue(gz, scope, rl, loaded, ident);
3680 switch (rl) {
3681 .ref, .none_or_ref => return local_ptr.ptr,
3682 else => {
3683 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
3684 return rvalue(gz, scope, rl, loaded, ident);
3685 },
3686 }
34803687 }
34813688 s = local_ptr.parent;
34823689 },
......@@ -3485,15 +3692,15 @@ fn identifier(
34853692 };
34863693 }
34873694
3488 const gop = try gz.astgen.decl_map.getOrPut(mod.gpa, ident_name);
3489 if (!gop.found_existing) {
3490 const decl = mod.lookupDeclName(scope, ident_name) orelse
3491 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
3492 try gz.astgen.decls.append(mod.gpa, decl);
3493 }
3494 const decl_index = @intCast(u32, gop.index);
3695 const decl = mod.lookupDeclName(scope, ident_name) orelse {
3696 // TODO insert a "dependency on the non-existence of a decl" here to make this
3697 // compile error go away when the decl is introduced. This data should be in a global
3698 // sparse map since it is only relevant when a compile error occurs.
3699 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
3700 };
3701 const decl_index = try mod.declareDeclDependency(astgen.decl, decl);
34953702 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),
34973704 else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),
34983705 }
34993706}
......@@ -3626,12 +3833,23 @@ fn floatLiteral(
36263833 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
36273834 error.InvalidCharacter => unreachable, // validated by tokenizer
36283835 };
3629 const typed_value = try arena.create(TypedValue);
3630 typed_value.* = .{
3631 .ty = Type.initTag(.comptime_float),
3632 .val = try Value.Tag.float_128.create(arena, float_number),
3633 };
3634 const result = try gz.addConst(typed_value);
3836 // If the value fits into a f32 without losing any precision, store it that way.
3837 @setFloatMode(.Strict);
3838 const smaller_float = @floatCast(f32, float_number);
3839 const bigger_again: f128 = smaller_float;
3840 if (bigger_again == float_number) {
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 });
36353853 return rvalue(gz, scope, rl, result, node);
36363854}
36373855
......@@ -3697,7 +3915,7 @@ fn as(
36973915) InnerError!zir.Inst.Ref {
36983916 const dest_type = try typeExpr(gz, scope, lhs);
36993917 switch (rl) {
3700 .none, .discard, .ref, .ty => {
3918 .none, .none_or_ref, .discard, .ref, .ty => {
37013919 const result = try expr(gz, scope, .{ .ty = dest_type }, rhs);
37023920 return rvalue(gz, scope, rl, result, node);
37033921 },
......@@ -3781,7 +3999,7 @@ fn bitCast(
37813999 });
37824000 return rvalue(gz, scope, rl, result, node);
37834001 },
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.
37854003 .ptr => |result_ptr| {
37864004 const casted_result_ptr = try gz.addUnNode(.bitcast_result_ptr, result_ptr, node);
37874005 return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);
......@@ -3882,11 +4100,11 @@ fn builtinCall(
38824100 return rvalue(gz, scope, rl, result, node);
38834101 },
38844102 .breakpoint => {
3885 const result = try gz.add(.{
4103 _ = try gz.add(.{
38864104 .tag = .breakpoint,
38874105 .data = .{ .node = gz.astgen.decl.nodeIndexToRelative(node) },
38884106 });
3889 return rvalue(gz, scope, rl, result, node);
4107 return rvalue(gz, scope, rl, .void_value, node);
38904108 },
38914109 .import => {
38924110 const target = try expr(gz, scope, .none, params[0]);
......@@ -3943,6 +4161,50 @@ fn builtinCall(
39434161 .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),
39444162 .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
39464208 .add_with_overflow,
39474209 .align_cast,
39484210 .align_of,
......@@ -3969,17 +4231,13 @@ fn builtinCall(
39694231 .div_floor,
39704232 .div_trunc,
39714233 .embed_file,
3972 .enum_to_int,
39734234 .error_name,
39744235 .error_return_trace,
39754236 .err_set_cast,
3976 .@"export",
39774237 .fence,
39784238 .field_parent_ptr,
39794239 .float_to_int,
3980 .has_decl,
39814240 .has_field,
3982 .int_to_enum,
39834241 .int_to_float,
39844242 .int_to_ptr,
39854243 .memcpy,
......@@ -4023,7 +4281,6 @@ fn builtinCall(
40234281 .This,
40244282 .truncate,
40254283 .Type,
4026 .type_info,
40274284 .type_name,
40284285 .union_init,
40294286 => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{
......@@ -4354,7 +4611,7 @@ fn rvalue(
43544611 src_node: ast.Node.Index,
43554612) InnerError!zir.Inst.Ref {
43564613 switch (rl) {
4357 .none => return result,
4614 .none, .none_or_ref => return result,
43584615 .discard => {
43594616 // Emit a compile error for discarding error values.
43604617 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
src/BuiltinFn.zig+1-1
......@@ -484,7 +484,7 @@ pub const list = list: {
484484 "@intToEnum",
485485 .{
486486 .tag = .int_to_enum,
487 .param_count = 1,
487 .param_count = 2,
488488 },
489489 },
490490 .{
src/Compilation.zig+132-58
......@@ -272,32 +272,57 @@ pub const AllErrors = struct {
272272 line: u32,
273273 column: u32,
274274 byte_offset: u32,
275 /// Does not include the trailing newline.
276 source_line: ?[]const u8,
275277 notes: []Message = &.{},
276278 },
277279 plain: struct {
278280 msg: []const u8,
279281 },
280282
281 pub fn renderToStdErr(msg: Message) void {
282 return msg.renderToStdErrInner("error");
283 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
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;
283289 }
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();
286299 switch (msg) {
287300 .src => |src| {
288 std.debug.print("{s}:{d}:{d}: {s}: {s}\n", .{
301 ttyconf.setColor(stderr, .Bold);
302 try stderr.print("{s}:{d}:{d}: ", .{
289303 src.src_path,
290304 src.line + 1,
291305 src.column + 1,
292 kind,
293 src.msg,
294306 });
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 }
295320 for (src.notes) |note| {
296 note.renderToStdErrInner("note");
321 try note.renderToStdErrInner(ttyconf, stderr_file, "note:", .Cyan);
297322 }
298323 },
299324 .plain => |plain| {
300 std.debug.print("{s}: {s}\n", .{ kind, plain.msg });
325 try stderr.print("{s}: {s}\n", .{ kind, plain.msg });
301326 },
302327 }
303328 }
......@@ -327,6 +352,7 @@ pub const AllErrors = struct {
327352 .byte_offset = byte_offset,
328353 .line = @intCast(u32, loc.line),
329354 .column = @intCast(u32, loc.column),
355 .source_line = try arena.allocator.dupe(u8, loc.source_line),
330356 },
331357 };
332358 }
......@@ -342,6 +368,7 @@ pub const AllErrors = struct {
342368 .line = @intCast(u32, loc.line),
343369 .column = @intCast(u32, loc.column),
344370 .notes = notes,
371 .source_line = try arena.allocator.dupe(u8, loc.source_line),
345372 },
346373 });
347374 }
......@@ -906,38 +933,56 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
906933 artifact_sub_dir,
907934 };
908935
909 // TODO when we implement serialization and deserialization of incremental compilation metadata,
910 // this is where we would load it. We have open a handle to the directory where
911 // the output either already is, or will be.
936 // If we rely on stage1, we must not redundantly add these packages.
937 const use_stage1 = build_options.is_stage1 and use_llvm;
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.
912966 // However we currently do not have serialization of such metadata, so for now
913967 // we set up an empty Module that does the entire compilation fresh.
914968
915 const root_scope = rs: {
916 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
917 const root_scope = try gpa.create(Module.Scope.File);
918 const struct_ty = try Type.Tag.empty_struct.create(
919 gpa,
920 &root_scope.root_container,
921 );
922 root_scope.* = .{
923 // TODO this is duped so it can be freed in Container.deinit
924 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
925 .source = .{ .unloaded = {} },
926 .tree = undefined,
927 .status = .never_loaded,
928 .pkg = root_pkg,
929 .root_container = .{
930 .file_scope = root_scope,
931 .decls = .{},
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 }
969 const root_scope = try gpa.create(Module.Scope.File);
970 errdefer gpa.destroy(root_scope);
971
972 const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container);
973 root_scope.* = .{
974 // TODO this is duped so it can be freed in Container.deinit
975 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
976 .source = .{ .unloaded = {} },
977 .tree = undefined,
978 .status = .never_loaded,
979 .pkg = root_pkg,
980 .root_container = .{
981 .file_scope = root_scope,
982 .decls = .{},
983 .ty = struct_ty,
984 .parent_name_hash = root_pkg.namespace_hash,
985 },
941986 };
942987
943988 const module = try arena.create(Module);
......@@ -1339,16 +1384,17 @@ pub fn update(self: *Compilation) !void {
13391384 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
13401385 }
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);
13431389 if (!use_stage1) {
13441390 if (self.bin_file.options.module) |module| {
13451391 module.compile_log_text.shrinkAndFree(module.gpa, 0);
13461392 module.generation += 1;
13471393
13481394 // TODO Detect which source files changed.
1349 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
1350 // to force a refresh we unload now.
1351 module.root_scope.unload(module.gpa);
1395 // Until then we simulate a full cache miss. Source files could have been loaded
1396 // for any reason; to force a refresh we unload now.
1397 module.unloadFile(module.root_scope);
13521398 module.failed_root_src_file = null;
13531399 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
13541400 error.AnalysisFail => {
......@@ -1362,7 +1408,7 @@ pub fn update(self: *Compilation) !void {
13621408
13631409 // TODO only analyze imports if they are still referenced
13641410 for (module.import_table.items()) |entry| {
1365 entry.value.unload(module.gpa);
1411 module.unloadFile(entry.value);
13661412 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
13671413 error.AnalysisFail => {
13681414 assert(self.totalErrorCount() != 0);
......@@ -1377,14 +1423,17 @@ pub fn update(self: *Compilation) !void {
13771423
13781424 if (!use_stage1) {
13791425 if (self.bin_file.options.module) |module| {
1380 // Process the deletion set.
1381 while (module.deletion_set.popOrNull()) |decl| {
1382 if (decl.dependants.items().len != 0) {
1383 decl.deletion_flag = false;
1384 continue;
1385 }
1386 try module.deleteDecl(decl);
1426 // Process the deletion set. We use a while loop here because the
1427 // deletion set may grow as we call `deleteDecl` within this loop,
1428 // and more unreferenced Decls are revealed.
1429 var entry_i: usize = 0;
1430 while (entry_i < module.deletion_set.entries.items.len) : (entry_i += 1) {
1431 const decl = module.deletion_set.entries.items[entry_i].key;
1432 assert(decl.deletion_flag);
1433 assert(decl.dependants.items().len == 0);
1434 try module.deleteDecl(decl, null);
13871435 }
1436 module.deletion_set.shrinkRetainingCapacity(0);
13881437 }
13891438 }
13901439
......@@ -1429,11 +1478,25 @@ pub fn totalErrorCount(self: *Compilation) usize {
14291478 var total: usize = self.failed_c_objects.items().len;
14301479
14311480 if (self.bin_file.options.module) |module| {
1432 total += module.failed_decls.count() +
1433 module.emit_h_failed_decls.count() +
1434 module.failed_exports.items().len +
1481 total += module.failed_exports.items().len +
14351482 module.failed_files.items().len +
14361483 @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 }
14371500 }
14381501
14391502 // The "no entry point found" error only counts if there are no other errors.
......@@ -1472,6 +1535,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
14721535 .byte_offset = 0,
14731536 .line = err_msg.line,
14741537 .column = err_msg.column,
1538 .source_line = null, // TODO
14751539 },
14761540 });
14771541 }
......@@ -1480,9 +1544,19 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
14801544 try AllErrors.add(module, &arena, &errors, entry.value.*);
14811545 }
14821546 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 }
14831552 try AllErrors.add(module, &arena, &errors, entry.value.*);
14841553 }
14851554 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 }
14861560 try AllErrors.add(module, &arena, &errors, entry.value.*);
14871561 }
14881562 for (module.failed_exports.items()) |entry| {
......@@ -2437,7 +2511,7 @@ pub fn addCCArgs(
24372511 try argv.append("-fPIC");
24382512 }
24392513 },
2440 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig, .zir => {},
2514 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig => {},
24412515 }
24422516 if (out_dep_path) |p| {
24432517 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
......@@ -2511,7 +2585,6 @@ pub const FileExt = enum {
25112585 object,
25122586 static_library,
25132587 zig,
2514 zir,
25152588 unknown,
25162589
25172590 pub fn clangSupportsDepFile(ext: FileExt) bool {
......@@ -2525,7 +2598,6 @@ pub const FileExt = enum {
25252598 .object,
25262599 .static_library,
25272600 .zig,
2528 .zir,
25292601 .unknown,
25302602 => false,
25312603 };
......@@ -2597,8 +2669,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
25972669 return .h;
25982670 } else if (mem.endsWith(u8, filename, ".zig")) {
25992671 return .zig;
2600 } else if (mem.endsWith(u8, filename, ".zir")) {
2601 return .zir;
26022672 } else if (hasSharedLibraryExt(filename)) {
26032673 return .shared_library;
26042674 } else if (hasStaticLibraryExt(filename)) {
......@@ -2619,7 +2689,6 @@ test "classifyFileExt" {
26192689 std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));
26202690 std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));
26212691 std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
2622 std.testing.expectEqual(FileExt.zir, classifyFileExt("foo.zir"));
26232692}
26242693
26252694fn haveFramePointer(comp: *const Compilation) bool {
......@@ -2814,6 +2883,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28142883
28152884 const target = comp.getTarget();
28162885 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
28182889 @setEvalBranchQuota(4000);
28192890 try buffer.writer().print(
......@@ -2826,6 +2897,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28262897 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
28272898 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
28282899 \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}");
2900 \\pub const zig_is_stage2 = {};
28292901 \\
28302902 \\pub const output_mode = OutputMode.{};
28312903 \\pub const link_mode = LinkMode.{};
......@@ -2839,6 +2911,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28392911 \\
28402912 , .{
28412913 build_options.version,
2914 !use_stage1,
28422915 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
28432916 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
28442917 comp.bin_file.options.is_test,
......@@ -3044,6 +3117,7 @@ fn buildOutputFromZig(
30443117 .handle = special_dir,
30453118 },
30463119 .root_src_path = src_basename,
3120 .namespace_hash = Package.root_namespace_hash,
30473121 };
30483122 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
30493123 const target = comp.getTarget();
src/Module.zig+320-132
......@@ -65,8 +65,8 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
6565/// Keep track of one `@compileLog` callsite per owner Decl.
6666compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},
6767/// 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.
69failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *ErrorMsg) = .{},
68/// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator.
69failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{},
7070/// Using a map here for consistency with the other fields here.
7171/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
7272failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
......@@ -75,7 +75,7 @@ next_anon_name_index: usize = 0,
7575
7676/// Candidates for deletion. After a semantic analysis update completes, this list
7777/// 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
8080/// Error tags and their values, tag names are duped with mod.gpa.
8181/// Corresponds with `error_name_list`.
......@@ -150,9 +150,15 @@ pub const Decl = struct {
150150 /// The direct parent container of the Decl.
151151 /// Reference to externally owned memory.
152152 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.
154159 /// Must be recomputed when the corresponding source file is modified.
155 src_index: usize,
160 src_node: ast.Node.Index,
161
156162 /// The most recent value of the Decl after a successful semantic analysis.
157163 typed_value: union(enum) {
158164 never_succeeded: void,
......@@ -192,17 +198,12 @@ pub const Decl = struct {
192198 /// to require re-analysis.
193199 outdated,
194200 },
195 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared
201 /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared
196202 /// when removed.
197203 deletion_flag: bool,
198204 /// Whether the corresponding AST decl has a `pub` keyword.
199205 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
206207 /// Represents the position of the code in the output file.
207208 /// This is populated regardless of semantic analysis and code generation.
208209 link: link.File.LinkBlock,
......@@ -249,11 +250,11 @@ pub const Decl = struct {
249250 }
250251
251252 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));
253254 }
254255
255256 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);
257258 }
258259
259260 pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {
......@@ -271,14 +272,9 @@ pub const Decl = struct {
271272 };
272273 }
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
279275 pub fn srcToken(decl: Decl) u32 {
280276 const tree = &decl.container.file_scope.tree;
281 return tree.firstToken(decl.srcNode());
277 return tree.firstToken(decl.src_node);
282278 }
283279
284280 pub fn srcByteOffset(decl: Decl) u32 {
......@@ -290,6 +286,18 @@ pub const Decl = struct {
290286 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
291287 }
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
293301 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {
294302 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;
295303 return tvm.typed_value;
......@@ -354,6 +362,13 @@ pub const ErrorSet = struct {
354362 /// The string bytes are stored in the owner Decl arena.
355363 /// They are in the same order they appear in the AST.
356364 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 }
357372};
358373
359374/// Represents the data that a struct declaration provides.
......@@ -364,7 +379,7 @@ pub const Struct = struct {
364379 /// Represents the declarations inside this struct.
365380 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.
368383 node_offset: i32,
369384
370385 pub const Field = struct {
......@@ -373,6 +388,64 @@ pub const Struct = struct {
373388 /// Uses `unreachable_value` to indicate no default.
374389 default_val: Value,
375390 };
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 }
376449};
377450
378451/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
......@@ -601,6 +674,7 @@ pub const Scope = struct {
601674 base: Scope = Scope{ .tag = base_tag },
602675
603676 file_scope: *Scope.File,
677 parent_name_hash: NameHash,
604678
605679 /// Direct children of the file.
606680 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
......@@ -619,8 +693,12 @@ pub const Scope = struct {
619693 }
620694
621695 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
622 // TODO container scope qualified names.
623 return std.zig.hashSrc(name);
696 return std.zig.hashName(cont.parent_name_hash, ".", 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);
624702 }
625703 };
626704
......@@ -650,10 +728,12 @@ pub const Scope = struct {
650728
651729 pub fn unload(file: *File, gpa: *Allocator) void {
652730 switch (file.status) {
653 .never_loaded,
654731 .unloaded_parse_failure,
732 .never_loaded,
655733 .unloaded_success,
656 => {},
734 => {
735 file.status = .unloaded_success;
736 },
657737
658738 .loaded_success => {
659739 file.tree.deinit(gpa);
......@@ -1018,7 +1098,6 @@ pub const Scope = struct {
10181098 .instructions = gz.astgen.instructions.toOwnedSlice(),
10191099 .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),
10201100 .extra = gz.astgen.extra.toOwnedSlice(gpa),
1021 .decls = gz.astgen.decls.toOwnedSlice(gpa),
10221101 };
10231102 }
10241103
......@@ -1048,6 +1127,9 @@ pub const Scope = struct {
10481127 gz.rl_ty_inst = ty_inst;
10491128 gz.break_result_loc = parent_rl;
10501129 },
1130 .none_or_ref => {
1131 gz.break_result_loc = .ref;
1132 },
10511133 .discard, .none, .ptr, .ref => {
10521134 gz.break_result_loc = parent_rl;
10531135 },
......@@ -1227,6 +1309,16 @@ pub const Scope = struct {
12271309 });
12281310 }
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
12301322 pub fn addUnNode(
12311323 gz: *GenZir,
12321324 tag: zir.Inst.Tag,
......@@ -1435,13 +1527,6 @@ pub const Scope = struct {
14351527 return new_index;
14361528 }
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
14451530 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
14461531 return gz.astgen.indexToRef(try gz.addAsIndex(inst));
14471532 }
......@@ -1572,6 +1657,7 @@ pub const SrcLoc = struct {
15721657 .byte_offset,
15731658 .token_offset,
15741659 .node_offset,
1660 .node_offset_back2tok,
15751661 .node_offset_var_decl_ty,
15761662 .node_offset_for_cond,
15771663 .node_offset_builtin_call_arg0,
......@@ -1633,6 +1719,14 @@ pub const SrcLoc = struct {
16331719 const token_starts = tree.tokens.items(.start);
16341720 return token_starts[tok_index];
16351721 },
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 },
16361730 .node_offset_var_decl_ty => |node_off| {
16371731 const decl = src_loc.container.decl;
16381732 const node = decl.relativeToNodeIndex(node_off);
......@@ -1747,7 +1841,10 @@ pub const SrcLoc = struct {
17471841 const node_datas = tree.nodes.items(.data);
17481842 const node_tags = tree.nodes.items(.tag);
17491843 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 };
17511848 const token_starts = tree.tokens.items(.start);
17521849 return token_starts[tok_index];
17531850 },
......@@ -1988,6 +2085,10 @@ pub const LazySrcLoc = union(enum) {
19882085 /// from its containing Decl node AST index.
19892086 /// The Decl is determined contextually.
19902087 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,
19912092 /// The source location points to a variable declaration type expression,
19922093 /// found by taking this AST node index offset from the containing
19932094 /// Decl AST node, which points to a variable declaration AST node. Next, navigate
......@@ -2026,10 +2127,10 @@ pub const LazySrcLoc = union(enum) {
20262127 /// to the callee expression.
20272128 /// The Decl is determined contextually.
20282129 node_offset_call_func: i32,
2029 /// The source location points to the field name of a field access expression,
2030 /// found by taking this AST node index offset from the containing
2031 /// Decl AST node, which points to a field access AST node. Next, navigate
2032 /// to the field name token.
2130 /// The payload is offset from the containing Decl AST node.
2131 /// The source location points to the field name of:
2132 /// * a field access expression (`a.b`), or
2133 /// * the operand ("b" node) of a field initialization expression (`.a = b`)
20332134 /// The Decl is determined contextually.
20342135 node_offset_field_name: i32,
20352136 /// The source location points to the pointer of a pointer deref expression,
......@@ -2114,6 +2215,7 @@ pub const LazySrcLoc = union(enum) {
21142215 .byte_offset,
21152216 .token_offset,
21162217 .node_offset,
2218 .node_offset_back2tok,
21172219 .node_offset_var_decl_ty,
21182220 .node_offset_for_cond,
21192221 .node_offset_builtin_call_arg0,
......@@ -2156,6 +2258,7 @@ pub const LazySrcLoc = union(enum) {
21562258 .byte_offset,
21572259 .token_offset,
21582260 .node_offset,
2261 .node_offset_back2tok,
21592262 .node_offset_var_decl_ty,
21602263 .node_offset_for_cond,
21612264 .node_offset_builtin_call_arg0,
......@@ -2189,6 +2292,20 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail };
21892292pub fn deinit(mod: *Module) void {
21902293 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
21922309 mod.compile_log_text.deinit(gpa);
21932310
21942311 mod.zig_cache_artifact_directory.handle.close();
......@@ -2288,7 +2405,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
22882405 // We don't perform a deletion here, because this Decl or another one
22892406 // may end up referencing it before the update is complete.
22902407 dep.deletion_flag = true;
2291 try mod.deletion_set.append(mod.gpa, dep);
2408 try mod.deletion_set.put(mod.gpa, dep, {});
22922409 }
22932410 }
22942411 decl.dependencies.clearRetainingCapacity();
......@@ -2351,7 +2468,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
23512468 const tree = try mod.getAstTree(decl.container.file_scope);
23522469 const node_tags = tree.nodes.items(.tag);
23532470 const node_datas = tree.nodes.items(.data);
2354 const decl_node = tree.rootDecls()[decl.src_index];
2471 const decl_node = decl.src_node;
23552472 switch (node_tags[decl_node]) {
23562473 .fn_decl => {
23572474 const fn_proto = node_datas[decl_node].lhs;
......@@ -2406,6 +2523,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
24062523
24072524 const block_expr = node_datas[decl_node].lhs;
24082525 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
2526 _ = try gen_scope.addBreak(.break_inline, 0, .void_value);
24092527
24102528 const code = try gen_scope.finish();
24112529 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
......@@ -3087,12 +3205,19 @@ fn astgenAndSemaVarDecl(
30873205 return type_changed;
30883206}
30893207
3090pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
3091 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.items().len + 1);
3092 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.items().len + 1);
3208/// Returns the depender's index of the dependee.
3209pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 {
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, {});
30953218 dependee.dependants.putAssumeCapacity(depender, {});
3219 const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);
3220 return @intCast(u32, gop.index);
30963221}
30973222
30983223pub 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 {
31173242 var msg = std.ArrayList(u8).init(mod.gpa);
31183243 defer msg.deinit();
31193244
3245 const token_starts = tree.tokens.items(.start);
3246
31203247 try tree.renderError(parse_err, msg.writer());
31213248 const err_msg = try mod.gpa.create(ErrorMsg);
31223249 err_msg.* = .{
31233250 .src_loc = .{
31243251 .container = .{ .file_scope = root_scope },
3125 .lazy = .{ .token_abs = parse_err.token },
3252 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
31263253 },
31273254 .msg = msg.toOwnedSlice(),
31283255 };
31293256
3130 mod.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
3257 mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg);
31313258 root_scope.status = .unloaded_parse_failure;
31323259 return error.AnalysisFail;
31333260 }
......@@ -3167,7 +3294,15 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
31673294 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
31683295 }
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]) {
31713306 .fn_decl => {
31723307 const fn_proto = node_datas[decl_node].lhs;
31733308 const body = node_datas[decl_node].rhs;
......@@ -3177,8 +3312,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
31773312 try mod.semaContainerFn(
31783313 container_scope,
31793314 &deleted_decls,
3315 &outdated_decls,
31803316 decl_node,
3181 decl_i,
31823317 tree.*,
31833318 body,
31843319 tree.fnProtoSimple(&params, fn_proto),
......@@ -3187,8 +3322,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
31873322 .fn_proto_multi => try mod.semaContainerFn(
31883323 container_scope,
31893324 &deleted_decls,
3325 &outdated_decls,
31903326 decl_node,
3191 decl_i,
31923327 tree.*,
31933328 body,
31943329 tree.fnProtoMulti(fn_proto),
......@@ -3198,8 +3333,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
31983333 try mod.semaContainerFn(
31993334 container_scope,
32003335 &deleted_decls,
3336 &outdated_decls,
32013337 decl_node,
3202 decl_i,
32033338 tree.*,
32043339 body,
32053340 tree.fnProtoOne(&params, fn_proto),
......@@ -3208,8 +3343,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32083343 .fn_proto => try mod.semaContainerFn(
32093344 container_scope,
32103345 &deleted_decls,
3346 &outdated_decls,
32113347 decl_node,
3212 decl_i,
32133348 tree.*,
32143349 body,
32153350 tree.fnProto(fn_proto),
......@@ -3222,8 +3357,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32223357 try mod.semaContainerFn(
32233358 container_scope,
32243359 &deleted_decls,
3360 &outdated_decls,
32253361 decl_node,
3226 decl_i,
32273362 tree.*,
32283363 0,
32293364 tree.fnProtoSimple(&params, decl_node),
......@@ -3232,8 +3367,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32323367 .fn_proto_multi => try mod.semaContainerFn(
32333368 container_scope,
32343369 &deleted_decls,
3370 &outdated_decls,
32353371 decl_node,
3236 decl_i,
32373372 tree.*,
32383373 0,
32393374 tree.fnProtoMulti(decl_node),
......@@ -3243,8 +3378,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32433378 try mod.semaContainerFn(
32443379 container_scope,
32453380 &deleted_decls,
3381 &outdated_decls,
32463382 decl_node,
3247 decl_i,
32483383 tree.*,
32493384 0,
32503385 tree.fnProtoOne(&params, decl_node),
......@@ -3253,8 +3388,8 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32533388 .fn_proto => try mod.semaContainerFn(
32543389 container_scope,
32553390 &deleted_decls,
3391 &outdated_decls,
32563392 decl_node,
3257 decl_i,
32583393 tree.*,
32593394 0,
32603395 tree.fnProto(decl_node),
......@@ -3263,32 +3398,32 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32633398 .global_var_decl => try mod.semaContainerVar(
32643399 container_scope,
32653400 &deleted_decls,
3401 &outdated_decls,
32663402 decl_node,
3267 decl_i,
32683403 tree.*,
32693404 tree.globalVarDecl(decl_node),
32703405 ),
32713406 .local_var_decl => try mod.semaContainerVar(
32723407 container_scope,
32733408 &deleted_decls,
3409 &outdated_decls,
32743410 decl_node,
3275 decl_i,
32763411 tree.*,
32773412 tree.localVarDecl(decl_node),
32783413 ),
32793414 .simple_var_decl => try mod.semaContainerVar(
32803415 container_scope,
32813416 &deleted_decls,
3417 &outdated_decls,
32823418 decl_node,
3283 decl_i,
32843419 tree.*,
32853420 tree.simpleVarDecl(decl_node),
32863421 ),
32873422 .aligned_var_decl => try mod.semaContainerVar(
32883423 container_scope,
32893424 &deleted_decls,
3425 &outdated_decls,
32903426 decl_node,
3291 decl_i,
32923427 tree.*,
32933428 tree.alignedVarDecl(decl_node),
32943429 ),
......@@ -3301,49 +3436,48 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33013436 const name_hash = container_scope.fullyQualifiedNameHash(name);
33023437 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);
33053440 container_scope.decls.putAssumeCapacity(new_decl, {});
33063441 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
33073442 },
33083443
3309 .container_field_init => try mod.semaContainerField(
3310 container_scope,
3311 &deleted_decls,
3312 decl_node,
3313 decl_i,
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 ),
3444 // Container fields are handled in AstGen.
3445 .container_field_init,
3446 .container_field_align,
3447 .container_field,
3448 => continue,
33333449
33343450 .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 }
33363454 },
33373455 .@"usingnamespace" => {
33383456 log.err("TODO: analyze usingnamespace decl", .{});
33393457 },
33403458 else => unreachable,
33413459 };
3342 // Handle explicitly deleted decls from the source code. Not to be confused
3343 // with when we delete decls because they are no longer referenced.
3460 // Handle explicitly deleted decls from the source code. This is one of two
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.
33443468 for (deleted_decls.items()) |entry| {
3345 log.debug("noticed '{s}' deleted from source", .{entry.key.name});
3346 try mod.deleteDecl(entry.key);
3469 const decl = 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);
33473481 }
33483482}
33493483
......@@ -3351,8 +3485,8 @@ fn semaContainerFn(
33513485 mod: *Module,
33523486 container_scope: *Scope.Container,
33533487 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3488 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
33543489 decl_node: ast.Node.Index,
3355 decl_i: usize,
33563490 tree: ast.Tree,
33573491 body_node: ast.Node.Index,
33583492 fn_proto: ast.full.FnProto,
......@@ -3361,28 +3495,34 @@ fn semaContainerFn(
33613495 defer tracy.end();
33623496
33633497 // 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 {
33653499 // This problem will go away with #1717.
33663500 @panic("TODO missing function name");
33673501 };
3368 const name = tree.tokenSlice(name_tok); // TODO use identifierTokenString
3502 const name = tree.tokenSlice(name_token); // TODO use identifierTokenString
33693503 const name_hash = container_scope.fullyQualifiedNameHash(name);
33703504 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
33713505 if (mod.decl_table.get(name_hash)) |decl| {
33723506 // Update the AST Node index of the decl, even if its contents are unchanged, it may
33733507 // have been re-ordered.
3374 decl.src_index = decl_i;
3508 const prev_src_node = decl.src_node;
3509 decl.src_node = decl_node;
33753510 if (deleted_decls.swapRemove(decl) == null) {
33763511 decl.analysis = .sema_failure;
33773512 const msg = try ErrorMsg.create(mod.gpa, .{
33783513 .container = .{ .file_scope = container_scope.file_scope },
3379 .lazy = .{ .token_abs = name_tok },
3514 .lazy = .{ .token_abs = name_token },
33803515 }, "redefinition of '{s}'", .{decl.name});
33813516 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", .{});
33823522 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
33833523 } else {
33843524 if (!srcHashEql(decl.contents_hash, contents_hash)) {
3385 try mod.markOutdatedDecl(decl);
3525 try outdated_decls.put(decl, {});
33863526 decl.contents_hash = contents_hash;
33873527 } else switch (mod.comp.bin_file.tag) {
33883528 .coff => {
......@@ -3402,7 +3542,7 @@ fn semaContainerFn(
34023542 }
34033543 }
34043544 } 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);
34063546 container_scope.decls.putAssumeCapacity(new_decl, {});
34073547 if (fn_proto.extern_export_token) |maybe_export_token| {
34083548 const token_tags = tree.tokens.items(.tag);
......@@ -3410,6 +3550,7 @@ fn semaContainerFn(
34103550 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
34113551 }
34123552 }
3553 new_decl.is_pub = fn_proto.visib_token != null;
34133554 }
34143555}
34153556
......@@ -3417,8 +3558,8 @@ fn semaContainerVar(
34173558 mod: *Module,
34183559 container_scope: *Scope.Container,
34193560 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3561 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
34203562 decl_node: ast.Node.Index,
3421 decl_i: usize,
34223563 tree: ast.Tree,
34233564 var_decl: ast.full.VarDecl,
34243565) !void {
......@@ -3432,21 +3573,27 @@ fn semaContainerVar(
34323573 if (mod.decl_table.get(name_hash)) |decl| {
34333574 // Update the AST Node index of the decl, even if its contents are unchanged, it may
34343575 // have been re-ordered.
3435 decl.src_index = decl_i;
3576 const prev_src_node = decl.src_node;
3577 decl.src_node = decl_node;
34363578 if (deleted_decls.swapRemove(decl) == null) {
34373579 decl.analysis = .sema_failure;
3438 const err_msg = try ErrorMsg.create(mod.gpa, .{
3580 const msg = try ErrorMsg.create(mod.gpa, .{
34393581 .container = .{ .file_scope = container_scope.file_scope },
34403582 .lazy = .{ .token_abs = name_token },
34413583 }, "redefinition of '{s}'", .{decl.name});
3442 errdefer err_msg.destroy(mod.gpa);
3443 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);
3584 errdefer msg.destroy(mod.gpa);
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);
34443591 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
3445 try mod.markOutdatedDecl(decl);
3592 try outdated_decls.put(decl, {});
34463593 decl.contents_hash = contents_hash;
34473594 }
34483595 } 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);
34503597 container_scope.decls.putAssumeCapacity(new_decl, {});
34513598 if (var_decl.extern_export_token) |maybe_export_token| {
34523599 const token_tags = tree.tokens.items(.tag);
......@@ -3454,35 +3601,31 @@ fn semaContainerVar(
34543601 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
34553602 }
34563603 }
3604 new_decl.is_pub = var_decl.visib_token != null;
34573605 }
34583606}
34593607
3460fn semaContainerField(
3608pub fn deleteDecl(
34613609 mod: *Module,
3462 container_scope: *Scope.Container,
3463 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3464 decl_node: ast.Node.Index,
3465 decl_i: usize,
3466 tree: ast.Tree,
3467 field: ast.full.ContainerField,
3610 decl: *Decl,
3611 outdated_decls: ?*std.AutoArrayHashMap(*Decl, void),
34683612) !void {
34693613 const tracy = trace(@src());
34703614 defer tracy.end();
34713615
3472 log.err("TODO: analyze container field", .{});
3473}
3474
3475pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
3476 const tracy = trace(@src());
3477 defer tracy.end();
3616 log.debug("deleting decl '{s}'", .{decl.name});
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
34813625 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
34823626 // not be present in the set, and this does nothing.
34833627 decl.container.removeDecl(decl);
34843628
3485 log.debug("deleting decl '{s}'", .{decl.name});
34863629 const name_hash = decl.fullyQualifiedNameHash();
34873630 mod.decl_table.removeAssertDiscard(name_hash);
34883631 // 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 {
34933636 // We don't recursively perform a deletion here, because during the update,
34943637 // another reference to it may turn up.
34953638 dep.deletion_flag = true;
3496 mod.deletion_set.appendAssumeCapacity(dep);
3639 mod.deletion_set.putAssumeCapacity(dep, {});
34973640 }
34983641 }
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.
35003643 for (decl.dependants.items()) |entry| {
35013644 const dep = entry.key;
35023645 dep.removeDependency(decl);
3503 if (dep.analysis != .outdated) {
3504 // TODO Move this failure possibility to the top of the function.
3505 try mod.markOutdatedDecl(dep);
3646 if (outdated_decls) |map| {
3647 map.putAssumeCapacity(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));
35063655 }
35073656 }
35083657 if (mod.failed_decls.swapRemove(decl)) |entry| {
......@@ -3638,7 +3787,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
36383787fn allocateNewDecl(
36393788 mod: *Module,
36403789 scope: *Scope,
3641 src_index: usize,
3790 src_node: ast.Node.Index,
36423791 contents_hash: std.zig.SrcHash,
36433792) !*Decl {
36443793 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.
......@@ -3654,7 +3803,7 @@ fn allocateNewDecl(
36543803 new_decl.* = .{
36553804 .name = "",
36563805 .container = scope.namespace(),
3657 .src_index = src_index,
3806 .src_node = src_node,
36583807 .typed_value = .{ .never_succeeded = {} },
36593808 .analysis = .unreferenced,
36603809 .deletion_flag = false,
......@@ -3664,7 +3813,7 @@ fn allocateNewDecl(
36643813 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
36653814 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
36663815 .c => .{ .c = link.File.C.DeclBlock.empty },
3667 .wasm => .{ .wasm = {} },
3816 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
36683817 .spirv => .{ .spirv = {} },
36693818 },
36703819 .fn_link = switch (mod.comp.bin_file.tag) {
......@@ -3672,7 +3821,7 @@ fn allocateNewDecl(
36723821 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
36733822 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
36743823 .c => .{ .c = link.File.C.FnBlock.empty },
3675 .wasm => .{ .wasm = null },
3824 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
36763825 .spirv => .{ .spirv = .{} },
36773826 },
36783827 .generation = 0,
......@@ -3685,12 +3834,12 @@ fn createNewDecl(
36853834 mod: *Module,
36863835 scope: *Scope,
36873836 decl_name: []const u8,
3688 src_index: usize,
3837 src_node: ast.Node.Index,
36893838 name_hash: Scope.NameHash,
36903839 contents_hash: std.zig.SrcHash,
36913840) !*Decl {
36923841 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);
36943843 errdefer mod.gpa.destroy(new_decl);
36953844 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
36963845 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
......@@ -3903,7 +4052,7 @@ pub fn createAnonymousDecl(
39034052 defer mod.gpa.free(name);
39044053 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
39054054 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);
39074056 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
39084057
39094058 decl_arena_state.* = decl_arena.state;
......@@ -3939,7 +4088,7 @@ pub fn createContainerDecl(
39394088 defer mod.gpa.free(name);
39404089 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
39414090 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);
39434092 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
39444093
39454094 decl_arena_state.* = decl_arena.state;
......@@ -4003,13 +4152,23 @@ pub fn errNote(
40034152 parent: *ErrorMsg,
40044153 comptime format: []const u8,
40054154 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,
40064165) error{OutOfMemory}!void {
40074166 const msg = try std.fmt.allocPrint(mod.gpa, format, args);
40084167 errdefer mod.gpa.free(msg);
40094168
40104169 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
40114170 parent.notes[parent.notes.len - 1] = .{
4012 .src_loc = src.toSrcLoc(scope),
4171 .src_loc = src_loc,
40134172 .msg = msg,
40144173 };
40154174}
......@@ -4412,7 +4571,29 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
44124571 var buf: ArrayListUnmanaged(u8) = .{};
44134572 defer buf.deinit(mod.gpa);
44144573 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);
44164597}
44174598
44184599/// Given an identifier token, obtain the string for it (possibly parsing as a string
......@@ -4502,3 +4683,10 @@ pub fn parseStrLit(
45024683 },
45034684 }
45044685}
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");
44const fs = std.fs;
55const mem = std.mem;
66const Allocator = mem.Allocator;
7const assert = std.debug.assert;
78
89const Compilation = @import("Compilation.zig");
10const Module = @import("Module.zig");
911
1012pub 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
1219root_src_directory: Compilation.Directory,
1320/// Relative to `root_src_directory`. May contain path separators.
1421root_src_path: []const u8,
1522table: Table = .{},
1623parent: ?*Package = null,
24namespace_hash: Module.Scope.NameHash,
25/// Whether to free `root_src_directory` on `destroy`.
26root_src_directory_owned: bool = false,
1727
1828/// Allocate a Package. No references to the slices passed are kept.
29/// Don't forget to set `namespace_hash` later.
1930pub fn create(
2031 gpa: *Allocator,
2132 /// Null indicates the current working directory
......@@ -38,27 +49,69 @@ pub fn create(
3849 .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(),
3950 },
4051 .root_src_path = owned_src_path,
52 .root_src_directory_owned = true,
53 .namespace_hash = undefined,
4154 };
4255
4356 return ptr;
4457}
4558
46/// Free all memory associated with this package and recursively call destroy
47/// on all packages in its table
59pub fn createWithDir(
60 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.
48100pub fn destroy(pkg: *Package, gpa: *Allocator) void {
49101 gpa.free(pkg.root_src_path);
50102
51 // If root_src_directory.path is null then the handle is the cwd()
52 // which shouldn't be closed.
53 if (pkg.root_src_directory.path) |p| {
54 gpa.free(p);
55 pkg.root_src_directory.handle.close();
103 if (pkg.root_src_directory_owned) {
104 // If root_src_directory.path is null then the handle is the cwd()
105 // which shouldn't be closed.
106 if (pkg.root_src_directory.path) |p| {
107 gpa.free(p);
108 pkg.root_src_directory.handle.close();
109 }
56110 }
57111
58112 {
59113 var it = pkg.table.iterator();
60114 while (it.next()) |kv| {
61 kv.value.destroy(gpa);
62115 gpa.free(kv.key);
63116 }
64117 }
......@@ -72,3 +125,10 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)
72125 const name_dupe = try mem.dupe(gpa, u8, name);
73126 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
74127}
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(
168168 .cmp_lte => try sema.zirCmp(block, inst, .lte),
169169 .cmp_neq => try sema.zirCmp(block, inst, .neq),
170170 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
171 .@"const" => try sema.zirConst(block, inst),
172171 .decl_ref => try sema.zirDeclRef(block, inst),
173172 .decl_val => try sema.zirDeclVal(block, inst),
174173 .load => try sema.zirLoad(block, inst),
......@@ -179,6 +178,8 @@ pub fn analyzeBody(
179178 .elem_val_node => try sema.zirElemValNode(block, inst),
180179 .enum_literal => try sema.zirEnumLiteral(block, inst),
181180 .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),
182183 .err_union_code => try sema.zirErrUnionCode(block, inst),
183184 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
184185 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
......@@ -198,9 +199,12 @@ pub fn analyzeBody(
198199 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
199200 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
200201 .fn_type_var_args => try sema.zirFnType(block, inst, true),
202 .has_decl => try sema.zirHasDecl(block, inst),
201203 .import => try sema.zirImport(block, inst),
202204 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
203205 .int => try sema.zirInt(block, inst),
206 .float => try sema.zirFloat(block, inst),
207 .float128 => try sema.zirFloat128(block, inst),
204208 .int_type => try sema.zirIntType(block, inst),
205209 .intcast => try sema.zirIntcast(block, inst),
206210 .is_err => try sema.zirIsErr(block, inst),
......@@ -255,16 +259,20 @@ pub fn analyzeBody(
255259 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
256260 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
257261 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
262 .type_info => try sema.zirTypeInfo(block, inst),
258263 .typeof => try sema.zirTypeof(block, inst),
259264 .typeof_elem => try sema.zirTypeofElem(block, inst),
260265 .typeof_peer => try sema.zirTypeofPeer(block, inst),
261266 .xor => try sema.zirBitwise(block, inst, .xor),
262267 .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
264271 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
265272 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
266273 .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),
268276 .union_decl => try sema.zirUnionDecl(block, inst),
269277 .opaque_decl => try sema.zirOpaqueDecl(block, inst),
270278
......@@ -338,6 +346,10 @@ pub fn analyzeBody(
338346 try sema.zirValidateStructInitPtr(block, inst);
339347 continue;
340348 },
349 .@"export" => {
350 try sema.zirExport(block, inst);
351 continue;
352 },
341353
342354 // Special case instructions to handle comptime control flow.
343355 .repeat_inline => {
......@@ -498,18 +510,6 @@ fn resolveInstConst(
498510 };
499511}
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
513513fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
514514 const tracy = trace(@src());
515515 defer tracy.end();
......@@ -600,6 +600,11 @@ fn zirStructDecl(
600600
601601 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
602602 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 });
603608 struct_obj.* = .{
604609 .owner_decl = sema.owner_decl,
605610 .fields = fields_map,
......@@ -607,16 +612,18 @@ fn zirStructDecl(
607612 .container = .{
608613 .ty = struct_ty,
609614 .file_scope = block.getFileScope(),
615 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
610616 },
611617 };
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 });
616618 return sema.analyzeDeclVal(block, src, new_decl);
617619}
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 {
620627 const tracy = trace(@src());
621628 defer tracy.end();
622629
......@@ -787,8 +794,8 @@ fn zirAllocInferred(
787794 const tracy = trace(@src());
788795 defer tracy.end();
789796
790 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
791 const src = inst_data.src();
797 const src_node = sema.code.instructions.items(.data)[inst].node;
798 const src: LazySrcLoc = .{ .node_offset = src_node };
792799
793800 const val_payload = try sema.arena.create(Value.Payload.InferredAlloc);
794801 val_payload.* = .{
......@@ -837,12 +844,100 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind
837844 const tracy = trace(@src());
838845 defer tracy.end();
839846
840 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
841 const src = inst_data.src();
842 const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
843 const instrs = sema.code.extra[extra.end..][0..extra.data.body_len];
847 const gpa = sema.gpa;
848 const mod = sema.mod;
849 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
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);
846941}
847942
848943fn 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
9811076 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
9821077}
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
9841104fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
9851105 const tracy = trace(@src());
9861106 defer tracy.end();
......@@ -1222,6 +1342,28 @@ fn analyzeBlockBody(
12221342 return &merges.block_inst.base;
12231343}
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
12251367fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
12261368 const tracy = trace(@src());
12271369 defer tracy.end();
......@@ -1291,22 +1433,16 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
12911433}
12921434
12931435fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1294 const tracy = trace(@src());
1295 defer tracy.end();
1296
12971436 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
12981437 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;
13001439 return sema.analyzeDeclRef(block, src, decl);
13011440}
13021441
13031442fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1304 const tracy = trace(@src());
1305 defer tracy.end();
1306
13071443 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13081444 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;
13101446 return sema.analyzeDeclVal(block, src, decl);
13111447}
13121448
......@@ -1763,6 +1899,143 @@ fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I
17631899 });
17641900}
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
17662039/// Pointer in, pointer out.
17672040fn zirOptionalPayloadPtr(
17682041 sema: *Sema,
......@@ -2139,7 +2412,10 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro
21392412 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
21402413 const field_name = sema.code.nullTerminatedString(extra.field_name_start);
21412414 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);
21432419 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
21442420 return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
21452421}
......@@ -2292,7 +2568,10 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
22922568
22932569 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
22942570 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);
22962575 const elem_index = try sema.resolveInst(bin_inst.rhs);
22972576 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
22982577 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
23072586 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
23082587 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
23092588 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);
23112593 const elem_index = try sema.resolveInst(extra.rhs);
23122594 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
23132595 return sema.analyzeLoad(block, src, result_ptr, src);
......@@ -2492,6 +2774,8 @@ fn analyzeSwitch(
24922774 src_node_offset: i32,
24932775) InnerError!*Inst {
24942776 const gpa = sema.gpa;
2777 const mod = sema.mod;
2778
24952779 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
24962780 .none => .{ .body = &.{}, .end = extra_end },
24972781 .under, .@"else" => blk: {
......@@ -2509,16 +2793,16 @@ fn analyzeSwitch(
25092793 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
25102794
25112795 // Validate usage of '_' prongs.
2512 if (special_prong == .under and !operand.ty.isExhaustiveEnum()) {
2796 if (special_prong == .under and !operand.ty.isNonexhaustiveEnum()) {
25132797 const msg = msg: {
2514 const msg = try sema.mod.errMsg(
2798 const msg = try mod.errMsg(
25152799 &block.base,
25162800 src,
25172801 "'_' prong only allowed when switching on non-exhaustive enums",
25182802 .{},
25192803 );
25202804 errdefer msg.destroy(gpa);
2521 try sema.mod.errNote(
2805 try mod.errNote(
25222806 &block.base,
25232807 special_prong_src,
25242808 msg,
......@@ -2527,14 +2811,123 @@ fn analyzeSwitch(
25272811 );
25282812 break :msg msg;
25292813 };
2530 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
2814 return mod.failWithOwnedErrorMsg(&block.base, msg);
25312815 }
25322816
25332817 // Validate for duplicate items, missing else prong, and invalid range.
25342818 switch (operand.ty.zigTypeTag()) {
2535 .Enum => return sema.mod.fail(&block.base, src, "TODO validate switch .Enum", .{}),
2536 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),
2537 .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),
2819 .Enum => {
2820 var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount());
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", .{}),
25382931 .Int, .ComptimeInt => {
25392932 var range_set = RangeSet.init(gpa);
25402933 defer range_set.deinit();
......@@ -2607,11 +3000,11 @@ fn analyzeSwitch(
26073000 var arena = std.heap.ArenaAllocator.init(gpa);
26083001 defer arena.deinit();
26093002
2610 const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());
2611 const max_int = try operand.ty.maxInt(&arena, sema.mod.getTarget());
3003 const min_int = try operand.ty.minInt(&arena, mod.getTarget());
3004 const max_int = try operand.ty.maxInt(&arena, mod.getTarget());
26123005 if (try range_set.spans(min_int, max_int)) {
26133006 if (special_prong == .@"else") {
2614 return sema.mod.fail(
3007 return mod.fail(
26153008 &block.base,
26163009 special_prong_src,
26173010 "unreachable else prong; all cases already handled",
......@@ -2622,7 +3015,7 @@ fn analyzeSwitch(
26223015 }
26233016 }
26243017 if (special_prong != .@"else") {
2625 return sema.mod.fail(
3018 return mod.fail(
26263019 &block.base,
26273020 src,
26283021 "switch must handle all possibilities",
......@@ -2685,7 +3078,7 @@ fn analyzeSwitch(
26853078 switch (special_prong) {
26863079 .@"else" => {
26873080 if (true_count + false_count == 2) {
2688 return sema.mod.fail(
3081 return mod.fail(
26893082 &block.base,
26903083 src,
26913084 "unreachable else prong; all cases already handled",
......@@ -2695,7 +3088,7 @@ fn analyzeSwitch(
26953088 },
26963089 .under, .none => {
26973090 if (true_count + false_count < 2) {
2698 return sema.mod.fail(
3091 return mod.fail(
26993092 &block.base,
27003093 src,
27013094 "switch must handle all possibilities",
......@@ -2707,7 +3100,7 @@ fn analyzeSwitch(
27073100 },
27083101 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
27093102 if (special_prong != .@"else") {
2710 return sema.mod.fail(
3103 return mod.fail(
27113104 &block.base,
27123105 src,
27133106 "else prong required when switching on type '{}'",
......@@ -2779,7 +3172,7 @@ fn analyzeSwitch(
27793172 .AnyFrame,
27803173 .ComptimeFloat,
27813174 .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 '{}'", .{
27833176 operand.ty,
27843177 }),
27853178 }
......@@ -3054,7 +3447,7 @@ fn resolveSwitchItemVal(
30543447 switch_node_offset: i32,
30553448 switch_prong_src: AstGen.SwitchProngSrc,
30563449 range_expand: AstGen.SwitchProngSrc.RangeExpand,
3057) InnerError!Value {
3450) InnerError!TypedValue {
30583451 const item = try sema.resolveInst(item_ref);
30593452 // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc
30603453 // because we only have the switch AST node. Only if we know for sure we need to report
......@@ -3064,7 +3457,7 @@ fn resolveSwitchItemVal(
30643457 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
30653458 return sema.failWithUseOfUndef(block, src);
30663459 }
3067 return val;
3460 return TypedValue{ .ty = item.ty, .val = val };
30683461 }
30693462 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
30703463 return sema.failWithNeededComptime(block, src);
......@@ -3079,8 +3472,8 @@ fn validateSwitchRange(
30793472 src_node_offset: i32,
30803473 switch_prong_src: AstGen.SwitchProngSrc,
30813474) InnerError!void {
3082 const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
3083 const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
3475 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
3476 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
30843477 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
30853478 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
30863479}
......@@ -3093,11 +3486,46 @@ fn validateSwitchItem(
30933486 src_node_offset: i32,
30943487 switch_prong_src: AstGen.SwitchProngSrc,
30953488) 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;
30973490 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
30983491 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
30993492}
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
31013529fn validateSwitchDupe(
31023530 sema: *Sema,
31033531 block: *Scope.Block,
......@@ -3106,17 +3534,18 @@ fn validateSwitchDupe(
31063534 src_node_offset: i32,
31073535) InnerError!void {
31083536 const prev_prong_src = maybe_prev_src orelse return;
3537 const mod = sema.mod;
31093538 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
31103539 const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none);
31113540 const msg = msg: {
3112 const msg = try sema.mod.errMsg(
3541 const msg = try mod.errMsg(
31133542 &block.base,
31143543 src,
31153544 "duplicate switch value",
31163545 .{},
31173546 );
31183547 errdefer msg.destroy(sema.gpa);
3119 try sema.mod.errNote(
3548 try mod.errNote(
31203549 &block.base,
31213550 prev_src,
31223551 msg,
......@@ -3125,7 +3554,7 @@ fn validateSwitchDupe(
31253554 );
31263555 break :msg msg;
31273556 };
3128 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
3557 return mod.failWithOwnedErrorMsg(&block.base, msg);
31293558}
31303559
31313560fn validateSwitchItemBool(
......@@ -3137,7 +3566,7 @@ fn validateSwitchItemBool(
31373566 src_node_offset: i32,
31383567 switch_prong_src: AstGen.SwitchProngSrc,
31393568) 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;
31413570 if (item_val.toBool()) {
31423571 true_count.* += 1;
31433572 } else {
......@@ -3159,7 +3588,7 @@ fn validateSwitchItemSparse(
31593588 src_node_offset: i32,
31603589 switch_prong_src: AstGen.SwitchProngSrc,
31613590) 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;
31633592 const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
31643593 return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);
31653594}
......@@ -3197,6 +3626,34 @@ fn validateSwitchNoRange(
31973626 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
31983627}
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
32003657fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
32013658 const tracy = trace(@src());
32023659 defer tracy.end();
......@@ -3448,6 +3905,7 @@ fn analyzeArithmetic(
34483905 .subwrap => .subwrap,
34493906 .mul => .mul,
34503907 .mulwrap => .mulwrap,
3908 .div => .div,
34513909 else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}''", .{@tagName(zir_tag)}),
34523910 };
34533911
......@@ -3539,9 +3997,13 @@ fn zirCmp(
35393997 const tracy = trace(@src());
35403998 defer tracy.end();
35413999
4000 const mod = sema.mod;
4001
35424002 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
35434003 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
35444004 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 };
35454007 const lhs = try sema.resolveInst(extra.lhs);
35464008 const rhs = try sema.resolveInst(extra.rhs);
35474009
......@@ -3553,7 +4015,7 @@ fn zirCmp(
35534015 const rhs_ty_tag = rhs.ty.zigTypeTag();
35544016 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
35554017 // null == null, null != null
3556 return sema.mod.constBool(sema.arena, src, op == .eq);
4018 return mod.constBool(sema.arena, src, op == .eq);
35574019 } else if (is_equality_cmp and
35584020 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
35594021 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
......@@ -3564,23 +4026,23 @@ fn zirCmp(
35644026 } else if (is_equality_cmp and
35654027 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
35664028 {
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", .{});
35684030 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
35694031 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});
35714033 } else if (is_equality_cmp and
35724034 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
35734035 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
35744036 {
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", .{});
35764038 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
35774039 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)});
35794041 }
35804042 if (rhs.value()) |rval| {
35814043 if (lhs.value()) |lval| {
35824044 // 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));
35844046 }
35854047 }
35864048 try sema.requireRuntimeBlock(block, src);
......@@ -3592,11 +4054,36 @@ fn zirCmp(
35924054 return sema.cmpNumeric(block, src, lhs, rhs, op);
35934055 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
35944056 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)});
35964058 }
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));
35984060 }
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", .{});
36004087}
36014088
36024089fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
......@@ -3740,7 +4227,7 @@ fn zirBoolBr(
37404227 _ = try rhs_block.addBr(src, block_inst, rhs_result);
37414228
37424229 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) };
37444231 _ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body);
37454232
37464233 block_inst.body = .{
......@@ -4016,6 +4503,18 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
40164503 });
40174504}
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
40194518fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
40204519 if (sema.func == null) {
40214520 return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
......@@ -4123,22 +4622,25 @@ fn namedFieldPtr(
41234622 field_name: []const u8,
41244623 field_name_src: LazySrcLoc,
41254624) InnerError!*Inst {
4625 const mod = sema.mod;
4626 const arena = sema.arena;
4627
41264628 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
41274629 .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}),
41294631 };
41304632 switch (elem_ty.zigTypeTag()) {
41314633 .Array => {
41324634 if (mem.eql(u8, field_name, "len")) {
4133 return sema.mod.constInst(sema.arena, src, .{
4635 return mod.constInst(arena, src, .{
41344636 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
41354637 .val = try Value.Tag.ref_val.create(
4136 sema.arena,
4137 try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()),
4638 arena,
4639 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
41384640 ),
41394641 });
41404642 } else {
4141 return sema.mod.fail(
4643 return mod.fail(
41424644 &block.base,
41434645 field_name_src,
41444646 "no member named '{s}' in '{}'",
......@@ -4151,15 +4653,15 @@ fn namedFieldPtr(
41514653 switch (ptr_child.zigTypeTag()) {
41524654 .Array => {
41534655 if (mem.eql(u8, field_name, "len")) {
4154 return sema.mod.constInst(sema.arena, src, .{
4656 return mod.constInst(arena, src, .{
41554657 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
41564658 .val = try Value.Tag.ref_val.create(
4157 sema.arena,
4158 try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()),
4659 arena,
4660 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
41594661 ),
41604662 });
41614663 } else {
4162 return sema.mod.fail(
4664 return mod.fail(
41634665 &block.base,
41644666 field_name_src,
41654667 "no member named '{s}' in '{}'",
......@@ -4174,7 +4676,7 @@ fn namedFieldPtr(
41744676 _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
41754677 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
41764678 const val = result.value().?;
4177 const child_type = try val.toType(sema.arena);
4679 const child_type = try val.toType(arena);
41784680 switch (child_type.zigTypeTag()) {
41794681 .ErrorSet => {
41804682 // TODO resolve inferred error sets
......@@ -4188,42 +4690,92 @@ fn namedFieldPtr(
41884690 break :blk name;
41894691 }
41904692 }
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 '{}'", .{
41924694 field_name,
41934695 child_type,
41944696 });
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, .{
4198 .ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One),
4699 return mod.constInst(arena, src, .{
4700 .ty = try mod.simplePtrType(arena, child_type, false, .One),
41994701 .val = try Value.Tag.ref_val.create(
4200 sema.arena,
4201 try Value.Tag.@"error".create(sema.arena, .{
4702 arena,
4703 try Value.Tag.@"error".create(arena, .{
42024704 .name = name,
42034705 }),
42044706 ),
42054707 });
42064708 },
4207 .Struct => {
4208 const container_scope = child_type.getContainerScope();
4209 if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4210 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4211 return sema.analyzeDeclRef(block, src, decl);
4212 }
4709 .Struct, .Opaque, .Union => {
4710 if (child_type.getContainerScope()) |container_scope| {
4711 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4712 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))
4713 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
4714 return sema.analyzeDeclRef(block, src, decl);
4715 }
42134716
4214 if (container_scope.file_scope == sema.mod.root_scope) {
4215 return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});
4216 } else {
4217 return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
4717 // TODO this will give false positives for structs inside the root file
4718 if (container_scope.file_scope == mod.root_scope) {
4719 return mod.fail(
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 }
42184745 }
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 });
42194771 },
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}),
42214773 }
42224774 },
42234775 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
42244776 else => {},
42254777 }
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});
42274779}
42284780
42294781fn analyzeStructFieldPtr(
......@@ -4241,12 +4793,8 @@ fn analyzeStructFieldPtr(
42414793
42424794 const struct_obj = elem_ty.castTag(.@"struct").?.data;
42434795
4244 const field_index = struct_obj.fields.getIndex(field_name) orelse {
4245 // TODO note: struct S declared here
4246 return mod.fail(&block.base, field_name_src, "no field named '{s}' in struct '{}'", .{
4247 field_name, elem_ty,
4248 });
4249 };
4796 const field_index = struct_obj.fields.getIndex(field_name) orelse
4797 return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
42504798 const field = struct_obj.fields.entries.items[field_index].value;
42514799 const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);
42524800 // TODO comptime field access
......@@ -4262,37 +4810,51 @@ fn elemPtr(
42624810 elem_index: *Inst,
42634811 elem_index_src: LazySrcLoc,
42644812) InnerError!*Inst {
4265 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
4813 const array_ty = switch (array_ptr.ty.zigTypeTag()) {
42664814 .Pointer => array_ptr.ty.elemType(),
42674815 else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
42684816 };
4269 if (!elem_ty.isIndexable()) {
4270 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{elem_ty});
4817 if (!array_ty.isIndexable()) {
4818 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{array_ty});
42714819 }
4272
4273 if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
4820 if (array_ty.isSinglePointer() and array_ty.elemType().zigTypeTag() == .Array) {
42744821 // we have to deref the ptr operand to get the actual array pointer
42754822 const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);
4276 if (array_ptr_deref.value()) |array_ptr_val| {
4277 if (elem_index.value()) |index_val| {
4278 // Both array pointer and index are compile-time known.
4279 const index_u64 = index_val.toUnsignedInt();
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 }
4823 return sema.elemPtrArray(block, src, array_ptr_deref, elem_index, elem_index_src);
4824 }
4825 if (array_ty.zigTypeTag() == .Array) {
4826 return sema.elemPtrArray(block, src, array_ptr, elem_index, elem_index_src);
42914827 }
42924828
42934829 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});
42944830}
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
42964858fn coerce(
42974859 sema: *Sema,
42984860 block: *Scope.Block,
......@@ -4312,10 +4874,13 @@ fn coerce(
43124874 return sema.bitcast(block, dest_type, inst);
43134875 }
43144876
4877 const mod = sema.mod;
4878 const arena = sema.arena;
4879
43154880 // undefined to anything
43164881 if (inst.value()) |val| {
43174882 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 });
43194884 }
43204885 }
43214886 assert(inst.ty.zigTypeTag() != .Undefined);
......@@ -4329,13 +4894,13 @@ fn coerce(
43294894 if (try sema.coerceNum(block, dest_type, inst)) |some|
43304895 return some;
43314896
4332 const target = sema.mod.getTarget();
4897 const target = mod.getTarget();
43334898
43344899 switch (dest_type.zigTypeTag()) {
43354900 .Optional => {
43364901 // null to ?T
43374902 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) });
43394904 }
43404905
43414906 // T to ?T
......@@ -4421,10 +4986,40 @@ fn coerce(
44214986 }
44224987 }
44234988 },
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 },
44245019 else => {},
44255020 }
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 });
44285023}
44295024
44305025const InMemoryCoercionResult = enum {
......@@ -4542,7 +5137,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
45425137}
45435138
45445139fn 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);
45465141 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
45475142 if (sema.func) |func| {
45485143 func.state = .dependency_failure;
......@@ -4742,9 +5337,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
47425337 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
47435338 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| {
47465341 sema.gpa.free(resolved_path);
4747 return some;
5342 return cached_import;
47485343 }
47495344
47505345 if (found_pkg == null) {
......@@ -4762,6 +5357,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
47625357 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);
47635358 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
47655365 file_scope.* = .{
47665366 .sub_file_path = resolved_path,
47675367 .source = .{ .unloaded = {} },
......@@ -4772,6 +5372,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
47725372 .file_scope = file_scope,
47735373 .decls = .{},
47745374 .ty = struct_ty,
5375 .parent_name_hash = container_name_hash,
47755376 },
47765377 };
47775378 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
src/clang.zig+27
......@@ -300,6 +300,14 @@ pub const ConstantExpr = opaque {};
300300
301301pub 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
303311pub const DecayedType = opaque {
304312 pub const getDecayedType = ZigClangDecayedType_getDecayedType;
305313 extern fn ZigClangDecayedType_getDecayedType(*const DecayedType) QualType;
......@@ -748,6 +756,14 @@ pub const ReturnStmt = opaque {
748756 extern fn ZigClangReturnStmt_getRetValue(*const ReturnStmt) ?*const Expr;
749757};
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
751767pub const SourceManager = opaque {
752768 pub const getSpellingLoc = ZigClangSourceManager_getSpellingLoc;
753769 extern fn ZigClangSourceManager_getSpellingLoc(*const SourceManager, Loc: SourceLocation) SourceLocation;
......@@ -837,6 +853,9 @@ pub const Type = opaque {
837853 pub const isRecordType = ZigClangType_isRecordType;
838854 extern fn ZigClangType_isRecordType(*const Type) bool;
839855
856 pub const isVectorType = ZigClangType_isVectorType;
857 extern fn ZigClangType_isVectorType(*const Type) bool;
858
840859 pub const isIncompleteOrZeroLengthArrayType = ZigClangType_isIncompleteOrZeroLengthArrayType;
841860 extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(*const Type, *const ASTContext) bool;
842861
......@@ -937,6 +956,14 @@ pub const VarDecl = opaque {
937956 extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType;
938957};
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
940967pub const WhileStmt = opaque {
941968 pub const getCond = ZigClangWhileStmt_getCond;
942969 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 {
417417 const node_datas = tree.nodes.items(.data);
418418 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;
421421 assert(node_tags[fn_decl] == .fn_decl);
422422 const block = node_datas[fn_decl].rhs;
423423 const lbrace_src = token_starts[tree.firstToken(block)];
......@@ -855,6 +855,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
855855 .not => return self.genNot(inst.castTag(.not).?),
856856 .mul => return self.genMul(inst.castTag(.mul).?),
857857 .mulwrap => return self.genMulWrap(inst.castTag(.mulwrap).?),
858 .div => return self.genDiv(inst.castTag(.div).?),
858859 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
859860 .ref => return self.genRef(inst.castTag(.ref).?),
860861 .ret => return self.genRet(inst.castTag(.ret).?),
......@@ -1092,6 +1093,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10921093 }
10931094 }
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
10951105 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
10961106 // No side effects, so if it's unreferenced, do nothing.
10971107 if (inst.base.isUnused())
......@@ -1735,7 +1745,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17351745
17361746 switch (result) {
17371747 .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);
17391750 },
17401751 else => {},
17411752 }
......@@ -1783,8 +1794,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17831794 switch (mc_arg) {
17841795 .none => continue,
17851796 .register => |reg| {
1797 try self.register_manager.getRegWithoutTracking(reg);
17861798 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1787 // TODO interact with the register allocator to mark the instruction as moved.
17881799 },
17891800 .stack_offset => {
17901801 // Here we need to emit instructions like this:
......@@ -1925,8 +1936,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19251936 .compare_flags_signed => unreachable,
19261937 .compare_flags_unsigned => unreachable,
19271938 .register => |reg| {
1939 try self.register_manager.getRegWithoutTracking(reg);
19281940 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1929 // TODO interact with the register allocator to mark the instruction as moved.
19301941 },
19311942 .stack_offset => {
19321943 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 {
19881999 .compare_flags_signed => unreachable,
19892000 .compare_flags_unsigned => unreachable,
19902001 .register => |reg| {
2002 try self.register_manager.getRegWithoutTracking(reg);
19912003 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1992 // TODO interact with the register allocator to mark the instruction as moved.
19932004 },
19942005 .stack_offset => {
19952006 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 {
20392050 switch (mc_arg) {
20402051 .none => continue,
20412052 .register => |reg| {
2053 try self.register_manager.getRegWithoutTracking(reg);
20422054 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2043 // TODO interact with the register allocator to mark the instruction as moved.
20442055 },
20452056 .stack_offset => {
20462057 // Here we need to emit instructions like this:
......@@ -2704,8 +2715,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27042715 const reg_name = input[1 .. input.len - 1];
27052716 const reg = parseRegName(reg_name) orelse
27062717 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2707 const arg = try self.resolveInst(inst.args[i]);
2708 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2718
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);
27092723 }
27102724
27112725 if (mem.eql(u8, inst.asm_source, "svc #0")) {
......@@ -2734,8 +2748,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27342748 const reg_name = input[1 .. input.len - 1];
27352749 const reg = parseRegName(reg_name) orelse
27362750 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2737 const arg = try self.resolveInst(inst.args[i]);
2738 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2751
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);
27392756 }
27402757
27412758 if (mem.eql(u8, inst.asm_source, "svc #0")) {
......@@ -2766,8 +2783,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27662783 const reg_name = input[1 .. input.len - 1];
27672784 const reg = parseRegName(reg_name) orelse
27682785 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2769 const arg = try self.resolveInst(inst.args[i]);
2770 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2786
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);
27712791 }
27722792
27732793 if (mem.eql(u8, inst.asm_source, "ecall")) {
......@@ -2796,8 +2816,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27962816 const reg_name = input[1 .. input.len - 1];
27972817 const reg = parseRegName(reg_name) orelse
27982818 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2799 const arg = try self.resolveInst(inst.args[i]);
2800 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2819
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);
28012824 }
28022825
28032826 if (mem.eql(u8, inst.asm_source, "syscall")) {
......@@ -3302,6 +3325,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
33023325 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());
33033326 }
33043327 },
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 },
33053365 else => return self.fail(src, "TODO implement genSetReg for aarch64 {}", .{mcv}),
33063366 },
33073367 .riscv64 => switch (mcv) {
src/codegen/aarch64.zig+209-56
......@@ -200,7 +200,7 @@ test "FloatingPointRegister.toX" {
200200
201201/// Represents an instruction in the AArch64 instruction set
202202pub const Instruction = union(enum) {
203 MoveWideImmediate: packed struct {
203 move_wide_immediate: packed struct {
204204 rd: u5,
205205 imm16: u16,
206206 hw: u2,
......@@ -208,14 +208,14 @@ pub const Instruction = union(enum) {
208208 opc: u2,
209209 sf: u1,
210210 },
211 PCRelativeAddress: packed struct {
211 pc_relative_address: packed struct {
212212 rd: u5,
213213 immhi: u19,
214214 fixed: u5 = 0b10000,
215215 immlo: u2,
216216 op: u1,
217217 },
218 LoadStoreRegister: packed struct {
218 load_store_register: packed struct {
219219 rt: u5,
220220 rn: u5,
221221 offset: u12,
......@@ -225,7 +225,7 @@ pub const Instruction = union(enum) {
225225 fixed: u3 = 0b111,
226226 size: u2,
227227 },
228 LoadStorePairOfRegisters: packed struct {
228 load_store_register_pair: packed struct {
229229 rt1: u5,
230230 rn: u5,
231231 rt2: u5,
......@@ -235,20 +235,20 @@ pub const Instruction = union(enum) {
235235 fixed: u5 = 0b101_0_0,
236236 opc: u2,
237237 },
238 LoadLiteral: packed struct {
238 load_literal: packed struct {
239239 rt: u5,
240240 imm19: u19,
241241 fixed: u6 = 0b011_0_00,
242242 opc: u2,
243243 },
244 ExceptionGeneration: packed struct {
244 exception_generation: packed struct {
245245 ll: u2,
246246 op2: u3,
247247 imm16: u16,
248248 opc: u3,
249249 fixed: u8 = 0b1101_0100,
250250 },
251 UnconditionalBranchRegister: packed struct {
251 unconditional_branch_register: packed struct {
252252 op4: u5,
253253 rn: u5,
254254 op3: u6,
......@@ -256,15 +256,15 @@ pub const Instruction = union(enum) {
256256 opc: u4,
257257 fixed: u7 = 0b1101_011,
258258 },
259 UnconditionalBranchImmediate: packed struct {
259 unconditional_branch_immediate: packed struct {
260260 imm26: u26,
261261 fixed: u5 = 0b00101,
262262 op: u1,
263263 },
264 NoOperation: packed struct {
264 no_operation: packed struct {
265265 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
266266 },
267 LogicalShiftedRegister: packed struct {
267 logical_shifted_register: packed struct {
268268 rd: u5,
269269 rn: u5,
270270 imm6: u6,
......@@ -275,7 +275,7 @@ pub const Instruction = union(enum) {
275275 opc: u2,
276276 sf: u1,
277277 },
278 AddSubtractImmediate: packed struct {
278 add_subtract_immediate: packed struct {
279279 rd: u5,
280280 rn: u5,
281281 imm12: u12,
......@@ -285,6 +285,20 @@ pub const Instruction = union(enum) {
285285 op: u1,
286286 sf: u1,
287287 },
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
289303 pub const Shift = struct {
290304 shift: Type = .lsl,
......@@ -303,19 +317,73 @@ pub const Instruction = union(enum) {
303317 };
304318 };
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
306371 pub fn toU32(self: Instruction) u32 {
307372 return switch (self) {
308 .MoveWideImmediate => |v| @bitCast(u32, v),
309 .PCRelativeAddress => |v| @bitCast(u32, v),
310 .LoadStoreRegister => |v| @bitCast(u32, v),
311 .LoadStorePairOfRegisters => |v| @bitCast(u32, v),
312 .LoadLiteral => |v| @bitCast(u32, v),
313 .ExceptionGeneration => |v| @bitCast(u32, v),
314 .UnconditionalBranchRegister => |v| @bitCast(u32, v),
315 .UnconditionalBranchImmediate => |v| @bitCast(u32, v),
316 .NoOperation => |v| @bitCast(u32, v),
317 .LogicalShiftedRegister => |v| @bitCast(u32, v),
318 .AddSubtractImmediate => |v| @bitCast(u32, v),
373 .move_wide_immediate => |v| @bitCast(u32, v),
374 .pc_relative_address => |v| @bitCast(u32, v),
375 .load_store_register => |v| @bitCast(u32, v),
376 .load_store_register_pair => |v| @bitCast(u32, v),
377 .load_literal => |v| @bitCast(u32, v),
378 .exception_generation => |v| @bitCast(u32, v),
379 .unconditional_branch_register => |v| @bitCast(u32, v),
380 .unconditional_branch_immediate => |v| @bitCast(u32, v),
381 .no_operation => |v| @bitCast(u32, v),
382 .logical_shifted_register => |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),
319387 };
320388 }
321389
......@@ -329,7 +397,7 @@ pub const Instruction = union(enum) {
329397 32 => {
330398 assert(shift % 16 == 0 and shift <= 16);
331399 return Instruction{
332 .MoveWideImmediate = .{
400 .move_wide_immediate = .{
333401 .rd = rd.id(),
334402 .imm16 = imm16,
335403 .hw = @intCast(u2, shift / 16),
......@@ -341,7 +409,7 @@ pub const Instruction = union(enum) {
341409 64 => {
342410 assert(shift % 16 == 0 and shift <= 48);
343411 return Instruction{
344 .MoveWideImmediate = .{
412 .move_wide_immediate = .{
345413 .rd = rd.id(),
346414 .imm16 = imm16,
347415 .hw = @intCast(u2, shift / 16),
......@@ -358,7 +426,7 @@ pub const Instruction = union(enum) {
358426 assert(rd.size() == 64);
359427 const imm21_u = @bitCast(u21, imm21);
360428 return Instruction{
361 .PCRelativeAddress = .{
429 .pc_relative_address = .{
362430 .rd = rd.id(),
363431 .immlo = @truncate(u2, imm21_u),
364432 .immhi = @truncate(u19, imm21_u >> 2),
......@@ -487,11 +555,17 @@ pub const Instruction = union(enum) {
487555 /// Which kind of load/store to perform
488556 const LoadStoreVariant = enum {
489557 /// 32-bit or 64-bit
490 normal,
491 /// 16-bit
492 half,
493 /// 8-bit
494 byte,
558 str,
559 /// 16-bit, zero-extended
560 strh,
561 /// 8-bit, zero-extended
562 strb,
563 /// 32-bit or 64-bit
564 ldr,
565 /// 16-bit, zero-extended
566 ldrh,
567 /// 8-bit, zero-extended
568 ldrb,
495569 };
496570
497571 fn loadStoreRegister(
......@@ -499,7 +573,6 @@ pub const Instruction = union(enum) {
499573 rn: Register,
500574 offset: LoadStoreOffset,
501575 variant: LoadStoreVariant,
502 load: bool,
503576 ) Instruction {
504577 const off = offset.toU12();
505578 const op1: u2 = blk: {
......@@ -512,9 +585,12 @@ pub const Instruction = union(enum) {
512585 }
513586 break :blk 0b00;
514587 };
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 };
516592 return Instruction{
517 .LoadStoreRegister = .{
593 .load_store_register = .{
518594 .rt = rt.id(),
519595 .rn = rn.id(),
520596 .offset = off,
......@@ -523,20 +599,20 @@ pub const Instruction = union(enum) {
523599 .v = 0,
524600 .size = blk: {
525601 switch (variant) {
526 .normal => switch (rt.size()) {
602 .ldr, .str => switch (rt.size()) {
527603 32 => break :blk 0b10,
528604 64 => break :blk 0b11,
529605 else => unreachable, // unexpected register size
530606 },
531 .half => break :blk 0b01,
532 .byte => break :blk 0b00,
607 .ldrh, .strh => break :blk 0b01,
608 .ldrb, .strb => break :blk 0b00,
533609 }
534610 },
535611 },
536612 };
537613 }
538614
539 fn loadStorePairOfRegisters(
615 fn loadStoreRegisterPair(
540616 rt1: Register,
541617 rt2: Register,
542618 rn: Register,
......@@ -549,7 +625,7 @@ pub const Instruction = union(enum) {
549625 assert(-256 <= offset and offset <= 252);
550626 const imm7 = @truncate(u7, @bitCast(u9, offset >> 2));
551627 return Instruction{
552 .LoadStorePairOfRegisters = .{
628 .load_store_register_pair = .{
553629 .rt1 = rt1.id(),
554630 .rn = rn.id(),
555631 .rt2 = rt2.id(),
......@@ -564,7 +640,7 @@ pub const Instruction = union(enum) {
564640 assert(-512 <= offset and offset <= 504);
565641 const imm7 = @truncate(u7, @bitCast(u9, offset >> 3));
566642 return Instruction{
567 .LoadStorePairOfRegisters = .{
643 .load_store_register_pair = .{
568644 .rt1 = rt1.id(),
569645 .rn = rn.id(),
570646 .rt2 = rt2.id(),
......@@ -583,7 +659,7 @@ pub const Instruction = union(enum) {
583659 switch (rt.size()) {
584660 32 => {
585661 return Instruction{
586 .LoadLiteral = .{
662 .load_literal = .{
587663 .rt = rt.id(),
588664 .imm19 = imm19,
589665 .opc = 0b00,
......@@ -592,7 +668,7 @@ pub const Instruction = union(enum) {
592668 },
593669 64 => {
594670 return Instruction{
595 .LoadLiteral = .{
671 .load_literal = .{
596672 .rt = rt.id(),
597673 .imm19 = imm19,
598674 .opc = 0b01,
......@@ -610,7 +686,7 @@ pub const Instruction = union(enum) {
610686 imm16: u16,
611687 ) Instruction {
612688 return Instruction{
613 .ExceptionGeneration = .{
689 .exception_generation = .{
614690 .ll = ll,
615691 .op2 = op2,
616692 .imm16 = imm16,
......@@ -629,7 +705,7 @@ pub const Instruction = union(enum) {
629705 assert(rn.size() == 64);
630706
631707 return Instruction{
632 .UnconditionalBranchRegister = .{
708 .unconditional_branch_register = .{
633709 .op4 = op4,
634710 .rn = rn.id(),
635711 .op3 = op3,
......@@ -644,7 +720,7 @@ pub const Instruction = union(enum) {
644720 offset: i28,
645721 ) Instruction {
646722 return Instruction{
647 .UnconditionalBranchImmediate = .{
723 .unconditional_branch_immediate = .{
648724 .imm26 = @bitCast(u26, @intCast(i26, offset >> 2)),
649725 .op = op,
650726 },
......@@ -663,7 +739,7 @@ pub const Instruction = union(enum) {
663739 32 => {
664740 assert(shift.amount < 32);
665741 return Instruction{
666 .LogicalShiftedRegister = .{
742 .logical_shifted_register = .{
667743 .rd = rd.id(),
668744 .rn = rn.id(),
669745 .imm6 = shift.amount,
......@@ -677,7 +753,7 @@ pub const Instruction = union(enum) {
677753 },
678754 64 => {
679755 return Instruction{
680 .LogicalShiftedRegister = .{
756 .logical_shifted_register = .{
681757 .rd = rd.id(),
682758 .rn = rn.id(),
683759 .imm6 = shift.amount,
......@@ -702,7 +778,7 @@ pub const Instruction = union(enum) {
702778 shift: bool,
703779 ) Instruction {
704780 return Instruction{
705 .AddSubtractImmediate = .{
781 .add_subtract_immediate = .{
706782 .rd = rd.id(),
707783 .rn = rn.id(),
708784 .imm12 = imm12,
......@@ -718,6 +794,43 @@ pub const Instruction = union(enum) {
718794 };
719795 }
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
721834 // Helper functions for assembly syntax functions
722835
723836 // Move wide (immediate)
......@@ -756,25 +869,33 @@ pub const Instruction = union(enum) {
756869
757870 pub fn ldr(rt: Register, args: LdrArgs) Instruction {
758871 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),
760873 .literal => |literal| return loadLiteral(rt, literal),
761874 }
762875 }
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
764885 pub const StrArgs = struct {
765886 offset: LoadStoreOffset = LoadStoreOffset.none,
766887 };
767888
768889 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);
770891 }
771892
772893 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);
774895 }
775896
776897 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);
778899 }
779900
780901 // Load or store pair of registers
......@@ -805,19 +926,19 @@ pub const Instruction = union(enum) {
805926 };
806927
807928 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);
809930 }
810931
811932 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);
813934 }
814935
815936 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);
817938 }
818939
819940 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);
821942 }
822943
823944 // Exception generation
......@@ -869,7 +990,7 @@ pub const Instruction = union(enum) {
869990 // Nop
870991
871992 pub fn nop() Instruction {
872 return Instruction{ .NoOperation = .{} };
993 return Instruction{ .no_operation = .{} };
873994 }
874995
875996 // Logical (shifted register)
......@@ -923,6 +1044,22 @@ pub const Instruction = union(enum) {
9231044 pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
9241045 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
9251046 }
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 }
9261063};
9271064
9281065test {
......@@ -1004,6 +1141,14 @@ test "serialize instructions" {
10041141 .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }),
10051142 .expected = 0b01_011_0_00_0000000000000000001_00010,
10061143 },
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 },
10071152 .{ // str x2, [x1]
10081153 .inst = Instruction.str(.x2, .x1, .{}),
10091154 .expected = 0b11_111_0_01_00_000000000000_00001_00010,
......@@ -1068,6 +1213,14 @@ test "serialize instructions" {
10681213 .inst = Instruction.subs(.x0, .x5, 11, true),
10691214 .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000,
10701215 },
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 },
10711224 };
10721225
10731226 for (testcases) |case| {
src/codegen/c.zig+164-17
......@@ -44,22 +44,34 @@ fn formatTypeAsCIdentifier(
4444 var buffer = [1]u8{0} ** 128;
4545 // We don't care if it gets cut off, it's still more unique than a number
4646 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| {
4961 switch (c) {
50 0 => return writer.writeAll(buf[0..i]),
51 'a'...'z', 'A'...'Z', '_', '$' => {},
62 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),
5263 '0'...'9' => if (i == 0) {
53 buf[i] = '_';
64 try writer.print("${x:2}", .{c});
65 } else {
66 try writer.writeByte(c);
5467 },
55 else => buf[i] = '_',
68 else => try writer.print("${x:2}", .{c}),
5669 }
5770 }
58 return writer.writeAll(buf);
5971}
6072
61pub fn typeToCIdentifier(t: Type) std.fmt.Formatter(formatTypeAsCIdentifier) {
62 return .{ .data = t };
73pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
74 return .{ .data = ident };
6375}
6476
6577/// This data is available when outputting .c code for a Module.
......@@ -160,7 +172,10 @@ pub const DeclGen = struct {
160172 val: Value,
161173 ) error{ OutOfMemory, AnalysisFail }!void {
162174 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", .{});
164179 }
165180 switch (t.zigTypeTag()) {
166181 .Int => {
......@@ -276,6 +291,31 @@ pub const DeclGen = struct {
276291 try writer.writeAll(", .error = 0 }");
277292 }
278293 },
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 },
279319 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
280320 @tagName(e),
281321 }),
......@@ -356,6 +396,9 @@ pub const DeclGen = struct {
356396 else => unreachable,
357397 }
358398 },
399
400 .Float => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Float", .{}),
401
359402 .Pointer => {
360403 if (t.isSlice()) {
361404 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});
......@@ -430,10 +473,59 @@ pub const DeclGen = struct {
430473 try w.writeAll(name);
431474 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
432475 },
433 .Null, .Undefined => unreachable, // must be const or comptime
434 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{
435 @tagName(e),
436 }),
476 .Struct => {
477 if (dg.typedefs.get(t)) |some| {
478 return w.writeAll(some.name);
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
437529 }
438530 }
439531
......@@ -525,8 +617,26 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
525617
526618 for (body.instructions) |inst| {
527619 const result_value = switch (inst.tag) {
528 .constant => unreachable, // excluded from function bodies
620 // TODO use a different strategy for add that communicates to the optimizer
621 // that wrapping is UB.
529622 .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
530640 .alloc => try genAlloc(o, inst.castTag(.alloc).?),
531641 .arg => genArg(o),
532642 .assembly => try genAsm(o, inst.castTag(.assembly).?),
......@@ -546,7 +656,6 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
546656 .ret => try genRet(o, inst.castTag(.ret).?),
547657 .retvoid => try genRetVoid(o),
548658 .store => try genStore(o, inst.castTag(.store).?),
549 .sub => try genBinOp(o, inst.castTag(.sub).?, " - "),
550659 .unreach => try genUnreach(o, inst.castTag(.unreach).?),
551660 .loop => try genLoop(o, inst.castTag(.loop).?),
552661 .condbr => try genCondBr(o, inst.castTag(.condbr).?),
......@@ -567,17 +676,24 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
567676 .wrap_optional => try genWrapOptional(o, inst.castTag(.wrap_optional).?),
568677 .optional_payload => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
569678 .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
570682 .is_err => try genIsErr(o, inst.castTag(.is_err).?),
571683 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),
572684 .error_to_int => try genErrorToInt(o, inst.castTag(.error_to_int).?),
573685 .int_to_error => try genIntToError(o, inst.castTag(.int_to_error).?),
686
574687 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
575688 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
576689 .unwrap_errunion_payload_ptr => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload_ptr).?),
577690 .unwrap_errunion_err_ptr => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err_ptr).?),
578691 .wrap_errunion_payload => try genWrapErrUnionPay(o, inst.castTag(.wrap_errunion_payload).?),
579692 .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", .{}),
581697 };
582698 switch (result_value) {
583699 .none => {},
......@@ -996,6 +1112,37 @@ fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue {
9961112 return local;
9971113}
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
9991146// *(E!T) -> E NOT *E
10001147fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {
10011148 const writer = o.writer();
......@@ -1088,7 +1235,7 @@ fn IndentWriter(comptime UnderlyingWriter: type) type {
10881235 pub const Error = UnderlyingWriter.Error;
10891236 pub const Writer = std.io.Writer(*Self, Error, write);
10901237
1091 pub const indent_delta = 4;
1238 pub const indent_delta = 1;
10921239
10931240 underlying_writer: UnderlyingWriter,
10941241 indent_count: usize = 0,
src/codegen/llvm.zig-1
......@@ -76,7 +76,6 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
7676 .spirv32 => return error.LLVMBackendDoesNotSupportSPIRV,
7777 .spirv64 => return error.LLVMBackendDoesNotSupportSPIRV,
7878 };
79 // TODO Add a sub-arch for some architectures depending on CPU features.
8079
8180 const llvm_os = switch (target.os.tag) {
8281 .freestanding => "unknown",
src/codegen/wasm.zig+623-139
......@@ -2,6 +2,7 @@ const std = @import("std");
22const Allocator = std.mem.Allocator;
33const ArrayList = std.ArrayList;
44const assert = std.debug.assert;
5const testing = std.testing;
56const leb = std.leb;
67const mem = std.mem;
78const wasm = std.wasm;
......@@ -15,9 +16,12 @@ const Value = @import("../value.zig").Value;
1516const Compilation = @import("../Compilation.zig");
1617const AnyMCValue = @import("../codegen.zig").AnyMCValue;
1718const LazySrcLoc = Module.LazySrcLoc;
19const link = @import("../link.zig");
20const TypedValue = @import("../TypedValue.zig");
1821
1922/// Wasm Value, created when generating an instruction
2023const WValue = union(enum) {
24 /// May be referenced but is unused
2125 none: void,
2226 /// Index of the local variable
2327 local: u32,
......@@ -29,6 +33,450 @@ const WValue = union(enum) {
2933 block_idx: u32,
3034};
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
32480/// Hashmap to store generated `WValue` for each `Inst`
33481pub const ValueTable = std.AutoHashMapUnmanaged(*Inst, WValue);
34482
......@@ -58,10 +506,14 @@ pub const Context = struct {
58506 /// List of all locals' types generated throughout this declaration
59507 /// used to emit locals count at start of 'code' section.
60508 locals: std.ArrayListUnmanaged(u8),
509 /// The Target we're emitting (used to call intInfo)
510 target: std.Target,
61511
62512 const InnerError = error{
63513 OutOfMemory,
64514 CodegenFail,
515 /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed
516 AnalysisFail,
65517 };
66518
67519 pub fn deinit(self: *Context) void {
......@@ -89,17 +541,31 @@ pub const Context = struct {
89541 return self.values.get(inst).?; // Instruction does not dominate all uses!
90542 }
91543
92 /// Using a given `Type`, returns the corresponding wasm value type
93 fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
94 return switch (ty.tag()) {
95 .f32 => wasm.valtype(.f32),
96 .f64 => wasm.valtype(.f64),
97 .u32, .i32, .bool => wasm.valtype(.i32),
98 .u64, .i64 => wasm.valtype(.i64),
99 else => self.fail(src, "TODO - Wasm genValtype for type '{s}'", .{ty.tag()}),
544 /// Using a given `Type`, returns the corresponding wasm Valtype
545 fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype {
546 return switch (ty.zigTypeTag()) {
547 .Float => blk: {
548 const bits = ty.floatBits(self.target);
549 if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32;
550 if (bits == 64) break :blk wasm.Valtype.f64;
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()}),
100561 };
101562 }
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
103569 /// Using a given `Type`, returns the corresponding wasm value type
104570 /// Differently from `genValtype` this also allows `void` to create a block
105571 /// with no return type
......@@ -157,59 +623,97 @@ pub const Context = struct {
157623 }
158624
159625 /// Generates the wasm bytecode for the function declaration belonging to `Context`
160 pub fn gen(self: *Context) InnerError!void {
161 assert(self.code.items.len == 0);
162 try self.genFunctype();
163
164 // Write instructions
165 // TODO: check for and handle death of instructions
166 const tv = self.decl.typed_value.most_recent.typed_value;
167 const mod_fn = blk: {
168 if (tv.val.castTag(.function)) |func| break :blk func.data;
169 if (tv.val.castTag(.extern_fn)) |ext_fn| return; // don't need codegen for extern functions
170 return self.fail(.{ .node_offset = 0 }, "TODO: Wasm codegen for decl type '{s}'", .{tv.ty.tag()});
171 };
172
173 // Reserve space to write the size after generating the code as well as space for locals count
174 try self.code.resize(10);
175
176 try self.genBody(mod_fn.body);
177
178 // finally, write our local types at the 'offset' position
179 {
180 leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
181
182 // offset into 'code' section where we will put our locals types
183 var local_offset: usize = 10;
184
185 // emit the actual locals amount
186 for (self.locals.items) |local| {
187 var buf: [6]u8 = undefined;
188 leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
189 buf[5] = local;
190 try self.code.insertSlice(local_offset, &buf);
191 local_offset += 6;
192 }
626 pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
627 switch (typed_value.ty.zigTypeTag()) {
628 .Fn => {
629 try self.genFunctype();
630
631 // Write instructions
632 // TODO: check for and handle death of instructions
633 const mod_fn = blk: {
634 if (typed_value.val.castTag(.function)) |func| break :blk func.data;
635 if (typed_value.val.castTag(.extern_fn)) |ext_fn| return Result.appended; // don't need code body for extern functions
636 unreachable;
637 };
638
639 // Reserve space to write the size after generating the code as well as space for locals count
640 try self.code.resize(10);
641
642 try self.genBody(mod_fn.body);
643
644 // finally, write our local types at the 'offset' position
645 {
646 leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
647
648 // offset into 'code' section where we will put our locals types
649 var local_offset: usize = 10;
650
651 // emit the actual locals amount
652 for (self.locals.items) |local| {
653 var buf: [6]u8 = undefined;
654 leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
655 buf[5] = local;
656 try self.code.insertSlice(local_offset, &buf);
657 local_offset += 6;
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}),
193701 }
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));
202702 }
203703
204704 fn genInst(self: *Context, inst: *Inst) InnerError!WValue {
205705 return switch (inst.tag) {
206 .add => self.genAdd(inst.castTag(.add).?),
706 .add => self.genBinOp(inst.castTag(.add).?, .add),
207707 .alloc => self.genAlloc(inst.castTag(.alloc).?),
208708 .arg => self.genArg(inst.castTag(.arg).?),
209709 .block => self.genBlock(inst.castTag(.block).?),
210710 .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
211711 .br => self.genBr(inst.castTag(.br).?),
212712 .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"),
213717 .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
214718 .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
215719 .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
......@@ -221,10 +725,14 @@ pub const Context = struct {
221725 .dbg_stmt => WValue.none,
222726 .load => self.genLoad(inst.castTag(.load).?),
223727 .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),
224731 .not => self.genNot(inst.castTag(.not).?),
225732 .ret => self.genRet(inst.castTag(.ret).?),
226733 .retvoid => WValue.none,
227734 .store => self.genStore(inst.castTag(.store).?),
735 .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
228736 .unreach => self.genUnreachable(inst.castTag(.unreach).?),
229737 else => self.fail(inst.src, "TODO: Implement wasm inst: {s}", .{inst.tag}),
230738 };
......@@ -266,7 +774,7 @@ pub const Context = struct {
266774
267775 // The function index immediate argument will be filled in using this data
268776 // 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, .{
270778 .offset = @intCast(u32, self.code.items.len),
271779 .decl = target,
272780 });
......@@ -305,56 +813,76 @@ pub const Context = struct {
305813 return WValue{ .local = self.local_index };
306814 }
307815
308 fn genAdd(self: *Context, inst: *Inst.BinOp) InnerError!WValue {
816 fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue {
309817 const lhs = self.resolveInst(inst.lhs);
310818 const rhs = self.resolveInst(inst.rhs);
311819
312820 try self.emitWValue(lhs);
313821 try self.emitWValue(rhs);
314822
315 const opcode: wasm.Opcode = switch (inst.base.ty.tag()) {
316 .u32, .i32 => .i32_add,
317 .u64, .i64 => .i64_add,
318 .f32 => .f32_add,
319 .f64 => .f64_add,
320 else => return self.fail(inst.base.src, "TODO - Implement wasm genAdd for type '{s}'", .{inst.base.ty.tag()}),
321 };
322
823 const opcode: wasm.Opcode = buildOpcode(.{
824 .op = op,
825 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
826 .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
827 });
323828 try self.code.append(wasm.opcode(opcode));
324829 return .none;
325830 }
326831
327832 fn emitConstant(self: *Context, inst: *Inst.Constant) InnerError!void {
328833 const writer = self.code.writer();
329 switch (inst.base.ty.tag()) {
330 .u32 => {
331 try writer.writeByte(wasm.opcode(.i32_const));
332 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
834 switch (inst.base.ty.zigTypeTag()) {
835 .Int => {
836 // write opcode
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 }
333847 },
334 .i32, .bool => {
848 .Bool => {
849 // write opcode
335850 try writer.writeByte(wasm.opcode(.i32_const));
851 // write constant
336852 try leb.writeILEB128(writer, inst.val.toSignedInt());
337853 },
338 .u64 => {
339 try writer.writeByte(wasm.opcode(.i64_const));
340 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
341 },
342 .i64 => {
343 try writer.writeByte(wasm.opcode(.i64_const));
344 try leb.writeILEB128(writer, inst.val.toSignedInt());
854 .Float => {
855 // write opcode
856 const opcode: wasm.Opcode = buildOpcode(.{
857 .op = .@"const",
858 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
859 });
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 }
345867 },
346 .f32 => {
347 try writer.writeByte(wasm.opcode(.f32_const));
348 // TODO: enforce LE byte order
349 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f32)));
868 .Pointer => {
869 if (inst.val.castTag(.decl_ref)) |payload| {
870 const decl = payload.data;
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()});
350883 },
351 .f64 => {
352 try writer.writeByte(wasm.opcode(.f64_const));
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}),
884 .Void => {},
885 else => |ty| return self.fail(inst.base.src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{ty}),
358886 }
359887 }
360888
......@@ -455,62 +983,18 @@ pub const Context = struct {
455983 try self.emitWValue(lhs);
456984 try self.emitWValue(rhs);
457985
458 const opcode_maybe: ?wasm.Opcode = switch (op) {
459 .lt => @as(?wasm.Opcode, switch (ty) {
460 .i32 => .i32_lt_s,
461 .u32 => .i32_lt_u,
462 .i64 => .i64_lt_s,
463 .u64 => .i64_lt_u,
464 .f32 => .f32_lt,
465 .f64 => .f64_lt,
466 else => null,
467 }),
468 .lte => @as(?wasm.Opcode, switch (ty) {
469 .i32 => .i32_le_s,
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
986 const opcode: wasm.Opcode = buildOpcode(.{
987 .valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty),
988 .op = switch (op) {
989 .lt => .lt,
990 .lte => .le,
991 .eq => .eq,
992 .neq => .ne,
993 .gte => .ge,
994 .gt => .gt,
995 },
996 .signedness = inst.lhs.ty.intInfo(self.target).signedness,
997 });
514998 try self.code.append(wasm.opcode(opcode));
515999 return WValue{ .code_offset = offset };
5161000 }
src/ir.zig+4
......@@ -115,6 +115,7 @@ pub const Inst = struct {
115115 unreach,
116116 mul,
117117 mulwrap,
118 div,
118119 not,
119120 floatcast,
120121 intcast,
......@@ -181,6 +182,7 @@ pub const Inst = struct {
181182 .subwrap,
182183 .mul,
183184 .mulwrap,
185 .div,
184186 .cmp_lt,
185187 .cmp_lte,
186188 .cmp_eq,
......@@ -752,6 +754,7 @@ const DumpTzir = struct {
752754 .subwrap,
753755 .mul,
754756 .mulwrap,
757 .div,
755758 .cmp_lt,
756759 .cmp_lte,
757760 .cmp_eq,
......@@ -891,6 +894,7 @@ const DumpTzir = struct {
891894 .subwrap,
892895 .mul,
893896 .mulwrap,
897 .div,
894898 .cmp_lt,
895899 .cmp_lte,
896900 .cmp_eq,
src/link.zig+4-3
......@@ -138,7 +138,7 @@ pub const File = struct {
138138 coff: Coff.TextBlock,
139139 macho: MachO.TextBlock,
140140 c: C.DeclBlock,
141 wasm: void,
141 wasm: Wasm.DeclBlock,
142142 spirv: void,
143143 };
144144
......@@ -147,7 +147,7 @@ pub const File = struct {
147147 coff: Coff.SrcFn,
148148 macho: MachO.SrcFn,
149149 c: C.FnBlock,
150 wasm: ?Wasm.FnData,
150 wasm: Wasm.FnData,
151151 spirv: SpirV.FnData,
152152 };
153153
......@@ -328,7 +328,8 @@ pub const File = struct {
328328 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
329329 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),
330330 .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),
331 .wasm, .spirv => {},
331 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),
332 .spirv => {},
332333 }
333334 }
334335
src/link/Elf.zig+2-4
......@@ -2228,10 +2228,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
22282228 const node_datas = tree.nodes.items(.data);
22292229 const token_starts = tree.tokens.items(.start);
22302230
2231 const file_ast_decls = tree.rootDecls();
22322231 // TODO Look into improving the performance here by adding a token-index-to-line
22332232 // 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;
22352234 assert(node_tags[fn_decl] == .fn_decl);
22362235 const block = node_datas[fn_decl].rhs;
22372236 const lbrace = tree.firstToken(block);
......@@ -2755,10 +2754,9 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
27552754 const node_datas = tree.nodes.items(.data);
27562755 const token_starts = tree.tokens.items(.start);
27572756
2758 const file_ast_decls = tree.rootDecls();
27592757 // TODO Look into improving the performance here by adding a token-index-to-line
27602758 // 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;
27622760 assert(node_tags[fn_decl] == .fn_decl);
27632761 const block = node_datas[fn_decl].rhs;
27642762 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 {
12561256 const inst = code_buffer.items[fixup.offset..][0..4];
12571257 var parsed = mem.bytesAsValue(meta.TagPayload(
12581258 aarch64.Instruction,
1259 aarch64.Instruction.PCRelativeAddress,
1259 aarch64.Instruction.pc_relative_address,
12601260 ), inst);
12611261 const this_page = @intCast(i32, this_addr >> 12);
12621262 const target_page = @intCast(i32, target_addr >> 12);
......@@ -1268,7 +1268,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
12681268 const inst = code_buffer.items[fixup.offset + 4 ..][0..4];
12691269 var parsed = mem.bytesAsValue(meta.TagPayload(
12701270 aarch64.Instruction,
1271 aarch64.Instruction.LoadStoreRegister,
1271 aarch64.Instruction.load_store_register,
12721272 ), inst);
12731273 const narrowed = @truncate(u12, target_addr);
12741274 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
909909 const node_datas = tree.nodes.items(.data);
910910 const token_starts = tree.tokens.items(.start);
911911
912 const file_ast_decls = tree.rootDecls();
913912 // TODO Look into improving the performance here by adding a token-index-to-line
914913 // 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;
916915 assert(node_tags[fn_decl] == .fn_decl);
917916 const block = node_datas[fn_decl].rhs;
918917 const lbrace = tree.firstToken(block);
......@@ -959,10 +958,9 @@ pub fn initDeclDebugBuffers(
959958 const node_datas = tree.nodes.items(.data);
960959 const token_starts = tree.tokens.items(.start);
961960
962 const file_ast_decls = tree.rootDecls();
963961 // TODO Look into improving the performance here by adding a token-index-to-line
964962 // 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;
966964 assert(node_tags[fn_decl] == .fn_decl);
967965 const block = node_datas[fn_decl].rhs;
968966 const lbrace = tree.firstToken(block);
src/link/MachO/Zld.zig+6-6
......@@ -1668,7 +1668,7 @@ fn doRelocs(self: *Zld) !void {
16681668 var parsed = mem.bytesAsValue(
16691669 meta.TagPayload(
16701670 aarch64.Instruction,
1671 aarch64.Instruction.UnconditionalBranchImmediate,
1671 aarch64.Instruction.unconditional_branch_immediate,
16721672 ),
16731673 inst,
16741674 );
......@@ -1688,7 +1688,7 @@ fn doRelocs(self: *Zld) !void {
16881688 var parsed = mem.bytesAsValue(
16891689 meta.TagPayload(
16901690 aarch64.Instruction,
1691 aarch64.Instruction.PCRelativeAddress,
1691 aarch64.Instruction.pc_relative_address,
16921692 ),
16931693 inst,
16941694 );
......@@ -1706,7 +1706,7 @@ fn doRelocs(self: *Zld) !void {
17061706 var parsed = mem.bytesAsValue(
17071707 meta.TagPayload(
17081708 aarch64.Instruction,
1709 aarch64.Instruction.AddSubtractImmediate,
1709 aarch64.Instruction.add_subtract_immediate,
17101710 ),
17111711 inst,
17121712 );
......@@ -1719,7 +1719,7 @@ fn doRelocs(self: *Zld) !void {
17191719 var parsed = mem.bytesAsValue(
17201720 meta.TagPayload(
17211721 aarch64.Instruction,
1722 aarch64.Instruction.LoadStoreRegister,
1722 aarch64.Instruction.load_store_register,
17231723 ),
17241724 inst,
17251725 );
......@@ -1774,7 +1774,7 @@ fn doRelocs(self: *Zld) !void {
17741774 const curr = mem.bytesAsValue(
17751775 meta.TagPayload(
17761776 aarch64.Instruction,
1777 aarch64.Instruction.AddSubtractImmediate,
1777 aarch64.Instruction.add_subtract_immediate,
17781778 ),
17791779 inst,
17801780 );
......@@ -1783,7 +1783,7 @@ fn doRelocs(self: *Zld) !void {
17831783 const curr = mem.bytesAsValue(
17841784 meta.TagPayload(
17851785 aarch64.Instruction,
1786 aarch64.Instruction.LoadStoreRegister,
1786 aarch64.Instruction.load_store_register,
17871787 ),
17881788 inst,
17891789 );
src/link/Wasm.zig+279-62
......@@ -16,21 +16,11 @@ const link = @import("../link.zig");
1616const trace = @import("../tracy.zig").trace;
1717const build_options = @import("build_options");
1818const Cache = @import("../Cache.zig");
19const TypedValue = @import("../TypedValue.zig");
1920
2021pub 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
3223base: link.File,
33
3424/// List of all function Decls to be written to the output file. The index of
3525/// each Decl in this list at the time of writing the binary is used as the
3626/// 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) = .{},
4535/// to support existing code.
4636/// TODO: Allow setting this through a flag?
4737host_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
49110pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
50111 assert(options.object_format == .wasm);
......@@ -52,7 +113,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
52113 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForWasm; // TODO
53114 if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO
54115
55 // TODO: read the file and keep vaild parts instead of truncating
116 // TODO: read the file and keep valid parts instead of truncating
56117 const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
57118 errdefer file.close();
58119
......@@ -80,58 +141,76 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {
80141}
81142
82143pub fn deinit(self: *Wasm) void {
83 for (self.funcs.items) |decl| {
84 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
85 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
86 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);
144 for (self.symbols.items) |decl| {
145 decl.fn_link.wasm.functype.deinit(self.base.allocator);
146 decl.fn_link.wasm.code.deinit(self.base.allocator);
147 decl.fn_link.wasm.idx_refs.deinit(self.base.allocator);
92148 }
149
93150 self.funcs.deinit(self.base.allocator);
94151 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);
95155}
96156
97// Generate code for the Decl, storing it in memory to be later written to
98// the file on flush().
99pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
100 const typed_value = decl.typed_value.most_recent.typed_value;
101 if (typed_value.ty.zigTypeTag() != .Fn)
102 return error.TODOImplementNonFnDeclsForWasm;
157pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
158 if (decl.link.wasm.init) return;
159
160 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
161 try self.symbols.ensureCapacity(self.base.allocator, self.symbols.items.len + 1);
103162
104 if (decl.fn_link.wasm) |*fn_data| {
105 fn_data.functype.items.len = 0;
106 fn_data.code.items.len = 0;
107 fn_data.idx_refs.items.len = 0;
163 const block = &decl.link.wasm;
164 block.init = true;
165
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;
108171 } else {
109 decl.fn_link.wasm = .{};
110 // dependent on function type, appends it to the correct list
111 switch (decl.typed_value.most_recent.typed_value.val.tag()) {
172 block.offset_index = @intCast(u32, self.offset_table.items.len);
173 _ = self.offset_table.addOneAssumeCapacity();
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
112182 .function => try self.funcs.append(self.base.allocator, decl),
113183 .extern_fn => try self.ext_funcs.append(self.base.allocator, decl),
114 else => return error.TODOImplementNonFnDeclsForWasm,
184 else => unreachable,
115185 }
116186 }
117 const fn_data = &decl.fn_link.wasm.?;
187}
118188
119 var managed_functype = fn_data.functype.toManaged(self.base.allocator);
120 var managed_code = fn_data.code.toManaged(self.base.allocator);
189// Generate code for the Decl, storing it in memory to be later written to
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
122200 var context = codegen.Context{
123201 .gpa = self.base.allocator,
124202 .values = .{},
125 .code = managed_code,
126 .func_type_data = managed_functype,
203 .code = fn_data.code.toManaged(self.base.allocator),
204 .func_type_data = fn_data.functype.toManaged(self.base.allocator),
127205 .decl = decl,
128206 .err_msg = undefined,
129207 .locals = .{},
208 .target = self.base.options.target,
130209 };
131210 defer context.deinit();
132211
133212 // 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) {
135214 error.CodegenFail => {
136215 decl.analysis = .codegen_failure;
137216 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 {
140219 else => |e| return err,
141220 };
142221
143 // as locals are patched afterwards, the offsets of funcidx's are off,
144 // here we update them to correct them
145 for (decl.fn_link.wasm.?.idx_refs.items) |*func| {
146 // For each local, add 6 bytes (count + type)
147 func.offset += @intCast(u32, context.locals.items.len * 6);
148 }
222 const code: []const u8 = switch (result) {
223 .appended => @as([]const u8, context.code.items),
224 .externally_managed => |payload| payload,
225 };
149226
150 fn_data.functype = context.func_type_data.toUnmanaged();
151227 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;
152254}
153255
154256pub fn updateDeclExports(
......@@ -159,18 +261,34 @@ pub fn updateDeclExports(
159261) !void {}
160262
161263pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
162 // TODO: remove this assert when non-function Decls are implemented
163 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);
164 const func_idx = self.getFuncidx(decl).?;
165 switch (decl.typed_value.most_recent.typed_value.val.tag()) {
166 .function => _ = self.funcs.swapRemove(func_idx),
167 .extern_fn => _ = self.ext_funcs.swapRemove(func_idx),
168 else => unreachable,
264 if (self.getFuncidx(decl)) |func_idx| {
265 switch (decl.typed_value.most_recent.typed_value.val.tag()) {
266 .function => _ = self.funcs.swapRemove(func_idx),
267 .extern_fn => _ = self.ext_funcs.swapRemove(func_idx),
268 else => unreachable,
269 }
270 }
271 const block = &decl.link.wasm;
272
273 if (self.last_block == block) {
274 self.last_block = block.prev;
169275 }
170 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
171 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
172 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
173 decl.fn_link.wasm = null;
276
277 block.unplug();
278
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;
174292}
175293
176294pub fn flush(self: *Wasm, comp: *Compilation) !void {
......@@ -187,6 +305,25 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
187305
188306 const file = self.base.file.?;
189307 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
191328 // No need to rewrite the magic/version header
192329 try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));
......@@ -198,8 +335,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
198335
199336 // extern functions are defined in the wasm binary first through the `import`
200337 // section, so define their func types first
201 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);
338 for (self.ext_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
204341 try writeVecSectionHeader(
205342 file,
......@@ -256,6 +393,31 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
256393 );
257394 }
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
259421 // Export section
260422 if (self.base.options.module) |module| {
261423 const header_offset = try reserveVecSectionHeader(file);
......@@ -280,6 +442,16 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
280442 count += 1;
281443 }
282444 }
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
283455 try writeVecSectionHeader(
284456 file,
285457 header_offset,
......@@ -294,7 +466,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
294466 const header_offset = try reserveVecSectionHeader(file);
295467 const writer = file.writer();
296468 for (self.funcs.items) |decl| {
297 const fn_data = &decl.fn_link.wasm.?;
469 const fn_data = &decl.fn_link.wasm;
298470
299471 // Write the already generated code to the file, inserting
300472 // function indexes where required.
......@@ -319,6 +491,51 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
319491 @intCast(u32, self.funcs.items.len),
320492 );
321493 }
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 }
322539}
323540
324541fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
src/main.zig+34-25
......@@ -505,7 +505,6 @@ fn buildOutputType(
505505 var emit_bin: EmitBin = .yes_default_path;
506506 var emit_asm: Emit = .no;
507507 var emit_llvm_ir: Emit = .no;
508 var emit_zir: Emit = .no;
509508 var emit_docs: Emit = .no;
510509 var emit_analysis: Emit = .no;
511510 var target_arch_os_abi: []const u8 = "native";
......@@ -599,15 +598,15 @@ fn buildOutputType(
599598 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);
600599 defer test_exec_args.deinit();
601600
602 const pkg_tree_root = try gpa.create(Package);
603601 // This package only exists to clean up the code parsing --pkg-begin and
604602 // --pkg-end flags. Use dummy values that are safe for the destroy call.
605 pkg_tree_root.* = .{
603 var pkg_tree_root: Package = .{
606604 .root_src_directory = .{ .path = null, .handle = fs.cwd() },
607605 .root_src_path = &[0]u8{},
606 .namespace_hash = Package.root_namespace_hash,
608607 };
609 defer pkg_tree_root.destroy(gpa);
610 var cur_pkg: *Package = pkg_tree_root;
608 defer freePkgTree(gpa, &pkg_tree_root, false);
609 var cur_pkg: *Package = &pkg_tree_root;
611610
612611 switch (arg_mode) {
613612 .build, .translate_c, .zig_test, .run => {
......@@ -658,8 +657,7 @@ fn buildOutputType(
658657 ) catch |err| {
659658 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });
660659 };
661 new_cur_pkg.parent = cur_pkg;
662 try cur_pkg.add(gpa, pkg_name, new_cur_pkg);
660 try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg);
663661 cur_pkg = new_cur_pkg;
664662 } else if (mem.eql(u8, arg, "--pkg-end")) {
665663 cur_pkg = cur_pkg.parent orelse
......@@ -924,12 +922,6 @@ fn buildOutputType(
924922 emit_bin = .{ .yes = arg["-femit-bin=".len..] };
925923 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
926924 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;
933925 } else if (mem.eql(u8, arg, "-femit-h")) {
934926 emit_h = .yes_default_path;
935927 } else if (mem.startsWith(u8, arg, "-femit-h=")) {
......@@ -1026,7 +1018,7 @@ fn buildOutputType(
10261018 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
10271019 });
10281020 },
1029 .zig, .zir => {
1021 .zig => {
10301022 if (root_src_file) |other| {
10311023 fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
10321024 } else {
......@@ -1087,7 +1079,7 @@ fn buildOutputType(
10871079 .unknown, .shared_library, .object, .static_library => {
10881080 try link_objects.append(it.only_arg);
10891081 },
1090 .zig, .zir => {
1082 .zig => {
10911083 if (root_src_file) |other| {
10921084 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
10931085 } else {
......@@ -1725,13 +1717,6 @@ fn buildOutputType(
17251717 var emit_docs_resolved = try emit_docs.resolve("docs");
17261718 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
17351720 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
17361721 if (main_pkg_path) |p| {
17371722 const rel_src_path = try fs.path.relative(gpa, p, src_path);
......@@ -1747,6 +1732,7 @@ fn buildOutputType(
17471732 if (root_pkg) |pkg| {
17481733 pkg.table = pkg_tree_root.table;
17491734 pkg_tree_root.table = .{};
1735 pkg.namespace_hash = pkg_tree_root.namespace_hash;
17501736 }
17511737
17521738 const self_exe_path = try fs.selfExePathAlloc(arena);
......@@ -1815,6 +1801,11 @@ fn buildOutputType(
18151801 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);
18161802 }
18171803
1804 const clang_passthrough_mode = switch (arg_mode) {
1805 .cc, .cpp, .translate_c => true,
1806 else => false,
1807 };
1808
18181809 gimmeMoreOfThoseSweetSweetFileDescriptors();
18191810
18201811 const comp = Compilation.create(gpa, .{
......@@ -1886,7 +1877,7 @@ fn buildOutputType(
18861877 .function_sections = function_sections,
18871878 .self_exe_path = self_exe_path,
18881879 .thread_pool = &thread_pool,
1889 .clang_passthrough_mode = arg_mode != .build,
1880 .clang_passthrough_mode = clang_passthrough_mode,
18901881 .clang_preprocessor_mode = clang_preprocessor_mode,
18911882 .version = optional_version,
18921883 .libc_installation = if (libc_installation) |*lci| lci else null,
......@@ -2101,8 +2092,12 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
21012092 defer errors.deinit(comp.gpa);
21022093
21032094 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 };
21042099 for (errors.list) |full_err_msg| {
2105 full_err_msg.renderToStdErr();
2100 full_err_msg.renderToStdErr(ttyconf);
21062101 }
21072102 const log_text = comp.getCompileLogOutput();
21082103 if (log_text.len != 0) {
......@@ -2146,6 +2141,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
21462141 }
21472142}
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
21492156fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
21502157 if (!build_options.have_llvm)
21512158 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
25002507 .handle = try zig_lib_directory.handle.openDir(std_special, .{}),
25012508 },
25022509 .root_src_path = "build_runner.zig",
2510 .namespace_hash = Package.root_namespace_hash,
25032511 };
25042512 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
25452553 var build_pkg: Package = .{
25462554 .root_src_directory = build_directory,
25472555 .root_src_path = build_zig_basename,
2556 .namespace_hash = undefined,
25482557 };
2549 try root_pkg.table.put(arena, "@build", &build_pkg);
2558 try root_pkg.addAndAdopt(arena, "@build", &build_pkg);
25502559
25512560 var global_cache_directory: Compilation.Directory = l: {
25522561 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
src/register_manager.zig+89-2
......@@ -35,6 +35,10 @@ pub fn RegisterManager(
3535 self.registers.deinit(allocator);
3636 }
3737
38 fn isTracked(reg: Register) bool {
39 return std.mem.indexOfScalar(Register, callee_preserved_regs, reg) != null;
40 }
41
3842 fn markRegUsed(self: *Self, reg: Register) void {
3943 if (FreeRegInt == u0) return;
4044 const index = reg.allocIndex() orelse return;
......@@ -51,6 +55,13 @@ pub fn RegisterManager(
5155 self.free_registers |= @as(FreeRegInt, 1) << shift;
5256 }
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
5465 /// Returns whether this register was allocated in the course
5566 /// of this function
5667 pub fn isRegAllocated(self: Self, reg: Register) bool {
......@@ -117,17 +128,61 @@ pub fn RegisterManager(
117128 const regs_entry = self.registers.remove(reg).?;
118129 const spilled_inst = regs_entry.value;
119130 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
131 self.markRegFree(reg);
120132
121133 break :b reg;
122134 };
123135 }
124136
125 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) !void {
126 try self.registers.putNoClobber(self.getFunction().gpa, reg, inst);
137 /// Allocates the specified register with the specified
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);
127179 self.markRegUsed(reg);
128180 }
129181
182 /// Marks the specified register as free
130183 pub fn freeReg(self: *Self, reg: Register) void {
184 if (!isTracked(reg)) return;
185
131186 _ = self.registers.remove(reg);
132187 self.markRegFree(reg);
133188 }
......@@ -226,3 +281,35 @@ test "allocReg: spilling" {
226281 std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction));
227282 std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
228283}
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) {
91109110 buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));
91119111 buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));
91129112 buf_appendf(contents, "pub const code_model = CodeModel.default;\n");
9113 buf_appendf(contents, "pub const zig_is_stage2 = false;\n");
91139114
91149115 {
91159116 TargetSubsystem detected_subsystem = detect_subsystem(g);
src/test.zig+21-42
......@@ -122,11 +122,6 @@ pub const TestContext = struct {
122122 path: []const u8,
123123 };
124124
125 pub const Extension = enum {
126 Zig,
127 ZIR,
128 };
129
130125 /// A `Case` consists of a list of `Update`. The same `Compilation` is used for each
131126 /// update, so each update's source is treated as a single file being
132127 /// updated by the test harness and incrementally compiled.
......@@ -141,7 +136,6 @@ pub const TestContext = struct {
141136 /// to Executable.
142137 output_mode: std.builtin.OutputMode,
143138 updates: std.ArrayList(Update),
144 extension: Extension,
145139 object_format: ?std.builtin.ObjectFormat = null,
146140 emit_h: bool = false,
147141 llvm_backend: bool = false,
......@@ -238,14 +232,12 @@ pub const TestContext = struct {
238232 ctx: *TestContext,
239233 name: []const u8,
240234 target: CrossTarget,
241 extension: Extension,
242235 ) *Case {
243236 ctx.cases.append(Case{
244237 .name = name,
245238 .target = target,
246239 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
247240 .output_mode = .Exe,
248 .extension = extension,
249241 .files = std.ArrayList(File).init(ctx.cases.allocator),
250242 }) catch @panic("out of memory");
251243 return &ctx.cases.items[ctx.cases.items.len - 1];
......@@ -253,7 +245,7 @@ pub const TestContext = struct {
253245
254246 /// Adds a test case for Zig input, producing an executable
255247 pub fn exe(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
256 return ctx.addExe(name, target, .Zig);
248 return ctx.addExe(name, target);
257249 }
258250
259251 /// Adds a test case for ZIR input, producing an executable
......@@ -269,7 +261,6 @@ pub const TestContext = struct {
269261 .target = target,
270262 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
271263 .output_mode = .Exe,
272 .extension = .Zig,
273264 .object_format = .c,
274265 .files = std.ArrayList(File).init(ctx.cases.allocator),
275266 }) catch @panic("out of memory");
......@@ -284,7 +275,6 @@ pub const TestContext = struct {
284275 .target = target,
285276 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
286277 .output_mode = .Exe,
287 .extension = .Zig,
288278 .files = std.ArrayList(File).init(ctx.cases.allocator),
289279 .llvm_backend = true,
290280 }) catch @panic("out of memory");
......@@ -295,14 +285,12 @@ pub const TestContext = struct {
295285 ctx: *TestContext,
296286 name: []const u8,
297287 target: CrossTarget,
298 extension: Extension,
299288 ) *Case {
300289 ctx.cases.append(Case{
301290 .name = name,
302291 .target = target,
303292 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
304293 .output_mode = .Obj,
305 .extension = extension,
306294 .files = std.ArrayList(File).init(ctx.cases.allocator),
307295 }) catch @panic("out of memory");
308296 return &ctx.cases.items[ctx.cases.items.len - 1];
......@@ -310,7 +298,7 @@ pub const TestContext = struct {
310298
311299 /// Adds a test case for Zig input, producing an object file.
312300 pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
313 return ctx.addObj(name, target, .Zig);
301 return ctx.addObj(name, target);
314302 }
315303
316304 /// Adds a test case for ZIR input, producing an object file.
......@@ -319,13 +307,12 @@ pub const TestContext = struct {
319307 }
320308
321309 /// 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 {
323311 ctx.cases.append(Case{
324312 .name = name,
325313 .target = target,
326314 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
327315 .output_mode = .Obj,
328 .extension = ext,
329316 .object_format = .c,
330317 .files = std.ArrayList(File).init(ctx.cases.allocator),
331318 }) catch @panic("out of memory");
......@@ -333,21 +320,20 @@ pub const TestContext = struct {
333320 }
334321
335322 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);
337324 }
338325
339326 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);
341328 }
342329
343330 pub fn addCompareOutput(
344331 ctx: *TestContext,
345332 name: []const u8,
346 extension: Extension,
347333 src: [:0]const u8,
348334 expected_stdout: []const u8,
349335 ) void {
350 ctx.addExe(name, .{}, extension).addCompareOutput(src, expected_stdout);
336 ctx.addExe(name, .{}).addCompareOutput(src, expected_stdout);
351337 }
352338
353339 /// Adds a test case that compiles the Zig source given in `src`, executes
......@@ -358,7 +344,7 @@ pub const TestContext = struct {
358344 src: [:0]const u8,
359345 expected_stdout: []const u8,
360346 ) void {
361 return ctx.addCompareOutput(name, .Zig, src, expected_stdout);
347 return ctx.addCompareOutput(name, src, expected_stdout);
362348 }
363349
364350 /// Adds a test case that compiles the ZIR source given in `src`, executes
......@@ -376,11 +362,10 @@ pub const TestContext = struct {
376362 ctx: *TestContext,
377363 name: []const u8,
378364 target: CrossTarget,
379 extension: Extension,
380365 src: [:0]const u8,
381366 result: [:0]const u8,
382367 ) void {
383 ctx.addObj(name, target, extension).addTransform(src, result);
368 ctx.addObj(name, target).addTransform(src, result);
384369 }
385370
386371 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests
......@@ -392,7 +377,7 @@ pub const TestContext = struct {
392377 src: [:0]const u8,
393378 result: [:0]const u8,
394379 ) void {
395 ctx.addTransform(name, target, .Zig, src, result);
380 ctx.addTransform(name, target, src, result);
396381 }
397382
398383 /// Adds a test case that cleans up the ZIR source given in `src`, and
......@@ -411,11 +396,10 @@ pub const TestContext = struct {
411396 ctx: *TestContext,
412397 name: []const u8,
413398 target: CrossTarget,
414 extension: Extension,
415399 src: [:0]const u8,
416400 expected_errors: []const []const u8,
417401 ) void {
418 ctx.addObj(name, target, extension).addError(src, expected_errors);
402 ctx.addObj(name, target).addError(src, expected_errors);
419403 }
420404
421405 /// Adds a test case that ensures that the Zig given in `src` fails to
......@@ -428,7 +412,7 @@ pub const TestContext = struct {
428412 src: [:0]const u8,
429413 expected_errors: []const []const u8,
430414 ) void {
431 ctx.addError(name, target, .Zig, src, expected_errors);
415 ctx.addError(name, target, src, expected_errors);
432416 }
433417
434418 /// Adds a test case that ensures that the ZIR given in `src` fails to
......@@ -448,10 +432,9 @@ pub const TestContext = struct {
448432 ctx: *TestContext,
449433 name: []const u8,
450434 target: CrossTarget,
451 extension: Extension,
452435 src: [:0]const u8,
453436 ) void {
454 ctx.addObj(name, target, extension).compiles(src);
437 ctx.addObj(name, target).compiles(src);
455438 }
456439
457440 /// Adds a test case that asserts that the Zig given in `src` compiles
......@@ -462,7 +445,7 @@ pub const TestContext = struct {
462445 target: CrossTarget,
463446 src: [:0]const u8,
464447 ) void {
465 ctx.addCompiles(name, target, .Zig, src);
448 ctx.addCompiles(name, target, src);
466449 }
467450
468451 /// Adds a test case that asserts that the ZIR given in `src` compiles
......@@ -489,7 +472,7 @@ pub const TestContext = struct {
489472 expected_errors: []const []const u8,
490473 fixed_src: [:0]const u8,
491474 ) void {
492 var case = ctx.addObj(name, target, .Zig);
475 var case = ctx.addObj(name, target);
493476 case.addError(src, expected_errors);
494477 case.compiles(fixed_src);
495478 }
......@@ -614,15 +597,14 @@ pub const TestContext = struct {
614597 .path = try std.fs.path.join(arena, &[_][]const u8{ tmp_dir_path, "zig-cache" }),
615598 };
616599
617 const tmp_src_path = switch (case.extension) {
618 .Zig => "test_case.zig",
619 .ZIR => "test_case.zir",
620 };
600 const tmp_src_path = "test_case.zig";
621601
622602 var root_pkg: Package = .{
623603 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
624604 .root_src_path = tmp_src_path,
605 .namespace_hash = Package.root_namespace_hash,
625606 };
607 defer root_pkg.table.deinit(allocator);
626608
627609 const bin_name = try std.zig.binNameAlloc(arena, .{
628610 .root_name = "test_case",
......@@ -639,13 +621,10 @@ pub const TestContext = struct {
639621 .directory = emit_directory,
640622 .basename = bin_name,
641623 };
642 const emit_h: ?Compilation.EmitLoc = if (case.emit_h)
643 .{
644 .directory = emit_directory,
645 .basename = "test_case.h",
646 }
647 else
648 null;
624 const emit_h: ?Compilation.EmitLoc = if (case.emit_h) .{
625 .directory = emit_directory,
626 .basename = "test_case.h",
627 } else null;
649628 const comp = try Compilation.create(allocator, .{
650629 .local_cache_directory = zig_cache_directory,
651630 .global_cache_directory = global_cache_directory,
src/translate_c.zig+233-13
......@@ -1123,6 +1123,16 @@ fn transStmt(
11231123 const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt);
11241124 return transExpr(c, scope, gen_sel.getResultExpr(), result_used);
11251125 },
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 },
11261136 // When adding new cases here, see comment for maybeBlockify()
11271137 else => {
11281138 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
......@@ -1130,6 +1140,128 @@ fn transStmt(
11301140 }
11311141}
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
11331265/// Translate a "simple" offsetof expression containing exactly one component,
11341266/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
11351267fn transSimpleOffsetOfExpr(
......@@ -1935,6 +2067,10 @@ fn cIsEnum(qt: clang.QualType) bool {
19352067 return qt.getCanonicalType().getTypeClass() == .Enum;
19362068}
19372069
2070fn cIsVector(qt: clang.QualType) bool {
2071 return qt.getCanonicalType().getTypeClass() == .Vector;
2072}
2073
19382074/// Get the underlying int type of an enum. The C compiler chooses a signed int
19392075/// type that is large enough to hold all of the enum's values. It is not required
19402076/// to be the smallest possible type that can hold all the values.
......@@ -1991,6 +2127,11 @@ fn transCCast(
19912127 // @bitCast(dest_type, intermediate_value)
19922128 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr });
19932129 }
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 }
19942135 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
19952136 // @intCast(dest_type, @ptrToInt(val))
19962137 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
......@@ -2209,6 +2350,63 @@ fn transInitListExprArray(
22092350 }
22102351}
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
22122410fn transInitListExpr(
22132411 c: *Context,
22142412 scope: *Scope,
......@@ -2235,6 +2433,14 @@ fn transInitListExpr(
22352433 expr,
22362434 qual_type,
22372435 ));
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 ));
22382444 } else {
22392445 const type_name = c.str(qual_type.getTypeClassName());
22402446 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
40854291 };
40864292 return Tag.typeof.create(c.arena, underlying_expr);
40874293 },
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 },
40884303 else => {
40894304 const type_name = c.str(ty.getTypeClassName());
40904305 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 {
52115426 }
52125427 },
52135428 .LParen => {
5214 var args = std.ArrayList(Node).init(c.gpa);
5215 defer args.deinit();
5216 while (true) {
5217 const arg = try parseCCondExpr(c, m, scope);
5218 try args.append(arg);
5219 switch (m.next().?) {
5220 .Comma => {},
5221 .RParen => break,
5222 else => {
5223 try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});
5224 return error.ParseError;
5225 },
5429 if (m.peek().? == .RParen) {
5430 m.i += 1;
5431 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });
5432 } else {
5433 var args = std.ArrayList(Node).init(c.gpa);
5434 defer args.deinit();
5435 while (true) {
5436 const arg = try parseCCondExpr(c, m, scope);
5437 try args.append(arg);
5438 switch (m.next().?) {
5439 .Comma => {},
5440 .RParen => break,
5441 else => {
5442 try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});
5443 return error.ParseError;
5444 },
5445 }
52265446 }
5447 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
52275448 }
5228 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
52295449 },
52305450 .LBrace => {
52315451 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 {
6666 @"enum",
6767 @"struct",
6868 @"union",
69 @"comptime",
6970 array_init,
7071 tuple,
7172 container_init,
......@@ -154,6 +155,8 @@ pub const Node = extern union {
154155 div_exact,
155156 /// @byteOffsetOf(lhs, rhs)
156157 byte_offset_of,
158 /// @shuffle(type, a, b, mask)
159 shuffle,
157160
158161 negate,
159162 negate_wrap,
......@@ -172,6 +175,7 @@ pub const Node = extern union {
172175 sizeof,
173176 alignof,
174177 typeof,
178 typeinfo,
175179 type,
176180
177181 optional_type,
......@@ -182,6 +186,10 @@ pub const Node = extern union {
182186
183187 /// @import("std").meta.sizeof(operand)
184188 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,
185193 /// @import("std").mem.zeroes(operand)
186194 std_mem_zeroes,
187195 /// @import("std").mem.zeroInit(lhs, rhs)
......@@ -233,6 +241,7 @@ pub const Node = extern union {
233241
234242 .std_mem_zeroes,
235243 .@"return",
244 .@"comptime",
236245 .discard,
237246 .std_math_Log2Int,
238247 .negate,
......@@ -255,6 +264,7 @@ pub const Node = extern union {
255264 .sizeof,
256265 .alignof,
257266 .typeof,
267 .typeinfo,
258268 => Payload.UnOp,
259269
260270 .add,
......@@ -308,6 +318,8 @@ pub const Node = extern union {
308318 .align_cast,
309319 .array_access,
310320 .std_mem_zeroinit,
321 .std_meta_shuffle_vector_index,
322 .std_meta_vector,
311323 .ptr_cast,
312324 .div_exact,
313325 .byte_offset_of,
......@@ -346,6 +358,7 @@ pub const Node = extern union {
346358 .pub_inline_fn => Payload.PubInlineFn,
347359 .field_access => Payload.FieldAccess,
348360 .string_slice => Payload.StringSlice,
361 .shuffle => Payload.Shuffle,
349362 };
350363 }
351364
......@@ -678,6 +691,16 @@ pub const Payload = struct {
678691 end: usize,
679692 },
680693 };
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 };
681704};
682705
683706/// Converts the nodes into a Zig ast.
......@@ -868,6 +891,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
868891 const import_node = try renderStdImport(c, "mem", "zeroInit");
869892 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
870893 },
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 },
871904 .call => {
872905 const payload = node.castTag(.call).?.data;
873906 const lhs = try renderNode(c, payload.lhs);
......@@ -964,6 +997,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
964997 },
965998 });
966999 },
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 },
9671011 .type => {
9681012 const payload = node.castTag(.type).?.data;
9691013 return c.addNode(.{
......@@ -1217,6 +1261,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12171261 const payload = node.castTag(.sizeof).?.data;
12181262 return renderBuiltinCall(c, "@sizeOf", &.{payload});
12191263 },
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 },
12201273 .alignof => {
12211274 const payload = node.castTag(.alignof).?.data;
12221275 return renderBuiltinCall(c, "@alignOf", &.{payload});
......@@ -1225,6 +1278,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12251278 const payload = node.castTag(.typeof).?.data;
12261279 return renderBuiltinCall(c, "@TypeOf", &.{payload});
12271280 },
1281 .typeinfo => {
1282 const payload = node.castTag(.typeinfo).?.data;
1283 return renderBuiltinCall(c, "@typeInfo", &.{payload});
1284 },
12281285 .negate => return renderPrefixOp(c, node, .negation, .minus, "-"),
12291286 .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"),
12301287 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),
......@@ -2085,9 +2142,12 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
20852142 .sizeof,
20862143 .alignof,
20872144 .typeof,
2145 .typeinfo,
20882146 .std_meta_sizeof,
20892147 .std_meta_cast,
20902148 .std_meta_promoteIntLiteral,
2149 .std_meta_vector,
2150 .std_meta_shuffle_vector_index,
20912151 .std_mem_zeroinit,
20922152 .integer_literal,
20932153 .float_literal,
......@@ -2118,6 +2178,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
21182178 .bool_to_int,
21192179 .div_exact,
21202180 .byte_offset_of,
2181 .shuffle,
21212182 => {
21222183 // no grouping needed
21232184 return renderNode(c, node);
......@@ -2185,6 +2246,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
21852246 .discard,
21862247 .@"continue",
21872248 .@"return",
2249 .@"comptime",
21882250 .usingnamespace_builtins,
21892251 .while_true,
21902252 .if_not_break,
......@@ -2327,6 +2389,8 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node
23272389 _ = try c.addToken(.l_paren, "(");
23282390 var arg_1: NodeIndex = 0;
23292391 var arg_2: NodeIndex = 0;
2392 var arg_3: NodeIndex = 0;
2393 var arg_4: NodeIndex = 0;
23302394 switch (args.len) {
23312395 0 => {},
23322396 1 => {
......@@ -2337,18 +2401,41 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node
23372401 _ = try c.addToken(.comma, ",");
23382402 arg_2 = try renderNode(c, args[1]);
23392403 },
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 },
23402413 else => unreachable, // expand this function as needed.
23412414 }
23422415
23432416 _ = try c.addToken(.r_paren, ")");
2344 return c.addNode(.{
2345 .tag = .builtin_call_two,
2346 .main_token = builtin_tok,
2347 .data = .{
2348 .lhs = arg_1,
2349 .rhs = arg_2,
2350 },
2351 });
2417 if (args.len <= 2) {
2418 return c.addNode(.{
2419 .tag = .builtin_call_two,
2420 .main_token = builtin_tok,
2421 .data = .{
2422 .lhs = arg_1,
2423 .rhs = arg_2,
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 }
23522439}
23532440
23542441fn renderVar(c: *Context, node: Node) !NodeIndex {
src/type.zig+621-1734
......@@ -93,14 +93,56 @@ pub const Type = extern union {
9393
9494 .anyerror_void_error_union, .error_union => return .ErrorUnion,
9595
96 .empty_struct => return .Struct,
97 .empty_struct_literal => return .Struct,
98 .@"struct" => return .Struct,
96 .empty_struct,
97 .empty_struct_literal,
98 .@"struct",
99 => return .Struct,
100
101 .enum_full,
102 .enum_nonexhaustive,
103 .enum_simple,
104 => return .Enum,
99105
100106 .var_args_param => unreachable, // can be any type
101107 }
102108 }
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
104146 pub fn initTag(comptime small_tag: Tag) Type {
105147 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
106148 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
......@@ -614,6 +656,8 @@ pub const Type = extern union {
614656 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
615657 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
616658 .@"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),
617661 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
618662 }
619663 }
......@@ -626,13 +670,13 @@ pub const Type = extern union {
626670 }
627671
628672 pub fn format(
629 self: Type,
673 start_type: Type,
630674 comptime fmt: []const u8,
631675 options: std.fmt.FormatOptions,
632 out_stream: anytype,
633 ) @TypeOf(out_stream).Error!void {
676 writer: anytype,
677 ) @TypeOf(writer).Error!void {
634678 comptime assert(fmt.len == 0);
635 var ty = self;
679 var ty = start_type;
636680 while (true) {
637681 const t = ty.tag();
638682 switch (t) {
......@@ -670,132 +714,149 @@ pub const Type = extern union {
670714 .comptime_float,
671715 .noreturn,
672716 .var_args_param,
673 => return out_stream.writeAll(@tagName(t)),
674
675 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
676 .@"null" => return out_stream.writeAll("@Type(.Null)"),
677 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
678
679 .empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"),
680 .@"struct" => return out_stream.writeAll("(struct)"),
681 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
682 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
683 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
684 .fn_void_no_args => return out_stream.writeAll("fn() void"),
685 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
686 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
687 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
717 => return writer.writeAll(@tagName(t)),
718
719 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
720 .@"null" => return writer.writeAll("@Type(.Null)"),
721 .@"undefined" => return writer.writeAll("@Type(.Undefined)"),
722
723 .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"),
724
725 .@"struct" => {
726 const struct_obj = ty.castTag(.@"struct").?.data;
727 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
728 },
729 .enum_full, .enum_nonexhaustive => {
730 const enum_full = ty.cast(Payload.EnumFull).?.data;
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"),
688749 .function => {
689750 const payload = ty.castTag(.function).?.data;
690 try out_stream.writeAll("fn(");
751 try writer.writeAll("fn(");
691752 for (payload.param_types) |param_type, i| {
692 if (i != 0) try out_stream.writeAll(", ");
693 try param_type.format("", .{}, out_stream);
753 if (i != 0) try writer.writeAll(", ");
754 try param_type.format("", .{}, writer);
694755 }
695756 if (payload.is_var_args) {
696757 if (payload.param_types.len != 0) {
697 try out_stream.writeAll(", ");
758 try writer.writeAll(", ");
698759 }
699 try out_stream.writeAll("...");
760 try writer.writeAll("...");
700761 }
701 try out_stream.writeAll(") callconv(.");
702 try out_stream.writeAll(@tagName(payload.cc));
703 try out_stream.writeAll(")");
762 try writer.writeAll(") callconv(.");
763 try writer.writeAll(@tagName(payload.cc));
764 try writer.writeAll(")");
704765 ty = payload.return_type;
705766 continue;
706767 },
707768
708769 .array_u8 => {
709770 const len = ty.castTag(.array_u8).?.data;
710 return out_stream.print("[{d}]u8", .{len});
771 return writer.print("[{d}]u8", .{len});
711772 },
712773 .array_u8_sentinel_0 => {
713774 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});
715776 },
716777 .array => {
717778 const payload = ty.castTag(.array).?.data;
718 try out_stream.print("[{d}]", .{payload.len});
779 try writer.print("[{d}]", .{payload.len});
719780 ty = payload.elem_type;
720781 continue;
721782 },
722783 .array_sentinel => {
723784 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 });
725786 ty = payload.elem_type;
726787 continue;
727788 },
728789 .single_const_pointer => {
729790 const pointee_type = ty.castTag(.single_const_pointer).?.data;
730 try out_stream.writeAll("*const ");
791 try writer.writeAll("*const ");
731792 ty = pointee_type;
732793 continue;
733794 },
734795 .single_mut_pointer => {
735796 const pointee_type = ty.castTag(.single_mut_pointer).?.data;
736 try out_stream.writeAll("*");
797 try writer.writeAll("*");
737798 ty = pointee_type;
738799 continue;
739800 },
740801 .many_const_pointer => {
741802 const pointee_type = ty.castTag(.many_const_pointer).?.data;
742 try out_stream.writeAll("[*]const ");
803 try writer.writeAll("[*]const ");
743804 ty = pointee_type;
744805 continue;
745806 },
746807 .many_mut_pointer => {
747808 const pointee_type = ty.castTag(.many_mut_pointer).?.data;
748 try out_stream.writeAll("[*]");
809 try writer.writeAll("[*]");
749810 ty = pointee_type;
750811 continue;
751812 },
752813 .c_const_pointer => {
753814 const pointee_type = ty.castTag(.c_const_pointer).?.data;
754 try out_stream.writeAll("[*c]const ");
815 try writer.writeAll("[*c]const ");
755816 ty = pointee_type;
756817 continue;
757818 },
758819 .c_mut_pointer => {
759820 const pointee_type = ty.castTag(.c_mut_pointer).?.data;
760 try out_stream.writeAll("[*c]");
821 try writer.writeAll("[*c]");
761822 ty = pointee_type;
762823 continue;
763824 },
764825 .const_slice => {
765826 const pointee_type = ty.castTag(.const_slice).?.data;
766 try out_stream.writeAll("[]const ");
827 try writer.writeAll("[]const ");
767828 ty = pointee_type;
768829 continue;
769830 },
770831 .mut_slice => {
771832 const pointee_type = ty.castTag(.mut_slice).?.data;
772 try out_stream.writeAll("[]");
833 try writer.writeAll("[]");
773834 ty = pointee_type;
774835 continue;
775836 },
776837 .int_signed => {
777838 const bits = ty.castTag(.int_signed).?.data;
778 return out_stream.print("i{d}", .{bits});
839 return writer.print("i{d}", .{bits});
779840 },
780841 .int_unsigned => {
781842 const bits = ty.castTag(.int_unsigned).?.data;
782 return out_stream.print("u{d}", .{bits});
843 return writer.print("u{d}", .{bits});
783844 },
784845 .optional => {
785846 const child_type = ty.castTag(.optional).?.data;
786 try out_stream.writeByte('?');
847 try writer.writeByte('?');
787848 ty = child_type;
788849 continue;
789850 },
790851 .optional_single_const_pointer => {
791852 const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;
792 try out_stream.writeAll("?*const ");
853 try writer.writeAll("?*const ");
793854 ty = pointee_type;
794855 continue;
795856 },
796857 .optional_single_mut_pointer => {
797858 const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;
798 try out_stream.writeAll("?*");
859 try writer.writeAll("?*");
799860 ty = pointee_type;
800861 continue;
801862 },
......@@ -804,48 +865,46 @@ pub const Type = extern union {
804865 const payload = ty.castTag(.pointer).?.data;
805866 if (payload.sentinel) |some| switch (payload.size) {
806867 .One, .C => unreachable,
807 .Many => try out_stream.print("[*:{}]", .{some}),
808 .Slice => try out_stream.print("[:{}]", .{some}),
868 .Many => try writer.print("[*:{}]", .{some}),
869 .Slice => try writer.print("[:{}]", .{some}),
809870 } else switch (payload.size) {
810 .One => try out_stream.writeAll("*"),
811 .Many => try out_stream.writeAll("[*]"),
812 .C => try out_stream.writeAll("[*c]"),
813 .Slice => try out_stream.writeAll("[]"),
871 .One => try writer.writeAll("*"),
872 .Many => try writer.writeAll("[*]"),
873 .C => try writer.writeAll("[*c]"),
874 .Slice => try writer.writeAll("[]"),
814875 }
815876 if (payload.@"align" != 0) {
816 try out_stream.print("align({d}", .{payload.@"align"});
877 try writer.print("align({d}", .{payload.@"align"});
817878
818879 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 });
820881 }
821 try out_stream.writeAll(") ");
882 try writer.writeAll(") ");
822883 }
823 if (!payload.mutable) try out_stream.writeAll("const ");
824 if (payload.@"volatile") try out_stream.writeAll("volatile ");
825 if (payload.@"allowzero") try out_stream.writeAll("allowzero ");
884 if (!payload.mutable) try writer.writeAll("const ");
885 if (payload.@"volatile") try writer.writeAll("volatile ");
886 if (payload.@"allowzero") try writer.writeAll("allowzero ");
826887
827888 ty = payload.pointee_type;
828889 continue;
829890 },
830891 .error_union => {
831892 const payload = ty.castTag(.error_union).?.data;
832 try payload.error_set.format("", .{}, out_stream);
833 try out_stream.writeAll("!");
893 try payload.error_set.format("", .{}, writer);
894 try writer.writeAll("!");
834895 ty = payload.payload;
835896 continue;
836897 },
837898 .error_set => {
838899 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));
840901 },
841902 .error_set_single => {
842903 const name = ty.castTag(.error_set_single).?.data;
843 return out_stream.print("error{{{s}}}", .{name});
904 return writer.print("error{{{s}}}", .{name});
844905 },
845 .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"),
846 .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"),
847 // TODO use declaration name
848 .@"opaque" => return out_stream.writeAll("opaque {}"),
906 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
907 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
849908 }
850909 unreachable;
851910 }
......@@ -954,6 +1013,19 @@ pub const Type = extern union {
9541013 return false;
9551014 }
9561015 },
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
9581030 // TODO lazy types
9591031 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
......@@ -1112,13 +1184,37 @@ pub const Type = extern union {
11121184 } else if (!payload.payload.hasCodeGenBits()) {
11131185 return payload.error_set.abiAlignment(target);
11141186 }
1115 @panic("TODO abiAlignment error union");
1187 return std.math.max(
1188 payload.payload.abiAlignment(target),
1189 payload.error_set.abiAlignment(target),
1190 );
11161191 },
11171192
11181193 .@"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);
11201217 },
1121
11221218 .c_void,
11231219 .void,
11241220 .type,
......@@ -1166,6 +1262,11 @@ pub const Type = extern union {
11661262 .@"struct" => {
11671263 @panic("TODO abiSize struct");
11681264 },
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
11701271 .u8,
11711272 .i8,
......@@ -1276,76 +1377,25 @@ pub const Type = extern union {
12761377 };
12771378 }
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
12791397 pub fn isSinglePointer(self: Type) bool {
12801398 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
13491399 .single_const_pointer,
13501400 .single_mut_pointer,
13511401 .single_const_pointer_to_comptime_int,
......@@ -1354,73 +1404,14 @@ pub const Type = extern union {
13541404 => true,
13551405
13561406 .pointer => self.castTag(.pointer).?.data.size == .One,
1407
1408 else => false,
13571409 };
13581410 }
13591411
13601412 /// Asserts the `Type` is a pointer.
13611413 pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size {
13621414 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
14241415 .const_slice,
14251416 .mut_slice,
14261417 .const_slice_u8,
......@@ -1442,159 +1433,26 @@ pub const Type = extern union {
14421433 => .One,
14431434
14441435 .pointer => self.castTag(.pointer).?.data.size,
1436
1437 else => unreachable,
14451438 };
14461439 }
14471440
14481441 pub fn isSlice(self: Type) bool {
14491442 return switch (self.tag()) {
1450 .u8,
1451 .i8,
1452 .u16,
1453 .i16,
1454 .u32,
1455 .i32,
1456 .u64,
1457 .i64,
1458 .u128,
1459 .i128,
1460 .usize,
1461 .isize,
1462 .c_short,
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
1443 .const_slice,
1444 .mut_slice,
1445 .const_slice_u8,
1446 => true,
1447
1448 .pointer => self.castTag(.pointer).?.data.size == .Slice,
1449
1450 else => false,
1451 };
1452 }
1453
1454 pub fn isConstPtr(self: Type) bool {
1455 return switch (self.tag()) {
15981456 .single_const_pointer,
15991457 .many_const_pointer,
16001458 .c_const_pointer,
......@@ -1604,182 +1462,52 @@ pub const Type = extern union {
16041462 => true,
16051463
16061464 .pointer => !self.castTag(.pointer).?.data.mutable,
1465
1466 else => false,
16071467 };
16081468 }
16091469
16101470 pub fn isVolatilePtr(self: Type) bool {
16111471 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
16851472 .pointer => {
16861473 const payload = self.castTag(.pointer).?.data;
16871474 return payload.@"volatile";
16881475 },
1476 else => false,
16891477 };
16901478 }
16911479
16921480 pub fn isAllowzeroPtr(self: Type) bool {
16931481 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
17671482 .pointer => {
17681483 const payload = self.castTag(.pointer).?.data;
17691484 return payload.@"allowzero";
17701485 },
1486 else => false,
17711487 };
17721488 }
17731489
1774 /// Asserts that the type is an optional
1775 pub fn isPtrLikeOptional(self: Type) bool {
1776 switch (self.tag()) {
1777 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
1778 .optional => {
1779 var buf: Payload.ElemType = undefined;
1780 const child_type = self.optionalChild(&buf);
1781 // optionals of zero sized pointers behave like bools
1782 if (!child_type.hasCodeGenBits()) return false;
1490 pub fn isCPtr(self: Type) bool {
1491 return switch (self.tag()) {
1492 .c_const_pointer,
1493 .c_mut_pointer,
1494 => return true,
1495
1496 .pointer => self.castTag(.pointer).?.data.size == .C,
1497
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
17841512 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();
17851513 },
......@@ -1833,64 +1561,6 @@ pub const Type = extern union {
18331561 /// Asserts the type is a pointer or array type.
18341562 pub fn elemType(self: Type) Type {
18351563 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
18941564 .array => self.castTag(.array).?.data.elem_type,
18951565 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
18961566 .single_const_pointer,
......@@ -1902,9 +1572,12 @@ pub const Type = extern union {
19021572 .const_slice,
19031573 .mut_slice,
19041574 => self.castPointer().?.data,
1575
19051576 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
19061577 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
19071578 .pointer => self.castTag(.pointer).?.data.pointee_type,
1579
1580 else => unreachable,
19081581 };
19091582 }
19101583
......@@ -1972,823 +1645,120 @@ pub const Type = extern union {
19721645 /// Asserts the type is an array or vector.
19731646 pub fn arrayLen(self: Type) u64 {
19741647 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
20451648 .array => self.castTag(.array).?.data.len,
20461649 .array_sentinel => self.castTag(.array_sentinel).?.data.len,
20471650 .array_u8 => self.castTag(.array_u8).?.data,
20481651 .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,
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),
1653 else => unreachable,
21311654 };
21321655 }
21331656
2134 /// Returns true if and only if the type is a fixed-width integer.
2135 pub fn isInt(self: Type) bool {
2136 return self.isSignedInt() or self.isUnsignedInt();
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,
1657 /// Asserts the type is an array, pointer or vector.
1658 pub fn sentinel(self: Type) ?Value {
1659 return switch (self.tag()) {
26891660 .single_const_pointer,
26901661 .single_mut_pointer,
26911662 .many_const_pointer,
26921663 .many_mut_pointer,
26931664 .c_const_pointer,
26941665 .c_mut_pointer,
2695 .const_slice,
2696 .mut_slice,
26971666 .single_const_pointer_to_comptime_int,
2698 .const_slice_u8,
2699 .u8,
1667 .array,
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,
27001688 .i8,
2701 .u16,
1689 .isize,
1690 .c_short,
1691 .c_int,
1692 .c_long,
1693 .c_longlong,
27021694 .i16,
2703 .u32,
27041695 .i32,
2705 .u64,
27061696 .i64,
2707 .u128,
27081697 .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,
27091709 .usize,
2710 .isize,
2711 .c_short,
27121710 .c_ushort,
2713 .c_int,
27141711 .c_uint,
2715 .c_long,
27161712 .c_ulong,
2717 .c_longlong,
27181713 .c_ulonglong,
2719 .int_unsigned,
2720 .int_signed,
2721 .optional,
2722 .optional_single_mut_pointer,
2723 .optional_single_const_pointer,
2724 .enum_literal,
2725 .error_union,
2726 .anyerror_void_error_union,
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 }
1714 .u16,
1715 .u32,
1716 .u64,
1717 .u128,
1718 => true,
1719
1720 else => false,
1721 };
27381722 }
27391723
2740 /// Asserts the type is a function.
2741 pub fn fnReturnType(self: Type) Type {
1724 /// Asserts the type is an integer.
1725 pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
27421726 return switch (self.tag()) {
2743 .fn_noreturn_no_args => Type.initTag(.noreturn),
2744 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
2745
2746 .fn_void_no_args,
2747 .fn_ccc_void_no_args,
2748 => Type.initTag(.void),
1727 .int_unsigned => .{
1728 .signedness = .unsigned,
1729 .bits = self.castTag(.int_unsigned).?.data,
1730 },
1731 .int_signed => .{
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,
2753 .f32,
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,
1760 pub fn isNamedInt(self: Type) bool {
1761 return switch (self.tag()) {
27921762 .usize,
27931763 .isize,
27941764 .c_short,
......@@ -2799,24 +1769,93 @@ pub const Type = extern union {
27991769 .c_ulong,
28001770 .c_longlong,
28011771 .c_ulonglong,
2802 .int_unsigned,
2803 .int_signed,
2804 .optional,
2805 .optional_single_mut_pointer,
2806 .optional_single_const_pointer,
2807 .enum_literal,
2808 .error_union,
2809 .anyerror_void_error_union,
2810 .error_set,
2811 .error_set_single,
2812 .@"struct",
2813 .empty_struct,
2814 .empty_struct_literal,
2815 .inferred_alloc_const,
2816 .inferred_alloc_mut,
2817 .@"opaque",
2818 .var_args_param,
2819 => unreachable,
1772 => true,
1773
1774 else => false,
1775 };
1776 }
1777
1778 pub fn isFloat(self: Type) bool {
1779 return switch (self.tag()) {
1780 .f16,
1781 .f32,
1782 .f64,
1783 .f128,
1784 .c_longdouble,
1785 => true,
1786
1787 else => false,
1788 };
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,
28201859 };
28211860 }
28221861
......@@ -2829,74 +1868,7 @@ pub const Type = extern union {
28291868 .fn_ccc_void_no_args => .C,
28301869 .function => self.castTag(.function).?.data.cc,
28311870
2832 .f16,
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,
1871 else => unreachable,
29001872 };
29011873 }
29021874
......@@ -2909,74 +1881,7 @@ pub const Type = extern union {
29091881 .fn_ccc_void_no_args => false,
29101882 .function => self.castTag(.function).?.data.is_var_args,
29111883
2912 .f16,
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,
1884 else => unreachable,
29801885 };
29811886 }
29821887
......@@ -2984,84 +1889,41 @@ pub const Type = extern union {
29841889 return switch (self.tag()) {
29851890 .f16,
29861891 .f32,
2987 .f64,
2988 .f128,
2989 .c_longdouble,
2990 .comptime_int,
2991 .comptime_float,
2992 .u8,
2993 .i8,
2994 .u16,
2995 .i16,
2996 .u32,
2997 .i32,
2998 .u64,
2999 .i64,
3000 .u128,
3001 .i128,
3002 .usize,
3003 .isize,
3004 .c_short,
3005 .c_ushort,
3006 .c_int,
3007 .c_uint,
3008 .c_long,
3009 .c_ulong,
3010 .c_longlong,
3011 .c_ulonglong,
3012 .int_unsigned,
3013 .int_signed,
3014 => true,
3015
3016 .c_void,
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,
1892 .f64,
1893 .f128,
1894 .c_longdouble,
1895 .comptime_int,
1896 .comptime_float,
1897 .u8,
1898 .i8,
1899 .u16,
1900 .i16,
1901 .u32,
1902 .i32,
1903 .u64,
1904 .i64,
1905 .u128,
1906 .i128,
1907 .usize,
1908 .isize,
1909 .c_short,
1910 .c_ushort,
1911 .c_int,
1912 .c_uint,
1913 .c_long,
1914 .c_ulong,
1915 .c_longlong,
1916 .c_ulonglong,
1917 .int_unsigned,
1918 .int_signed,
1919 => true,
1920
1921 else => false,
30601922 };
30611923 }
30621924
3063 pub fn onePossibleValue(self: Type) ?Value {
3064 var ty = self;
1925 pub fn onePossibleValue(starting_type: Type) ?Value {
1926 var ty = starting_type;
30651927 while (true) switch (ty.tag()) {
30661928 .f16,
30671929 .f32,
......@@ -3118,9 +1980,32 @@ pub const Type = extern union {
31181980 => return null,
31191981
31201982 .@"struct" => {
3121 log.warn("TODO implement Type.onePossibleValue for structs", .{});
3122 return null;
1983 const s = ty.castTag(.@"struct").?.data;
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 }
31232007 },
2008 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
31242009
31252010 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
31262011 .void => return Value.initTag(.void_value),
......@@ -3160,87 +2045,6 @@ pub const Type = extern union {
31602045 };
31612046 }
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
32442048 pub fn isIndexable(self: Type) bool {
32452049 const zig_tag = self.zigTypeTag();
32462050 // TODO tuples are indexable
......@@ -3248,83 +2052,15 @@ pub const Type = extern union {
32482052 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
32492053 }
32502054
3251 /// Asserts that the type is a container. (note: ErrorSet is not a container).
3252 pub fn getContainerScope(self: Type) *Module.Scope.Container {
2055 /// Returns null if the type has no container.
2056 pub fn getContainerScope(self: Type) ?*Module.Scope.Container {
32532057 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
33252058 .@"struct" => &self.castTag(.@"struct").?.data.container,
2059 .enum_full => &self.castTag(.enum_full).?.data.container,
33262060 .empty_struct => self.castTag(.empty_struct).?.data,
33272061 .@"opaque" => &self.castTag(.@"opaque").?.data,
2062
2063 else => null,
33282064 };
33292065 }
33302066
......@@ -3383,8 +2119,144 @@ pub const Type = extern union {
33832119 }
33842120 }
33852121
3386 pub fn isExhaustiveEnum(ty: Type) bool {
3387 return false; // TODO
2122 pub fn isNonexhaustiveEnum(ty: Type) bool {
2123 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 }
33882260 }
33892261
33902262 /// This enum does not directly correspond to `std.builtin.TypeId` because
......@@ -3476,6 +2348,9 @@ pub const Type = extern union {
34762348 empty_struct,
34772349 @"opaque",
34782350 @"struct",
2351 enum_simple,
2352 enum_full,
2353 enum_nonexhaustive,
34792354
34802355 pub const last_no_payload_tag = Tag.inferred_alloc_const;
34812356 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -3562,6 +2437,8 @@ pub const Type = extern union {
35622437 .error_set_single => Payload.Name,
35632438 .@"opaque" => Payload.Opaque,
35642439 .@"struct" => Payload.Struct,
2440 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
2441 .enum_simple => Payload.EnumSimple,
35652442 .empty_struct => Payload.ContainerScope,
35662443 };
35672444 }
......@@ -3699,6 +2576,16 @@ pub const Type = extern union {
36992576 base: Payload = .{ .tag = .@"struct" },
37002577 data: *Module.Struct,
37012578 };
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 };
37022589 };
37032590};
37042591
src/value.zig+57-780
......@@ -103,6 +103,8 @@ pub const Value = extern union {
103103 float_64,
104104 float_128,
105105 enum_literal,
106 /// A specific enum tag, indicated by the field index (declaration order).
107 enum_field_index,
106108 @"error",
107109 error_union,
108110 /// This is a special value that tracks a set of types that have been stored
......@@ -186,6 +188,8 @@ pub const Value = extern union {
186188 .enum_literal,
187189 => Payload.Bytes,
188190
191 .enum_field_index => Payload.U32,
192
189193 .ty => Payload.Ty,
190194 .int_type => Payload.IntType,
191195 .int_u64 => Payload.U64,
......@@ -394,6 +398,7 @@ pub const Value = extern union {
394398 };
395399 return Value{ .ptr_otherwise = &new_payload.base };
396400 },
401 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
397402 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
398403 .error_union => {
399404 const payload = self.castTag(.error_union).?;
......@@ -416,6 +421,8 @@ pub const Value = extern union {
416421 return Value{ .ptr_otherwise = &new_payload.base };
417422 }
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.
419426 pub fn format(
420427 self: Value,
421428 comptime fmt: []const u8,
......@@ -506,6 +513,7 @@ pub const Value = extern union {
506513 },
507514 .empty_array => return out_stream.writeAll(".{}"),
508515 .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}),
509517 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),
510518 .repeated => {
511519 try out_stream.writeAll("(repeated) ");
......@@ -626,6 +634,7 @@ pub const Value = extern union {
626634 .float_64,
627635 .float_128,
628636 .enum_literal,
637 .enum_field_index,
629638 .@"error",
630639 .error_union,
631640 .empty_struct_value,
......@@ -638,76 +647,6 @@ pub const Value = extern union {
638647 /// Asserts the value is an integer.
639648 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
640649 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
711650 .zero,
712651 .bool_false,
713652 => return BigIntMutable.init(&space.limbs, 0).toConst(),
......@@ -720,82 +659,15 @@ pub const Value = extern union {
720659 .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
721660 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
722661 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
662
663 .undef => unreachable,
664 else => unreachable,
723665 }
724666 }
725667
726668 /// Asserts the value is an integer and it fits in a u64
727669 pub fn toUnsignedInt(self: Value) u64 {
728670 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
799671 .zero,
800672 .bool_false,
801673 => return 0,
......@@ -808,82 +680,15 @@ pub const Value = extern union {
808680 .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
809681 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
810682 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
683
684 .undef => unreachable,
685 else => unreachable,
811686 }
812687 }
813688
814689 /// Asserts the value is an integer and it fits in a i64
815690 pub fn toSignedInt(self: Value) i64 {
816691 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
887692 .zero,
888693 .bool_false,
889694 => return 0,
......@@ -896,6 +701,9 @@ pub const Value = extern union {
896701 .int_i64 => return self.castTag(.int_i64).?.data,
897702 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
898703 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
704
705 .undef => unreachable,
706 else => unreachable,
899707 }
900708 }
901709
......@@ -929,75 +737,6 @@ pub const Value = extern union {
929737 /// Returns the number of bits the value requires to represent stored in twos complement form.
930738 pub fn intBitCountTwosComp(self: Value) usize {
931739 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
1001740 .zero,
1002741 .bool_false,
1003742 => return 0,
......@@ -1016,80 +755,14 @@ pub const Value = extern union {
1016755 },
1017756 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1018757 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
758
759 else => unreachable,
1019760 }
1020761 }
1021762
1022763 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
1023764 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
1024765 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
1093766 .zero,
1094767 .undef,
1095768 .bool_false,
......@@ -1144,6 +817,8 @@ pub const Value = extern union {
1144817 .ComptimeInt => return true,
1145818 else => unreachable,
1146819 },
820
821 else => unreachable,
1147822 }
1148823 }
1149824
......@@ -1180,77 +855,6 @@ pub const Value = extern union {
1180855 /// Asserts the value is a float
1181856 pub fn floatHasFraction(self: Value) bool {
1182857 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
1254858 .zero,
1255859 .one,
1256860 => false,
......@@ -1260,76 +864,13 @@ pub const Value = extern union {
1260864 .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
1261865 // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
1262866 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
867
868 else => unreachable,
1263869 };
1264870 }
1265871
1266872 pub fn orderAgainstZero(lhs: Value) std.math.Order {
1267873 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
1333874 .zero,
1334875 .bool_false,
1335876 => .eq,
......@@ -1347,6 +888,8 @@ pub const Value = extern union {
1347888 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
1348889 .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
1349890 .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
891
892 else => unreachable,
1350893 };
1351894 }
1352895
......@@ -1396,10 +939,12 @@ pub const Value = extern union {
1396939 }
1397940
1398941 pub fn eql(a: Value, b: Value) bool {
1399 if (a.tag() == b.tag()) {
1400 if (a.tag() == .void_value or a.tag() == .null_value) {
942 const a_tag = a.tag();
943 const b_tag = b.tag();
944 if (a_tag == b_tag) {
945 if (a_tag == .void_value or a_tag == .null_value) {
1401946 return true;
1402 } else if (a.tag() == .enum_literal) {
947 } else if (a_tag == .enum_literal) {
1403948 const a_name = a.castTag(.enum_literal).?.data;
1404949 const b_name = b.castTag(.enum_literal).?.data;
1405950 return std.mem.eql(u8, a_name, b_name);
......@@ -1416,6 +961,10 @@ pub const Value = extern union {
1416961 return compare(a, .eq, b);
1417962 }
1418963
964 pub fn hash_u32(self: Value) u32 {
965 return @truncate(u32, self.hash());
966 }
967
1419968 pub fn hash(self: Value) u64 {
1420969 var hasher = std.hash.Wyhash.init(0);
1421970
......@@ -1493,11 +1042,18 @@ pub const Value = extern union {
14931042 .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),
14941043 .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
14971049 .enum_literal => {
14981050 const payload = self.castTag(.enum_literal).?;
14991051 hasher.update(payload.data);
15001052 },
1053 .enum_field_index => {
1054 const payload = self.castTag(.enum_field_index).?;
1055 std.hash.autoHash(&hasher, payload.data);
1056 },
15011057 .bytes => {
15021058 const payload = self.castTag(.bytes).?;
15031059 hasher.update(payload.data);
......@@ -1573,80 +1129,6 @@ pub const Value = extern union {
15731129 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
15741130 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
15751131 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
16501132 .ref_val => self.castTag(.ref_val).?.data,
16511133 .decl_ref => self.castTag(.decl_ref).?.data.value(),
16521134 .elem_ptr => {
......@@ -1654,6 +1136,8 @@ pub const Value = extern union {
16541136 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
16551137 return array_val.elemValue(allocator, elem_ptr.index);
16561138 },
1139
1140 else => unreachable,
16571141 };
16581142 }
16591143
......@@ -1661,86 +1145,14 @@ pub const Value = extern union {
16611145 /// or an unknown-length pointer, and returns the element value at the index.
16621146 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
16631147 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
17381148 .empty_array => unreachable, // out of bounds array index
17391149
17401150 .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
17411151
17421152 // No matter the index; all the elements are the same!
17431153 .repeated => return self.castTag(.repeated).?.data,
1154
1155 else => unreachable,
17441156 }
17451157 }
17461158
......@@ -1766,161 +1178,18 @@ pub const Value = extern union {
17661178 /// Valid for all types. Asserts the value is not undefined and not unreachable.
17671179 pub fn isNull(self: Value) bool {
17681180 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
18421181 .undef => unreachable,
18431182 .unreachable_value => unreachable,
18441183 .inferred_alloc => unreachable,
18451184 .null_value => true,
1185
1186 else => false,
18461187 };
18471188 }
18481189
18491190 /// Valid for all types. Asserts the value is not undefined and not unreachable.
18501191 pub fn getError(self: Value) ?[]const u8 {
18511192 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
19241193 .error_union => {
19251194 const data = self.castTag(.error_union).?.data;
19261195 return if (data.tag() == .@"error")
......@@ -1932,6 +1201,8 @@ pub const Value = extern union {
19321201 .undef => unreachable,
19331202 .unreachable_value => unreachable,
19341203 .inferred_alloc => unreachable,
1204
1205 else => null,
19351206 };
19361207 }
19371208 /// Valid for all types. Asserts the value is not undefined.
......@@ -2021,6 +1292,7 @@ pub const Value = extern union {
20211292 .float_128,
20221293 .void_value,
20231294 .enum_literal,
1295 .enum_field_index,
20241296 .@"error",
20251297 .error_union,
20261298 .empty_struct_value,
......@@ -2038,6 +1310,11 @@ pub const Value = extern union {
20381310 pub const Payload = struct {
20391311 tag: Tag,
20401312
1313 pub const U32 = struct {
1314 base: Payload,
1315 data: u32,
1316 };
1317
20411318 pub const U64 = struct {
20421319 base: Payload,
20431320 data: u64,
src/zig_clang.cpp+34
......@@ -2060,6 +2060,11 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {
20602060 return casted->isRecordType();
20612061}
20622062
2063bool ZigClangType_isVectorType(const ZigClangType *self) {
2064 auto casted = reinterpret_cast<const clang::Type *>(self);
2065 return casted->isVectorType();
2066}
2067
20632068bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,
20642069 const struct ZigClangASTContext *ctx)
20652070{
......@@ -2752,6 +2757,16 @@ struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBina
27522757 return bitcast(casted->getType());
27532758}
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
27552770struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *self) {
27562771 auto casted = reinterpret_cast<const clang::DecayedType *>(self);
27572772 return bitcast(casted->getDecayedType());
......@@ -2857,6 +2872,16 @@ struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl
28572872 return bitcast(casted->getType());
28582873}
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
28602885const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) {
28612886 auto casted = reinterpret_cast<const clang::WhileStmt *>(self);
28622887 return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());
......@@ -2936,6 +2961,15 @@ struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(
29362961 return bitcast(casted->getBeginLoc());
29372962}
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
29402974enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(
29412975 const struct ZigClangUnaryExprOrTypeTraitExpr *self)
src/zig_clang.h+10
......@@ -1071,6 +1071,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
10711071ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
10721072ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
10731073ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
1074ZIG_EXTERN_C bool ZigClangType_isVectorType(const struct ZigClangType *self);
10741075ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);
10751076ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);
10761077ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
......@@ -1206,6 +1207,9 @@ ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const stru
12061207ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *);
12071208ZIG_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
12091213ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *);
12101214
12111215ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *);
......@@ -1235,6 +1239,9 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(con
12351239
12361240ZIG_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
12381245ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *);
12391246ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *);
12401247
......@@ -1259,6 +1266,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryExprOrTypeTraitExpr_getTypeOfA
12591266ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(const struct ZigClangUnaryExprOrTypeTraitExpr *);
12601267ZIG_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
12621272ZIG_EXTERN_C const struct ZigClangStmt *ZigClangDoStmt_getBody(const struct ZigClangDoStmt *);
12631273ZIG_EXTERN_C const struct ZigClangExpr *ZigClangDoStmt_getCond(const struct ZigClangDoStmt *);
12641274
src/zir.zig+118-23
......@@ -37,8 +37,6 @@ pub const Code = struct {
3737 string_bytes: []u8,
3838 /// The meaning of this data is determined by `Inst.Tag` value.
3939 extra: []u32,
40 /// Used for decl_val and decl_ref instructions.
41 decls: []*Module.Decl,
4240
4341 /// Returns the requested data, as well as the new index which is at the start of the
4442 /// trailers for the object.
......@@ -78,7 +76,6 @@ pub const Code = struct {
7876 code.instructions.deinit(gpa);
7977 gpa.free(code.string_bytes);
8078 gpa.free(code.extra);
81 gpa.free(code.decls);
8279 code.* = undefined;
8380 }
8481
......@@ -133,7 +130,7 @@ pub const Inst = struct {
133130 /// Same as `alloc` except mutable.
134131 alloc_mut,
135132 /// Same as `alloc` except the type is inferred.
136 /// The operand is unused.
133 /// Uses the `node` union field.
137134 alloc_inferred,
138135 /// Same as `alloc_inferred` except mutable.
139136 alloc_inferred_mut,
......@@ -267,9 +264,6 @@ pub const Inst = struct {
267264 /// only the taken branch is analyzed. The then block and else block must
268265 /// terminate with an "inline" variant of a noreturn instruction.
269266 condbr_inline,
270 /// A comptime known value.
271 /// Uses the `const` union field.
272 @"const",
273267 /// A struct type definition. Contains references to ZIR instructions for
274268 /// the field types, defaults, and alignments.
275269 /// Uses the `pl_node` union field. Payload is `StructDecl`.
......@@ -286,6 +280,8 @@ pub const Inst = struct {
286280 /// the field value expressions and optional type tag expression.
287281 /// Uses the `pl_node` union field. Payload is `EnumDecl`.
288282 enum_decl,
283 /// Same as `enum_decl`, except the enum is non-exhaustive.
284 enum_decl_nonexhaustive,
289285 /// An opaque type definition. Provides an AST node only.
290286 /// Uses the `node` union field.
291287 opaque_decl,
......@@ -332,12 +328,16 @@ pub const Inst = struct {
332328 error_union_type,
333329 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
334330 error_value,
331 /// Implements the `@export` builtin function.
332 /// Uses the `pl_node` union field. Payload is `Bin`.
333 @"export",
335334 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
336335 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
337336 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
338337 field_ptr,
339338 /// Given a struct or object that contains virtual fields, returns the named field.
340339 /// The field name is stored in string_bytes. Used by a.b syntax.
340 /// This instruction also accepts a pointer.
341341 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
342342 field_val,
343343 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
......@@ -363,11 +363,19 @@ pub const Inst = struct {
363363 fn_type_cc,
364364 /// Same as `fn_type_cc` but the function is variadic.
365365 fn_type_cc_var_args,
366 /// Implements the `@hasDecl` builtin.
367 /// Uses the `pl_node` union field. Payload is `Bin`.
368 has_decl,
366369 /// `@import(operand)`.
367370 /// Uses the `un_node` field.
368371 import,
369372 /// Integer literal that fits in a u64. Uses the int union value.
370373 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,
371379 /// Convert an integer value to another integer type, asserting that the destination type
372380 /// can hold the same mathematical value.
373381 /// Uses the `pl_node` field. AST is the `@intCast` syntax.
......@@ -659,11 +667,28 @@ pub const Inst = struct {
659667 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
660668 /// initialization expression, and emits compile errors for duplicate fields
661669 /// 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.
662672 /// Uses the `pl_node` field. Payload is `Block`.
663673 validate_struct_init_ptr,
664674 /// A struct literal with a specified type, with no fields.
665675 /// Uses the `un_node` field.
666676 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
668693 /// Returns whether the instruction is one of the control flow "noreturn" types.
669694 /// Function calls do not count.
......@@ -709,12 +734,12 @@ pub const Inst = struct {
709734 .cmp_gt,
710735 .cmp_neq,
711736 .coerce_result_ptr,
712 .@"const",
713737 .struct_decl,
714738 .struct_decl_packed,
715739 .struct_decl_extern,
716740 .union_decl,
717741 .enum_decl,
742 .enum_decl_nonexhaustive,
718743 .opaque_decl,
719744 .dbg_stmt_node,
720745 .decl_ref,
......@@ -727,6 +752,7 @@ pub const Inst = struct {
727752 .elem_val_node,
728753 .ensure_result_used,
729754 .ensure_result_non_error,
755 .@"export",
730756 .floatcast,
731757 .field_ptr,
732758 .field_val,
......@@ -736,7 +762,10 @@ pub const Inst = struct {
736762 .fn_type_var_args,
737763 .fn_type_cc,
738764 .fn_type_cc_var_args,
765 .has_decl,
739766 .int,
767 .float,
768 .float128,
740769 .intcast,
741770 .int_type,
742771 .is_non_null,
......@@ -819,6 +848,11 @@ pub const Inst = struct {
819848 .switch_block_ref_under_multi,
820849 .validate_struct_init_ptr,
821850 .struct_init_empty,
851 .struct_init,
852 .field_type,
853 .int_to_enum,
854 .enum_to_int,
855 .type_info,
822856 => false,
823857
824858 .@"break",
......@@ -1181,7 +1215,6 @@ pub const Inst = struct {
11811215 }
11821216 },
11831217 bin: Bin,
1184 @"const": *TypedValue,
11851218 /// For strings which may contain null bytes.
11861219 str: struct {
11871220 /// Offset into `string_bytes`.
......@@ -1223,6 +1256,16 @@ pub const Inst = struct {
12231256 /// Offset from Decl AST node index.
12241257 node: i32,
12251258 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 },
12261269 array_type_sentinel: struct {
12271270 len: Ref,
12281271 /// index into extra, points to an `ArrayTypeSentinel`
......@@ -1504,6 +1547,40 @@ pub const Inst = struct {
15041547 tag_type: Ref,
15051548 fields_len: u32,
15061549 };
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 };
15071584};
15081585
15091586pub const SpecialProng = enum { none, @"else", under };
......@@ -1533,12 +1610,11 @@ const Writer = struct {
15331610 .intcast,
15341611 .store,
15351612 .store_to_block_ptr,
1613 .store_to_inferred_ptr,
15361614 => try self.writeBin(stream, inst),
15371615
15381616 .alloc,
15391617 .alloc_mut,
1540 .alloc_inferred,
1541 .alloc_inferred_mut,
15421618 .indexable_ptr_len,
15431619 .bit_not,
15441620 .bool_not,
......@@ -1578,6 +1654,8 @@ const Writer = struct {
15781654 .typeof,
15791655 .typeof_elem,
15801656 .struct_init_empty,
1657 .enum_to_int,
1658 .type_info,
15811659 => try self.writeUnNode(stream, inst),
15821660
15831661 .ref,
......@@ -1591,11 +1669,12 @@ const Writer = struct {
15911669 => try self.writeBoolBr(stream, inst),
15921670
15931671 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
1594 .@"const" => try self.writeConst(stream, inst),
15951672 .param_type => try self.writeParamType(stream, inst),
15961673 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
15971674 .ptr_type => try self.writePtrType(stream, inst),
15981675 .int => try self.writeInt(stream, inst),
1676 .float => try self.writeFloat(stream, inst),
1677 .float128 => try self.writeFloat128(stream, inst),
15991678 .str => try self.writeStr(stream, inst),
16001679 .elided => try stream.writeAll(")"),
16011680 .int_type => try self.writeIntType(stream, inst),
......@@ -1616,6 +1695,9 @@ const Writer = struct {
16161695 .slice_sentinel,
16171696 .union_decl,
16181697 .enum_decl,
1698 .enum_decl_nonexhaustive,
1699 .struct_init,
1700 .field_type,
16191701 => try self.writePlNode(stream, inst),
16201702
16211703 .add,
......@@ -1635,15 +1717,18 @@ const Writer = struct {
16351717 .cmp_gt,
16361718 .cmp_neq,
16371719 .div,
1720 .has_decl,
16381721 .mod_rem,
16391722 .shl,
16401723 .shr,
16411724 .xor,
16421725 .store_node,
16431726 .error_union_type,
1727 .@"export",
16441728 .merge_error_sets,
16451729 .bit_and,
16461730 .bit_or,
1731 .int_to_enum,
16471732 => try self.writePlNodeBin(stream, inst),
16481733
16491734 .call,
......@@ -1701,6 +1786,8 @@ const Writer = struct {
17011786 .ret_type,
17021787 .repeat,
17031788 .repeat_inline,
1789 .alloc_inferred,
1790 .alloc_inferred_mut,
17041791 => try self.writeNode(stream, inst),
17051792
17061793 .error_value,
......@@ -1726,7 +1813,6 @@ const Writer = struct {
17261813
17271814 .bitcast,
17281815 .bitcast_result_ptr,
1729 .store_to_inferred_ptr,
17301816 => try stream.writeAll("TODO)"),
17311817 }
17321818 }
......@@ -1770,15 +1856,6 @@ const Writer = struct {
17701856 try stream.writeAll("TODO)");
17711857 }
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
17821859 fn writeParamType(
17831860 self: *Writer,
17841861 stream: anytype,
......@@ -1816,6 +1893,23 @@ const Writer = struct {
18161893 try stream.print("{d})", .{inst_data});
18171894 }
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
18191913 fn writeStr(
18201914 self: *Writer,
18211915 stream: anytype,
......@@ -2133,7 +2227,8 @@ const Writer = struct {
21332227
21342228 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
21352229 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;
21372232 try stream.print("{s}) ", .{decl.name});
21382233 try self.writeSrc(stream, inst_data.src());
21392234 }
test/run_translated_c.zig+102
......@@ -1308,4 +1308,106 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
13081308 \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted
13091309 \\}
13101310 , "");
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
13111413}
test/stack_traces.zig+173-409
......@@ -3,16 +3,56 @@ const os = std.os;
33const tests = @import("tests.zig");
44
55pub fn addCases(cases: *tests.StackTracesContext) void {
6 const source_return =
7 \\const std = @import("std");
8 \\
6 cases.addCase(.{
7 .name = "return",
8 .source =
99 \\pub fn main() !void {
1010 \\ return error.TheSkyIsFalling;
1111 \\}
12 ;
13 const source_try_return =
14 \\const std = @import("std");
15 \\
12 ,
13 .Debug = .{
14 .expect =
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 =
1656 \\fn foo() !void {
1757 \\ return error.TheSkyIsFalling;
1858 \\}
......@@ -20,10 +60,56 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
2060 \\pub fn main() !void {
2161 \\ try foo();
2262 \\}
23 ;
24 const source_try_try_return_return =
25 \\const std = @import("std");
26 \\
63 ,
64 .Debug = .{
65 .expect =
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 =
27113 \\fn foo() !void {
28114 \\ try bar();
29115 \\}
......@@ -39,9 +125,71 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
39125 \\pub fn main() !void {
40126 \\ try foo();
41127 \\}
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 =
45193 \\const std = @import("std");
46194 \\
47195 \\fn bar() void {
......@@ -54,401 +202,17 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
54202 \\ foo();
55203 \\ return 1;
56204 \\}
57 ;
58
59 switch (std.Target.current.os.tag) {
60 .freebsd => {
61 cases.addCase(
62 "return",
63 source_return,
64 [_][]const u8{
65 // debug
66 \\error: TheSkyIsFalling
67 \\source.zig:4:5: [address] in main (test)
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 );
205 ,
206 .Debug = .{
207 .expect =
208 \\source.zig:7:8: [address] in foo (test)
209 \\ bar();
210 \\ ^
211 \\source.zig:10:8: [address] in main (test)
212 \\ foo();
213 \\ ^
214 \\
215 ,
451216 },
452 else => {},
453 }
217 });
454218}
test/stage2/cbe.zig+315-2
......@@ -280,6 +280,15 @@ pub fn addCases(ctx: *TestContext) !void {
280280 \\}
281281 , "");
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
283292 // Switch expression
284293 case.addCompareOutput(
285294 \\export fn main() c_int {
......@@ -481,6 +490,310 @@ pub fn addCases(ctx: *TestContext) !void {
481490 \\}
482491 , "");
483492 }
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
484797 ctx.c("empty start function", linux_x64,
485798 \\export fn _start() noreturn {
486799 \\ unreachable;
......@@ -489,8 +802,8 @@ pub fn addCases(ctx: *TestContext) !void {
489802 \\ZIG_EXTERN_C zig_noreturn void _start(void);
490803 \\
491804 \\zig_noreturn void _start(void) {
492 \\ zig_breakpoint();
493 \\ zig_unreachable();
805 \\ zig_breakpoint();
806 \\ zig_unreachable();
494807 \\}
495808 \\
496809 );
test/stage2/test.zig+78-2
......@@ -941,6 +941,32 @@ pub fn addCases(ctx: *TestContext) !void {
941941 "",
942942 );
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
944970 // 64bit set stack
945971 case.addCompareOutput(
946972 \\export fn _start() noreturn {
......@@ -1022,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {
10221048 "Hello, World!\n",
10231049 );
10241050 try case.files.append(.{
1025 .src =
1051 .src =
10261052 \\pub fn print() void {
10271053 \\ asm volatile ("syscall"
10281054 \\ :
......@@ -1038,11 +1064,61 @@ pub fn addCases(ctx: *TestContext) !void {
10381064 .path = "print.zig",
10391065 });
10401066 }
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
10421105 ctx.compileError("function redefinition", linux_x64,
1106 \\// dummy comment
10431107 \\fn entry() void {}
10441108 \\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
10471123 ctx.compileError("compileError", linux_x64,
10481124 \\export fn _start() noreturn {
test/stage2/wasm.zig+132
......@@ -121,6 +121,138 @@ pub fn addCases(ctx: *TestContext) !void {
121121 \\ return x + y;
122122 \\}
123123 , "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");
124256 }
125257
126258 {
test/tests.zig+98-33
......@@ -566,42 +566,87 @@ pub const StackTracesContext = struct {
566566
567567 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(
570608 self: *StackTracesContext,
571609 name: []const u8,
572610 source: []const u8,
573 expect: Expect,
611 mode: Mode,
612 mode_config: anytype,
574613 ) void {
575 const b = self.b;
576
577 for (self.modes) |mode| {
578 const expect_for_mode = expect[@enumToInt(mode)];
579 if (expect_for_mode.len == 0) continue;
580
581 const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s} ({s})", .{
582 "stack-trace",
583 name,
584 @tagName(mode),
585 }) catch unreachable;
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 );
614 if (@hasField(@TypeOf(mode_config), "exclude")) {
615 if (mode_config.exclude.exclude()) return;
616 }
617 if (@hasField(@TypeOf(mode_config), "exclude_arch")) {
618 const exclude_arch: []const builtin.Cpu.Arch = &mode_config.exclude_arch;
619 for (exclude_arch) |arch| if (arch == builtin.cpu.arch) return;
620 }
621 if (@hasField(@TypeOf(mode_config), "exclude_os")) {
622 const exclude_os: []const builtin.Os.Tag = &mode_config.exclude_os;
623 for (exclude_os) |os| if (os == builtin.os.tag) return;
624 }
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;
604633 }
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);
605650 }
606651
607652 const RunAndCompareStep = struct {
......@@ -703,6 +748,7 @@ pub const StackTracesContext = struct {
703748 // process result
704749 // - keep only basename of source file path
705750 // - replace address with symbolic string
751 // - replace function name with symbolic string when mode != .Debug
706752 // - skip empty lines
707753 const got: []const u8 = got_result: {
708754 var buf = ArrayList(u8).init(b.allocator);
......@@ -711,26 +757,45 @@ pub const StackTracesContext = struct {
711757 var it = mem.split(stderr, "\n");
712758 process_lines: while (it.next()) |line| {
713759 if (line.len == 0) continue;
714 const delims = [_][]const u8{ ":", ":", ":", " in " };
715 var marks = [_]usize{0} ** 4;
716760 // offset search past `[drive]:` on windows
717761 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;
718765 for (delims) |delim, i| {
719766 marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {
767 // unexpected pattern: emit raw line and cont
720768 try buf.appendSlice(line);
721769 try buf.appendSlice("\n");
722770 continue :process_lines;
723771 };
724772 pos = marks[i] + delim.len;
725773 }
774 // locate source basename
726775 pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse {
776 // unexpected pattern: emit raw line and cont
727777 try buf.appendSlice(line);
728778 try buf.appendSlice("\n");
729779 continue :process_lines;
730780 };
781 // end processing if source basename changes
782 if (!mem.eql(u8, "source.zig", line[pos + 1 .. marks[0]])) break;
783 // emit substituted line
731784 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);
732785 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 }
734799 try buf.appendSlice("\n");
735800 }
736801 break :got_result buf.toOwnedSlice();
test/translate_c.zig+8
......@@ -2529,6 +2529,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
25292529 \\}
25302530 });
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
25322540 cases.add("logical and, logical or",
25332541 \\int max(int a, int b) {
25342542 \\ if (a < b || a == b)